1 import { myAuthRequired } from "@utils/app";
2 import { capitalizeFirstLetter, randomStr } from "@utils/helpers";
3 import { Component, linkEvent } from "inferno";
4 import { Prompt } from "inferno-router";
10 } from "lemmy-js-client";
11 import { I18NextService } from "../../services";
12 import { Icon, Spinner } from "../common/icon";
13 import { ImageUploadForm } from "../common/image-upload-form";
14 import { LanguageSelect } from "../common/language-select";
15 import { MarkdownTextArea } from "../common/markdown-textarea";
17 interface CommunityFormProps {
18 community_view?: CommunityView; // If a community is given, that means this is an edit
19 allLanguages: Language[];
20 siteLanguages: number[];
21 communityLanguages?: number[];
23 onUpsertCommunity(form: CreateCommunity | EditCommunity): void;
28 interface CommunityFormState {
36 posting_restricted_to_mods?: boolean;
37 discussion_languages?: number[];
42 export class CommunityForm extends Component<
46 private id = `community-form-${randomStr()}`;
48 state: CommunityFormState = {
53 constructor(props: any, context: any) {
54 super(props, context);
56 this.handleCommunityDescriptionChange =
57 this.handleCommunityDescriptionChange.bind(this);
59 this.handleIconUpload = this.handleIconUpload.bind(this);
60 this.handleIconRemove = this.handleIconRemove.bind(this);
62 this.handleBannerUpload = this.handleBannerUpload.bind(this);
63 this.handleBannerRemove = this.handleBannerRemove.bind(this);
65 this.handleDiscussionLanguageChange =
66 this.handleDiscussionLanguageChange.bind(this);
68 const cv = this.props.community_view;
74 name: cv.community.name,
75 title: cv.community.title,
76 description: cv.community.description,
77 nsfw: cv.community.nsfw,
78 icon: cv.community.icon,
79 banner: cv.community.banner,
80 posting_restricted_to_mods: cv.community.posting_restricted_to_mods,
81 discussion_languages: this.props.communityLanguages,
90 className="community-form"
91 onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}
94 message={I18NextService.i18n.t("block_leaving")}
96 !this.props.loading &&
98 this.state.form.name ||
99 this.state.form.title ||
100 this.state.form.description
102 !this.state.submitted
105 {!this.props.community_view && (
106 <div className="mb-3 row">
108 className="col-12 col-sm-2 col-form-label"
109 htmlFor="community-name"
111 {I18NextService.i18n.t("name")}
113 className="position-absolute pointer unselectable ms-2 text-muted"
114 data-tippy-content={I18NextService.i18n.t("name_explain")}
116 <Icon icon="help-circle" classes="icon-inline" />
119 <div className="col-12 col-sm-10">
123 className="form-control"
124 value={this.state.form.name}
125 onInput={linkEvent(this, this.handleCommunityNameChange)}
129 title={I18NextService.i18n.t("community_reqs")}
134 <div className="mb-3 row">
136 className="col-12 col-sm-2 col-form-label"
137 htmlFor="community-title"
139 {I18NextService.i18n.t("display_name")}
141 className="position-absolute pointer unselectable ms-2 text-muted"
142 data-tippy-content={I18NextService.i18n.t("display_name_explain")}
144 <Icon icon="help-circle" classes="icon-inline" />
147 <div className="col-12 col-sm-10">
151 value={this.state.form.title}
152 onInput={linkEvent(this, this.handleCommunityTitleChange)}
153 className="form-control"
160 <div className="mb-3 row">
161 <label className="col-12 col-sm-2 col-form-label">
162 {I18NextService.i18n.t("icon")}
164 <div className="col-12 col-sm-10">
166 uploadTitle={I18NextService.i18n.t("upload_icon")}
167 imageSrc={this.state.form.icon}
168 onUpload={this.handleIconUpload}
169 onRemove={this.handleIconRemove}
174 <div className="mb-3 row">
175 <label className="col-12 col-sm-2 col-form-label">
176 {I18NextService.i18n.t("banner")}
178 <div className="col-12 col-sm-10">
180 uploadTitle={I18NextService.i18n.t("upload_banner")}
181 imageSrc={this.state.form.banner}
182 onUpload={this.handleBannerUpload}
183 onRemove={this.handleBannerRemove}
187 <div className="mb-3 row">
188 <label className="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
189 {I18NextService.i18n.t("sidebar")}
191 <div className="col-12 col-sm-10">
193 initialContent={this.state.form.description}
194 placeholder={I18NextService.i18n.t("description") ?? undefined}
195 onContentChange={this.handleCommunityDescriptionChange}
196 hideNavigationWarnings
203 {this.props.enableNsfw && (
204 <div className="mb-3 row">
205 <legend className="col-form-label col-sm-2 pt-0">
206 {I18NextService.i18n.t("nsfw")}
208 <div className="col-10">
209 <div className="form-check">
211 className="form-check-input position-static"
214 checked={this.state.form.nsfw}
215 onChange={linkEvent(this, this.handleCommunityNsfwChange)}
221 <div className="mb-3 row">
222 <legend className="col-form-label col-6 pt-0">
223 {I18NextService.i18n.t("only_mods_can_post_in_community")}
225 <div className="col-6">
226 <div className="form-check">
228 className="form-check-input position-static"
229 id="community-only-mods-can-post"
231 checked={this.state.form.posting_restricted_to_mods}
234 this.handleCommunityPostingRestrictedToMods
241 allLanguages={this.props.allLanguages}
242 siteLanguages={this.props.siteLanguages}
244 selectedLanguageIds={this.state.form.discussion_languages}
246 onChange={this.handleDiscussionLanguageChange}
248 <div className="mb-3 row">
249 <div className="col-12">
252 className="btn btn-secondary me-2"
253 disabled={this.props.loading}
255 {this.props.loading ? (
257 ) : this.props.community_view ? (
258 capitalizeFirstLetter(I18NextService.i18n.t("save"))
260 capitalizeFirstLetter(I18NextService.i18n.t("create"))
263 {this.props.community_view && (
266 className="btn btn-secondary"
267 onClick={linkEvent(this, this.handleCancel)}
269 {I18NextService.i18n.t("cancel")}
278 handleCreateCommunitySubmit(i: CommunityForm, event: any) {
279 event.preventDefault();
280 i.setState({ submitted: true });
281 const cForm = i.state.form;
282 const auth = myAuthRequired();
284 const cv = i.props.community_view;
287 i.props.onUpsertCommunity({
288 community_id: cv.community.id,
290 description: cForm.description,
292 banner: cForm.banner,
294 posting_restricted_to_mods: cForm.posting_restricted_to_mods,
295 discussion_languages: cForm.discussion_languages,
299 if (cForm.title && cForm.name) {
300 i.props.onUpsertCommunity({
303 description: cForm.description,
305 banner: cForm.banner,
307 posting_restricted_to_mods: cForm.posting_restricted_to_mods,
308 discussion_languages: cForm.discussion_languages,
315 handleCommunityNameChange(i: CommunityForm, event: any) {
316 i.setState(s => ((s.form.name = event.target.value), s));
319 handleCommunityTitleChange(i: CommunityForm, event: any) {
320 i.setState(s => ((s.form.title = event.target.value), s));
323 handleCommunityDescriptionChange(val: string) {
324 this.setState(s => ((s.form.description = val), s));
327 handleCommunityNsfwChange(i: CommunityForm, event: any) {
328 i.setState(s => ((s.form.nsfw = event.target.checked), s));
331 handleCommunityPostingRestrictedToMods(i: CommunityForm, event: any) {
333 s => ((s.form.posting_restricted_to_mods = event.target.checked), s)
337 handleCancel(i: CommunityForm) {
338 i.props.onCancel?.();
341 handleIconUpload(url: string) {
342 this.setState(s => ((s.form.icon = url), s));
346 this.setState(s => ((s.form.icon = ""), s));
349 handleBannerUpload(url: string) {
350 this.setState(s => ((s.form.banner = url), s));
353 handleBannerRemove() {
354 this.setState(s => ((s.form.banner = ""), s));
357 handleDiscussionLanguageChange(val: number[]) {
358 this.setState(s => ((s.form.discussion_languages = val), s));