1 import { None, Option, Some } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
3 import { Prompt } from "inferno-router";
10 } from "lemmy-js-client";
11 import { i18n } from "../../i18next";
12 import { WebSocketService } from "../../services";
15 capitalizeFirstLetter,
19 import { Spinner } from "../common/icon";
20 import { ImageUploadForm } from "../common/image-upload-form";
21 import { ListingTypeSelect } from "../common/listing-type-select";
22 import { MarkdownTextArea } from "../common/markdown-textarea";
24 interface SiteFormProps {
25 site: Option<Site>; // If a site is given, that means this is an edit
31 interface SiteFormState {
34 themeList: Option<string[]>;
37 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
38 private emptyState: SiteFormState = {
39 siteForm: new EditSite({
40 enable_downvotes: Some(true),
41 open_registration: Some(true),
42 enable_nsfw: Some(true),
46 require_email_verification: None,
47 require_application: None,
48 application_question: None,
49 private_instance: None,
52 default_post_listing_type: None,
53 legal_information: None,
55 community_creation_admin_only: None,
62 constructor(props: any, context: any) {
63 super(props, context);
65 this.state = this.emptyState;
66 this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
67 this.handleSiteLegalInfoChange = this.handleSiteLegalInfoChange.bind(this);
68 this.handleSiteApplicationQuestionChange =
69 this.handleSiteApplicationQuestionChange.bind(this);
71 this.handleIconUpload = this.handleIconUpload.bind(this);
72 this.handleIconRemove = this.handleIconRemove.bind(this);
74 this.handleBannerUpload = this.handleBannerUpload.bind(this);
75 this.handleBannerRemove = this.handleBannerRemove.bind(this);
77 this.handleDefaultPostListingTypeChange =
78 this.handleDefaultPostListingTypeChange.bind(this);
80 this.props.site.match({
82 this.state.siteForm = new EditSite({
83 name: Some(site.name),
84 sidebar: site.sidebar,
85 description: site.description,
86 enable_downvotes: Some(site.enable_downvotes),
87 open_registration: Some(site.open_registration),
88 enable_nsfw: Some(site.enable_nsfw),
89 community_creation_admin_only: Some(
90 site.community_creation_admin_only
94 require_email_verification: Some(site.require_email_verification),
95 require_application: Some(site.require_application),
96 application_question: site.application_question,
97 private_instance: Some(site.private_instance),
98 default_theme: Some(site.default_theme),
99 default_post_listing_type: Some(site.default_post_listing_type),
100 legal_information: site.legal_information,
101 auth: auth(false).unwrap(),
108 async componentDidMount() {
109 this.state.themeList = Some(await fetchThemeList());
110 this.setState(this.state);
113 // Necessary to stop the loading
114 componentWillReceiveProps() {
115 this.state.loading = false;
116 this.setState(this.state);
119 componentDidUpdate() {
121 !this.state.loading &&
122 this.props.site.isNone() &&
123 (this.state.siteForm.name ||
124 this.state.siteForm.sidebar ||
125 this.state.siteForm.application_question ||
126 this.state.siteForm.description)
128 window.onbeforeunload = () => true;
130 window.onbeforeunload = undefined;
134 componentWillUnmount() {
135 window.onbeforeunload = null;
143 !this.state.loading &&
144 this.props.site.isNone() &&
145 (this.state.siteForm.name ||
146 this.state.siteForm.sidebar ||
147 this.state.siteForm.application_question ||
148 this.state.siteForm.description)
150 message={i18n.t("block_leaving")}
152 <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
154 this.props.site.isSome()
155 ? capitalizeFirstLetter(i18n.t("save"))
156 : capitalizeFirstLetter(i18n.t("name"))
157 } ${i18n.t("your_site")}`}</h5>
158 <div class="form-group row">
159 <label class="col-12 col-form-label" htmlFor="create-site-name">
165 id="create-site-name"
167 value={toUndefined(this.state.siteForm.name)}
168 onInput={linkEvent(this, this.handleSiteNameChange)}
175 <div class="form-group">
176 <label>{i18n.t("icon")}</label>
178 uploadTitle={i18n.t("upload_icon")}
179 imageSrc={this.state.siteForm.icon}
180 onUpload={this.handleIconUpload}
181 onRemove={this.handleIconRemove}
185 <div class="form-group">
186 <label>{i18n.t("banner")}</label>
188 uploadTitle={i18n.t("upload_banner")}
189 imageSrc={this.state.siteForm.banner}
190 onUpload={this.handleBannerUpload}
191 onRemove={this.handleBannerRemove}
194 <div class="form-group row">
195 <label class="col-12 col-form-label" htmlFor="site-desc">
196 {i18n.t("description")}
203 value={toUndefined(this.state.siteForm.description)}
204 onInput={linkEvent(this, this.handleSiteDescChange)}
209 <div class="form-group row">
210 <label class="col-12 col-form-label">{i18n.t("sidebar")}</label>
213 initialContent={this.state.siteForm.sidebar}
217 onContentChange={this.handleSiteSidebarChange}
218 hideNavigationWarnings
222 <div class="form-group row">
223 <label class="col-12 col-form-label">
224 {i18n.t("legal_information")}
228 initialContent={this.state.siteForm.legal_information}
232 onContentChange={this.handleSiteLegalInfoChange}
233 hideNavigationWarnings
237 {this.state.siteForm.require_application.unwrapOr(false) && (
238 <div class="form-group row">
239 <label class="col-12 col-form-label">
240 {i18n.t("application_questionnaire")}
244 initialContent={this.state.siteForm.application_question}
248 onContentChange={this.handleSiteApplicationQuestionChange}
249 hideNavigationWarnings
254 <div class="form-group row">
256 <div class="form-check">
258 class="form-check-input"
259 id="create-site-downvotes"
261 checked={toUndefined(this.state.siteForm.enable_downvotes)}
264 this.handleSiteEnableDownvotesChange
267 <label class="form-check-label" htmlFor="create-site-downvotes">
268 {i18n.t("enable_downvotes")}
273 <div class="form-group row">
275 <div class="form-check">
277 class="form-check-input"
278 id="create-site-enable-nsfw"
280 checked={toUndefined(this.state.siteForm.enable_nsfw)}
281 onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
284 class="form-check-label"
285 htmlFor="create-site-enable-nsfw"
287 {i18n.t("enable_nsfw")}
292 <div class="form-group row">
294 <div class="form-check">
296 class="form-check-input"
297 id="create-site-open-registration"
299 checked={toUndefined(this.state.siteForm.open_registration)}
302 this.handleSiteOpenRegistrationChange
306 class="form-check-label"
307 htmlFor="create-site-open-registration"
309 {i18n.t("open_registration")}
314 <div class="form-group row">
316 <div class="form-check">
318 class="form-check-input"
319 id="create-site-community-creation-admin-only"
321 checked={toUndefined(
322 this.state.siteForm.community_creation_admin_only
326 this.handleSiteCommunityCreationAdminOnly
330 class="form-check-label"
331 htmlFor="create-site-community-creation-admin-only"
333 {i18n.t("community_creation_admin_only")}
338 <div class="form-group row">
340 <div class="form-check">
342 class="form-check-input"
343 id="create-site-require-email-verification"
345 checked={toUndefined(
346 this.state.siteForm.require_email_verification
350 this.handleSiteRequireEmailVerification
354 class="form-check-label"
355 htmlFor="create-site-require-email-verification"
357 {i18n.t("require_email_verification")}
362 <div class="form-group row">
364 <div class="form-check">
366 class="form-check-input"
367 id="create-site-require-application"
369 checked={toUndefined(this.state.siteForm.require_application)}
370 onChange={linkEvent(this, this.handleSiteRequireApplication)}
373 class="form-check-label"
374 htmlFor="create-site-require-application"
376 {i18n.t("require_registration_application")}
381 <div class="form-group row">
384 class="form-check-label mr-2"
385 htmlFor="create-site-default-theme"
390 id="create-site-default-theme"
391 value={toUndefined(this.state.siteForm.default_theme)}
392 onChange={linkEvent(this, this.handleSiteDefaultTheme)}
393 class="custom-select w-auto"
395 <option value="browser">{i18n.t("browser_default")}</option>
396 {this.state.themeList.unwrapOr([]).map(theme => (
397 <option value={theme}>{theme}</option>
402 {this.props.showLocal && (
403 <form className="form-group row">
404 <label class="col-sm-3">{i18n.t("listing_type")}</label>
405 <div class="col-sm-9">
409 this.state.siteForm.default_post_listing_type.unwrapOr(
415 showSubscribed={false}
416 onChange={this.handleDefaultPostListingTypeChange}
421 <div class="form-group row">
423 <div class="form-check">
425 class="form-check-input"
426 id="create-site-private-instance"
428 value={toUndefined(this.state.siteForm.default_theme)}
429 onChange={linkEvent(this, this.handleSitePrivateInstance)}
432 class="form-check-label"
433 htmlFor="create-site-private-instance"
435 {i18n.t("private_instance")}
440 <div class="form-group row">
444 class="btn btn-secondary mr-2"
445 disabled={this.state.loading}
447 {this.state.loading ? (
449 ) : this.props.site.isSome() ? (
450 capitalizeFirstLetter(i18n.t("save"))
452 capitalizeFirstLetter(i18n.t("create"))
455 {this.props.site.isSome() && (
458 class="btn btn-secondary"
459 onClick={linkEvent(this, this.handleCancel)}
471 handleCreateSiteSubmit(i: SiteForm, event: any) {
472 event.preventDefault();
473 i.state.loading = true;
474 i.state.siteForm.auth = auth().unwrap();
476 if (i.props.site.isSome()) {
477 WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
480 let sForm = i.state.siteForm;
481 let form = new CreateSite({
482 name: sForm.name.unwrapOr("My site"),
483 sidebar: sForm.sidebar,
484 description: sForm.description,
486 banner: sForm.banner,
487 community_creation_admin_only: sForm.community_creation_admin_only,
488 enable_nsfw: sForm.enable_nsfw,
489 enable_downvotes: sForm.enable_downvotes,
490 require_application: sForm.require_application,
491 application_question: sForm.application_question,
492 open_registration: sForm.open_registration,
493 require_email_verification: sForm.require_email_verification,
494 private_instance: sForm.private_instance,
495 default_theme: sForm.default_theme,
496 default_post_listing_type: sForm.default_post_listing_type,
497 auth: auth().unwrap(),
499 WebSocketService.Instance.send(wsClient.createSite(form));
504 handleSiteNameChange(i: SiteForm, event: any) {
505 i.state.siteForm.name = Some(event.target.value);
509 handleSiteSidebarChange(val: string) {
510 this.state.siteForm.sidebar = Some(val);
511 this.setState(this.state);
514 handleSiteLegalInfoChange(val: string) {
515 this.state.siteForm.legal_information = Some(val);
516 this.setState(this.state);
519 handleSiteApplicationQuestionChange(val: string) {
520 this.state.siteForm.application_question = Some(val);
521 this.setState(this.state);
524 handleSiteDescChange(i: SiteForm, event: any) {
525 i.state.siteForm.description = Some(event.target.value);
529 handleSiteEnableNsfwChange(i: SiteForm, event: any) {
530 i.state.siteForm.enable_nsfw = Some(event.target.checked);
534 handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
535 i.state.siteForm.open_registration = Some(event.target.checked);
539 handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
540 i.state.siteForm.community_creation_admin_only = Some(event.target.checked);
544 handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
545 i.state.siteForm.enable_downvotes = Some(event.target.checked);
549 handleSiteRequireApplication(i: SiteForm, event: any) {
550 i.state.siteForm.require_application = Some(event.target.checked);
554 handleSiteRequireEmailVerification(i: SiteForm, event: any) {
555 i.state.siteForm.require_email_verification = Some(event.target.checked);
559 handleSitePrivateInstance(i: SiteForm, event: any) {
560 i.state.siteForm.private_instance = Some(event.target.checked);
564 handleSiteDefaultTheme(i: SiteForm, event: any) {
565 i.state.siteForm.default_theme = Some(event.target.value);
569 handleCancel(i: SiteForm) {
573 handleIconUpload(url: string) {
574 this.state.siteForm.icon = Some(url);
575 this.setState(this.state);
579 this.state.siteForm.icon = Some("");
580 this.setState(this.state);
583 handleBannerUpload(url: string) {
584 this.state.siteForm.banner = Some(url);
585 this.setState(this.state);
588 handleBannerRemove() {
589 this.state.siteForm.banner = Some("");
590 this.setState(this.state);
593 handleDefaultPostListingTypeChange(val: ListingType) {
594 this.state.siteForm.default_post_listing_type = Some(
595 ListingType[ListingType[val]]
597 this.setState(this.state);