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