]> Untitled Git - lemmy.git/blob - ui/src/components/sidebar.tsx
Merge branch 'master' into master
[lemmy.git] / ui / src / components / sidebar.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Link } from 'inferno-router';
3 import {
4   Community,
5   CommunityUser,
6   FollowCommunityForm,
7   CommunityForm as CommunityFormI,
8   UserView,
9 } from '../interfaces';
10 import { WebSocketService, UserService } from '../services';
11 import { mdToHtml, getUnixTime } from '../utils';
12 import { CommunityForm } from './community-form';
13 import { i18n } from '../i18next';
14 import { T } from 'inferno-i18next';
15
16 interface SidebarProps {
17   community: Community;
18   moderators: Array<CommunityUser>;
19   admins: Array<UserView>;
20 }
21
22 interface SidebarState {
23   showEdit: boolean;
24   showRemoveDialog: boolean;
25   removeReason: string;
26   removeExpires: string;
27 }
28
29 export class Sidebar extends Component<SidebarProps, SidebarState> {
30   private emptyState: SidebarState = {
31     showEdit: false,
32     showRemoveDialog: false,
33     removeReason: null,
34     removeExpires: null,
35   };
36
37   constructor(props: any, context: any) {
38     super(props, context);
39     this.state = this.emptyState;
40     this.handleEditCommunity = this.handleEditCommunity.bind(this);
41     this.handleEditCancel = this.handleEditCancel.bind(this);
42   }
43
44   render() {
45     return (
46       <div>
47         {!this.state.showEdit ? (
48           this.sidebar()
49         ) : (
50           <CommunityForm
51             community={this.props.community}
52             onEdit={this.handleEditCommunity}
53             onCancel={this.handleEditCancel}
54           />
55         )}
56       </div>
57     );
58   }
59
60   sidebar() {
61     let community = this.props.community;
62     return (
63       <div>
64         <div class="card border-secondary mb-3">
65           <div class="card-body">
66             <h5 className="mb-0">
67               <span>{community.title}</span>
68               {community.removed && (
69                 <small className="ml-2 text-muted font-italic">
70                   <T i18nKey="removed">#</T>
71                 </small>
72               )}
73               {community.deleted && (
74                 <small className="ml-2 text-muted font-italic">
75                   <T i18nKey="deleted">#</T>
76                 </small>
77               )}
78             </h5>
79             <Link className="text-muted" to={`/c/${community.name}`}>
80               /c/{community.name}
81             </Link>
82             <ul class="list-inline mb-1 text-muted small font-weight-bold">
83               {this.canMod && (
84                 <>
85                   <li className="list-inline-item">
86                     <span
87                       class="pointer"
88                       onClick={linkEvent(this, this.handleEditClick)}
89                     >
90                       <T i18nKey="edit">#</T>
91                     </span>
92                   </li>
93                   {this.amCreator && (
94                     <li className="list-inline-item">
95                       <span
96                         class="pointer"
97                         onClick={linkEvent(this, this.handleDeleteClick)}
98                       >
99                         {!community.deleted
100                           ? i18n.t('delete')
101                           : i18n.t('restore')}
102                       </span>
103                     </li>
104                   )}
105                 </>
106               )}
107               {this.canAdmin && (
108                 <li className="list-inline-item">
109                   {!this.props.community.removed ? (
110                     <span
111                       class="pointer"
112                       onClick={linkEvent(this, this.handleModRemoveShow)}
113                     >
114                       <T i18nKey="remove">#</T>
115                     </span>
116                   ) : (
117                     <span
118                       class="pointer"
119                       onClick={linkEvent(this, this.handleModRemoveSubmit)}
120                     >
121                       <T i18nKey="restore">#</T>
122                     </span>
123                   )}
124                 </li>
125               )}
126             </ul>
127             {this.state.showRemoveDialog && (
128               <form onSubmit={linkEvent(this, this.handleModRemoveSubmit)}>
129                 <div class="form-group row">
130                   <label class="col-form-label">
131                     <T i18nKey="reason">#</T>
132                   </label>
133                   <input
134                     type="text"
135                     class="form-control mr-2"
136                     placeholder={i18n.t('optional')}
137                     value={this.state.removeReason}
138                     onInput={linkEvent(this, this.handleModRemoveReasonChange)}
139                   />
140                 </div>
141                 {/* TODO hold off on expires for now */}
142                 {/* <div class="form-group row"> */}
143                 {/*   <label class="col-form-label">Expires</label> */}
144                 {/*   <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
145                 {/* </div> */}
146                 <div class="form-group row">
147                   <button type="submit" class="btn btn-secondary">
148                     <T i18nKey="remove_community">#</T>
149                   </button>
150                 </div>
151               </form>
152             )}
153             <ul class="my-1 list-inline">
154               <li className="list-inline-item">
155                 <Link className="badge badge-secondary" to="/communities">
156                   {community.category_name}
157                 </Link>
158               </li>
159               <li className="list-inline-item badge badge-secondary">
160                 <T
161                   i18nKey="number_of_subscribers"
162                   interpolation={{ count: community.number_of_subscribers }}
163                 >
164                   #
165                 </T>
166               </li>
167               <li className="list-inline-item badge badge-secondary">
168                 <T
169                   i18nKey="number_of_posts"
170                   interpolation={{ count: community.number_of_posts }}
171                 >
172                   #
173                 </T>
174               </li>
175               <li className="list-inline-item badge badge-secondary">
176                 <T
177                   i18nKey="number_of_comments"
178                   interpolation={{ count: community.number_of_comments }}
179                 >
180                   #
181                 </T>
182               </li>
183               <li className="list-inline-item">
184                 <Link
185                   className="badge badge-secondary"
186                   to={`/modlog/community/${this.props.community.id}`}
187                 >
188                   <T i18nKey="modlog">#</T>
189                 </Link>
190               </li>
191             </ul>
192             <ul class="list-inline small">
193               <li class="list-inline-item">{i18n.t('mods')}: </li>
194               {this.props.moderators.map(mod => (
195                 <li class="list-inline-item">
196                   <Link class="text-info" to={`/u/${mod.user_name}`}>
197                     {mod.user_name}
198                   </Link>
199                 </li>
200               ))}
201             </ul>
202             <Link
203               class={`btn btn-sm btn-secondary btn-block mb-3 ${(community.deleted ||
204                 community.removed) &&
205                 'no-click'}`}
206               to={`/create_post?community=${community.name}`}
207             >
208               <T i18nKey="create_a_post">#</T>
209             </Link>
210             <div>
211               {community.subscribed ? (
212                 <button
213                   class="btn btn-sm btn-secondary btn-block"
214                   onClick={linkEvent(community.id, this.handleUnsubscribe)}
215                 >
216                   <T i18nKey="unsubscribe">#</T>
217                 </button>
218               ) : (
219                 <button
220                   class="btn btn-sm btn-secondary btn-block"
221                   onClick={linkEvent(community.id, this.handleSubscribe)}
222                 >
223                   <T i18nKey="subscribe">#</T>
224                 </button>
225               )}
226             </div>
227           </div>
228         </div>
229         {community.description && (
230           <div class="card border-secondary">
231             <div class="card-body">
232               <div
233                 className="md-div"
234                 dangerouslySetInnerHTML={mdToHtml(community.description)}
235               />
236             </div>
237           </div>
238         )}
239       </div>
240     );
241   }
242
243   handleEditClick(i: Sidebar) {
244     i.state.showEdit = true;
245     i.setState(i.state);
246   }
247
248   handleEditCommunity() {
249     this.state.showEdit = false;
250     this.setState(this.state);
251   }
252
253   handleEditCancel() {
254     this.state.showEdit = false;
255     this.setState(this.state);
256   }
257
258   handleDeleteClick(i: Sidebar) {
259     event.preventDefault();
260     let deleteForm: CommunityFormI = {
261       name: i.props.community.name,
262       title: i.props.community.title,
263       category_id: i.props.community.category_id,
264       edit_id: i.props.community.id,
265       deleted: !i.props.community.deleted,
266       nsfw: i.props.community.nsfw,
267       auth: null,
268     };
269     WebSocketService.Instance.editCommunity(deleteForm);
270   }
271
272   handleUnsubscribe(communityId: number) {
273     let form: FollowCommunityForm = {
274       community_id: communityId,
275       follow: false,
276     };
277     WebSocketService.Instance.followCommunity(form);
278   }
279
280   handleSubscribe(communityId: number) {
281     let form: FollowCommunityForm = {
282       community_id: communityId,
283       follow: true,
284     };
285     WebSocketService.Instance.followCommunity(form);
286   }
287
288   private get amCreator(): boolean {
289     return this.props.community.creator_id == UserService.Instance.user.id;
290   }
291
292   get canMod(): boolean {
293     return (
294       UserService.Instance.user &&
295       this.props.moderators
296         .map(m => m.user_id)
297         .includes(UserService.Instance.user.id)
298     );
299   }
300
301   get canAdmin(): boolean {
302     return (
303       UserService.Instance.user &&
304       this.props.admins.map(a => a.id).includes(UserService.Instance.user.id)
305     );
306   }
307
308   handleModRemoveShow(i: Sidebar) {
309     i.state.showRemoveDialog = true;
310     i.setState(i.state);
311   }
312
313   handleModRemoveReasonChange(i: Sidebar, event: any) {
314     i.state.removeReason = event.target.value;
315     i.setState(i.state);
316   }
317
318   handleModRemoveExpiresChange(i: Sidebar, event: any) {
319     console.log(event.target.value);
320     i.state.removeExpires = event.target.value;
321     i.setState(i.state);
322   }
323
324   handleModRemoveSubmit(i: Sidebar) {
325     event.preventDefault();
326     let deleteForm: CommunityFormI = {
327       name: i.props.community.name,
328       title: i.props.community.title,
329       category_id: i.props.community.category_id,
330       edit_id: i.props.community.id,
331       removed: !i.props.community.removed,
332       reason: i.state.removeReason,
333       expires: getUnixTime(i.state.removeExpires),
334       nsfw: i.props.community.nsfw,
335       auth: null,
336     };
337     WebSocketService.Instance.editCommunity(deleteForm);
338
339     i.state.showRemoveDialog = false;
340     i.setState(i.state);
341   }
342 }