1 import { Component, linkEvent } from "inferno";
2 import { Prompt } from "inferno-router";
3 import { CreateSite, EditSite, ListingType, Site } from "lemmy-js-client";
4 import { i18n } from "../../i18next";
5 import { WebSocketService } from "../../services";
12 import { Spinner } from "../common/icon";
13 import { ImageUploadForm } from "../common/image-upload-form";
14 import { ListingTypeSelect } from "../common/listing-type-select";
15 import { MarkdownTextArea } from "../common/markdown-textarea";
17 interface SiteFormProps {
18 site?: Site; // If a site is given, that means this is an edit
24 interface SiteFormState {
30 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
31 private emptyState: SiteFormState = {
33 enable_downvotes: true,
34 open_registration: true,
39 require_email_verification: null,
40 require_application: null,
41 application_question: null,
42 private_instance: null,
44 default_post_listing_type: null,
45 auth: authField(false),
51 constructor(props: any, context: any) {
52 super(props, context);
54 this.state = this.emptyState;
55 this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
56 this.handleSiteApplicationQuestionChange =
57 this.handleSiteApplicationQuestionChange.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.handleDefaultPostListingTypeChange =
66 this.handleDefaultPostListingTypeChange.bind(this);
68 if (this.props.site) {
69 let site = this.props.site;
70 this.state.siteForm = {
72 sidebar: site.sidebar,
73 description: site.description,
74 enable_downvotes: site.enable_downvotes,
75 open_registration: site.open_registration,
76 enable_nsfw: site.enable_nsfw,
77 community_creation_admin_only: site.community_creation_admin_only,
80 require_email_verification: site.require_email_verification,
81 require_application: site.require_application,
82 application_question: site.application_question,
83 private_instance: site.private_instance,
84 default_theme: site.default_theme,
85 default_post_listing_type: site.default_post_listing_type,
86 auth: authField(false),
91 async componentDidMount() {
92 this.state.themeList = await fetchThemeList();
93 this.setState(this.state);
96 // Necessary to stop the loading
97 componentWillReceiveProps() {
98 this.state.loading = false;
99 this.setState(this.state);
102 componentDidUpdate() {
104 !this.state.loading &&
106 (this.state.siteForm.name ||
107 this.state.siteForm.sidebar ||
108 this.state.siteForm.application_question ||
109 this.state.siteForm.description)
111 window.onbeforeunload = () => true;
113 window.onbeforeunload = undefined;
117 componentWillUnmount() {
118 window.onbeforeunload = null;
126 !this.state.loading &&
128 (this.state.siteForm.name ||
129 this.state.siteForm.sidebar ||
130 this.state.siteForm.application_question ||
131 this.state.siteForm.description)
133 message={i18n.t("block_leaving")}
135 <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
138 ? capitalizeFirstLetter(i18n.t("save"))
139 : capitalizeFirstLetter(i18n.t("name"))
140 } ${i18n.t("your_site")}`}</h5>
141 <div class="form-group row">
142 <label class="col-12 col-form-label" htmlFor="create-site-name">
148 id="create-site-name"
150 value={this.state.siteForm.name}
151 onInput={linkEvent(this, this.handleSiteNameChange)}
158 <div class="form-group">
159 <label>{i18n.t("icon")}</label>
161 uploadTitle={i18n.t("upload_icon")}
162 imageSrc={this.state.siteForm.icon}
163 onUpload={this.handleIconUpload}
164 onRemove={this.handleIconRemove}
168 <div class="form-group">
169 <label>{i18n.t("banner")}</label>
171 uploadTitle={i18n.t("upload_banner")}
172 imageSrc={this.state.siteForm.banner}
173 onUpload={this.handleBannerUpload}
174 onRemove={this.handleBannerRemove}
177 <div class="form-group row">
178 <label class="col-12 col-form-label" htmlFor="site-desc">
179 {i18n.t("description")}
186 value={this.state.siteForm.description}
187 onInput={linkEvent(this, this.handleSiteDescChange)}
192 <div class="form-group row">
193 <label class="col-12 col-form-label">{i18n.t("sidebar")}</label>
196 initialContent={this.state.siteForm.sidebar}
197 onContentChange={this.handleSiteSidebarChange}
198 hideNavigationWarnings
202 {this.state.siteForm.require_application && (
203 <div class="form-group row">
204 <label class="col-12 col-form-label">
205 {i18n.t("application_questionnaire")}
209 initialContent={this.state.siteForm.application_question}
210 onContentChange={this.handleSiteApplicationQuestionChange}
211 hideNavigationWarnings
216 <div class="form-group row">
218 <div class="form-check">
220 class="form-check-input"
221 id="create-site-downvotes"
223 checked={this.state.siteForm.enable_downvotes}
226 this.handleSiteEnableDownvotesChange
229 <label class="form-check-label" htmlFor="create-site-downvotes">
230 {i18n.t("enable_downvotes")}
235 <div class="form-group row">
237 <div class="form-check">
239 class="form-check-input"
240 id="create-site-enable-nsfw"
242 checked={this.state.siteForm.enable_nsfw}
243 onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
246 class="form-check-label"
247 htmlFor="create-site-enable-nsfw"
249 {i18n.t("enable_nsfw")}
254 <div class="form-group row">
256 <div class="form-check">
258 class="form-check-input"
259 id="create-site-open-registration"
261 checked={this.state.siteForm.open_registration}
264 this.handleSiteOpenRegistrationChange
268 class="form-check-label"
269 htmlFor="create-site-open-registration"
271 {i18n.t("open_registration")}
276 <div class="form-group row">
278 <div class="form-check">
280 class="form-check-input"
281 id="create-site-community-creation-admin-only"
283 checked={this.state.siteForm.community_creation_admin_only}
286 this.handleSiteCommunityCreationAdminOnly
290 class="form-check-label"
291 htmlFor="create-site-community-creation-admin-only"
293 {i18n.t("community_creation_admin_only")}
298 <div class="form-group row">
300 <div class="form-check">
302 class="form-check-input"
303 id="create-site-require-email-verification"
305 checked={this.state.siteForm.require_email_verification}
308 this.handleSiteRequireEmailVerification
312 class="form-check-label"
313 htmlFor="create-site-require-email-verification"
315 {i18n.t("require_email_verification")}
320 <div class="form-group row">
322 <div class="form-check">
324 class="form-check-input"
325 id="create-site-require-application"
327 checked={this.state.siteForm.require_application}
328 onChange={linkEvent(this, this.handleSiteRequireApplication)}
331 class="form-check-label"
332 htmlFor="create-site-require-application"
334 {i18n.t("require_registration_application")}
339 <div class="form-group row">
342 class="form-check-label mr-2"
343 htmlFor="create-site-default-theme"
348 id="create-site-default-theme"
349 value={this.state.siteForm.default_theme}
350 onChange={linkEvent(this, this.handleSiteDefaultTheme)}
351 class="custom-select w-auto"
353 <option value="browser">{i18n.t("browser_default")}</option>
354 {this.state.themeList.map(theme => (
355 <option value={theme}>{theme}</option>
360 {this.props.showLocal && (
361 <form className="form-group row">
362 <label class="col-sm-3">{i18n.t("listing_type")}</label>
363 <div class="col-sm-9">
366 ListingType[this.state.siteForm.default_post_listing_type]
369 showSubscribed={false}
370 onChange={this.handleDefaultPostListingTypeChange}
375 <div class="form-group row">
377 <div class="form-check">
379 class="form-check-input"
380 id="create-site-private-instance"
382 value={this.state.siteForm.default_theme}
383 onChange={linkEvent(this, this.handleSitePrivateInstance)}
386 class="form-check-label"
387 htmlFor="create-site-private-instance"
389 {i18n.t("private_instance")}
394 <div class="form-group row">
398 class="btn btn-secondary mr-2"
399 disabled={this.state.loading}
401 {this.state.loading ? (
403 ) : this.props.site ? (
404 capitalizeFirstLetter(i18n.t("save"))
406 capitalizeFirstLetter(i18n.t("create"))
409 {this.props.site && (
412 class="btn btn-secondary"
413 onClick={linkEvent(this, this.handleCancel)}
425 handleCreateSiteSubmit(i: SiteForm, event: any) {
426 event.preventDefault();
427 i.state.loading = true;
429 WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
432 let form: CreateSite = {
433 name: i.state.siteForm.name || "My site",
436 WebSocketService.Instance.send(wsClient.createSite(form));
441 handleSiteNameChange(i: SiteForm, event: any) {
442 i.state.siteForm.name = event.target.value;
446 handleSiteSidebarChange(val: string) {
447 this.state.siteForm.sidebar = val;
448 this.setState(this.state);
451 handleSiteApplicationQuestionChange(val: string) {
452 this.state.siteForm.application_question = val;
453 this.setState(this.state);
456 handleSiteDescChange(i: SiteForm, event: any) {
457 i.state.siteForm.description = event.target.value;
461 handleSiteEnableNsfwChange(i: SiteForm, event: any) {
462 i.state.siteForm.enable_nsfw = event.target.checked;
466 handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
467 i.state.siteForm.open_registration = event.target.checked;
471 handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
472 i.state.siteForm.community_creation_admin_only = event.target.checked;
476 handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
477 i.state.siteForm.enable_downvotes = event.target.checked;
481 handleSiteRequireApplication(i: SiteForm, event: any) {
482 i.state.siteForm.require_application = event.target.checked;
486 handleSiteRequireEmailVerification(i: SiteForm, event: any) {
487 i.state.siteForm.require_email_verification = event.target.checked;
491 handleSitePrivateInstance(i: SiteForm, event: any) {
492 i.state.siteForm.private_instance = event.target.checked;
496 handleSiteDefaultTheme(i: SiteForm, event: any) {
497 i.state.siteForm.default_theme = event.target.value;
501 handleCancel(i: SiteForm) {
505 handleIconUpload(url: string) {
506 this.state.siteForm.icon = url;
507 this.setState(this.state);
511 this.state.siteForm.icon = "";
512 this.setState(this.state);
515 handleBannerUpload(url: string) {
516 this.state.siteForm.banner = url;
517 this.setState(this.state);
520 handleBannerRemove() {
521 this.state.siteForm.banner = "";
522 this.setState(this.state);
525 handleDefaultPostListingTypeChange(val: ListingType) {
526 this.state.siteForm.default_post_listing_type =
527 ListingType[ListingType[val]];
528 this.setState(this.state);