]> Untitled Git - lemmy.git/blob - ui/src/components/site-form.tsx
Merge remote-tracking branch 'upstream/master' into cake-day
[lemmy.git] / ui / src / components / site-form.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Prompt } from 'inferno-router';
3 import { Site, SiteForm as SiteFormI } from '../interfaces';
4 import { WebSocketService } from '../services';
5 import { capitalizeFirstLetter, randomStr, setupTribute } from '../utils';
6 import autosize from 'autosize';
7 import Tribute from 'tributejs/src/Tribute.js';
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: SiteFormI;
17   loading: boolean;
18 }
19
20 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
21   private id = `site-form-${randomStr()}`;
22   private tribute: Tribute;
23   private emptyState: SiteFormState = {
24     siteForm: {
25       enable_downvotes: true,
26       open_registration: true,
27       enable_nsfw: true,
28       name: null,
29     },
30     loading: false,
31   };
32
33   constructor(props: any, context: any) {
34     super(props, context);
35
36     this.tribute = setupTribute();
37     this.state = this.emptyState;
38
39     if (this.props.site) {
40       this.state.siteForm = {
41         name: this.props.site.name,
42         description: this.props.site.description,
43         enable_downvotes: this.props.site.enable_downvotes,
44         open_registration: this.props.site.open_registration,
45         enable_nsfw: this.props.site.enable_nsfw,
46       };
47     }
48   }
49
50   componentDidMount() {
51     var textarea: any = document.getElementById(this.id);
52     autosize(textarea);
53     this.tribute.attach(textarea);
54     textarea.addEventListener('tribute-replaced', () => {
55       this.state.siteForm.description = textarea.value;
56       this.setState(this.state);
57       autosize.update(textarea);
58     });
59   }
60
61   // Necessary to stop the loading
62   componentWillReceiveProps() {
63     this.state.loading = false;
64     this.setState(this.state);
65   }
66
67   componentDidUpdate() {
68     if (
69       !this.state.loading &&
70       !this.props.site &&
71       (this.state.siteForm.name || this.state.siteForm.description)
72     ) {
73       window.onbeforeunload = () => true;
74     } else {
75       window.onbeforeunload = undefined;
76     }
77   }
78
79   componentWillUnmount() {
80     window.onbeforeunload = null;
81   }
82
83   render() {
84     return (
85       <>
86         <Prompt
87           when={
88             !this.state.loading &&
89             !this.props.site &&
90             (this.state.siteForm.name || this.state.siteForm.description)
91           }
92           message={i18n.t('block_leaving')}
93         />
94         <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
95           <h5>{`${
96             this.props.site
97               ? capitalizeFirstLetter(i18n.t('save'))
98               : capitalizeFirstLetter(i18n.t('name'))
99           } ${i18n.t('your_site')}`}</h5>
100           <div class="form-group row">
101             <label class="col-12 col-form-label" htmlFor="create-site-name">
102               {i18n.t('name')}
103             </label>
104             <div class="col-12">
105               <input
106                 type="text"
107                 id="create-site-name"
108                 class="form-control"
109                 value={this.state.siteForm.name}
110                 onInput={linkEvent(this, this.handleSiteNameChange)}
111                 required
112                 minLength={3}
113                 maxLength={20}
114               />
115             </div>
116           </div>
117           <div class="form-group row">
118             <label class="col-12 col-form-label" htmlFor={this.id}>
119               {i18n.t('sidebar')}
120             </label>
121             <div class="col-12">
122               <textarea
123                 id={this.id}
124                 value={this.state.siteForm.description}
125                 onInput={linkEvent(this, this.handleSiteDescriptionChange)}
126                 class="form-control"
127                 rows={3}
128                 maxLength={10000}
129               />
130             </div>
131           </div>
132           <div class="form-group row">
133             <div class="col-12">
134               <div class="form-check">
135                 <input
136                   class="form-check-input"
137                   id="create-site-downvotes"
138                   type="checkbox"
139                   checked={this.state.siteForm.enable_downvotes}
140                   onChange={linkEvent(
141                     this,
142                     this.handleSiteEnableDownvotesChange
143                   )}
144                 />
145                 <label class="form-check-label" htmlFor="create-site-downvotes">
146                   {i18n.t('enable_downvotes')}
147                 </label>
148               </div>
149             </div>
150           </div>
151           <div class="form-group row">
152             <div class="col-12">
153               <div class="form-check">
154                 <input
155                   class="form-check-input"
156                   id="create-site-enable-nsfw"
157                   type="checkbox"
158                   checked={this.state.siteForm.enable_nsfw}
159                   onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
160                 />
161                 <label
162                   class="form-check-label"
163                   htmlFor="create-site-enable-nsfw"
164                 >
165                   {i18n.t('enable_nsfw')}
166                 </label>
167               </div>
168             </div>
169           </div>
170           <div class="form-group row">
171             <div class="col-12">
172               <div class="form-check">
173                 <input
174                   class="form-check-input"
175                   id="create-site-open-registration"
176                   type="checkbox"
177                   checked={this.state.siteForm.open_registration}
178                   onChange={linkEvent(
179                     this,
180                     this.handleSiteOpenRegistrationChange
181                   )}
182                 />
183                 <label
184                   class="form-check-label"
185                   htmlFor="create-site-open-registration"
186                 >
187                   {i18n.t('open_registration')}
188                 </label>
189               </div>
190             </div>
191           </div>
192           <div class="form-group row">
193             <div class="col-12">
194               <button
195                 type="submit"
196                 class="btn btn-secondary mr-2"
197                 disabled={this.state.loading}
198               >
199                 {this.state.loading ? (
200                   <svg class="icon icon-spinner spin">
201                     <use xlinkHref="#icon-spinner"></use>
202                   </svg>
203                 ) : this.props.site ? (
204                   capitalizeFirstLetter(i18n.t('save'))
205                 ) : (
206                   capitalizeFirstLetter(i18n.t('create'))
207                 )}
208               </button>
209               {this.props.site && (
210                 <button
211                   type="button"
212                   class="btn btn-secondary"
213                   onClick={linkEvent(this, this.handleCancel)}
214                 >
215                   {i18n.t('cancel')}
216                 </button>
217               )}
218             </div>
219           </div>
220         </form>
221       </>
222     );
223   }
224
225   handleCreateSiteSubmit(i: SiteForm, event: any) {
226     event.preventDefault();
227     i.state.loading = true;
228     if (i.props.site) {
229       WebSocketService.Instance.editSite(i.state.siteForm);
230     } else {
231       WebSocketService.Instance.createSite(i.state.siteForm);
232     }
233     i.setState(i.state);
234   }
235
236   handleSiteNameChange(i: SiteForm, event: any) {
237     i.state.siteForm.name = event.target.value;
238     i.setState(i.state);
239   }
240
241   handleSiteDescriptionChange(i: SiteForm, event: any) {
242     i.state.siteForm.description = event.target.value;
243     i.setState(i.state);
244   }
245
246   handleSiteEnableNsfwChange(i: SiteForm, event: any) {
247     i.state.siteForm.enable_nsfw = event.target.checked;
248     i.setState(i.state);
249   }
250
251   handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
252     i.state.siteForm.open_registration = event.target.checked;
253     i.setState(i.state);
254   }
255
256   handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
257     i.state.siteForm.enable_downvotes = event.target.checked;
258     i.setState(i.state);
259   }
260
261   handleCancel(i: SiteForm) {
262     i.props.onCancel();
263   }
264 }