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