]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/site-form.tsx
Re-organized components folder. (#339)
[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 {
7   authField,
8   capitalizeFirstLetter,
9   randomStr,
10   wsClient,
11 } from "../../utils";
12 import { Spinner } from "../common/icon";
13 import { ImageUploadForm } from "../common/image-upload-form";
14 import { MarkdownTextArea } from "../common/markdown-textarea";
15
16 interface SiteFormProps {
17   site?: Site; // If a site is given, that means this is an edit
18   onCancel?(): any;
19 }
20
21 interface SiteFormState {
22   siteForm: EditSite;
23   loading: boolean;
24 }
25
26 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
27   private id = `site-form-${randomStr()}`;
28   private emptyState: SiteFormState = {
29     siteForm: {
30       enable_downvotes: true,
31       open_registration: true,
32       enable_nsfw: true,
33       name: null,
34       icon: null,
35       banner: null,
36       auth: authField(),
37     },
38     loading: false,
39   };
40
41   constructor(props: any, context: any) {
42     super(props, context);
43
44     this.state = this.emptyState;
45     this.handleSiteSidebarChange = this.handleSiteSidebarChange.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       this.state.siteForm = {
55         name: this.props.site.name,
56         sidebar: this.props.site.sidebar,
57         description: this.props.site.description,
58         enable_downvotes: this.props.site.enable_downvotes,
59         open_registration: this.props.site.open_registration,
60         enable_nsfw: this.props.site.enable_nsfw,
61         community_creation_admin_only:
62           this.props.site.community_creation_admin_only,
63         icon: this.props.site.icon,
64         banner: this.props.site.banner,
65         auth: authField(),
66       };
67     }
68   }
69
70   // Necessary to stop the loading
71   componentWillReceiveProps() {
72     this.state.loading = false;
73     this.setState(this.state);
74   }
75
76   componentDidUpdate() {
77     if (
78       !this.state.loading &&
79       !this.props.site &&
80       (this.state.siteForm.name ||
81         this.state.siteForm.sidebar ||
82         this.state.siteForm.description)
83     ) {
84       window.onbeforeunload = () => true;
85     } else {
86       window.onbeforeunload = undefined;
87     }
88   }
89
90   componentWillUnmount() {
91     window.onbeforeunload = null;
92   }
93
94   render() {
95     return (
96       <>
97         <Prompt
98           when={
99             !this.state.loading &&
100             !this.props.site &&
101             (this.state.siteForm.name ||
102               this.state.siteForm.sidebar ||
103               this.state.siteForm.description)
104           }
105           message={i18n.t("block_leaving")}
106         />
107         <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
108           <h5>{`${
109             this.props.site
110               ? capitalizeFirstLetter(i18n.t("save"))
111               : capitalizeFirstLetter(i18n.t("name"))
112           } ${i18n.t("your_site")}`}</h5>
113           <div class="form-group row">
114             <label class="col-12 col-form-label" htmlFor="create-site-name">
115               {i18n.t("name")}
116             </label>
117             <div class="col-12">
118               <input
119                 type="text"
120                 id="create-site-name"
121                 class="form-control"
122                 value={this.state.siteForm.name}
123                 onInput={linkEvent(this, this.handleSiteNameChange)}
124                 required
125                 minLength={3}
126                 maxLength={20}
127               />
128             </div>
129           </div>
130           <div class="form-group">
131             <label>{i18n.t("icon")}</label>
132             <ImageUploadForm
133               uploadTitle={i18n.t("upload_icon")}
134               imageSrc={this.state.siteForm.icon}
135               onUpload={this.handleIconUpload}
136               onRemove={this.handleIconRemove}
137               rounded
138             />
139           </div>
140           <div class="form-group">
141             <label>{i18n.t("banner")}</label>
142             <ImageUploadForm
143               uploadTitle={i18n.t("upload_banner")}
144               imageSrc={this.state.siteForm.banner}
145               onUpload={this.handleBannerUpload}
146               onRemove={this.handleBannerRemove}
147             />
148           </div>
149           <div class="form-group row">
150             <label class="col-12 col-form-label" htmlFor="site-desc">
151               {i18n.t("description")}
152             </label>
153             <div class="col-12">
154               <input
155                 type="text"
156                 class="form-control"
157                 id="site-desc"
158                 value={this.state.siteForm.description}
159                 onInput={linkEvent(this, this.handleSiteDescChange)}
160                 maxLength={150}
161               />
162             </div>
163           </div>
164           <div class="form-group row">
165             <label class="col-12 col-form-label" htmlFor={this.id}>
166               {i18n.t("sidebar")}
167             </label>
168             <div class="col-12">
169               <MarkdownTextArea
170                 initialContent={this.state.siteForm.sidebar}
171                 onContentChange={this.handleSiteSidebarChange}
172                 hideNavigationWarnings
173               />
174             </div>
175           </div>
176           <div class="form-group row">
177             <div class="col-12">
178               <div class="form-check">
179                 <input
180                   class="form-check-input"
181                   id="create-site-downvotes"
182                   type="checkbox"
183                   checked={this.state.siteForm.enable_downvotes}
184                   onChange={linkEvent(
185                     this,
186                     this.handleSiteEnableDownvotesChange
187                   )}
188                 />
189                 <label class="form-check-label" htmlFor="create-site-downvotes">
190                   {i18n.t("enable_downvotes")}
191                 </label>
192               </div>
193             </div>
194           </div>
195           <div class="form-group row">
196             <div class="col-12">
197               <div class="form-check">
198                 <input
199                   class="form-check-input"
200                   id="create-site-enable-nsfw"
201                   type="checkbox"
202                   checked={this.state.siteForm.enable_nsfw}
203                   onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
204                 />
205                 <label
206                   class="form-check-label"
207                   htmlFor="create-site-enable-nsfw"
208                 >
209                   {i18n.t("enable_nsfw")}
210                 </label>
211               </div>
212             </div>
213           </div>
214           <div class="form-group row">
215             <div class="col-12">
216               <div class="form-check">
217                 <input
218                   class="form-check-input"
219                   id="create-site-open-registration"
220                   type="checkbox"
221                   checked={this.state.siteForm.open_registration}
222                   onChange={linkEvent(
223                     this,
224                     this.handleSiteOpenRegistrationChange
225                   )}
226                 />
227                 <label
228                   class="form-check-label"
229                   htmlFor="create-site-open-registration"
230                 >
231                   {i18n.t("open_registration")}
232                 </label>
233               </div>
234             </div>
235           </div>
236           <div class="form-group row">
237             <div class="col-12">
238               <div class="form-check">
239                 <input
240                   class="form-check-input"
241                   id="create-site-community-creation-admin-only"
242                   type="checkbox"
243                   checked={this.state.siteForm.community_creation_admin_only}
244                   onChange={linkEvent(
245                     this,
246                     this.handleSiteCommunityCreationAdminOnly
247                   )}
248                 />
249                 <label
250                   class="form-check-label"
251                   htmlFor="create-site-community-creation-admin-only"
252                 >
253                   {i18n.t("community_creation_admin_only")}
254                 </label>
255               </div>
256             </div>
257           </div>
258           <div class="form-group row">
259             <div class="col-12">
260               <button
261                 type="submit"
262                 class="btn btn-secondary mr-2"
263                 disabled={this.state.loading}
264               >
265                 {this.state.loading ? (
266                   <Spinner />
267                 ) : this.props.site ? (
268                   capitalizeFirstLetter(i18n.t("save"))
269                 ) : (
270                   capitalizeFirstLetter(i18n.t("create"))
271                 )}
272               </button>
273               {this.props.site && (
274                 <button
275                   type="button"
276                   class="btn btn-secondary"
277                   onClick={linkEvent(this, this.handleCancel)}
278                 >
279                   {i18n.t("cancel")}
280                 </button>
281               )}
282             </div>
283           </div>
284         </form>
285       </>
286     );
287   }
288
289   handleCreateSiteSubmit(i: SiteForm, event: any) {
290     event.preventDefault();
291     i.state.loading = true;
292     if (i.props.site) {
293       WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
294     } else {
295       let form: CreateSite = {
296         name: i.state.siteForm.name || "My site",
297         ...i.state.siteForm,
298       };
299       WebSocketService.Instance.send(wsClient.createSite(form));
300     }
301     i.setState(i.state);
302   }
303
304   handleSiteNameChange(i: SiteForm, event: any) {
305     i.state.siteForm.name = event.target.value;
306     i.setState(i.state);
307   }
308
309   handleSiteSidebarChange(val: string) {
310     this.state.siteForm.sidebar = val;
311     this.setState(this.state);
312   }
313
314   handleSiteDescChange(i: SiteForm, event: any) {
315     i.state.siteForm.description = event.target.value;
316     i.setState(i.state);
317   }
318
319   handleSiteEnableNsfwChange(i: SiteForm, event: any) {
320     i.state.siteForm.enable_nsfw = event.target.checked;
321     i.setState(i.state);
322   }
323
324   handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
325     i.state.siteForm.open_registration = event.target.checked;
326     i.setState(i.state);
327   }
328
329   handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
330     i.state.siteForm.community_creation_admin_only = event.target.checked;
331     i.setState(i.state);
332   }
333
334   handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
335     i.state.siteForm.enable_downvotes = event.target.checked;
336     i.setState(i.state);
337   }
338
339   handleCancel(i: SiteForm) {
340     i.props.onCancel();
341   }
342
343   handleIconUpload(url: string) {
344     this.state.siteForm.icon = url;
345     this.setState(this.state);
346   }
347
348   handleIconRemove() {
349     this.state.siteForm.icon = "";
350     this.setState(this.state);
351   }
352
353   handleBannerUpload(url: string) {
354     this.state.siteForm.banner = url;
355     this.setState(this.state);
356   }
357
358   handleBannerRemove() {
359     this.state.siteForm.banner = "";
360     this.setState(this.state);
361   }
362 }