]> Untitled Git - lemmy.git/blob - ui/src/components/sidebar.tsx
Adding user avatars / icons. Requires pictshare.
[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, pictshareAvatarThumbnail } 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.avatar && (
198                       <img
199                         height="32"
200                         width="32"
201                         src={pictshareAvatarThumbnail(mod.avatar)}
202                         class="rounded-circle mr-1"
203                       />
204                     )}
205                     <span>{mod.user_name}</span>
206                   </Link>
207                 </li>
208               ))}
209             </ul>
210             <Link
211               class={`btn btn-sm btn-secondary btn-block mb-3 ${(community.deleted ||
212                 community.removed) &&
213                 'no-click'}`}
214               to={`/create_post?community=${community.name}`}
215             >
216               <T i18nKey="create_a_post">#</T>
217             </Link>
218             <div>
219               {community.subscribed ? (
220                 <button
221                   class="btn btn-sm btn-secondary btn-block"
222                   onClick={linkEvent(community.id, this.handleUnsubscribe)}
223                 >
224                   <T i18nKey="unsubscribe">#</T>
225                 </button>
226               ) : (
227                 <button
228                   class="btn btn-sm btn-secondary btn-block"
229                   onClick={linkEvent(community.id, this.handleSubscribe)}
230                 >
231                   <T i18nKey="subscribe">#</T>
232                 </button>
233               )}
234             </div>
235           </div>
236         </div>
237         {community.description && (
238           <div class="card border-secondary">
239             <div class="card-body">
240               <div
241                 className="md-div"
242                 dangerouslySetInnerHTML={mdToHtml(community.description)}
243               />
244             </div>
245           </div>
246         )}
247       </div>
248     );
249   }
250
251   handleEditClick(i: Sidebar) {
252     i.state.showEdit = true;
253     i.setState(i.state);
254   }
255
256   handleEditCommunity() {
257     this.state.showEdit = false;
258     this.setState(this.state);
259   }
260
261   handleEditCancel() {
262     this.state.showEdit = false;
263     this.setState(this.state);
264   }
265
266   handleDeleteClick(i: Sidebar) {
267     event.preventDefault();
268     let deleteForm: CommunityFormI = {
269       name: i.props.community.name,
270       title: i.props.community.title,
271       category_id: i.props.community.category_id,
272       edit_id: i.props.community.id,
273       deleted: !i.props.community.deleted,
274       nsfw: i.props.community.nsfw,
275       auth: null,
276     };
277     WebSocketService.Instance.editCommunity(deleteForm);
278   }
279
280   handleUnsubscribe(communityId: number) {
281     let form: FollowCommunityForm = {
282       community_id: communityId,
283       follow: false,
284     };
285     WebSocketService.Instance.followCommunity(form);
286   }
287
288   handleSubscribe(communityId: number) {
289     let form: FollowCommunityForm = {
290       community_id: communityId,
291       follow: true,
292     };
293     WebSocketService.Instance.followCommunity(form);
294   }
295
296   private get amCreator(): boolean {
297     return this.props.community.creator_id == UserService.Instance.user.id;
298   }
299
300   get canMod(): boolean {
301     return (
302       UserService.Instance.user &&
303       this.props.moderators
304         .map(m => m.user_id)
305         .includes(UserService.Instance.user.id)
306     );
307   }
308
309   get canAdmin(): boolean {
310     return (
311       UserService.Instance.user &&
312       this.props.admins.map(a => a.id).includes(UserService.Instance.user.id)
313     );
314   }
315
316   handleModRemoveShow(i: Sidebar) {
317     i.state.showRemoveDialog = true;
318     i.setState(i.state);
319   }
320
321   handleModRemoveReasonChange(i: Sidebar, event: any) {
322     i.state.removeReason = event.target.value;
323     i.setState(i.state);
324   }
325
326   handleModRemoveExpiresChange(i: Sidebar, event: any) {
327     console.log(event.target.value);
328     i.state.removeExpires = event.target.value;
329     i.setState(i.state);
330   }
331
332   handleModRemoveSubmit(i: Sidebar) {
333     event.preventDefault();
334     let deleteForm: CommunityFormI = {
335       name: i.props.community.name,
336       title: i.props.community.title,
337       category_id: i.props.community.category_id,
338       edit_id: i.props.community.id,
339       removed: !i.props.community.removed,
340       reason: i.state.removeReason,
341       expires: getUnixTime(i.state.removeExpires),
342       nsfw: i.props.community.nsfw,
343       auth: null,
344     };
345     WebSocketService.Instance.editCommunity(deleteForm);
346
347     i.state.showRemoveDialog = false;
348     i.setState(i.state);
349   }
350 }