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