]> Untitled Git - lemmy.git/blob - ui/src/components/communities.tsx
Merge branch 'master' into master
[lemmy.git] / ui / src / components / communities.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
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 } from '../interfaces';
14 import { WebSocketService } from '../services';
15 import { msgOp } from '../utils';
16 import { i18n } from '../i18next';
17 import { T } from 'inferno-i18next';
18
19 declare const Sortable: any;
20
21 interface CommunitiesState {
22   communities: Array<Community>;
23   page: number;
24   loading: boolean;
25 }
26
27 export class Communities extends Component<any, CommunitiesState> {
28   private subscription: Subscription;
29   private emptyState: CommunitiesState = {
30     communities: [],
31     loading: true,
32     page: this.getPageFromProps(this.props),
33   };
34
35   constructor(props: any, context: any) {
36     super(props, context);
37     this.state = this.emptyState;
38     this.subscription = WebSocketService.Instance.subject
39       .pipe(
40         retryWhen(errors =>
41           errors.pipe(
42             delay(3000),
43             take(10)
44           )
45         )
46       )
47       .subscribe(
48         msg => this.parseMessage(msg),
49         err => console.error(err),
50         () => console.log('complete')
51       );
52
53     this.refetch();
54   }
55
56   getPageFromProps(props: any): number {
57     return props.match.params.page ? Number(props.match.params.page) : 1;
58   }
59
60   componentWillUnmount() {
61     this.subscription.unsubscribe();
62   }
63
64   componentDidMount() {
65     document.title = `${i18n.t('communities')} - ${
66       WebSocketService.Instance.site.name
67     }`;
68   }
69
70   // Necessary for back button for some reason
71   componentWillReceiveProps(nextProps: any) {
72     if (nextProps.history.action == 'POP') {
73       this.state = this.emptyState;
74       this.state.page = this.getPageFromProps(nextProps);
75       this.refetch();
76     }
77   }
78
79   render() {
80     return (
81       <div class="container">
82         {this.state.loading ? (
83           <h5 class="">
84             <svg class="icon icon-spinner spin">
85               <use xlinkHref="#icon-spinner"></use>
86             </svg>
87           </h5>
88         ) : (
89           <div>
90             <h5>
91               <T i18nKey="list_of_communities">#</T>
92             </h5>
93             <div class="table-responsive">
94               <table id="community_table" class="table table-sm table-hover">
95                 <thead class="pointer">
96                   <tr>
97                     <th>
98                       <T i18nKey="name">#</T>
99                     </th>
100                     <th class="d-none d-lg-table-cell">
101                       <T i18nKey="title">#</T>
102                     </th>
103                     <th>
104                       <T i18nKey="category">#</T>
105                     </th>
106                     <th class="text-right">
107                       <T i18nKey="subscribers">#</T>
108                     </th>
109                     <th class="text-right d-none d-lg-table-cell">
110                       <T i18nKey="posts">#</T>
111                     </th>
112                     <th class="text-right d-none d-lg-table-cell">
113                       <T i18nKey="comments">#</T>
114                     </th>
115                     <th></th>
116                   </tr>
117                 </thead>
118                 <tbody>
119                   {this.state.communities.map(community => (
120                     <tr>
121                       <td>
122                         <Link to={`/c/${community.name}`}>
123                           {community.name}
124                         </Link>
125                       </td>
126                       <td class="d-none d-lg-table-cell">{community.title}</td>
127                       <td>{community.category_name}</td>
128                       <td class="text-right">
129                         {community.number_of_subscribers}
130                       </td>
131                       <td class="text-right d-none d-lg-table-cell">
132                         {community.number_of_posts}
133                       </td>
134                       <td class="text-right d-none d-lg-table-cell">
135                         {community.number_of_comments}
136                       </td>
137                       <td class="text-right">
138                         {community.subscribed ? (
139                           <span
140                             class="pointer btn-link"
141                             onClick={linkEvent(
142                               community.id,
143                               this.handleUnsubscribe
144                             )}
145                           >
146                             <T i18nKey="unsubscribe">#</T>
147                           </span>
148                         ) : (
149                           <span
150                             class="pointer btn-link"
151                             onClick={linkEvent(
152                               community.id,
153                               this.handleSubscribe
154                             )}
155                           >
156                             <T i18nKey="subscribe">#</T>
157                           </span>
158                         )}
159                       </td>
160                     </tr>
161                   ))}
162                 </tbody>
163               </table>
164             </div>
165             {this.paginator()}
166           </div>
167         )}
168       </div>
169     );
170   }
171
172   paginator() {
173     return (
174       <div class="mt-2">
175         {this.state.page > 1 && (
176           <button
177             class="btn btn-sm btn-secondary mr-1"
178             onClick={linkEvent(this, this.prevPage)}
179           >
180             <T i18nKey="prev">#</T>
181           </button>
182         )}
183         <button
184           class="btn btn-sm btn-secondary"
185           onClick={linkEvent(this, this.nextPage)}
186         >
187           <T i18nKey="next">#</T>
188         </button>
189       </div>
190     );
191   }
192
193   updateUrl() {
194     this.props.history.push(`/communities/page/${this.state.page}`);
195   }
196
197   nextPage(i: Communities) {
198     i.state.page++;
199     i.setState(i.state);
200     i.updateUrl();
201     i.refetch();
202   }
203
204   prevPage(i: Communities) {
205     i.state.page--;
206     i.setState(i.state);
207     i.updateUrl();
208     i.refetch();
209   }
210
211   handleUnsubscribe(communityId: number) {
212     let form: FollowCommunityForm = {
213       community_id: communityId,
214       follow: false,
215     };
216     WebSocketService.Instance.followCommunity(form);
217   }
218
219   handleSubscribe(communityId: number) {
220     let form: FollowCommunityForm = {
221       community_id: communityId,
222       follow: true,
223     };
224     WebSocketService.Instance.followCommunity(form);
225   }
226
227   refetch() {
228     let listCommunitiesForm: ListCommunitiesForm = {
229       sort: SortType[SortType.TopAll],
230       limit: 100,
231       page: this.state.page,
232     };
233
234     WebSocketService.Instance.listCommunities(listCommunitiesForm);
235   }
236
237   parseMessage(msg: any) {
238     console.log(msg);
239     let op: UserOperation = msgOp(msg);
240     if (msg.error) {
241       alert(i18n.t(msg.error));
242       return;
243     } else if (op == UserOperation.ListCommunities) {
244       let res: ListCommunitiesResponse = msg;
245       this.state.communities = res.communities;
246       this.state.communities.sort(
247         (a, b) => b.number_of_subscribers - a.number_of_subscribers
248       );
249       this.state.loading = false;
250       window.scrollTo(0, 0);
251       this.setState(this.state);
252       let table = document.querySelector('#community_table');
253       Sortable.initTable(table);
254     } else if (op == UserOperation.FollowCommunity) {
255       let res: CommunityResponse = msg;
256       let found = this.state.communities.find(c => c.id == res.community.id);
257       found.subscribed = res.community.subscribed;
258       found.number_of_subscribers = res.community.number_of_subscribers;
259       this.setState(this.state);
260     }
261   }
262 }