From cf58a0c4515f4c8ba772c00ca02a9f928fe749fc Mon Sep 17 00:00:00 2001
From: abias <abias1122@gmail.com>
Date: Sun, 21 May 2023 12:40:22 -0400
Subject: [PATCH] Allow user to submit rate limit changes

---
 src/shared/components/common/tabs.tsx         |   1 +
 src/shared/components/home/admin-settings.tsx |   4 +
 .../components/home/rate-limit-form.tsx       | 173 ++++++++++++------
 3 files changed, 124 insertions(+), 54 deletions(-)

diff --git a/src/shared/components/common/tabs.tsx b/src/shared/components/common/tabs.tsx
index 36e1a01..61ed396 100644
--- a/src/shared/components/common/tabs.tsx
+++ b/src/shared/components/common/tabs.tsx
@@ -35,6 +35,7 @@ export default class Tabs extends Component<TabsProps, TabsState> {
           {this.props.tabs.map(({ key, label }) => (
             <li key={key} className="nav-item">
               <button
+                type="button"
                 className={`nav-link btn${
                   this.state?.currentTab === key ? " active" : ""
                 }`}
diff --git a/src/shared/components/home/admin-settings.tsx b/src/shared/components/home/admin-settings.tsx
index 8370bec..d266db5 100644
--- a/src/shared/components/home/admin-settings.tsx
+++ b/src/shared/components/home/admin-settings.tsx
@@ -157,6 +157,10 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
                     localSiteRateLimit={
                       this.state.siteRes.site_view.local_site_rate_limit
                     }
+                    applicationQuestion={
+                      this.state.siteRes.site_view.local_site
+                        .application_question
+                    }
                   />
                 ),
               },
diff --git a/src/shared/components/home/rate-limit-form.tsx b/src/shared/components/home/rate-limit-form.tsx
index 95f7fee..db37090 100644
--- a/src/shared/components/home/rate-limit-form.tsx
+++ b/src/shared/components/home/rate-limit-form.tsx
@@ -1,6 +1,9 @@
 import { Component, FormEventHandler, linkEvent } from "inferno";
-import { LocalSiteRateLimit } from "lemmy-js-client";
+import { EditSite, LocalSiteRateLimit } from "lemmy-js-client";
 import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
+import { capitalizeFirstLetter, myAuth, wsClient } from "../../utils";
+import { Spinner } from "../common/icon";
 import Tabs from "../common/tabs";
 
 const rateLimitTypes = [
@@ -22,21 +25,25 @@ interface RateLimitsProps {
 
 interface RateLimitFormProps {
   localSiteRateLimit: LocalSiteRateLimit;
+  applicationQuestion?: string;
 }
 
 interface RateLimitFormState {
-  message?: number;
-  message_per_second?: number;
-  post?: number;
-  post_per_second?: number;
-  comment?: number;
-  comment_per_second?: number;
-  image?: number;
-  image_per_second?: number;
-  search?: number;
-  search_per_second?: number;
-  register?: number;
-  register_per_second?: number;
+  form: {
+    message?: number;
+    message_per_second?: number;
+    post?: number;
+    post_per_second?: number;
+    comment?: number;
+    comment_per_second?: number;
+    image?: number;
+    image_per_second?: number;
+    search?: number;
+    search_per_second?: number;
+    register?: number;
+    register_per_second?: number;
+  };
+  loading: boolean;
 }
 
 function RateLimits({
@@ -78,25 +85,52 @@ function handleRateLimitChange(
   { rateLimitType, ctx }: { rateLimitType: string; ctx: RateLimitsForm },
   event: any
 ) {
-  ctx.setState({
-    [rateLimitType]: Number(event.target.value),
-  });
+  ctx.setState(prev => ({
+    ...prev,
+    form: {
+      ...prev.form,
+      [rateLimitType]: Number(event.target.value),
+    },
+  }));
 }
 
 function handlePerSecondChange(
   { rateLimitType, ctx }: { rateLimitType: string; ctx: RateLimitsForm },
   event: any
 ) {
-  ctx.setState({
-    [`${rateLimitType}_per_second`]: Number(event.target.value),
-  });
+  ctx.setState(prev => ({
+    ...prev,
+    form: {
+      ...prev.form,
+      [`${rateLimitType}_per_second`]: Number(event.target.value),
+    },
+  }));
+}
+
+function submitRateLimitForm(i: RateLimitsForm, event: any) {
+  event.preventDefault();
+  const auth = myAuth() ?? "TODO";
+  const form: EditSite = Object.entries(i.state.form).reduce(
+    (acc, [key, val]) => {
+      acc[`rate_limit_${key}`] = val;
+      return acc;
+    },
+    { auth, application_question: i.props.applicationQuestion }
+  );
+
+  i.setState({ loading: true });
+
+  WebSocketService.Instance.send(wsClient.editSite(form));
 }
 
 export default class RateLimitsForm extends Component<
   RateLimitFormProps,
   RateLimitFormState
 > {
-  state: RateLimitFormState = {};
+  state: RateLimitFormState = {
+    loading: false,
+    form: {},
+  };
   constructor(props: RateLimitFormProps, context) {
     super(props, context);
 
@@ -116,46 +150,77 @@ export default class RateLimitsForm extends Component<
     } = props.localSiteRateLimit;
 
     this.state = {
-      comment,
-      comment_per_second,
-      image,
-      image_per_second,
-      message,
-      message_per_second,
-      post,
-      post_per_second,
-      register,
-      register_per_second,
-      search,
-      search_per_second,
+      ...this.state,
+      form: {
+        comment,
+        comment_per_second,
+        image,
+        image_per_second,
+        message,
+        message_per_second,
+        post,
+        post_per_second,
+        register,
+        register_per_second,
+        search,
+        search_per_second,
+      },
     };
   }
 
   render() {
     return (
-      <Tabs
-        tabs={rateLimitTypes.map(rateLimitType => ({
-          key: rateLimitType,
-          label: rateLimitType,
-          getNode: () => (
-            <RateLimits
-              handleRateLimit={linkEvent(
-                { rateLimitType, ctx: this },
-                handleRateLimitChange
-              )}
-              handleRateLimitPerSecond={linkEvent(
-                { rateLimitType, ctx: this },
-                handlePerSecondChange
+      <form onSubmit={linkEvent(this, submitRateLimitForm)}>
+        <Tabs
+          tabs={rateLimitTypes.map(rateLimitType => ({
+            key: rateLimitType,
+            label: rateLimitType,
+            getNode: () => (
+              <RateLimits
+                handleRateLimit={linkEvent(
+                  { rateLimitType, ctx: this },
+                  handleRateLimitChange
+                )}
+                handleRateLimitPerSecond={linkEvent(
+                  { rateLimitType, ctx: this },
+                  handlePerSecondChange
+                )}
+                rateLimitLabel={i18n.t(`rate_limit_${rateLimitType}`)}
+                rateLimitValue={this.state.form[rateLimitType]}
+                rateLimitPerSecondValue={
+                  this.state.form[`${rateLimitType}_per_second`]
+                }
+              />
+            ),
+          }))}
+        />
+        <div className="form-group row">
+          <div className="col-12">
+            <button
+              type="submit"
+              className="btn btn-secondary mr-2"
+              disabled={this.state.loading}
+            >
+              {this.state.loading ? (
+                <Spinner />
+              ) : (
+                capitalizeFirstLetter(i18n.t("save"))
               )}
-              rateLimitLabel={i18n.t(`rate_limit_${rateLimitType}`)}
-              rateLimitValue={this.state[rateLimitType]}
-              rateLimitPerSecondValue={
-                this.state[`${rateLimitType}_per_second`]
-              }
-            />
-          ),
-        }))}
-      />
+            </button>
+          </div>
+        </div>
+      </form>
     );
   }
+
+  componentDidUpdate({ localSiteRateLimit }: RateLimitFormProps) {
+    if (
+      this.state.loading &&
+      Object.entries(localSiteRateLimit).some(
+        ([key, val]) => this.state.form[key] !== val
+      )
+    ) {
+      this.setState({ loading: false });
+    }
+  }
 }
-- 
2.44.1