]> Untitled Git - lemmy.git/blob - ui/src/components/community-form.tsx
Removing some commented lines from the dockerfile.
[lemmy.git] / ui / src / components / community-form.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Prompt } from 'inferno-router';
3 import { Subscription } from 'rxjs';
4 import { retryWhen, delay, take } from 'rxjs/operators';
5 import {
6   CommunityForm as CommunityFormI,
7   UserOperation,
8   Category,
9   ListCategoriesResponse,
10   CommunityResponse,
11   GetSiteResponse,
12   WebSocketJsonResponse,
13 } from '../interfaces';
14 import { WebSocketService } from '../services';
15 import {
16   wsJsonToRes,
17   capitalizeFirstLetter,
18   toast,
19   randomStr,
20   setupTribute,
21 } from '../utils';
22 import Tribute from 'tributejs/src/Tribute.js';
23 import autosize from 'autosize';
24 import { i18n } from '../i18next';
25
26 import { Community } from '../interfaces';
27
28 interface CommunityFormProps {
29   community?: Community; // If a community is given, that means this is an edit
30   onCancel?(): any;
31   onCreate?(community: Community): any;
32   onEdit?(community: Community): any;
33 }
34
35 interface CommunityFormState {
36   communityForm: CommunityFormI;
37   categories: Array<Category>;
38   loading: boolean;
39   enable_nsfw: boolean;
40 }
41
42 export class CommunityForm extends Component<
43   CommunityFormProps,
44   CommunityFormState
45 > {
46   private id = `community-form-${randomStr()}`;
47   private tribute: Tribute;
48   private subscription: Subscription;
49
50   private emptyState: CommunityFormState = {
51     communityForm: {
52       name: null,
53       title: null,
54       category_id: null,
55       nsfw: false,
56     },
57     categories: [],
58     loading: false,
59     enable_nsfw: null,
60   };
61
62   constructor(props: any, context: any) {
63     super(props, context);
64
65     this.tribute = setupTribute();
66     this.state = this.emptyState;
67
68     if (this.props.community) {
69       this.state.communityForm = {
70         name: this.props.community.name,
71         title: this.props.community.title,
72         category_id: this.props.community.category_id,
73         description: this.props.community.description,
74         edit_id: this.props.community.id,
75         nsfw: this.props.community.nsfw,
76         auth: null,
77       };
78     }
79
80     this.subscription = WebSocketService.Instance.subject
81       .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
82       .subscribe(
83         msg => this.parseMessage(msg),
84         err => console.error(err),
85         () => console.log('complete')
86       );
87
88     WebSocketService.Instance.listCategories();
89     WebSocketService.Instance.getSite();
90   }
91
92   componentDidMount() {
93     var textarea: any = document.getElementById(this.id);
94     autosize(textarea);
95     this.tribute.attach(textarea);
96     textarea.addEventListener('tribute-replaced', () => {
97       this.state.communityForm.description = textarea.value;
98       this.setState(this.state);
99       autosize.update(textarea);
100     });
101   }
102
103   componentWillUnmount() {
104     this.subscription.unsubscribe();
105   }
106
107   render() {
108     return (
109       <>
110         <Prompt
111           when={
112             !this.state.loading &&
113             (this.state.communityForm.name ||
114               this.state.communityForm.title ||
115               this.state.communityForm.description)
116           }
117           message={i18n.t('block_leaving')}
118         />
119         <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
120           <div class="form-group row">
121             <label class="col-12 col-form-label" htmlFor="community-name">
122               {i18n.t('name')}
123             </label>
124             <div class="col-12">
125               <input
126                 type="text"
127                 id="community-name"
128                 class="form-control"
129                 value={this.state.communityForm.name}
130                 onInput={linkEvent(this, this.handleCommunityNameChange)}
131                 required
132                 minLength={3}
133                 maxLength={20}
134                 pattern="[a-z0-9_]+"
135                 title={i18n.t('community_reqs')}
136               />
137             </div>
138           </div>
139
140           <div class="form-group row">
141             <label class="col-12 col-form-label" htmlFor="community-title">
142               {i18n.t('title')}
143             </label>
144             <div class="col-12">
145               <input
146                 type="text"
147                 id="community-title"
148                 value={this.state.communityForm.title}
149                 onInput={linkEvent(this, this.handleCommunityTitleChange)}
150                 class="form-control"
151                 required
152                 minLength={3}
153                 maxLength={100}
154               />
155             </div>
156           </div>
157           <div class="form-group row">
158             <label class="col-12 col-form-label" htmlFor={this.id}>
159               {i18n.t('sidebar')}
160             </label>
161             <div class="col-12">
162               <textarea
163                 id={this.id}
164                 value={this.state.communityForm.description}
165                 onInput={linkEvent(this, this.handleCommunityDescriptionChange)}
166                 class="form-control"
167                 rows={3}
168                 maxLength={10000}
169               />
170             </div>
171           </div>
172           <div class="form-group row">
173             <label class="col-12 col-form-label" htmlFor="community-category">
174               {i18n.t('category')}
175             </label>
176             <div class="col-12">
177               <select
178                 class="form-control"
179                 id="community-category"
180                 value={this.state.communityForm.category_id}
181                 onInput={linkEvent(this, this.handleCommunityCategoryChange)}
182               >
183                 {this.state.categories.map(category => (
184                   <option value={category.id}>{category.name}</option>
185                 ))}
186               </select>
187             </div>
188           </div>
189
190           {this.state.enable_nsfw && (
191             <div class="form-group row">
192               <div class="col-12">
193                 <div class="form-check">
194                   <input
195                     class="form-check-input"
196                     id="community-nsfw"
197                     type="checkbox"
198                     checked={this.state.communityForm.nsfw}
199                     onChange={linkEvent(this, this.handleCommunityNsfwChange)}
200                   />
201                   <label class="form-check-label" htmlFor="community-nsfw">
202                     {i18n.t('nsfw')}
203                   </label>
204                 </div>
205               </div>
206             </div>
207           )}
208           <div class="form-group row">
209             <div class="col-12">
210               <button type="submit" class="btn btn-secondary mr-2">
211                 {this.state.loading ? (
212                   <svg class="icon icon-spinner spin">
213                     <use xlinkHref="#icon-spinner"></use>
214                   </svg>
215                 ) : this.props.community ? (
216                   capitalizeFirstLetter(i18n.t('save'))
217                 ) : (
218                   capitalizeFirstLetter(i18n.t('create'))
219                 )}
220               </button>
221               {this.props.community && (
222                 <button
223                   type="button"
224                   class="btn btn-secondary"
225                   onClick={linkEvent(this, this.handleCancel)}
226                 >
227                   {i18n.t('cancel')}
228                 </button>
229               )}
230             </div>
231           </div>
232         </form>
233       </>
234     );
235   }
236
237   handleCreateCommunitySubmit(i: CommunityForm, event: any) {
238     event.preventDefault();
239     i.state.loading = true;
240     if (i.props.community) {
241       WebSocketService.Instance.editCommunity(i.state.communityForm);
242     } else {
243       WebSocketService.Instance.createCommunity(i.state.communityForm);
244     }
245     i.setState(i.state);
246   }
247
248   handleCommunityNameChange(i: CommunityForm, event: any) {
249     i.state.communityForm.name = event.target.value;
250     i.setState(i.state);
251   }
252
253   handleCommunityTitleChange(i: CommunityForm, event: any) {
254     i.state.communityForm.title = event.target.value;
255     i.setState(i.state);
256   }
257
258   handleCommunityDescriptionChange(i: CommunityForm, event: any) {
259     i.state.communityForm.description = event.target.value;
260     i.setState(i.state);
261   }
262
263   handleCommunityCategoryChange(i: CommunityForm, event: any) {
264     i.state.communityForm.category_id = Number(event.target.value);
265     i.setState(i.state);
266   }
267
268   handleCommunityNsfwChange(i: CommunityForm, event: any) {
269     i.state.communityForm.nsfw = event.target.checked;
270     i.setState(i.state);
271   }
272
273   handleCancel(i: CommunityForm) {
274     i.props.onCancel();
275   }
276
277   parseMessage(msg: WebSocketJsonResponse) {
278     let res = wsJsonToRes(msg);
279     console.log(msg);
280     if (msg.error) {
281       toast(i18n.t(msg.error), 'danger');
282       this.state.loading = false;
283       this.setState(this.state);
284       return;
285     } else if (res.op == UserOperation.ListCategories) {
286       let data = res.data as ListCategoriesResponse;
287       this.state.categories = data.categories;
288       if (!this.props.community) {
289         this.state.communityForm.category_id = data.categories[0].id;
290       }
291       this.setState(this.state);
292     } else if (res.op == UserOperation.CreateCommunity) {
293       let data = res.data as CommunityResponse;
294       this.state.loading = false;
295       this.props.onCreate(data.community);
296     }
297     // TODO is this necessary
298     else if (res.op == UserOperation.EditCommunity) {
299       let data = res.data as CommunityResponse;
300       this.state.loading = false;
301       this.props.onEdit(data.community);
302     } else if (res.op == UserOperation.GetSite) {
303       let data = res.data as GetSiteResponse;
304       this.state.enable_nsfw = data.site.enable_nsfw;
305       this.setState(this.state);
306     }
307   }
308 }