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