]> Untitled Git - lemmy-ui.git/blob - src/shared/components/post/post-listings.tsx
Merge pull request #1304 from ayan4m1/fix/hr-border
[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 {
5   AddAdmin,
6   AddModToCommunity,
7   BanFromCommunity,
8   BanPerson,
9   BlockPerson,
10   CreatePostLike,
11   CreatePostReport,
12   DeletePost,
13   EditPost,
14   FeaturePost,
15   Language,
16   LockPost,
17   PostView,
18   PurgePerson,
19   PurgePost,
20   RemovePost,
21   SavePost,
22   TransferCommunity,
23 } from "lemmy-js-client";
24 import { i18n } from "../../i18next";
25 import { PostListing } from "./post-listing";
26
27 interface PostListingsProps {
28   posts: PostView[];
29   allLanguages: Language[];
30   siteLanguages: number[];
31   showCommunity?: boolean;
32   removeDuplicates?: boolean;
33   enableDownvotes?: boolean;
34   enableNsfw?: boolean;
35   viewOnly?: boolean;
36   onPostEdit(form: EditPost): void;
37   onPostVote(form: CreatePostLike): void;
38   onPostReport(form: CreatePostReport): void;
39   onBlockPerson(form: BlockPerson): void;
40   onLockPost(form: LockPost): void;
41   onDeletePost(form: DeletePost): void;
42   onRemovePost(form: RemovePost): void;
43   onSavePost(form: SavePost): void;
44   onFeaturePost(form: FeaturePost): void;
45   onPurgePerson(form: PurgePerson): void;
46   onPurgePost(form: PurgePost): void;
47   onBanPersonFromCommunity(form: BanFromCommunity): void;
48   onBanPerson(form: BanPerson): void;
49   onAddModToCommunity(form: AddModToCommunity): void;
50   onAddAdmin(form: AddAdmin): void;
51   onTransferCommunity(form: TransferCommunity): void;
52 }
53
54 export class PostListings extends Component<PostListingsProps, any> {
55   duplicatesMap = new Map<number, PostView[]>();
56
57   constructor(props: any, context: any) {
58     super(props, context);
59   }
60
61   get posts() {
62     return this.props.removeDuplicates
63       ? this.removeDuplicates()
64       : this.props.posts;
65   }
66
67   render() {
68     return (
69       <div>
70         {this.posts.length > 0 ? (
71           this.posts.map((post_view, idx) => (
72             <>
73               <PostListing
74                 post_view={post_view}
75                 crossPosts={this.duplicatesMap.get(post_view.post.id)}
76                 showCommunity={this.props.showCommunity}
77                 enableDownvotes={this.props.enableDownvotes}
78                 enableNsfw={this.props.enableNsfw}
79                 viewOnly={this.props.viewOnly}
80                 allLanguages={this.props.allLanguages}
81                 siteLanguages={this.props.siteLanguages}
82                 onPostEdit={this.props.onPostEdit}
83                 onPostVote={this.props.onPostVote}
84                 onPostReport={this.props.onPostReport}
85                 onBlockPerson={this.props.onBlockPerson}
86                 onLockPost={this.props.onLockPost}
87                 onDeletePost={this.props.onDeletePost}
88                 onRemovePost={this.props.onRemovePost}
89                 onSavePost={this.props.onSavePost}
90                 onFeaturePost={this.props.onFeaturePost}
91                 onPurgePerson={this.props.onPurgePerson}
92                 onPurgePost={this.props.onPurgePost}
93                 onBanPersonFromCommunity={this.props.onBanPersonFromCommunity}
94                 onBanPerson={this.props.onBanPerson}
95                 onAddModToCommunity={this.props.onAddModToCommunity}
96                 onAddAdmin={this.props.onAddAdmin}
97                 onTransferCommunity={this.props.onTransferCommunity}
98               />
99               {idx + 1 !== this.posts.length && (
100                 <hr className="my-3 border border-primary" />
101               )}
102             </>
103           ))
104         ) : (
105           <>
106             <div>{i18n.t("no_posts")}</div>
107             {this.props.showCommunity && (
108               <T i18nKey="subscribe_to_communities">
109                 #<Link to="/communities">#</Link>
110               </T>
111             )}
112           </>
113         )}
114       </div>
115     );
116   }
117
118   removeDuplicates(): PostView[] {
119     // Must use a spread to clone the props, because splice will fail below otherwise.
120     const posts = [...this.props.posts].filter(empty => empty);
121
122     // A map from post url to list of posts (dupes)
123     const urlMap = new Map<string, PostView[]>();
124
125     // Loop over the posts, find ones with same urls
126     for (const pv of posts) {
127       const url = pv.post.url;
128       if (
129         !pv.post.deleted &&
130         !pv.post.removed &&
131         !pv.community.deleted &&
132         !pv.community.removed &&
133         url
134       ) {
135         if (!urlMap.get(url)) {
136           urlMap.set(url, [pv]);
137         } else {
138           urlMap.get(url)?.push(pv);
139         }
140       }
141     }
142
143     // Sort by oldest
144     // Remove the ones that have no length
145     for (const e of urlMap.entries()) {
146       if (e[1].length == 1) {
147         urlMap.delete(e[0]);
148       } else {
149         e[1].sort((a, b) => a.post.published.localeCompare(b.post.published));
150       }
151     }
152
153     for (let i = 0; i < posts.length; i++) {
154       const pv = posts[i];
155       const url = pv.post.url;
156       if (url) {
157         const found = urlMap.get(url);
158         if (found) {
159           // If its the oldest, add
160           if (pv.post.id == found[0].post.id) {
161             this.duplicatesMap.set(pv.post.id, found.slice(1));
162           }
163           // Otherwise, delete it
164           else {
165             posts.splice(i--, 1);
166           }
167         }
168       }
169     }
170
171     return posts;
172   }
173 }