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