1 import { Component, linkEvent } from "inferno";
2 import { Prompt } from "inferno-router";
3 import { CreateSite, EditSite, 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 { MarkdownTextArea } from "../common/markdown-textarea";
16 interface SiteFormProps {
17 site?: Site; // If a site is given, that means this is an edit
21 interface SiteFormState {
27 export class SiteForm extends Component<SiteFormProps, SiteFormState> {
28 private emptyState: SiteFormState = {
30 enable_downvotes: true,
31 open_registration: true,
36 require_email_verification: null,
37 require_application: null,
38 application_question: null,
39 private_instance: null,
47 constructor(props: any, context: any) {
48 super(props, context);
50 this.state = this.emptyState;
51 this.handleSiteSidebarChange = this.handleSiteSidebarChange.bind(this);
52 this.handleSiteApplicationQuestionChange =
53 this.handleSiteApplicationQuestionChange.bind(this);
55 this.handleIconUpload = this.handleIconUpload.bind(this);
56 this.handleIconRemove = this.handleIconRemove.bind(this);
58 this.handleBannerUpload = this.handleBannerUpload.bind(this);
59 this.handleBannerRemove = this.handleBannerRemove.bind(this);
61 if (this.props.site) {
62 let site = this.props.site;
63 this.state.siteForm = {
65 sidebar: site.sidebar,
66 description: site.description,
67 enable_downvotes: site.enable_downvotes,
68 open_registration: site.open_registration,
69 enable_nsfw: site.enable_nsfw,
70 community_creation_admin_only: site.community_creation_admin_only,
73 require_email_verification: site.require_email_verification,
74 require_application: site.require_application,
75 application_question: site.application_question,
76 private_instance: site.private_instance,
77 default_theme: site.default_theme,
83 async componentDidMount() {
84 this.state.themeList = await fetchThemeList();
85 this.setState(this.state);
88 // Necessary to stop the loading
89 componentWillReceiveProps() {
90 this.state.loading = false;
91 this.setState(this.state);
94 componentDidUpdate() {
96 !this.state.loading &&
98 (this.state.siteForm.name ||
99 this.state.siteForm.sidebar ||
100 this.state.siteForm.application_question ||
101 this.state.siteForm.description)
103 window.onbeforeunload = () => true;
105 window.onbeforeunload = undefined;
109 componentWillUnmount() {
110 window.onbeforeunload = null;
118 !this.state.loading &&
120 (this.state.siteForm.name ||
121 this.state.siteForm.sidebar ||
122 this.state.siteForm.application_question ||
123 this.state.siteForm.description)
125 message={i18n.t("block_leaving")}
127 <form onSubmit={linkEvent(this, this.handleCreateSiteSubmit)}>
130 ? capitalizeFirstLetter(i18n.t("save"))
131 : capitalizeFirstLetter(i18n.t("name"))
132 } ${i18n.t("your_site")}`}</h5>
133 <div class="form-group row">
134 <label class="col-12 col-form-label" htmlFor="create-site-name">
140 id="create-site-name"
142 value={this.state.siteForm.name}
143 onInput={linkEvent(this, this.handleSiteNameChange)}
150 <div class="form-group">
151 <label>{i18n.t("icon")}</label>
153 uploadTitle={i18n.t("upload_icon")}
154 imageSrc={this.state.siteForm.icon}
155 onUpload={this.handleIconUpload}
156 onRemove={this.handleIconRemove}
160 <div class="form-group">
161 <label>{i18n.t("banner")}</label>
163 uploadTitle={i18n.t("upload_banner")}
164 imageSrc={this.state.siteForm.banner}
165 onUpload={this.handleBannerUpload}
166 onRemove={this.handleBannerRemove}
169 <div class="form-group row">
170 <label class="col-12 col-form-label" htmlFor="site-desc">
171 {i18n.t("description")}
178 value={this.state.siteForm.description}
179 onInput={linkEvent(this, this.handleSiteDescChange)}
184 <div class="form-group row">
185 <label class="col-12 col-form-label">{i18n.t("sidebar")}</label>
188 initialContent={this.state.siteForm.sidebar}
189 onContentChange={this.handleSiteSidebarChange}
190 hideNavigationWarnings
194 {this.state.siteForm.require_application && (
195 <div class="form-group row">
196 <label class="col-12 col-form-label">
197 {i18n.t("application_questionnaire")}
201 initialContent={this.state.siteForm.application_question}
202 onContentChange={this.handleSiteApplicationQuestionChange}
203 hideNavigationWarnings
208 <div class="form-group row">
210 <div class="form-check">
212 class="form-check-input"
213 id="create-site-downvotes"
215 checked={this.state.siteForm.enable_downvotes}
218 this.handleSiteEnableDownvotesChange
221 <label class="form-check-label" htmlFor="create-site-downvotes">
222 {i18n.t("enable_downvotes")}
227 <div class="form-group row">
229 <div class="form-check">
231 class="form-check-input"
232 id="create-site-enable-nsfw"
234 checked={this.state.siteForm.enable_nsfw}
235 onChange={linkEvent(this, this.handleSiteEnableNsfwChange)}
238 class="form-check-label"
239 htmlFor="create-site-enable-nsfw"
241 {i18n.t("enable_nsfw")}
246 <div class="form-group row">
248 <div class="form-check">
250 class="form-check-input"
251 id="create-site-open-registration"
253 checked={this.state.siteForm.open_registration}
256 this.handleSiteOpenRegistrationChange
260 class="form-check-label"
261 htmlFor="create-site-open-registration"
263 {i18n.t("open_registration")}
268 <div class="form-group row">
270 <div class="form-check">
272 class="form-check-input"
273 id="create-site-community-creation-admin-only"
275 checked={this.state.siteForm.community_creation_admin_only}
278 this.handleSiteCommunityCreationAdminOnly
282 class="form-check-label"
283 htmlFor="create-site-community-creation-admin-only"
285 {i18n.t("community_creation_admin_only")}
290 <div class="form-group row">
292 <div class="form-check">
294 class="form-check-input"
295 id="create-site-require-email-verification"
297 checked={this.state.siteForm.require_email_verification}
300 this.handleSiteRequireEmailVerification
304 class="form-check-label"
305 htmlFor="create-site-require-email-verification"
307 {i18n.t("require_email_verification")}
312 <div class="form-group row">
314 <div class="form-check">
316 class="form-check-input"
317 id="create-site-require-application"
319 checked={this.state.siteForm.require_application}
320 onChange={linkEvent(this, this.handleSiteRequireApplication)}
323 class="form-check-label"
324 htmlFor="create-site-require-application"
326 {i18n.t("require_registration_application")}
331 <div class="form-group row">
334 class="form-check-label mr-2"
335 htmlFor="create-site-default-theme"
340 id="create-site-default-theme"
341 value={this.state.siteForm.default_theme}
342 onChange={linkEvent(this, this.handleSiteDefaultTheme)}
343 class="custom-select w-auto"
345 <option value="browser">{i18n.t("browser_default")}</option>
346 {this.state.themeList.map(theme => (
347 <option value={theme}>{theme}</option>
352 <div class="form-group row">
354 <div class="form-check">
356 class="form-check-input"
357 id="create-site-private-instance"
359 value={this.state.siteForm.default_theme}
360 onChange={linkEvent(this, this.handleSitePrivateInstance)}
363 class="form-check-label"
364 htmlFor="create-site-private-instance"
366 {i18n.t("private_instance")}
371 <div class="form-group row">
375 class="btn btn-secondary mr-2"
376 disabled={this.state.loading}
378 {this.state.loading ? (
380 ) : this.props.site ? (
381 capitalizeFirstLetter(i18n.t("save"))
383 capitalizeFirstLetter(i18n.t("create"))
386 {this.props.site && (
389 class="btn btn-secondary"
390 onClick={linkEvent(this, this.handleCancel)}
402 handleCreateSiteSubmit(i: SiteForm, event: any) {
403 event.preventDefault();
404 i.state.loading = true;
406 WebSocketService.Instance.send(wsClient.editSite(i.state.siteForm));
408 let form: CreateSite = {
409 name: i.state.siteForm.name || "My site",
412 WebSocketService.Instance.send(wsClient.createSite(form));
417 handleSiteNameChange(i: SiteForm, event: any) {
418 i.state.siteForm.name = event.target.value;
422 handleSiteSidebarChange(val: string) {
423 this.state.siteForm.sidebar = val;
424 this.setState(this.state);
427 handleSiteApplicationQuestionChange(val: string) {
428 this.state.siteForm.application_question = val;
429 this.setState(this.state);
432 handleSiteDescChange(i: SiteForm, event: any) {
433 i.state.siteForm.description = event.target.value;
437 handleSiteEnableNsfwChange(i: SiteForm, event: any) {
438 i.state.siteForm.enable_nsfw = event.target.checked;
442 handleSiteOpenRegistrationChange(i: SiteForm, event: any) {
443 i.state.siteForm.open_registration = event.target.checked;
447 handleSiteCommunityCreationAdminOnly(i: SiteForm, event: any) {
448 i.state.siteForm.community_creation_admin_only = event.target.checked;
452 handleSiteEnableDownvotesChange(i: SiteForm, event: any) {
453 i.state.siteForm.enable_downvotes = event.target.checked;
457 handleSiteRequireApplication(i: SiteForm, event: any) {
458 i.state.siteForm.require_application = event.target.checked;
462 handleSiteRequireEmailVerification(i: SiteForm, event: any) {
463 i.state.siteForm.require_email_verification = event.target.checked;
467 handleSitePrivateInstance(i: SiteForm, event: any) {
468 i.state.siteForm.private_instance = event.target.checked;
472 handleSiteDefaultTheme(i: SiteForm, event: any) {
473 i.state.siteForm.default_theme = event.target.value;
477 handleCancel(i: SiteForm) {
481 handleIconUpload(url: string) {
482 this.state.siteForm.icon = url;
483 this.setState(this.state);
487 this.state.siteForm.icon = "";
488 this.setState(this.state);
491 handleBannerUpload(url: string) {
492 this.state.siteForm.banner = url;
493 this.setState(this.state);
496 handleBannerRemove() {
497 this.state.siteForm.banner = "";
498 this.setState(this.state);