]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/community/community-form.tsx
Upgrading deps, running prettier. (#1987)
[lemmy-ui.git] / src / shared / components / community / community-form.tsx
index 0f12a252dccc12d1a23aca7616899ae38ee79e5e..e44675c91c608256aad56729ef91fb0de0f118cf 100644 (file)
@@ -1,39 +1,42 @@
+import { myAuthRequired } from "@utils/app";
+import { capitalizeFirstLetter, randomStr } from "@utils/helpers";
 import { Component, linkEvent } from "inferno";
 import { Prompt } from "inferno-router";
 import {
-  CommunityResponse,
   CommunityView,
   CreateCommunity,
   EditCommunity,
-  UserOperation,
+  Language,
 } from "lemmy-js-client";
-import { Subscription } from "rxjs";
-import { i18n } from "../../i18next";
-import { UserService, WebSocketService } from "../../services";
-import {
-  authField,
-  capitalizeFirstLetter,
-  randomStr,
-  wsClient,
-  wsJsonToRes,
-  wsSubscribe,
-  wsUserOp,
-} from "../../utils";
+import { I18NextService } from "../../services";
 import { Icon, Spinner } from "../common/icon";
 import { ImageUploadForm } from "../common/image-upload-form";
+import { LanguageSelect } from "../common/language-select";
 import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface CommunityFormProps {
   community_view?: CommunityView; // If a community is given, that means this is an edit
+  allLanguages: Language[];
+  siteLanguages: number[];
+  communityLanguages?: number[];
   onCancel?(): any;
-  onCreate?(community: CommunityView): any;
-  onEdit?(community: CommunityView): any;
-  enableNsfw: boolean;
+  onUpsertCommunity(form: CreateCommunity | EditCommunity): void;
+  enableNsfw?: boolean;
+  loading?: boolean;
 }
 
 interface CommunityFormState {
-  communityForm: CreateCommunity;
-  loading: boolean;
+  form: {
+    name?: string;
+    title?: string;
+    description?: string;
+    icon?: string;
+    banner?: string;
+    nsfw?: boolean;
+    posting_restricted_to_mods?: boolean;
+    discussion_languages?: number[];
+  };
+  submitted: boolean;
 }
 
 export class CommunityForm extends Component<
@@ -41,26 +44,15 @@ export class CommunityForm extends Component<
   CommunityFormState
 > {
   private id = `community-form-${randomStr()}`;
-  private subscription: Subscription;
 
-  private emptyState: CommunityFormState = {
-    communityForm: {
-      name: null,
-      title: null,
-      nsfw: false,
-      icon: null,
-      banner: null,
-      posting_restricted_to_mods: false,
-      auth: authField(false),
-    },
-    loading: false,
+  state: CommunityFormState = {
+    form: {},
+    submitted: false,
   };
 
   constructor(props: any, context: any) {
     super(props, context);
 
-    this.state = this.emptyState;
-
     this.handleCommunityDescriptionChange =
       this.handleCommunityDescriptionChange.bind(this);
 
@@ -70,326 +62,299 @@ export class CommunityForm extends Component<
     this.handleBannerUpload = this.handleBannerUpload.bind(this);
     this.handleBannerRemove = this.handleBannerRemove.bind(this);
 
-    let cv = this.props.community_view;
-    if (cv) {
-      this.state.communityForm = {
-        name: cv.community.name,
-        title: cv.community.title,
-        description: cv.community.description,
-        nsfw: cv.community.nsfw,
-        icon: cv.community.icon,
-        banner: cv.community.banner,
-        posting_restricted_to_mods: cv.community.posting_restricted_to_mods,
-        auth: authField(),
-      };
-    }
+    this.handleDiscussionLanguageChange =
+      this.handleDiscussionLanguageChange.bind(this);
 
-    this.parseMessage = this.parseMessage.bind(this);
-    this.subscription = wsSubscribe(this.parseMessage);
-  }
+    const cv = this.props.community_view;
 
-  // TODO this should be checked out
-  componentDidUpdate() {
-    if (
-      !this.state.loading &&
-      (this.state.communityForm.name ||
-        this.state.communityForm.title ||
-        this.state.communityForm.description)
-    ) {
-      window.onbeforeunload = () => true;
-    } else {
-      window.onbeforeunload = undefined;
+    if (cv) {
+      this.state = {
+        ...this.state,
+        form: {
+          name: cv.community.name,
+          title: cv.community.title,
+          description: cv.community.description,
+          nsfw: cv.community.nsfw,
+          icon: cv.community.icon,
+          banner: cv.community.banner,
+          posting_restricted_to_mods: cv.community.posting_restricted_to_mods,
+          discussion_languages: this.props.communityLanguages,
+        },
+      };
     }
   }
 
-  componentWillUnmount() {
-    this.subscription.unsubscribe();
-    window.onbeforeunload = null;
-  }
-
   render() {
     return (
-      <>
+      <form
+        className="community-form"
+        onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}
+      >
         <Prompt
+          message={I18NextService.i18n.t("block_leaving")}
           when={
-            !this.state.loading &&
-            (this.state.communityForm.name ||
-              this.state.communityForm.title ||
-              this.state.communityForm.description)
+            !this.props.loading &&
+            !!(
+              this.state.form.name ||
+              this.state.form.title ||
+              this.state.form.description
+            ) &&
+            !this.state.submitted
           }
-          message={i18n.t("block_leaving")}
         />
-        <form onSubmit={linkEvent(this, this.handleCreateCommunitySubmit)}>
-          {!this.props.community_view && (
-            <div class="form-group row">
-              <label
-                class="col-12 col-sm-2 col-form-label"
-                htmlFor="community-name"
-              >
-                {i18n.t("name")}
-                <span
-                  class="position-absolute pointer unselectable ml-2 text-muted"
-                  data-tippy-content={i18n.t("name_explain")}
-                >
-                  <Icon icon="help-circle" classes="icon-inline" />
-                </span>
-              </label>
-              <div class="col-12 col-sm-10">
-                <input
-                  type="text"
-                  id="community-name"
-                  class="form-control"
-                  value={this.state.communityForm.name}
-                  onInput={linkEvent(this, this.handleCommunityNameChange)}
-                  required
-                  minLength={3}
-                  pattern="[a-z0-9_]+"
-                  title={i18n.t("community_reqs")}
-                />
-              </div>
-            </div>
-          )}
-          <div class="form-group row">
+        {!this.props.community_view && (
+          <div className="mb-3 row">
             <label
-              class="col-12 col-sm-2 col-form-label"
-              htmlFor="community-title"
+              className="col-12 col-sm-2 col-form-label"
+              htmlFor="community-name"
             >
-              {i18n.t("display_name")}
+              {I18NextService.i18n.t("name")}
               <span
-                class="position-absolute pointer unselectable ml-2 text-muted"
-                data-tippy-content={i18n.t("display_name_explain")}
+                className="position-absolute pointer unselectable ms-2 text-muted"
+                data-tippy-content={I18NextService.i18n.t("name_explain")}
               >
                 <Icon icon="help-circle" classes="icon-inline" />
               </span>
             </label>
-            <div class="col-12 col-sm-10">
+            <div className="col-12 col-sm-10">
               <input
                 type="text"
-                id="community-title"
-                value={this.state.communityForm.title}
-                onInput={linkEvent(this, this.handleCommunityTitleChange)}
-                class="form-control"
+                id="community-name"
+                className="form-control"
+                value={this.state.form.name}
+                onInput={linkEvent(this, this.handleCommunityNameChange)}
                 required
                 minLength={3}
-                maxLength={100}
+                pattern="[a-z0-9_]+"
+                title={I18NextService.i18n.t("community_reqs")}
               />
             </div>
           </div>
-          <div class="form-group row">
-            <label class="col-12 col-sm-2">{i18n.t("icon")}</label>
-            <div class="col-12 col-sm-10">
-              <ImageUploadForm
-                uploadTitle={i18n.t("upload_icon")}
-                imageSrc={this.state.communityForm.icon}
-                onUpload={this.handleIconUpload}
-                onRemove={this.handleIconRemove}
-                rounded
-              />
-            </div>
+        )}
+        <div className="mb-3 row">
+          <label
+            className="col-12 col-sm-2 col-form-label"
+            htmlFor="community-title"
+          >
+            {I18NextService.i18n.t("display_name")}
+            <span
+              className="position-absolute pointer unselectable ms-2 text-muted"
+              data-tippy-content={I18NextService.i18n.t("display_name_explain")}
+            >
+              <Icon icon="help-circle" classes="icon-inline" />
+            </span>
+          </label>
+          <div className="col-12 col-sm-10">
+            <input
+              type="text"
+              id="community-title"
+              value={this.state.form.title}
+              onInput={linkEvent(this, this.handleCommunityTitleChange)}
+              className="form-control"
+              required
+              minLength={3}
+              maxLength={100}
+            />
           </div>
-          <div class="form-group row">
-            <label class="col-12 col-sm-2">{i18n.t("banner")}</label>
-            <div class="col-12 col-sm-10">
-              <ImageUploadForm
-                uploadTitle={i18n.t("upload_banner")}
-                imageSrc={this.state.communityForm.banner}
-                onUpload={this.handleBannerUpload}
-                onRemove={this.handleBannerRemove}
-              />
-            </div>
+        </div>
+        <div className="mb-3 row">
+          <label className="col-12 col-sm-2 col-form-label">
+            {I18NextService.i18n.t("icon")}
+          </label>
+          <div className="col-12 col-sm-10">
+            <ImageUploadForm
+              uploadTitle={I18NextService.i18n.t("upload_icon")}
+              imageSrc={this.state.form.icon}
+              onUpload={this.handleIconUpload}
+              onRemove={this.handleIconRemove}
+              rounded
+            />
           </div>
-          <div class="form-group row">
-            <label class="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
-              {i18n.t("sidebar")}
-            </label>
-            <div class="col-12 col-sm-10">
-              <MarkdownTextArea
-                initialContent={this.state.communityForm.description}
-                onContentChange={this.handleCommunityDescriptionChange}
-              />
-            </div>
+        </div>
+        <div className="mb-3 row">
+          <label className="col-12 col-sm-2 col-form-label">
+            {I18NextService.i18n.t("banner")}
+          </label>
+          <div className="col-12 col-sm-10">
+            <ImageUploadForm
+              uploadTitle={I18NextService.i18n.t("upload_banner")}
+              imageSrc={this.state.form.banner}
+              onUpload={this.handleBannerUpload}
+              onRemove={this.handleBannerRemove}
+            />
+          </div>
+        </div>
+        <div className="mb-3 row">
+          <label className="col-12 col-sm-2 col-form-label" htmlFor={this.id}>
+            {I18NextService.i18n.t("sidebar")}
+          </label>
+          <div className="col-12 col-sm-10">
+            <MarkdownTextArea
+              initialContent={this.state.form.description}
+              placeholder={I18NextService.i18n.t("description") ?? undefined}
+              onContentChange={this.handleCommunityDescriptionChange}
+              hideNavigationWarnings
+              allLanguages={[]}
+              siteLanguages={[]}
+            />
           </div>
+        </div>
 
-          {this.props.enableNsfw && (
-            <div class="form-group row">
-              <legend class="col-form-label col-sm-2 pt-0">
-                {i18n.t("nsfw")}
-              </legend>
-              <div class="col-10">
-                <div class="form-check">
-                  <input
-                    class="form-check-input position-static"
-                    id="community-nsfw"
-                    type="checkbox"
-                    checked={this.state.communityForm.nsfw}
-                    onChange={linkEvent(this, this.handleCommunityNsfwChange)}
-                  />
-                </div>
-              </div>
-            </div>
-          )}
-          <div class="form-group row">
-            <legend class="col-form-label col-6 pt-0">
-              {i18n.t("only_mods_can_post_in_community")}
+        {this.props.enableNsfw && (
+          <div className="mb-3 row">
+            <legend className="col-form-label col-sm-2 pt-0">
+              {I18NextService.i18n.t("nsfw")}
             </legend>
-            <div class="col-6">
-              <div class="form-check">
+            <div className="col-10">
+              <div className="form-check">
                 <input
-                  class="form-check-input position-static"
-                  id="community-only-mods-can-post"
+                  className="form-check-input position-static"
+                  id="community-nsfw"
                   type="checkbox"
-                  checked={this.state.communityForm.posting_restricted_to_mods}
-                  onChange={linkEvent(
-                    this,
-                    this.handleCommunityPostingRestrictedToMods
-                  )}
+                  checked={this.state.form.nsfw}
+                  onChange={linkEvent(this, this.handleCommunityNsfwChange)}
                 />
               </div>
             </div>
           </div>
-          <div class="form-group row">
-            <div class="col-12">
+        )}
+        <div className="mb-3 row">
+          <legend className="col-form-label col-6 pt-0">
+            {I18NextService.i18n.t("only_mods_can_post_in_community")}
+          </legend>
+          <div className="col-6">
+            <div className="form-check">
+              <input
+                className="form-check-input position-static"
+                id="community-only-mods-can-post"
+                type="checkbox"
+                checked={this.state.form.posting_restricted_to_mods}
+                onChange={linkEvent(
+                  this,
+                  this.handleCommunityPostingRestrictedToMods,
+                )}
+              />
+            </div>
+          </div>
+        </div>
+        <LanguageSelect
+          allLanguages={this.props.allLanguages}
+          siteLanguages={this.props.siteLanguages}
+          showSite
+          selectedLanguageIds={this.state.form.discussion_languages}
+          multiple={true}
+          onChange={this.handleDiscussionLanguageChange}
+        />
+        <div className="mb-3 row">
+          <div className="col-12">
+            <button
+              type="submit"
+              className="btn btn-secondary me-2"
+              disabled={this.props.loading}
+            >
+              {this.props.loading ? (
+                <Spinner />
+              ) : this.props.community_view ? (
+                capitalizeFirstLetter(I18NextService.i18n.t("save"))
+              ) : (
+                capitalizeFirstLetter(I18NextService.i18n.t("create"))
+              )}
+            </button>
+            {this.props.community_view && (
               <button
-                type="submit"
-                class="btn btn-secondary mr-2"
-                disabled={this.state.loading}
+                type="button"
+                className="btn btn-secondary"
+                onClick={linkEvent(this, this.handleCancel)}
               >
-                {this.state.loading ? (
-                  <Spinner />
-                ) : this.props.community_view ? (
-                  capitalizeFirstLetter(i18n.t("save"))
-                ) : (
-                  capitalizeFirstLetter(i18n.t("create"))
-                )}
+                {I18NextService.i18n.t("cancel")}
               </button>
-              {this.props.community_view && (
-                <button
-                  type="button"
-                  class="btn btn-secondary"
-                  onClick={linkEvent(this, this.handleCancel)}
-                >
-                  {i18n.t("cancel")}
-                </button>
-              )}
-            </div>
+            )}
           </div>
-        </form>
-      </>
+        </div>
+      </form>
     );
   }
 
   handleCreateCommunitySubmit(i: CommunityForm, event: any) {
     event.preventDefault();
-    i.state.loading = true;
-    if (i.props.community_view) {
-      let form: EditCommunity = {
-        ...i.state.communityForm,
-        community_id: i.props.community_view.community.id,
-      };
-      WebSocketService.Instance.send(wsClient.editCommunity(form));
+    i.setState({ submitted: true });
+    const cForm = i.state.form;
+    const auth = myAuthRequired();
+
+    const cv = i.props.community_view;
+
+    if (cv) {
+      i.props.onUpsertCommunity({
+        community_id: cv.community.id,
+        title: cForm.title,
+        description: cForm.description,
+        icon: cForm.icon,
+        banner: cForm.banner,
+        nsfw: cForm.nsfw,
+        posting_restricted_to_mods: cForm.posting_restricted_to_mods,
+        discussion_languages: cForm.discussion_languages,
+        auth,
+      });
     } else {
-      WebSocketService.Instance.send(
-        wsClient.createCommunity(i.state.communityForm)
-      );
+      if (cForm.title && cForm.name) {
+        i.props.onUpsertCommunity({
+          name: cForm.name,
+          title: cForm.title,
+          description: cForm.description,
+          icon: cForm.icon,
+          banner: cForm.banner,
+          nsfw: cForm.nsfw,
+          posting_restricted_to_mods: cForm.posting_restricted_to_mods,
+          discussion_languages: cForm.discussion_languages,
+          auth,
+        });
+      }
     }
-    i.setState(i.state);
   }
 
   handleCommunityNameChange(i: CommunityForm, event: any) {
-    i.state.communityForm.name = event.target.value;
-    i.setState(i.state);
+    i.setState(s => ((s.form.name = event.target.value), s));
   }
 
   handleCommunityTitleChange(i: CommunityForm, event: any) {
-    i.state.communityForm.title = event.target.value;
-    i.setState(i.state);
+    i.setState(s => ((s.form.title = event.target.value), s));
   }
 
   handleCommunityDescriptionChange(val: string) {
-    this.state.communityForm.description = val;
-    this.setState(this.state);
+    this.setState(s => ((s.form.description = val), s));
   }
 
   handleCommunityNsfwChange(i: CommunityForm, event: any) {
-    i.state.communityForm.nsfw = event.target.checked;
-    i.setState(i.state);
+    i.setState(s => ((s.form.nsfw = event.target.checked), s));
   }
 
   handleCommunityPostingRestrictedToMods(i: CommunityForm, event: any) {
-    i.state.communityForm.posting_restricted_to_mods = event.target.checked;
-    i.setState(i.state);
+    i.setState(
+      s => ((s.form.posting_restricted_to_mods = event.target.checked), s),
+    );
   }
 
   handleCancel(i: CommunityForm) {
-    i.props.onCancel();
+    i.props.onCancel?.();
   }
 
   handleIconUpload(url: string) {
-    this.state.communityForm.icon = url;
-    this.setState(this.state);
+    this.setState(s => ((s.form.icon = url), s));
   }
 
   handleIconRemove() {
-    this.state.communityForm.icon = "";
-    this.setState(this.state);
+    this.setState(s => ((s.form.icon = ""), s));
   }
 
   handleBannerUpload(url: string) {
-    this.state.communityForm.banner = url;
-    this.setState(this.state);
+    this.setState(s => ((s.form.banner = url), s));
   }
 
   handleBannerRemove() {
-    this.state.communityForm.banner = "";
-    this.setState(this.state);
+    this.setState(s => ((s.form.banner = ""), s));
   }
 
-  parseMessage(msg: any) {
-    let op = wsUserOp(msg);
-    console.log(msg);
-    if (msg.error) {
-      // Errors handled by top level pages
-      // toast(i18n.t(msg.error), "danger");
-      this.state.loading = false;
-      this.setState(this.state);
-      return;
-    } else if (op == UserOperation.CreateCommunity) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
-      this.state.loading = false;
-      this.props.onCreate(data.community_view);
-
-      // Update myUserInfo
-      let community = data.community_view.community;
-      let person = UserService.Instance.myUserInfo.local_user_view.person;
-      UserService.Instance.myUserInfo.follows.push({
-        community,
-        follower: person,
-      });
-      UserService.Instance.myUserInfo.moderates.push({
-        community,
-        moderator: person,
-      });
-    } else if (op == UserOperation.EditCommunity) {
-      let data = wsJsonToRes<CommunityResponse>(msg).data;
-      this.state.loading = false;
-      this.props.onEdit(data.community_view);
-      let community = data.community_view.community;
-
-      let followFound = UserService.Instance.myUserInfo.follows.findIndex(
-        f => f.community.id == community.id
-      );
-      if (followFound) {
-        UserService.Instance.myUserInfo.follows[followFound].community =
-          community;
-      }
-
-      let moderatesFound = UserService.Instance.myUserInfo.moderates.findIndex(
-        f => f.community.id == community.id
-      );
-      if (moderatesFound) {
-        UserService.Instance.myUserInfo.moderates[moderatesFound].community =
-          community;
-      }
-    }
+  handleDiscussionLanguageChange(val: number[]) {
+    this.setState(s => ((s.form.discussion_languages = val), s));
   }
 }