]> Untitled Git - lemmy.git/blob - ui/src/components/sidebar.tsx
Merge branch 'federation' into dev_1
[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
20 interface SidebarProps {
21   community: Community;
22   moderators: Array<CommunityUser>;
23   admins: Array<UserView>;
24   online: number;
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                   {i18n.t('deleted')}
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" htmlFor="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 badge badge-secondary">
161                 {i18n.t('number_online', { count: this.props.online })}
162               </li>
163               <li className="list-inline-item badge badge-secondary">
164                 {i18n.t('number_of_subscribers', {
165                   count: community.number_of_subscribers,
166                 })}
167               </li>
168               <li className="list-inline-item badge badge-secondary">
169                 {i18n.t('number_of_posts', {
170                   count: community.number_of_posts,
171                 })}
172               </li>
173               <li className="list-inline-item badge badge-secondary">
174                 {i18n.t('number_of_comments', {
175                   count: community.number_of_comments,
176                 })}
177               </li>
178               <li className="list-inline-item">
179                 <Link className="badge badge-secondary" to="/communities">
180                   {community.category_name}
181                 </Link>
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                   {i18n.t('modlog')}
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 && showAvatars() && (
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               {i18n.t('create_a_post')}
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                   {i18n.t('unsubscribe')}
225                 </button>
226               ) : (
227                 <button
228                   class="btn btn-sm btn-secondary btn-block"
229                   onClick={linkEvent(community.id, this.handleSubscribe)}
230                 >
231                   {i18n.t('subscribe')}
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 }