]> Untitled Git - lemmy-ui.git/blob - src/shared/components/community/community-form.tsx
Merge branch 'AA/remove-pictrsdeletetoast-from-postform' of https://github.com/alectr...
[lemmy-ui.git] / src / shared / components / community / community-form.tsx
1 import { Component, linkEvent } from "inferno";
2 import {
3   CommunityView,
4   CreateCommunity,
5   EditCommunity,
6   Language,
7 } from "lemmy-js-client";
8 import { i18n } from "../../i18next";
9 import { capitalizeFirstLetter, myAuthRequired, randomStr } from "../../utils";
10 import { Icon, Spinner } from "../common/icon";
11 import { ImageUploadForm } from "../common/image-upload-form";
12 import { LanguageSelect } from "../common/language-select";
13 import { MarkdownTextArea } from "../common/markdown-textarea";
14 import NavigationPrompt from "../common/navigation-prompt";
15
16 interface CommunityFormProps {
17   community_view?: CommunityView; // If a community is given, that means this is an edit
18   allLanguages: Language[];
19   siteLanguages: number[];
20   communityLanguages?: number[];
21   onCancel?(): any;
22   onUpsertCommunity(form: CreateCommunity | EditCommunity): void;
23   enableNsfw?: boolean;
24   loading?: boolean;
25 }
26
27 interface CommunityFormState {
28   form: {
29     name?: string;
30     title?: string;
31     description?: string;
32     icon?: string;
33     banner?: string;
34     nsfw?: boolean;
35     posting_restricted_to_mods?: boolean;
36     discussion_languages?: number[];
37   };
38   submitted: boolean;
39 }
40
41 export class CommunityForm extends Component<
42   CommunityFormProps,
43   CommunityFormState
44 > {
45   private id = `community-form-${randomStr()}`;
46
47   state: CommunityFormState = {
48     form: {},
49     submitted: false,
50   };
51
52   constructor(props: any, context: any) {
53     super(props, context);
54
55     this.handleCommunityDescriptionChange =
56       this.handleCommunityDescriptionChange.bind(this);
57
58     this.handleIconUpload = this.handleIconUpload.bind(this);
59     this.handleIconRemove = this.handleIconRemove.bind(this);
60
61     this.handleBannerUpload = this.handleBannerUpload.bind(this);
62     this.handleBannerRemove = this.handleBannerRemove.bind(this);
63
64     this.handleDiscussionLanguageChange =
65       this.handleDiscussionLanguageChange.bind(this);
66
67     const cv = this.props.community_view;
68
69     if (cv) {
70       this.state = {
71         ...this.state,
72         form: {
73           name: cv.community.name,
74           title: cv.community.title,
75           description: cv.community.description,
76           nsfw: cv.community.nsfw,
77           icon: cv.community.icon,
78           banner: cv.community.banner,
79           posting_restricted_to_mods: cv.community.posting_restricted_to_mods,
80           discussion_languages: this.props.communityLanguages,
81         },
82       };
83     }
84   }
85
86   render() {
87     return (
88       <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
89         <NavigationPrompt
90           when={
91             !this.props.loading &&
92             !!(
93               this.state.form.name ||
94               this.state.form.title ||
95               this.state.form.description
96             ) &&
97             !this.state.submitted
98           }
99         />
100         {!this.props.community_view && (
101           <div className="form-group row">
102             <label
103               className="col-12 col-sm-2 col-form-label"
104               htmlFor="community-name"
105             >
106               {i18n.t("name")}
107               <span
108                 className="position-absolute pointer unselectable ml-2 text-muted"
109                 data-tippy-content={i18n.t("name_explain")}
110               >
111                 <Icon icon="help-circle" classes="icon-inline" />
112               </span>
113             </label>
114             <div className="col-12 col-sm-10">
115               <input
116                 type="text"
117                 id="community-name"
118                 className="form-control"
119                 value={this.state.form.name}
120                 onInput={linkEvent(this, this.handleCommunityNameChange)}
121                 required
122                 minLength={3}
123                 pattern="[a-z0-9_]+"
124                 title={i18n.t("community_reqs")}
125               />
126             </div>
127           </div>
128         )}
129         <div className="form-group row">
130           <label
131             className="col-12 col-sm-2 col-form-label"
132             htmlFor="community-title"
133           >
134             {i18n.t("display_name")}
135             <span
136               className="position-absolute pointer unselectable ml-2 text-muted"
137               data-tippy-content={i18n.t("display_name_explain")}
138             >
139               <Icon icon="help-circle" classes="icon-inline" />
140             </span>
141           </label>
142           <div className="col-12 col-sm-10">
143             <input
144               type="text"
145               id="community-title"
146               value={this.state.form.title}
147               onInput={linkEvent(this, this.handleCommunityTitleChange)}
148               className="form-control"
149               required
150               minLength={3}
151               maxLength={100}
152             />
153           </div>
154         </div>
155         <div className="form-group row">
156           <label className="col-12 col-sm-2">{i18n.t("icon")}</label>
157           <div className="col-12 col-sm-10">
158             <ImageUploadForm
159               uploadTitle={i18n.t("upload_icon")}
160               imageSrc={this.state.form.icon}
161               onUpload={this.handleIconUpload}
162               onRemove={this.handleIconRemove}
163               rounded
164             />
165           </div>
166         </div>
167         <div className="form-group row">
168           <label className="col-12 col-sm-2">{i18n.t("banner")}</label>
169           <div className="col-12 col-sm-10">
170             <ImageUploadForm
171               uploadTitle={i18n.t("upload_banner")}
172               imageSrc={this.state.form.banner}
173               onUpload={this.handleBannerUpload}
174               onRemove={this.handleBannerRemove}
175             />
176           </div>
177         </div>
178         <div className="form-group row">
179           <label className="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
180             {i18n.t("sidebar")}
181           </label>
182           <div className="col-12 col-sm-10">
183             <MarkdownTextArea
184               initialContent={this.state.form.description}
185               placeholder={i18n.t("description")}
186               onContentChange={this.handleCommunityDescriptionChange}
187               hideNavigationWarnings
188               allLanguages={[]}
189               siteLanguages={[]}
190             />
191           </div>
192         </div>
193
194         {this.props.enableNsfw && (
195           <div className="form-group row">
196             <legend className="col-form-label col-sm-2 pt-0">
197               {i18n.t("nsfw")}
198             </legend>
199             <div className="col-10">
200               <div className="form-check">
201                 <input
202                   className="form-check-input position-static"
203                   id="community-nsfw"
204                   type="checkbox"
205                   checked={this.state.form.nsfw}
206                   onChange={linkEvent(this, this.handleCommunityNsfwChange)}
207                 />
208               </div>
209             </div>
210           </div>
211         )}
212         <div className="form-group row">
213           <legend className="col-form-label col-6 pt-0">
214             {i18n.t("only_mods_can_post_in_community")}
215           </legend>
216           <div className="col-6">
217             <div className="form-check">
218               <input
219                 className="form-check-input position-static"
220                 id="community-only-mods-can-post"
221                 type="checkbox"
222                 checked={this.state.form.posting_restricted_to_mods}
223                 onChange={linkEvent(
224                   this,
225                   this.handleCommunityPostingRestrictedToMods
226                 )}
227               />
228             </div>
229           </div>
230         </div>
231         <LanguageSelect
232           allLanguages={this.props.allLanguages}
233           siteLanguages={this.props.siteLanguages}
234           showSite
235           selectedLanguageIds={this.state.form.discussion_languages}
236           multiple={true}
237           onChange={this.handleDiscussionLanguageChange}
238         />
239         <div className="form-group row">
240           <div className="col-12">
241             <button
242               type="submit"
243               className="btn btn-secondary mr-2"
244               disabled={this.props.loading}
245             >
246               {this.props.loading ? (
247                 <Spinner />
248               ) : this.props.community_view ? (
249                 capitalizeFirstLetter(i18n.t("save"))
250               ) : (
251                 capitalizeFirstLetter(i18n.t("create"))
252               )}
253             </button>
254             {this.props.community_view && (
255               <button
256                 type="button"
257                 className="btn btn-secondary"
258                 onClick={linkEvent(this, this.handleCancel)}
259               >
260                 {i18n.t("cancel")}
261               </button>
262             )}
263           </div>
264         </div>
265       </form>
266     );
267   }
268
269   handleCreateCommunitySubmit(i: CommunityForm, event: any) {
270     event.preventDefault();
271     i.setState({ submitted: true });
272     const cForm = i.state.form;
273     const auth = myAuthRequired();
274
275     const cv = i.props.community_view;
276
277     if (cv) {
278       i.props.onUpsertCommunity({
279         community_id: cv.community.id,
280         title: cForm.title,
281         description: cForm.description,
282         icon: cForm.icon,
283         banner: cForm.banner,
284         nsfw: cForm.nsfw,
285         posting_restricted_to_mods: cForm.posting_restricted_to_mods,
286         discussion_languages: cForm.discussion_languages,
287         auth,
288       });
289     } else {
290       if (cForm.title && cForm.name) {
291         i.props.onUpsertCommunity({
292           name: cForm.name,
293           title: cForm.title,
294           description: cForm.description,
295           icon: cForm.icon,
296           banner: cForm.banner,
297           nsfw: cForm.nsfw,
298           posting_restricted_to_mods: cForm.posting_restricted_to_mods,
299           discussion_languages: cForm.discussion_languages,
300           auth,
301         });
302       }
303     }
304   }
305
306   handleCommunityNameChange(i: CommunityForm, event: any) {
307     i.setState(s => ((s.form.name = event.target.value), s));
308   }
309
310   handleCommunityTitleChange(i: CommunityForm, event: any) {
311     i.setState(s => ((s.form.title = event.target.value), s));
312   }
313
314   handleCommunityDescriptionChange(val: string) {
315     this.setState(s => ((s.form.description = val), s));
316   }
317
318   handleCommunityNsfwChange(i: CommunityForm, event: any) {
319     i.setState(s => ((s.form.nsfw = event.target.checked), s));
320   }
321
322   handleCommunityPostingRestrictedToMods(i: CommunityForm, event: any) {
323     i.setState(
324       s => ((s.form.posting_restricted_to_mods = event.target.checked), s)
325     );
326   }
327
328   handleCancel(i: CommunityForm) {
329     i.props.onCancel?.();
330   }
331
332   handleIconUpload(url: string) {
333     this.setState(s => ((s.form.icon = url), s));
334   }
335
336   handleIconRemove() {
337     this.setState(s => ((s.form.icon = ""), s));
338   }
339
340   handleBannerUpload(url: string) {
341     this.setState(s => ((s.form.banner = url), s));
342   }
343
344   handleBannerRemove() {
345     this.setState(s => ((s.form.banner = ""), s));
346   }
347
348   handleDiscussionLanguageChange(val: number[]) {
349     this.setState(s => ((s.form.discussion_languages = val), s));
350   }
351 }