1 import { myAuthRequired } from "@utils/app";
2 import { capitalizeFirstLetter, validInstanceTLD } from "@utils/helpers";
15 } from "lemmy-js-client";
16 import { I18NextService } from "../../services";
17 import { Icon, Spinner } from "../common/icon";
18 import { ImageUploadForm } from "../common/image-upload-form";
19 import { LanguageSelect } from "../common/language-select";
20 import { ListingTypeSelect } from "../common/listing-type-select";
21 import { MarkdownTextArea } from "../common/markdown-textarea";
22 import NavigationPrompt from "../common/navigation-prompt";
24 interface SiteFormProps {
25 blockedInstances?: Instance[];
26 allowedInstances?: Instance[];
29 onSaveSite(form: EditSite): void;
30 siteRes: GetSiteResponse;
34 interface SiteFormState {
37 allowed_instances: string;
38 blocked_instances: string;
43 type InstanceKey = "allowed_instances" | "blocked_instances";
45 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
46 state: SiteFormState = {
47 siteForm: this.initSiteForm(),
49 allowed_instances: "",
50 blocked_instances: "",
55 initSiteForm(): EditSite {
56 const site = this.props.siteRes.site_view.site;
57 const ls = this.props.siteRes.site_view.local_site;
60 sidebar: site.sidebar,
61 description: site.description,
62 enable_downvotes: ls.enable_downvotes,
63 registration_mode: ls.registration_mode,
64 enable_nsfw: ls.enable_nsfw,
65 community_creation_admin_only: ls.community_creation_admin_only,
68 require_email_verification: ls.require_email_verification,
69 application_question: ls.application_question,
70 private_instance: ls.private_instance,
71 default_theme: ls.default_theme,
72 default_post_listing_type: ls.default_post_listing_type,
73 legal_information: ls.legal_information,
74 application_email_admins: ls.application_email_admins,
75 reports_email_admins: ls.reports_email_admins,
76 hide_modlog_mod_names: ls.hide_modlog_mod_names,
77 discussion_languages: this.props.siteRes.discussion_languages,
78 slur_filter_regex: ls.slur_filter_regex,
79 actor_name_max_length: ls.actor_name_max_length,
80 federation_enabled: ls.federation_enabled,
81 captcha_enabled: ls.captcha_enabled,
82 captcha_difficulty: ls.captcha_difficulty,
83 allowed_instances: this.props.allowedInstances?.map(i => i.domain),
84 blocked_instances: this.props.blockedInstances?.map(i => i.domain),
89 constructor(props: any, context: any) {
90 super(props, context);
92 this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
93 this.handleSiteLegalInfoChange = this.handleSiteLegalInfoChange.bind(this);
94 this.handleSiteApplicationQuestionChange =
95 this.handleSiteApplicationQuestionChange.bind(this);
97 this.handleIconUpload = this.handleIconUpload.bind(this);
98 this.handleIconRemove = this.handleIconRemove.bind(this);
100 this.handleBannerUpload = this.handleBannerUpload.bind(this);
101 this.handleBannerRemove = this.handleBannerRemove.bind(this);
103 this.handleDefaultPostListingTypeChange =
104 this.handleDefaultPostListingTypeChange.bind(this);
106 this.handleDiscussionLanguageChange =
107 this.handleDiscussionLanguageChange.bind(this);
109 this.handleAddInstance = this.handleAddInstance.bind(this);
110 this.handleRemoveInstance = this.handleRemoveInstance.bind(this);
112 this.handleInstanceEnterPress = this.handleInstanceEnterPress.bind(this);
113 this.handleInstanceTextChange = this.handleInstanceTextChange.bind(this);
117 const siteSetup = this.props.siteRes.site_view.local_site.site_setup;
120 className="site-form"
121 onSubmit={linkEvent(this, this.handleSaveSiteSubmit)}
125 !this.props.loading &&
128 this.state.siteForm.name ||
129 this.state.siteForm.sidebar ||
130 this.state.siteForm.application_question ||
131 this.state.siteForm.description
133 !this.state.submitted
138 ? capitalizeFirstLetter(I18NextService.i18n.t("edit"))
139 : capitalizeFirstLetter(I18NextService.i18n.t("setup"))
140 } ${I18NextService.i18n.t("your_site")}`}</h5>
141 <div className="mb-3 row">
142 <label className="col-12 col-form-label" htmlFor="create-site-name">
143 {I18NextService.i18n.t("name")}
145 <div className="col-12">
148 id="create-site-name"
149 className="form-control"
150 value={this.state.siteForm.name}
151 onInput={linkEvent(this, this.handleSiteNameChange)}
158 <div className="row mb-3">
159 <label className="col-sm-2 col-form-label">
160 {I18NextService.i18n.t("icon")}
162 <div className="col-sm-10">
164 uploadTitle={I18NextService.i18n.t("upload_icon")}
165 imageSrc={this.state.siteForm.icon}
166 onUpload={this.handleIconUpload}
167 onRemove={this.handleIconRemove}
172 <div className="row mb-3">
173 <label className="col-sm-2 col-form-label">
174 {I18NextService.i18n.t("banner")}
176 <div className="col-sm-10">
178 uploadTitle={I18NextService.i18n.t("upload_banner")}
179 imageSrc={this.state.siteForm.banner}
180 onUpload={this.handleBannerUpload}
181 onRemove={this.handleBannerRemove}
185 <div className="mb-3 row">
186 <label className="col-12 col-form-label" htmlFor="site-desc">
187 {I18NextService.i18n.t("description")}
189 <div className="col-12">
192 className="form-control"
194 value={this.state.siteForm.description}
195 onInput={linkEvent(this, this.handleSiteDescChange)}
200 <div className="mb-3 row">
201 <label className="col-12 col-form-label">
202 {I18NextService.i18n.t("sidebar")}
204 <div className="col-12">
206 initialContent={this.state.siteForm.sidebar}
207 onContentChange={this.handleSiteSidebarChange}
208 hideNavigationWarnings
214 <div className="mb-3 row">
215 <label className="col-12 col-form-label">
216 {I18NextService.i18n.t("legal_information")}
218 <div className="col-12">
220 initialContent={this.state.siteForm.legal_information}
221 onContentChange={this.handleSiteLegalInfoChange}
222 hideNavigationWarnings
228 <div className="mb-3 row">
229 <div className="col-12">
230 <div className="form-check">
232 className="form-check-input"
233 id="create-site-downvotes"
235 checked={this.state.siteForm.enable_downvotes}
236 onChange={linkEvent(this, this.handleSiteEnableDownvotesChange)}
239 className="form-check-label"
240 htmlFor="create-site-downvotes"
242 {I18NextService.i18n.t("enable_downvotes")}
247 <div className="mb-3 row">
248 <div className="col-12">
249 <div className="form-check">
251 className="form-check-input"
252 id="create-site-enable-nsfw"
254 checked={this.state.siteForm.enable_nsfw}
255 onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
258 className="form-check-label"
259 htmlFor="create-site-enable-nsfw"
261 {I18NextService.i18n.t("enable_nsfw")}
266 <div className="mb-3 row">
267 <div className="col-12">
269 className="form-check-label me-2"
270 htmlFor="create-site-registration-mode"
272 {I18NextService.i18n.t("registration_mode")}
275 id="create-site-registration-mode"
276 value={this.state.siteForm.registration_mode}
277 onChange={linkEvent(this, this.handleSiteRegistrationModeChange)}
278 className="form-select d-inline-block w-auto"
280 <option value={"RequireApplication"}>
281 {I18NextService.i18n.t("require_registration_application")}
283 <option value={"Open"}>
284 {I18NextService.i18n.t("open_registration")}
286 <option value={"Closed"}>
287 {I18NextService.i18n.t("close_registration")}
292 {this.state.siteForm.registration_mode == "RequireApplication" && (
293 <div className="mb-3 row">
294 <label className="col-12 col-form-label">
295 {I18NextService.i18n.t("application_questionnaire")}
297 <div className="col-12">
299 initialContent={this.state.siteForm.application_question}
300 onContentChange={this.handleSiteApplicationQuestionChange}
301 hideNavigationWarnings
308 <div className="mb-3 row">
309 <div className="col-12">
310 <div className="form-check">
312 className="form-check-input"
313 id="create-site-community-creation-admin-only"
315 checked={this.state.siteForm.community_creation_admin_only}
318 this.handleSiteCommunityCreationAdminOnly
322 className="form-check-label"
323 htmlFor="create-site-community-creation-admin-only"
325 {I18NextService.i18n.t("community_creation_admin_only")}
330 <div className="mb-3 row">
331 <div className="col-12">
332 <div className="form-check">
334 className="form-check-input"
335 id="create-site-require-email-verification"
337 checked={this.state.siteForm.require_email_verification}
340 this.handleSiteRequireEmailVerification
344 className="form-check-label"
345 htmlFor="create-site-require-email-verification"
347 {I18NextService.i18n.t("require_email_verification")}
352 <div className="mb-3 row">
353 <div className="col-12">
354 <div className="form-check">
356 className="form-check-input"
357 id="create-site-application-email-admins"
359 checked={this.state.siteForm.application_email_admins}
362 this.handleSiteApplicationEmailAdmins
366 className="form-check-label"
367 htmlFor="create-site-email-admins"
369 {I18NextService.i18n.t("application_email_admins")}
374 <div className="mb-3 row">
375 <div className="col-12">
376 <div className="form-check">
378 className="form-check-input"
379 id="create-site-reports-email-admins"
381 checked={this.state.siteForm.reports_email_admins}
382 onChange={linkEvent(this, this.handleSiteReportsEmailAdmins)}
385 className="form-check-label"
386 htmlFor="create-site-reports-email-admins"
388 {I18NextService.i18n.t("reports_email_admins")}
393 <div className="mb-3 row">
394 <div className="col-12">
396 className="form-check-label me-2"
397 htmlFor="create-site-default-theme"
399 {I18NextService.i18n.t("theme")}
402 id="create-site-default-theme"
403 value={this.state.siteForm.default_theme}
404 onChange={linkEvent(this, this.handleSiteDefaultTheme)}
405 className="form-select d-inline-block w-auto"
407 <option value="browser">
408 {I18NextService.i18n.t("browser_default")}
410 {this.props.themeList?.map(theme => (
411 <option key={theme} value={theme}>
418 {this.props.showLocal && (
419 <form className="mb-3 row">
420 <label className="col-sm-3 col-form-label">
421 {I18NextService.i18n.t("listing_type")}
423 <div className="col-sm-9">
425 type_={this.state.siteForm.default_post_listing_type ?? "Local"}
427 showSubscribed={false}
428 onChange={this.handleDefaultPostListingTypeChange}
433 <div className="mb-3 row">
434 <div className="col-12">
435 <div className="form-check">
437 className="form-check-input"
438 id="create-site-private-instance"
440 checked={this.state.siteForm.private_instance}
441 onChange={linkEvent(this, this.handleSitePrivateInstance)}
444 className="form-check-label"
445 htmlFor="create-site-private-instance"
447 {I18NextService.i18n.t("private_instance")}
452 <div className="mb-3 row">
453 <div className="col-12">
454 <div className="form-check">
456 className="form-check-input"
457 id="create-site-hide-modlog-mod-names"
459 checked={this.state.siteForm.hide_modlog_mod_names}
460 onChange={linkEvent(this, this.handleSiteHideModlogModNames)}
463 className="form-check-label"
464 htmlFor="create-site-hide-modlog-mod-names"
466 {I18NextService.i18n.t("hide_modlog_mod_names")}
471 <div className="mb-3 row">
473 className="col-12 col-form-label"
474 htmlFor="create-site-slur-filter-regex"
476 {I18NextService.i18n.t("slur_filter_regex")}
478 <div className="col-12">
481 id="create-site-slur-filter-regex"
482 placeholder="(word1|word2)"
483 className="form-control"
484 value={this.state.siteForm.slur_filter_regex}
485 onInput={linkEvent(this, this.handleSiteSlurFilterRegex)}
491 allLanguages={this.props.siteRes.all_languages}
492 siteLanguages={this.props.siteRes.discussion_languages}
493 selectedLanguageIds={this.state.siteForm.discussion_languages}
495 onChange={this.handleDiscussionLanguageChange}
498 <div className="mb-3 row">
500 className="col-12 col-form-label"
501 htmlFor="create-site-actor-name"
503 {I18NextService.i18n.t("actor_name_max_length")}
505 <div className="col-12">
508 id="create-site-actor-name"
509 className="form-control"
511 value={this.state.siteForm.actor_name_max_length}
512 onInput={linkEvent(this, this.handleSiteActorNameMaxLength)}
516 <div className="mb-3 row">
517 <div className="col-12">
518 <div className="form-check">
520 className="form-check-input"
521 id="create-site-federation-enabled"
523 checked={this.state.siteForm.federation_enabled}
524 onChange={linkEvent(this, this.handleSiteFederationEnabled)}
527 className="form-check-label"
528 htmlFor="create-site-federation-enabled"
530 {I18NextService.i18n.t("federation_enabled")}
535 {this.state.siteForm.federation_enabled && (
537 <div className="mb-3 row">
538 {this.federatedInstanceSelect("allowed_instances")}
539 {this.federatedInstanceSelect("blocked_instances")}
541 <div className="mb-3 row">
542 <div className="col-12">
543 <div className="form-check">
545 className="form-check-input"
546 id="create-site-federation-debug"
548 checked={this.state.siteForm.federation_debug}
549 onChange={linkEvent(this, this.handleSiteFederationDebug)}
552 className="form-check-label"
553 htmlFor="create-site-federation-debug"
555 {I18NextService.i18n.t("federation_debug")}
562 <div className="mb-3 row">
563 <div className="col-12">
564 <div className="form-check">
566 className="form-check-input"
567 id="create-site-captcha-enabled"
569 checked={this.state.siteForm.captcha_enabled}
570 onChange={linkEvent(this, this.handleSiteCaptchaEnabled)}
573 className="form-check-label"
574 htmlFor="create-site-captcha-enabled"
576 {I18NextService.i18n.t("captcha_enabled")}
581 {this.state.siteForm.captcha_enabled && (
582 <div className="mb-3 row">
583 <div className="col-12">
585 className="form-check-label me-2"
586 htmlFor="create-site-captcha-difficulty"
588 {I18NextService.i18n.t("captcha_difficulty")}
591 id="create-site-captcha-difficulty"
592 value={this.state.siteForm.captcha_difficulty}
593 onChange={linkEvent(this, this.handleSiteCaptchaDifficulty)}
594 className="form-select d-inline-block w-auto"
596 <option value="easy">{I18NextService.i18n.t("easy")}</option>
597 <option value="medium">
598 {I18NextService.i18n.t("medium")}
600 <option value="hard">{I18NextService.i18n.t("hard")}</option>
605 <div className="mb-3 row">
606 <div className="col-12">
609 className="btn btn-secondary me-2"
610 disabled={this.props.loading}
612 {this.props.loading ? (
615 capitalizeFirstLetter(I18NextService.i18n.t("save"))
617 capitalizeFirstLetter(I18NextService.i18n.t("create"))
626 federatedInstanceSelect(key: InstanceKey) {
627 const id = `create_site_${key}`;
628 const value = this.state.instance_select[key];
629 const selectedInstances = this.state.siteForm[key];
631 <div className="col-12 col-md-6">
632 <label className="col-form-label" htmlFor={id}>
633 {I18NextService.i18n.t(key)}
635 <div className="d-flex justify-content-between align-items-center">
638 placeholder="instance.tld"
640 className="form-control"
642 onInput={linkEvent(key, this.handleInstanceTextChange)}
643 onKeyUp={linkEvent(key, this.handleInstanceEnterPress)}
647 className="btn btn-sm bg-success ms-2"
648 onClick={linkEvent(key, this.handleAddInstance)}
649 style={"width: 2rem; height: 2rem;"}
651 -1 /* Making this untabble because handling enter key in text input makes keyboard support for this button redundant */
656 classes="icon-inline text-light m-auto d-block position-static"
660 {selectedInstances && selectedInstances.length > 0 && (
661 <ul className="mt-3 list-unstyled w-100 d-flex flex-column justify-content-around align-items-center">
662 {selectedInstances.map(instance => (
665 className="my-1 w-100 w-md-75 d-flex align-items-center justify-content-between"
667 <label className="d-block m-0 w-100 " htmlFor={instance}>
668 <strong>{instance}</strong>
673 style={"width: 2rem; height: 2rem;"}
674 className="btn btn-sm bg-danger"
677 this.handleRemoveInstance
682 classes="icon-inline text-light m-auto d-block position-static"
693 handleInstanceTextChange(type: InstanceKey, event: any) {
694 this.setState(s => ({
697 ...s.instance_select,
698 [type]: event.target.value,
703 handleInstanceEnterPress(
705 event: InfernoKeyboardEvent<HTMLInputElement>
707 if (event.code.toLowerCase() === "enter") {
708 event.preventDefault();
710 this.handleAddInstance(key);
714 handleSaveSiteSubmit(i: SiteForm, event: any) {
715 event.preventDefault();
716 const auth = myAuthRequired();
717 i.setState(s => ((s.siteForm.auth = auth), s));
718 i.setState({ submitted: true });
720 const stateSiteForm = i.state.siteForm;
722 let form: EditSite | CreateSite;
724 if (i.props.siteRes.site_view.local_site.site_setup) {
725 form = stateSiteForm;
728 name: stateSiteForm.name ?? "My site",
729 sidebar: stateSiteForm.sidebar,
730 description: stateSiteForm.description,
731 icon: stateSiteForm.icon,
732 banner: stateSiteForm.banner,
733 community_creation_admin_only:
734 stateSiteForm.community_creation_admin_only,
735 enable_nsfw: stateSiteForm.enable_nsfw,
736 enable_downvotes: stateSiteForm.enable_downvotes,
737 application_question: stateSiteForm.application_question,
738 registration_mode: stateSiteForm.registration_mode,
739 require_email_verification: stateSiteForm.require_email_verification,
740 private_instance: stateSiteForm.private_instance,
741 default_theme: stateSiteForm.default_theme,
742 default_post_listing_type: stateSiteForm.default_post_listing_type,
743 application_email_admins: stateSiteForm.application_email_admins,
744 hide_modlog_mod_names: stateSiteForm.hide_modlog_mod_names,
745 legal_information: stateSiteForm.legal_information,
746 slur_filter_regex: stateSiteForm.slur_filter_regex,
747 actor_name_max_length: stateSiteForm.actor_name_max_length,
748 rate_limit_message: stateSiteForm.rate_limit_message,
749 rate_limit_message_per_second:
750 stateSiteForm.rate_limit_message_per_second,
751 rate_limit_comment: stateSiteForm.rate_limit_comment,
752 rate_limit_comment_per_second:
753 stateSiteForm.rate_limit_comment_per_second,
754 rate_limit_image: stateSiteForm.rate_limit_image,
755 rate_limit_image_per_second: stateSiteForm.rate_limit_image_per_second,
756 rate_limit_post: stateSiteForm.rate_limit_post,
757 rate_limit_post_per_second: stateSiteForm.rate_limit_post_per_second,
758 rate_limit_register: stateSiteForm.rate_limit_register,
759 rate_limit_register_per_second:
760 stateSiteForm.rate_limit_register_per_second,
761 rate_limit_search: stateSiteForm.rate_limit_search,
762 rate_limit_search_per_second:
763 stateSiteForm.rate_limit_search_per_second,
764 federation_enabled: stateSiteForm.federation_enabled,
765 federation_debug: stateSiteForm.federation_debug,
766 captcha_enabled: stateSiteForm.captcha_enabled,
767 captcha_difficulty: stateSiteForm.captcha_difficulty,
768 allowed_instances: stateSiteForm.allowed_instances,
769 blocked_instances: stateSiteForm.blocked_instances,
770 discussion_languages: stateSiteForm.discussion_languages,
775 i.props.onSaveSite(form);
778 handleAddInstance(key: InstanceKey) {
779 const instance = this.state.instance_select[key].trim();
781 if (!validInstanceTLD(instance)) {
785 if (!this.state.siteForm[key]?.includes(instance)) {
786 this.setState(s => ({
790 [key]: [...(s.siteForm[key] ?? []), instance],
793 ...s.instance_select,
798 const oppositeKey: InstanceKey =
799 key === "allowed_instances" ? "blocked_instances" : "allowed_instances";
800 if (this.state.siteForm[oppositeKey]?.includes(instance)) {
801 this.handleRemoveInstance({ key: oppositeKey, instance });
806 handleRemoveInstance({
813 this.setState(s => ({
817 [key]: s.siteForm[key]?.filter(i => i !== instance),
822 handleSiteNameChange(i: SiteForm, event: any) {
823 i.state.siteForm.name = event.target.value;
827 handleSiteSidebarChange(val: string) {
828 this.setState(s => ((s.siteForm.sidebar = val), s));
831 handleSiteLegalInfoChange(val: string) {
832 this.setState(s => ((s.siteForm.legal_information = val), s));
835 handleTaglineChange(i: SiteForm, index: number, val: string) {
836 const taglines = i.state.siteForm.taglines;
838 taglines[index] = val;
843 handleDeleteTaglineClick(
846 event: InfernoMouseEvent<HTMLButtonElement>
848 event.preventDefault();
849 const taglines = i.state.siteForm.taglines;
851 taglines.splice(index, 1);
852 i.state.siteForm.taglines = undefined;
854 i.state.siteForm.taglines = taglines;
859 handleAddTaglineClick(
861 event: InfernoMouseEvent<HTMLButtonElement>
863 event.preventDefault();
864 if (!i.state.siteForm.taglines) {
865 i.state.siteForm.taglines = [];
867 i.state.siteForm.taglines.push("");
871 handleSiteApplicationQuestionChange(val: string) {
872 this.setState(s => ((s.siteForm.application_question = val), s));
875 handleSiteDescChange(i: SiteForm, event: any) {
876 i.state.siteForm.description = event.target.value;
880 handleSiteEnableNsfwChange(i: SiteForm, event: any) {
881 i.state.siteForm.enable_nsfw = event.target.checked;
885 handleSiteRegistrationModeChange(i: SiteForm, event: any) {
886 i.state.siteForm.registration_mode = event.target.value;
890 handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
891 i.state.siteForm.community_creation_admin_only = event.target.checked;
895 handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
896 i.state.siteForm.enable_downvotes = event.target.checked;
900 handleSiteRequireEmailVerification(i: SiteForm, event: any) {
901 i.state.siteForm.require_email_verification = event.target.checked;
905 handleSiteApplicationEmailAdmins(i: SiteForm, event: any) {
906 i.state.siteForm.application_email_admins = event.target.checked;
910 handleSiteReportsEmailAdmins(i: SiteForm, event: any) {
911 i.state.siteForm.reports_email_admins = event.target.checked;
915 handleSitePrivateInstance(i: SiteForm, event: any) {
916 i.state.siteForm.private_instance = event.target.checked;
920 handleSiteHideModlogModNames(i: SiteForm, event: any) {
921 i.state.siteForm.hide_modlog_mod_names = event.target.checked;
925 handleSiteDefaultTheme(i: SiteForm, event: any) {
926 i.state.siteForm.default_theme = event.target.value;
930 handleIconUpload(url: string) {
931 this.setState(s => ((s.siteForm.icon = url), s));
935 this.setState(s => ((s.siteForm.icon = ""), s));
938 handleBannerUpload(url: string) {
939 this.setState(s => ((s.siteForm.banner = url), s));
942 handleBannerRemove() {
943 this.setState(s => ((s.siteForm.banner = ""), s));
946 handleSiteSlurFilterRegex(i: SiteForm, event: any) {
947 i.setState(s => ((s.siteForm.slur_filter_regex = event.target.value), s));
950 handleSiteActorNameMaxLength(i: SiteForm, event: any) {
952 s => ((s.siteForm.actor_name_max_length = Number(event.target.value)), s)
956 handleSiteFederationEnabled(i: SiteForm, event: any) {
957 i.state.siteForm.federation_enabled = event.target.checked;
961 handleSiteFederationDebug(i: SiteForm, event: any) {
962 i.state.siteForm.federation_debug = event.target.checked;
966 handleSiteCaptchaEnabled(i: SiteForm, event: any) {
967 i.state.siteForm.captcha_enabled = event.target.checked;
971 handleSiteCaptchaDifficulty(i: SiteForm, event: any) {
972 i.setState(s => ((s.siteForm.captcha_difficulty = event.target.value), s));
975 handleDiscussionLanguageChange(val: number[]) {
976 this.setState(s => ((s.siteForm.discussion_languages = val), s));
979 handleDefaultPostListingTypeChange(val: ListingType) {
980 this.setState(s => ((s.siteForm.default_post_listing_type = val), s));