]> Untitled Git - lemmy-ui.git/blobdiff - src/shared/components/home/admin-settings.tsx
Move banned users to a separate admin tab. (#2057)
[lemmy-ui.git] / src / shared / components / home / admin-settings.tsx
index 302e96bdf85e4a3798ee9af1e5c28e8c2305450d..4924508fbe9f23105bd18894da539700d5fd308b 100644 (file)
@@ -1,3 +1,12 @@
+import {
+  fetchThemeList,
+  myAuthRequired,
+  setIsoData,
+  showLocal,
+} from "@utils/app";
+import { capitalizeFirstLetter } from "@utils/helpers";
+import { RouteDataResponse } from "@utils/types";
+import classNames from "classnames";
 import { Component, linkEvent } from "inferno";
 import {
   BannedPersonsResponse,
@@ -9,20 +18,11 @@ import {
   GetSiteResponse,
   PersonView,
 } from "lemmy-js-client";
-import { i18n } from "../../i18next";
 import { InitialFetchRequest } from "../../interfaces";
-import { FirstLoadService } from "../../services/FirstLoadService";
+import { removeFromEmojiDataModel, updateEmojiDataModel } from "../../markdown";
+import { FirstLoadService, I18NextService } from "../../services";
 import { HttpService, RequestState } from "../../services/HttpService";
-import {
-  capitalizeFirstLetter,
-  fetchThemeList,
-  myAuthRequired,
-  removeFromEmojiDataModel,
-  setIsoData,
-  showLocal,
-  toast,
-  updateEmojiDataModel,
-} from "../../utils";
+import { toast } from "../../toast";
 import { HtmlTags } from "../common/html-tags";
 import { Spinner } from "../common/icon";
 import Tabs from "../common/tabs";
@@ -32,6 +32,11 @@ import RateLimitForm from "./rate-limit-form";
 import { SiteForm } from "./site-form";
 import { TaglineForm } from "./tagline-form";
 
+type AdminSettingsData = RouteDataResponse<{
+  bannedRes: BannedPersonsResponse;
+  instancesRes: GetFederatedInstancesResponse;
+}>;
+
 interface AdminSettingsState {
   siteRes: GetSiteResponse;
   banned: PersonView[];
@@ -39,14 +44,13 @@ interface AdminSettingsState {
   instancesRes: RequestState<GetFederatedInstancesResponse>;
   bannedRes: RequestState<BannedPersonsResponse>;
   leaveAdminTeamRes: RequestState<GetSiteResponse>;
-  emojiLoading: boolean;
   loading: boolean;
   themeList: string[];
   isIsomorphic: boolean;
 }
 
 export class AdminSettings extends Component<any, AdminSettingsState> {
-  private isoData = setIsoData(this.context);
+  private isoData = setIsoData<AdminSettingsData>(this.context);
   state: AdminSettingsState = {
     siteRes: this.isoData.site_res,
     banned: [],
@@ -54,7 +58,6 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
     bannedRes: { state: "empty" },
     instancesRes: { state: "empty" },
     leaveAdminTeamRes: { state: "empty" },
-    emojiLoading: false,
     loading: false,
     themeList: [],
     isIsomorphic: false,
@@ -70,7 +73,8 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
 
     // Only fetch the data if coming from another route
     if (FirstLoadService.isFirstLoad) {
-      const [bannedRes, instancesRes] = this.isoData.routeData;
+      const { bannedRes, instancesRes } = this.isoData.routeData;
+
       this.state = {
         ...this.state,
         bannedRes,
@@ -80,47 +84,18 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
     }
   }
 
-  async fetchData() {
-    this.setState({
-      bannedRes: { state: "loading" },
-      instancesRes: { state: "loading" },
-      themeList: [],
-      loading: true,
-    });
-
-    const auth = myAuthRequired();
-
-    const [bannedRes, instancesRes, themeList] = await Promise.all([
-      HttpService.client.getBannedPersons({ auth }),
-      HttpService.client.getFederatedInstances({ auth }),
-      fetchThemeList(),
-    ]);
-
-    this.setState({
-      bannedRes,
-      instancesRes,
-      themeList,
-      loading: false,
-    });
-  }
-
-  static fetchInitialData({
+  static async fetchInitialData({
     auth,
     client,
-  }: InitialFetchRequest): Promise<any>[] {
-    const promises: Promise<RequestState<any>>[] = [];
-
-    if (auth) {
-      promises.push(client.getBannedPersons({ auth }));
-      promises.push(client.getFederatedInstances({ auth }));
-    } else {
-      promises.push(
-        Promise.resolve({ state: "empty" }),
-        Promise.resolve({ state: "empty" })
-      );
-    }
-
-    return promises;
+  }: InitialFetchRequest): Promise<AdminSettingsData> {
+    return {
+      bannedRes: await client.getBannedPersons({
+        auth: auth as string,
+      }),
+      instancesRes: await client.getFederatedInstances({
+        auth: auth as string,
+      }),
+    };
   }
 
   async componentDidMount() {
@@ -130,7 +105,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
   }
 
   get documentTitle(): string {
-    return `${i18n.t("admin_settings")} - ${
+    return `${I18NextService.i18n.t("admin_settings")} - ${
       this.state.siteRes.site_view.site.name
     }`;
   }
@@ -142,7 +117,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
         : undefined;
 
     return (
-      <div className="container-lg">
+      <div className="admin-settings container-lg">
         <HtmlTags
           title={this.documentTitle}
           path={this.context.router.route.match.url}
@@ -151,64 +126,110 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
           tabs={[
             {
               key: "site",
-              label: i18n.t("site"),
-              getNode: () => (
-                <div className="row">
-                  <div className="col-12 col-md-6">
-                    <SiteForm
-                      showLocal={showLocal(this.isoData)}
-                      allowedInstances={federationData?.allowed}
-                      blockedInstances={federationData?.blocked}
-                      onSaveSite={this.handleEditSite}
-                      siteRes={this.state.siteRes}
-                      themeList={this.state.themeList}
-                      loading={this.state.loading}
-                    />
-                  </div>
-                  <div className="col-12 col-md-6">
-                    {this.admins()}
-                    {this.bannedUsers()}
+              label: I18NextService.i18n.t("site"),
+              getNode: isSelected => (
+                <div
+                  className={classNames("tab-pane show", {
+                    active: isSelected,
+                  })}
+                  role="tabpanel"
+                  id="site-tab-pane"
+                >
+                  <h1 className="h4 mb-4">
+                    {I18NextService.i18n.t("site_config")}
+                  </h1>
+                  <div className="row">
+                    <div className="col-12 col-md-6">
+                      <SiteForm
+                        showLocal={showLocal(this.isoData)}
+                        allowedInstances={federationData?.allowed}
+                        blockedInstances={federationData?.blocked}
+                        onSaveSite={this.handleEditSite}
+                        siteRes={this.state.siteRes}
+                        themeList={this.state.themeList}
+                        loading={this.state.loading}
+                      />
+                    </div>
+                    <div className="col-12 col-md-6">{this.admins()}</div>
                   </div>
                 </div>
               ),
             },
             {
-              key: "rate_limiting",
-              label: "Rate Limiting",
-              getNode: () => (
-                <RateLimitForm
-                  rateLimits={
-                    this.state.siteRes.site_view.local_site_rate_limit
-                  }
-                  onSaveSite={this.handleEditSite}
-                  loading={this.state.loading}
-                />
+              key: "banned_users",
+              label: I18NextService.i18n.t("banned_users"),
+              getNode: isSelected => (
+                <div
+                  className={classNames("tab-pane", {
+                    active: isSelected,
+                  })}
+                  role="tabpanel"
+                  id="banned_users-tab-pane"
+                >
+                  {this.bannedUsers()}
+                </div>
               ),
             },
             {
-              key: "taglines",
-              label: i18n.t("taglines"),
-              getNode: () => (
-                <div className="row">
-                  <TaglineForm
-                    taglines={this.state.siteRes.taglines}
+              key: "rate_limiting",
+              label: "Rate Limiting",
+              getNode: isSelected => (
+                <div
+                  className={classNames("tab-pane", {
+                    active: isSelected,
+                  })}
+                  role="tabpanel"
+                  id="rate_limiting-tab-pane"
+                >
+                  <RateLimitForm
+                    rateLimits={
+                      this.state.siteRes.site_view.local_site_rate_limit
+                    }
                     onSaveSite={this.handleEditSite}
                     loading={this.state.loading}
                   />
                 </div>
               ),
             },
+            {
+              key: "taglines",
+              label: I18NextService.i18n.t("taglines"),
+              getNode: isSelected => (
+                <div
+                  className={classNames("tab-pane", {
+                    active: isSelected,
+                  })}
+                  role="tabpanel"
+                  id="taglines-tab-pane"
+                >
+                  <div className="row">
+                    <TaglineForm
+                      taglines={this.state.siteRes.taglines}
+                      onSaveSite={this.handleEditSite}
+                      loading={this.state.loading}
+                    />
+                  </div>
+                </div>
+              ),
+            },
             {
               key: "emojis",
-              label: i18n.t("emojis"),
-              getNode: () => (
-                <div className="row">
-                  <EmojiForm
-                    onCreate={this.handleCreateEmoji}
-                    onDelete={this.handleDeleteEmoji}
-                    onEdit={this.handleEditEmoji}
-                    loading={this.state.emojiLoading}
-                  />
+              label: I18NextService.i18n.t("emojis"),
+              getNode: isSelected => (
+                <div
+                  className={classNames("tab-pane", {
+                    active: isSelected,
+                  })}
+                  role="tabpanel"
+                  id="emojis-tab-pane"
+                >
+                  <div className="row">
+                    <EmojiForm
+                      onCreate={this.handleCreateEmoji}
+                      onDelete={this.handleDeleteEmoji}
+                      onEdit={this.handleEditEmoji}
+                    />
+                  </div>
                 </div>
               ),
             },
@@ -218,10 +239,34 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
     );
   }
 
+  async fetchData() {
+    this.setState({
+      bannedRes: { state: "loading" },
+      instancesRes: { state: "loading" },
+      themeList: [],
+    });
+
+    const auth = myAuthRequired();
+
+    const [bannedRes, instancesRes, themeList] = await Promise.all([
+      HttpService.client.getBannedPersons({ auth }),
+      HttpService.client.getFederatedInstances({ auth }),
+      fetchThemeList(),
+    ]);
+
+    this.setState({
+      bannedRes,
+      instancesRes,
+      themeList,
+    });
+  }
+
   admins() {
     return (
       <>
-        <h5>{capitalizeFirstLetter(i18n.t("admins"))}</h5>
+        <h2 className="h5">
+          {capitalizeFirstLetter(I18NextService.i18n.t("admins"))}
+        </h2>
         <ul className="list-unstyled">
           {this.state.siteRes.admins.map(admin => (
             <li key={admin.person.id} className="list-inline-item">
@@ -240,10 +285,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
         onClick={linkEvent(this, this.handleLeaveAdminTeam)}
         className="btn btn-danger mb-2"
       >
-        {this.state.leaveAdminTeamRes.state == "loading" ? (
+        {this.state.leaveAdminTeamRes.state === "loading" ? (
           <Spinner />
         ) : (
-          i18n.t("leave_admin_team")
+          I18NextService.i18n.t("leave_admin_team")
         )}
       </button>
     );
@@ -261,7 +306,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
         const bans = this.state.bannedRes.data.banned;
         return (
           <>
-            <h5>{i18n.t("banned_users")}</h5>
+            <h1 className="h4 mb-4">{I18NextService.i18n.t("banned_users")}</h1>
             <ul className="list-unstyled">
               {bans.map(banned => (
                 <li key={banned.person.id} className="list-inline-item">
@@ -287,7 +332,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
         s.siteRes.taglines = editRes.data.taglines;
         return s;
       });
-      toast(i18n.t("site_saved"));
+      toast(I18NextService.i18n.t("site_saved"));
     }
 
     this.setState({ loading: false });
@@ -308,41 +353,29 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
     });
 
     if (this.state.leaveAdminTeamRes.state === "success") {
-      toast(i18n.t("left_admin_team"));
+      toast(I18NextService.i18n.t("left_admin_team"));
       this.context.router.history.replace("/");
     }
   }
 
   async handleEditEmoji(form: EditCustomEmoji) {
-    this.setState({ emojiLoading: true });
-
     const res = await HttpService.client.editCustomEmoji(form);
     if (res.state === "success") {
       updateEmojiDataModel(res.data.custom_emoji);
     }
-
-    this.setState({ emojiLoading: false });
   }
 
   async handleDeleteEmoji(form: DeleteCustomEmoji) {
-    this.setState({ emojiLoading: true });
-
     const res = await HttpService.client.deleteCustomEmoji(form);
     if (res.state === "success") {
       removeFromEmojiDataModel(res.data.id);
     }
-
-    this.setState({ emojiLoading: false });
   }
 
   async handleCreateEmoji(form: CreateCustomEmoji) {
-    this.setState({ emojiLoading: true });
-
     const res = await HttpService.client.createCustomEmoji(form);
     if (res.state === "success") {
       updateEmojiDataModel(res.data.custom_emoji);
     }
-
-    this.setState({ emojiLoading: false });
   }
 }