]> Untitled Git - lemmy-ui.git/blob - src/shared/components/post/post-listings.tsx
Fixing cross-posts showing on initial load. Fixes #457 (#464)
[lemmy-ui.git] / src / shared / components / post / post-listings.tsx
1 import { Component } from "inferno";
2 import { T } from "inferno-i18next-dess";
3 import { Link } from "inferno-router";
4 import { PostView } from "lemmy-js-client";
5 import { i18n } from "../../i18next";
6 import { PostListing } from "./post-listing";
7
8 interface PostListingsProps {
9   posts: PostView[];
10   showCommunity?: boolean;
11   removeDuplicates?: boolean;
12   enableDownvotes: boolean;
13   enableNsfw: boolean;
14 }
15
16 interface PostListingsState {
17   posts: PostView[];
18 }
19
20 export class PostListings extends Component<
21   PostListingsProps,
22   PostListingsState
23 > {
24   duplicatesMap = new Map<number, PostView[]>();
25
26   private emptyState: PostListingsState = {
27     posts: [],
28   };
29
30   constructor(props: any, context: any) {
31     super(props, context);
32     this.state = this.emptyState;
33     if (this.props.removeDuplicates) {
34       this.state.posts = this.removeDuplicates();
35     } else {
36       this.state.posts = this.props.posts;
37     }
38   }
39
40   render() {
41     return (
42       <div>
43         {this.state.posts.length > 0 ? (
44           this.state.posts.map(post_view => (
45             <>
46               <PostListing
47                 post_view={post_view}
48                 duplicates={this.duplicatesMap.get(post_view.post.id)}
49                 showCommunity={this.props.showCommunity}
50                 enableDownvotes={this.props.enableDownvotes}
51                 enableNsfw={this.props.enableNsfw}
52               />
53               <hr class="my-3" />
54             </>
55           ))
56         ) : (
57           <>
58             <div>{i18n.t("no_posts")}</div>
59             {this.props.showCommunity !== undefined && (
60               <T i18nKey="subscribe_to_communities">
61                 #<Link to="/communities">#</Link>
62               </T>
63             )}
64           </>
65         )}
66       </div>
67     );
68   }
69
70   removeDuplicates(): PostView[] {
71     // Must use a spread to clone the props, because splice will fail below otherwise.
72     let posts = [...this.props.posts];
73
74     // A map from post url to list of posts (dupes)
75     let urlMap = new Map<string, PostView[]>();
76
77     // Loop over the posts, find ones with same urls
78     for (let pv of posts) {
79       if (
80         pv.post.url &&
81         !pv.post.deleted &&
82         !pv.post.removed &&
83         !pv.community.deleted &&
84         !pv.community.removed
85       ) {
86         if (!urlMap.get(pv.post.url)) {
87           urlMap.set(pv.post.url, [pv]);
88         } else {
89           urlMap.get(pv.post.url).push(pv);
90         }
91       }
92     }
93
94     // Sort by oldest
95     // Remove the ones that have no length
96     for (let e of urlMap.entries()) {
97       if (e[1].length == 1) {
98         urlMap.delete(e[0]);
99       } else {
100         e[1].sort((a, b) => a.post.published.localeCompare(b.post.published));
101       }
102     }
103
104     for (let i = 0; i < posts.length; i++) {
105       let pv = posts[i];
106       if (pv.post.url) {
107         let found = urlMap.get(pv.post.url);
108         if (found) {
109           // If its the oldest, add
110           if (pv.post.id == found[0].post.id) {
111             this.duplicatesMap.set(pv.post.id, found.slice(1));
112           }
113           // Otherwise, delete it
114           else {
115             posts.splice(i--, 1);
116           }
117         }
118       }
119     }
120
121     return posts;
122   }
123 }