]> Untitled Git - lemmy-ui.git/blob - src/shared/components/post/post-listings.tsx
component classes v2
[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 className="post-listings">
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 && <hr className="my-3" />}
100             </>
101           ))
102         ) : (
103           <>
104             <div>{i18n.t("no_posts")}</div>
105             {this.props.showCommunity && (
106               <T i18nKey="subscribe_to_communities">
107                 #<Link to="/communities">#</Link>
108               </T>
109             )}
110           </>
111         )}
112       </div>
113     );
114   }
115
116   removeDuplicates(): PostView[] {
117     // Must use a spread to clone the props, because splice will fail below otherwise.
118     const posts = [...this.props.posts].filter(empty => empty);
119
120     // A map from post url to list of posts (dupes)
121     const urlMap = new Map<string, PostView[]>();
122
123     // Loop over the posts, find ones with same urls
124     for (const pv of posts) {
125       const url = pv.post.url;
126       if (
127         !pv.post.deleted &&
128         !pv.post.removed &&
129         !pv.community.deleted &&
130         !pv.community.removed &&
131         url
132       ) {
133         if (!urlMap.get(url)) {
134           urlMap.set(url, [pv]);
135         } else {
136           urlMap.get(url)?.push(pv);
137         }
138       }
139     }
140
141     // Sort by oldest
142     // Remove the ones that have no length
143     for (const e of urlMap.entries()) {
144       if (e[1].length == 1) {
145         urlMap.delete(e[0]);
146       } else {
147         e[1].sort((a, b) => a.post.published.localeCompare(b.post.published));
148       }
149     }
150
151     for (let i = 0; i < posts.length; i++) {
152       const pv = posts[i];
153       const url = pv.post.url;
154       if (url) {
155         const found = urlMap.get(url);
156         if (found) {
157           // If its the oldest, add
158           if (pv.post.id == found[0].post.id) {
159             this.duplicatesMap.set(pv.post.id, found.slice(1));
160           }
161           // Otherwise, delete it
162           else {
163             posts.splice(i--, 1);
164           }
165         }
166       }
167     }
168
169     return posts;
170   }
171 }