]> Untitled Git - lemmy-ui.git/blob - src/shared/components/communities.tsx
Somewhat working webpack. Sponsors and communities pages done.
[lemmy-ui.git] / src / shared / components / communities.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Helmet } from 'inferno-helmet';
3 import { Subscription } from 'rxjs';
4 import { retryWhen, delay, take } from 'rxjs/operators';
5 import {
6   UserOperation,
7   Community,
8   ListCommunitiesResponse,
9   CommunityResponse,
10   FollowCommunityForm,
11   ListCommunitiesForm,
12   SortType,
13   WebSocketJsonResponse,
14   GetSiteResponse,
15   Site,
16 } from 'lemmy-js-client';
17 import { WebSocketService } from '../services';
18 import {
19   wsJsonToRes,
20   toast,
21   getPageFromProps,
22   isBrowser,
23   lemmyHttp,
24   setAuth,
25 } from '../utils';
26 import { CommunityLink } from './community-link';
27 import { i18n } from '../i18next';
28 import { IsoData } from 'shared/interfaces';
29
30 const communityLimit = 100;
31
32 interface CommunitiesState {
33   communities: Community[];
34   page: number;
35   loading: boolean;
36   site: Site;
37 }
38
39 interface CommunitiesProps {
40   page: number;
41 }
42
43 export class Communities extends Component<any, CommunitiesState> {
44   private subscription: Subscription;
45   private emptyState: CommunitiesState = {
46     communities: [],
47     loading: true,
48     page: getPageFromProps(this.props),
49     site: undefined,
50   };
51
52   constructor(props: any, context: any) {
53     super(props, context);
54     this.state = this.emptyState;
55     let isoData: IsoData;
56
57     if (isBrowser()) {
58       this.subscription = WebSocketService.Instance.subject
59         .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
60         .subscribe(
61           msg => this.parseMessage(msg),
62           err => console.error(err),
63           () => console.log('complete')
64         );
65       isoData = window.isoData;
66     } else {
67       isoData = this.context.router.staticContext;
68     }
69
70     this.state.site = isoData.site.site;
71
72     // Only fetch the data if coming from another route
73     if (isoData.path == this.context.router.route.match.path) {
74       this.state.communities = isoData.routeData[0].communities;
75       this.state.loading = false;
76     } else {
77       this.refetch();
78     }
79   }
80
81   componentWillUnmount() {
82     if (isBrowser()) {
83       this.subscription.unsubscribe();
84     }
85   }
86
87   static getDerivedStateFromProps(props: any): CommunitiesProps {
88     return {
89       page: getPageFromProps(props),
90     };
91   }
92
93   componentDidUpdate(_: any, lastState: CommunitiesState) {
94     if (lastState.page !== this.state.page) {
95       this.setState({ loading: true });
96       this.refetch();
97     }
98   }
99
100   get documentTitle(): string {
101     if (this.state.site) {
102       return `${i18n.t('communities')} - ${this.state.site.name}`;
103     } else {
104       return 'Lemmy';
105     }
106   }
107
108   render() {
109     return (
110       <div class="container">
111         <Helmet title={this.documentTitle} />
112         {this.state.loading ? (
113           <h5 class="">
114             <svg class="icon icon-spinner spin">
115               <use xlinkHref="#icon-spinner"></use>
116             </svg>
117           </h5>
118         ) : (
119           <div>
120             <h5>{i18n.t('list_of_communities')}</h5>
121             <div class="table-responsive">
122               <table id="community_table" class="table table-sm table-hover">
123                 <thead class="pointer">
124                   <tr>
125                     <th>{i18n.t('name')}</th>
126                     <th>{i18n.t('category')}</th>
127                     <th class="text-right">{i18n.t('subscribers')}</th>
128                     <th class="text-right d-none d-lg-table-cell">
129                       {i18n.t('posts')}
130                     </th>
131                     <th class="text-right d-none d-lg-table-cell">
132                       {i18n.t('comments')}
133                     </th>
134                     <th></th>
135                   </tr>
136                 </thead>
137                 <tbody>
138                   {this.state.communities.map(community => (
139                     <tr>
140                       <td>
141                         <CommunityLink community={community} />
142                       </td>
143                       <td>{community.category_name}</td>
144                       <td class="text-right">
145                         {community.number_of_subscribers}
146                       </td>
147                       <td class="text-right d-none d-lg-table-cell">
148                         {community.number_of_posts}
149                       </td>
150                       <td class="text-right d-none d-lg-table-cell">
151                         {community.number_of_comments}
152                       </td>
153                       <td class="text-right">
154                         {community.subscribed ? (
155                           <span
156                             class="pointer btn-link"
157                             onClick={linkEvent(
158                               community.id,
159                               this.handleUnsubscribe
160                             )}
161                           >
162                             {i18n.t('unsubscribe')}
163                           </span>
164                         ) : (
165                           <span
166                             class="pointer btn-link"
167                             onClick={linkEvent(
168                               community.id,
169                               this.handleSubscribe
170                             )}
171                           >
172                             {i18n.t('subscribe')}
173                           </span>
174                         )}
175                       </td>
176                     </tr>
177                   ))}
178                 </tbody>
179               </table>
180             </div>
181             {this.paginator()}
182           </div>
183         )}
184       </div>
185     );
186   }
187
188   paginator() {
189     return (
190       <div class="mt-2">
191         {this.state.page > 1 && (
192           <button
193             class="btn btn-secondary mr-1"
194             onClick={linkEvent(this, this.prevPage)}
195           >
196             {i18n.t('prev')}
197           </button>
198         )}
199
200         {this.state.communities.length > 0 && (
201           <button
202             class="btn btn-secondary"
203             onClick={linkEvent(this, this.nextPage)}
204           >
205             {i18n.t('next')}
206           </button>
207         )}
208       </div>
209     );
210   }
211
212   updateUrl(paramUpdates: CommunitiesProps) {
213     const page = paramUpdates.page || this.state.page;
214     this.props.history.push(`/communities/page/${page}`);
215   }
216
217   nextPage(i: Communities) {
218     i.updateUrl({ page: i.state.page + 1 });
219   }
220
221   prevPage(i: Communities) {
222     i.updateUrl({ page: i.state.page - 1 });
223   }
224
225   handleUnsubscribe(communityId: number) {
226     let form: FollowCommunityForm = {
227       community_id: communityId,
228       follow: false,
229     };
230     WebSocketService.Instance.followCommunity(form);
231   }
232
233   handleSubscribe(communityId: number) {
234     let form: FollowCommunityForm = {
235       community_id: communityId,
236       follow: true,
237     };
238     WebSocketService.Instance.followCommunity(form);
239   }
240
241   refetch() {
242     let listCommunitiesForm: ListCommunitiesForm = {
243       sort: SortType.TopAll,
244       limit: communityLimit,
245       page: this.state.page,
246     };
247
248     WebSocketService.Instance.listCommunities(listCommunitiesForm);
249   }
250
251   static fetchInitialData(auth: string, path: string): Promise<any>[] {
252     let pathSplit = path.split('/');
253     let page = pathSplit[2] ? Number(pathSplit[2]) : 1;
254     let listCommunitiesForm: ListCommunitiesForm = {
255       sort: SortType.TopAll,
256       limit: communityLimit,
257       page,
258     };
259     setAuth(listCommunitiesForm, auth);
260
261     return [lemmyHttp.listCommunities(listCommunitiesForm)];
262   }
263
264   parseMessage(msg: WebSocketJsonResponse) {
265     console.log(msg);
266     let res = wsJsonToRes(msg);
267     if (msg.error) {
268       toast(i18n.t(msg.error), 'danger');
269       return;
270     } else if (res.op == UserOperation.ListCommunities) {
271       let data = res.data as ListCommunitiesResponse;
272       this.state.communities = data.communities;
273       this.state.communities.sort(
274         (a, b) => b.number_of_subscribers - a.number_of_subscribers
275       );
276       this.state.loading = false;
277       window.scrollTo(0, 0);
278       this.setState(this.state);
279     } else if (res.op == UserOperation.FollowCommunity) {
280       let data = res.data as CommunityResponse;
281       let found = this.state.communities.find(c => c.id == data.community.id);
282       found.subscribed = data.community.subscribed;
283       found.number_of_subscribers = data.community.number_of_subscribers;
284       this.setState(this.state);
285     } else if (res.op == UserOperation.GetSite) {
286       let data = res.data as GetSiteResponse;
287       this.state.site = data.site;
288       this.setState(this.state);
289     }
290   }
291 }