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