]> Untitled Git - lemmy.git/blob - ui/src/components/sidebar.tsx
Adding show_avatar user setting, and option to send notifications to inbox.
[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                   <T i18nKey="removed">#</T>
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                       <T i18nKey="edit">#</T>
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                       <T i18nKey="remove">#</T>
120                     </span>
121                   ) : (
122                     <span
123                       class="pointer"
124                       onClick={linkEvent(this, this.handleModRemoveSubmit)}
125                     >
126                       <T i18nKey="restore">#</T>
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">
136                     <T i18nKey="reason">#</T>
137                   </label>
138                   <input
139                     type="text"
140                     class="form-control mr-2"
141                     placeholder={i18n.t('optional')}
142                     value={this.state.removeReason}
143                     onInput={linkEvent(this, this.handleModRemoveReasonChange)}
144                   />
145                 </div>
146                 {/* TODO hold off on expires for now */}
147                 {/* <div class="form-group row"> */}
148                 {/*   <label class="col-form-label">Expires</label> */}
149                 {/*   <input type="date" class="form-control mr-2" placeholder={i18n.t('expires')} value={this.state.removeExpires} onInput={linkEvent(this, this.handleModRemoveExpiresChange)} /> */}
150                 {/* </div> */}
151                 <div class="form-group row">
152                   <button type="submit" class="btn btn-secondary">
153                     <T i18nKey="remove_community">#</T>
154                   </button>
155                 </div>
156               </form>
157             )}
158             <ul class="my-1 list-inline">
159               <li className="list-inline-item">
160                 <Link className="badge badge-secondary" to="/communities">
161                   {community.category_name}
162                 </Link>
163               </li>
164               <li className="list-inline-item badge badge-secondary">
165                 <T
166                   i18nKey="number_of_subscribers"
167                   interpolation={{ count: community.number_of_subscribers }}
168                 >
169                   #
170                 </T>
171               </li>
172               <li className="list-inline-item badge badge-secondary">
173                 <T
174                   i18nKey="number_of_posts"
175                   interpolation={{ count: community.number_of_posts }}
176                 >
177                   #
178                 </T>
179               </li>
180               <li className="list-inline-item badge badge-secondary">
181                 <T
182                   i18nKey="number_of_comments"
183                   interpolation={{ count: community.number_of_comments }}
184                 >
185                   #
186                 </T>
187               </li>
188               <li className="list-inline-item">
189                 <Link
190                   className="badge badge-secondary"
191                   to={`/modlog/community/${this.props.community.id}`}
192                 >
193                   <T i18nKey="modlog">#</T>
194                 </Link>
195               </li>
196             </ul>
197             <ul class="list-inline small">
198               <li class="list-inline-item">{i18n.t('mods')}: </li>
199               {this.props.moderators.map(mod => (
200                 <li class="list-inline-item">
201                   <Link class="text-info" to={`/u/${mod.user_name}`}>
202                     {mod.avatar && showAvatars() && (
203                       <img
204                         height="32"
205                         width="32"
206                         src={pictshareAvatarThumbnail(mod.avatar)}
207                         class="rounded-circle mr-1"
208                       />
209                     )}
210                     <span>{mod.user_name}</span>
211                   </Link>
212                 </li>
213               ))}
214             </ul>
215             <Link
216               class={`btn btn-sm btn-secondary btn-block mb-3 ${(community.deleted ||
217                 community.removed) &&
218                 'no-click'}`}
219               to={`/create_post?community=${community.name}`}
220             >
221               <T i18nKey="create_a_post">#</T>
222             </Link>
223             <div>
224               {community.subscribed ? (
225                 <button
226                   class="btn btn-sm btn-secondary btn-block"
227                   onClick={linkEvent(community.id, this.handleUnsubscribe)}
228                 >
229                   <T i18nKey="unsubscribe">#</T>
230                 </button>
231               ) : (
232                 <button
233                   class="btn btn-sm btn-secondary btn-block"
234                   onClick={linkEvent(community.id, this.handleSubscribe)}
235                 >
236                   <T i18nKey="subscribe">#</T>
237                 </button>
238               )}
239             </div>
240           </div>
241         </div>
242         {community.description && (
243           <div class="card border-secondary">
244             <div class="card-body">
245               <div
246                 className="md-div"
247                 dangerouslySetInnerHTML={mdToHtml(community.description)}
248               />
249             </div>
250           </div>
251         )}
252       </div>
253     );
254   }
255
256   handleEditClick(i: Sidebar) {
257     i.state.showEdit = true;
258     i.setState(i.state);
259   }
260
261   handleEditCommunity() {
262     this.state.showEdit = false;
263     this.setState(this.state);
264   }
265
266   handleEditCancel() {
267     this.state.showEdit = false;
268     this.setState(this.state);
269   }
270
271   handleDeleteClick(i: Sidebar) {
272     event.preventDefault();
273     let deleteForm: CommunityFormI = {
274       name: i.props.community.name,
275       title: i.props.community.title,
276       category_id: i.props.community.category_id,
277       edit_id: i.props.community.id,
278       deleted: !i.props.community.deleted,
279       nsfw: i.props.community.nsfw,
280       auth: null,
281     };
282     WebSocketService.Instance.editCommunity(deleteForm);
283   }
284
285   handleUnsubscribe(communityId: number) {
286     let form: FollowCommunityForm = {
287       community_id: communityId,
288       follow: false,
289     };
290     WebSocketService.Instance.followCommunity(form);
291   }
292
293   handleSubscribe(communityId: number) {
294     let form: FollowCommunityForm = {
295       community_id: communityId,
296       follow: true,
297     };
298     WebSocketService.Instance.followCommunity(form);
299   }
300
301   private get amCreator(): boolean {
302     return this.props.community.creator_id == UserService.Instance.user.id;
303   }
304
305   get canMod(): boolean {
306     return (
307       UserService.Instance.user &&
308       this.props.moderators
309         .map(m => m.user_id)
310         .includes(UserService.Instance.user.id)
311     );
312   }
313
314   get canAdmin(): boolean {
315     return (
316       UserService.Instance.user &&
317       this.props.admins.map(a => a.id).includes(UserService.Instance.user.id)
318     );
319   }
320
321   handleModRemoveShow(i: Sidebar) {
322     i.state.showRemoveDialog = true;
323     i.setState(i.state);
324   }
325
326   handleModRemoveReasonChange(i: Sidebar, event: any) {
327     i.state.removeReason = event.target.value;
328     i.setState(i.state);
329   }
330
331   handleModRemoveExpiresChange(i: Sidebar, event: any) {
332     console.log(event.target.value);
333     i.state.removeExpires = event.target.value;
334     i.setState(i.state);
335   }
336
337   handleModRemoveSubmit(i: Sidebar) {
338     event.preventDefault();
339     let deleteForm: CommunityFormI = {
340       name: i.props.community.name,
341       title: i.props.community.title,
342       category_id: i.props.community.category_id,
343       edit_id: i.props.community.id,
344       removed: !i.props.community.removed,
345       reason: i.state.removeReason,
346       expires: getUnixTime(i.state.removeExpires),
347       nsfw: i.props.community.nsfw,
348       auth: null,
349     };
350     WebSocketService.Instance.editCommunity(deleteForm);
351
352     i.state.showRemoveDialog = false;
353     i.setState(i.state);
354   }
355 }