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