]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/site-form.tsx
Private instances (#523)
[lemmy-ui.git] / src / shared / components / home / site-form.tsx
1 import { Component, linkEvent } from "inferno";
2 import { Prompt } from "inferno-router";
3 import { CreateSite, EditSite, Site } from "lemmy-js-client";
4 import { i18n } from "../../i18next";
5 import { WebSocketService } from "../../services";
6 import { authField, capitalizeFirstLetter, wsClient } from "../../utils";
7 import { Spinner } from "../common/icon";
8 import { ImageUploadForm } from "../common/image-upload-form";
9 import { MarkdownTextArea } from "../common/markdown-textarea";
10
11 interface SiteFormProps {
12   site?: Site; // If a site is given, that means this is an edit
13   onCancel?(): any;
14 }
15
16 interface SiteFormState {
17   siteForm: EditSite;
18   loading: boolean;
19 }
20
21 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
22   private emptyState: SiteFormState = {
23     siteForm: {
24       enable_downvotes: true,
25       open_registration: true,
26       enable_nsfw: true,
27       name: null,
28       icon: null,
29       banner: null,
30       require_email_verification: null,
31       require_application: null,
32       application_question: null,
33       private_instance: null,
34       auth: authField(),
35     },
36     loading: false,
37   };
38
39   constructor(props: any, context: any) {
40     super(props, context);
41
42     this.state = this.emptyState;
43     this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
44     this.handleSiteApplicationQuestionChange =
45       this.handleSiteApplicationQuestionChange.bind(this);
46
47     this.handleIconUpload = this.handleIconUpload.bind(this);
48     this.handleIconRemove = this.handleIconRemove.bind(this);
49
50     this.handleBannerUpload = this.handleBannerUpload.bind(this);
51     this.handleBannerRemove = this.handleBannerRemove.bind(this);
52
53     if (this.props.site) {
54       let site = this.props.site;
55       this.state.siteForm = {
56         name: site.name,
57         sidebar: site.sidebar,
58         description: site.description,
59         enable_downvotes: site.enable_downvotes,
60         open_registration: site.open_registration,
61         enable_nsfw: site.enable_nsfw,
62         community_creation_admin_only: site.community_creation_admin_only,
63         icon: site.icon,
64         banner: site.banner,
65         require_email_verification: site.require_email_verification,
66         require_application: site.require_application,
67         application_question: site.application_question,
68         private_instance: site.private_instance,
69         auth: authField(),
70       };
71     }
72   }
73
74   // Necessary to stop the loading
75   componentWillReceiveProps() {
76     this.state.loading = false;
77     this.setState(this.state);
78   }
79
80   componentDidUpdate() {
81     if (
82       !this.state.loading &&
83       !this.props.site &&
84       (this.state.siteForm.name ||
85         this.state.siteForm.sidebar ||
86         this.state.siteForm.application_question ||
87         this.state.siteForm.description)
88     ) {
89       window.onbeforeunload = () => true;
90     } else {
91       window.onbeforeunload = undefined;
92     }
93   }
94
95   componentWillUnmount() {
96     window.onbeforeunload = null;
97   }
98
99   render() {
100     return (
101       <>
102         <Prompt
103           when={
104             !this.state.loading &&
105             !this.props.site &&
106             (this.state.siteForm.name ||
107               this.state.siteForm.sidebar ||
108               this.state.siteForm.application_question ||
109               this.state.siteForm.description)
110           }
111           message={i18n.t("block_leaving")}
112         />
113         <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
114           <h5>{`${
115             this.props.site
116               ? capitalizeFirstLetter(i18n.t("save"))
117               : capitalizeFirstLetter(i18n.t("name"))
118           } ${i18n.t("your_site")}`}</h5>
119           <div class="form-group row">
120             <label class="col-12 col-form-label" htmlFor="create-site-name">
121               {i18n.t("name")}
122             </label>
123             <div class="col-12">
124               <input
125                 type="text"
126                 id="create-site-name"
127                 class="form-control"
128                 value={this.state.siteForm.name}
129                 onInput={linkEvent(this, this.handleSiteNameChange)}
130                 required
131                 minLength={3}
132                 maxLength={20}
133               />
134             </div>
135           </div>
136           <div class="form-group">
137             <label>{i18n.t("icon")}</label>
138             <ImageUploadForm
139               uploadTitle={i18n.t("upload_icon")}
140               imageSrc={this.state.siteForm.icon}
141               onUpload={this.handleIconUpload}
142               onRemove={this.handleIconRemove}
143               rounded
144             />
145           </div>
146           <div class="form-group">
147             <label>{i18n.t("banner")}</label>
148             <ImageUploadForm
149               uploadTitle={i18n.t("upload_banner")}
150               imageSrc={this.state.siteForm.banner}
151               onUpload={this.handleBannerUpload}
152               onRemove={this.handleBannerRemove}
153             />
154           </div>
155           <div class="form-group row">
156             <label class="col-12 col-form-label" htmlFor="site-desc">
157               {i18n.t("description")}
158             </label>
159             <div class="col-12">
160               <input
161                 type="text"
162                 class="form-control"
163                 id="site-desc"
164                 value={this.state.siteForm.description}
165                 onInput={linkEvent(this, this.handleSiteDescChange)}
166                 maxLength={150}
167               />
168             </div>
169           </div>
170           <div class="form-group row">
171             <label class="col-12 col-form-label">{i18n.t("sidebar")}</label>
172             <div class="col-12">
173               <MarkdownTextArea
174                 initialContent={this.state.siteForm.sidebar}
175                 onContentChange={this.handleSiteSidebarChange}
176                 hideNavigationWarnings
177               />
178             </div>
179           </div>
180           {this.state.siteForm.require_application && (
181             <div class="form-group row">
182               <label class="col-12 col-form-label">
183                 {i18n.t("application_questionnaire")}
184               </label>
185               <div class="col-12">
186                 <MarkdownTextArea
187                   initialContent={this.state.siteForm.application_question}
188                   onContentChange={this.handleSiteApplicationQuestionChange}
189                   hideNavigationWarnings
190                 />
191               </div>
192             </div>
193           )}
194           <div class="form-group row">
195             <div class="col-12">
196               <div class="form-check">
197                 <input
198                   class="form-check-input"
199                   id="create-site-downvotes"
200                   type="checkbox"
201                   checked={this.state.siteForm.enable_downvotes}
202                   onChange={linkEvent(
203                     this,
204                     this.handleSiteEnableDownvotesChange
205                   )}
206                 />
207                 <label class="form-check-label" htmlFor="create-site-downvotes">
208                   {i18n.t("enable_downvotes")}
209                 </label>
210               </div>
211             </div>
212           </div>
213           <div class="form-group row">
214             <div class="col-12">
215               <div class="form-check">
216                 <input
217                   class="form-check-input"
218                   id="create-site-enable-nsfw"
219                   type="checkbox"
220                   checked={this.state.siteForm.enable_nsfw}
221                   onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
222                 />
223                 <label
224                   class="form-check-label"
225                   htmlFor="create-site-enable-nsfw"
226                 >
227                   {i18n.t("enable_nsfw")}
228                 </label>
229               </div>
230             </div>
231           </div>
232           <div class="form-group row">
233             <div class="col-12">
234               <div class="form-check">
235                 <input
236                   class="form-check-input"
237                   id="create-site-open-registration"
238                   type="checkbox"
239                   checked={this.state.siteForm.open_registration}
240                   onChange={linkEvent(
241                     this,
242                     this.handleSiteOpenRegistrationChange
243                   )}
244                 />
245                 <label
246                   class="form-check-label"
247                   htmlFor="create-site-open-registration"
248                 >
249                   {i18n.t("open_registration")}
250                 </label>
251               </div>
252             </div>
253           </div>
254           <div class="form-group row">
255             <div class="col-12">
256               <div class="form-check">
257                 <input
258                   class="form-check-input"
259                   id="create-site-community-creation-admin-only"
260                   type="checkbox"
261                   checked={this.state.siteForm.community_creation_admin_only}
262                   onChange={linkEvent(
263                     this,
264                     this.handleSiteCommunityCreationAdminOnly
265                   )}
266                 />
267                 <label
268                   class="form-check-label"
269                   htmlFor="create-site-community-creation-admin-only"
270                 >
271                   {i18n.t("community_creation_admin_only")}
272                 </label>
273               </div>
274             </div>
275           </div>
276           <div class="form-group row">
277             <div class="col-12">
278               <div class="form-check">
279                 <input
280                   class="form-check-input"
281                   id="create-site-require-email-verification"
282                   type="checkbox"
283                   checked={this.state.siteForm.require_email_verification}
284                   onChange={linkEvent(
285                     this,
286                     this.handleSiteRequireEmailVerification
287                   )}
288                 />
289                 <label
290                   class="form-check-label"
291                   htmlFor="create-site-require-email-verification"
292                 >
293                   {i18n.t("require_email_verification")}
294                 </label>
295               </div>
296             </div>
297           </div>
298           <div class="form-group row">
299             <div class="col-12">
300               <div class="form-check">
301                 <input
302                   class="form-check-input"
303                   id="create-site-require-application"
304                   type="checkbox"
305                   checked={this.state.siteForm.require_application}
306                   onChange={linkEvent(this, this.handleSiteRequireApplication)}
307                 />
308                 <label
309                   class="form-check-label"
310                   htmlFor="create-site-require-application"
311                 >
312                   {i18n.t("require_registration_application")}
313                 </label>
314               </div>
315             </div>
316           </div>
317           <div class="form-group row">
318             <div class="col-12">
319               <div class="form-check">
320                 <input
321                   class="form-check-input"
322                   id="create-site-private-instance"
323                   type="checkbox"
324                   checked={this.state.siteForm.private_instance}
325                   onChange={linkEvent(this, this.handleSitePrivateInstance)}
326                 />
327                 <label
328                   class="form-check-label"
329                   htmlFor="create-site-private-instance"
330                 >
331                   {i18n.t("private_instance")}
332                 </label>
333               </div>
334             </div>
335           </div>
336           <div class="form-group row">
337             <div class="col-12">
338               <button
339                 type="submit"
340                 class="btn btn-secondary mr-2"
341                 disabled={this.state.loading}
342               >
343                 {this.state.loading ? (
344                   <Spinner />
345                 ) : this.props.site ? (
346                   capitalizeFirstLetter(i18n.t("save"))
347                 ) : (
348                   capitalizeFirstLetter(i18n.t("create"))
349                 )}
350               </button>
351               {this.props.site && (
352                 <button
353                   type="button"
354                   class="btn btn-secondary"
355                   onClick={linkEvent(this, this.handleCancel)}
356                 >
357                   {i18n.t("cancel")}
358                 </button>
359               )}
360             </div>
361           </div>
362         </form>
363       </>
364     );
365   }
366
367   handleCreateSiteSubmit(i: SiteForm, event: any) {
368     event.preventDefault();
369     i.state.loading = true;
370     if (i.props.site) {
371       WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
372     } else {
373       let form: CreateSite = {
374         name: i.state.siteForm.name || "My site",
375         ...i.state.siteForm,
376       };
377       WebSocketService.Instance.send(wsClient.createSite(form));
378     }
379     i.setState(i.state);
380   }
381
382   handleSiteNameChange(i: SiteForm, event: any) {
383     i.state.siteForm.name = event.target.value;
384     i.setState(i.state);
385   }
386
387   handleSiteSidebarChange(val: string) {
388     this.state.siteForm.sidebar = val;
389     this.setState(this.state);
390   }
391
392   handleSiteApplicationQuestionChange(val: string) {
393     this.state.siteForm.application_question = val;
394     this.setState(this.state);
395   }
396
397   handleSiteDescChange(i: SiteForm, event: any) {
398     i.state.siteForm.description = event.target.value;
399     i.setState(i.state);
400   }
401
402   handleSiteEnableNsfwChange(i: SiteForm, event: any) {
403     i.state.siteForm.enable_nsfw = event.target.checked;
404     i.setState(i.state);
405   }
406
407   handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
408     i.state.siteForm.open_registration = event.target.checked;
409     i.setState(i.state);
410   }
411
412   handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
413     i.state.siteForm.community_creation_admin_only = event.target.checked;
414     i.setState(i.state);
415   }
416
417   handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
418     i.state.siteForm.enable_downvotes = event.target.checked;
419     i.setState(i.state);
420   }
421
422   handleSiteRequireApplication(i: SiteForm, event: any) {
423     i.state.siteForm.require_application = event.target.checked;
424     i.setState(i.state);
425   }
426
427   handleSiteRequireEmailVerification(i: SiteForm, event: any) {
428     i.state.siteForm.require_email_verification = event.target.checked;
429     i.setState(i.state);
430   }
431
432   handleSitePrivateInstance(i: SiteForm, event: any) {
433     i.state.siteForm.private_instance = event.target.checked;
434     i.setState(i.state);
435   }
436
437   handleCancel(i: SiteForm) {
438     i.props.onCancel();
439   }
440
441   handleIconUpload(url: string) {
442     this.state.siteForm.icon = url;
443     this.setState(this.state);
444   }
445
446   handleIconRemove() {
447     this.state.siteForm.icon = "";
448     this.setState(this.state);
449   }
450
451   handleBannerUpload(url: string) {
452     this.state.siteForm.banner = url;
453     this.setState(this.state);
454   }
455
456   handleBannerRemove() {
457     this.state.siteForm.banner = "";
458     this.setState(this.state);
459   }
460 }