]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/rate-limit-form.tsx
8f2a1a81603d6e51b4c1f90b1552f1f31fd9fdfc
[lemmy-ui.git] / src / shared / components / home / rate-limit-form.tsx
1 import { Component, FormEventHandler, linkEvent } from "inferno";
2 import { EditSite, LocalSiteRateLimit } from "lemmy-js-client";
3 import { i18n } from "../../i18next";
4 import { WebSocketService } from "../../services";
5 import { capitalizeFirstLetter, myAuth, wsClient } from "../../utils";
6 import { Spinner } from "../common/icon";
7 import Tabs from "../common/tabs";
8
9 const rateLimitTypes = [
10   "message",
11   "post",
12   "image",
13   "comment",
14   "search",
15   "register",
16 ] as const;
17
18 interface RateLimitsProps {
19   handleRateLimit: FormEventHandler<HTMLInputElement>;
20   handleRateLimitPerSecond: FormEventHandler<HTMLInputElement>;
21   rateLimitValue?: number;
22   rateLimitPerSecondValue?: number;
23 }
24
25 interface RateLimitFormProps {
26   localSiteRateLimit: LocalSiteRateLimit;
27   applicationQuestion?: string;
28 }
29
30 interface RateLimitFormState {
31   form: {
32     message?: number;
33     message_per_second?: number;
34     post?: number;
35     post_per_second?: number;
36     comment?: number;
37     comment_per_second?: number;
38     image?: number;
39     image_per_second?: number;
40     search?: number;
41     search_per_second?: number;
42     register?: number;
43     register_per_second?: number;
44   };
45   loading: boolean;
46 }
47
48 function RateLimits({
49   handleRateLimit,
50   handleRateLimitPerSecond,
51   rateLimitPerSecondValue,
52   rateLimitValue,
53 }: RateLimitsProps) {
54   return (
55     <div className="form-group row">
56       <label className="col-12 col-form-label" htmlFor="rate-limit">
57         {i18n.t("rate_limit")}
58       </label>
59       <input
60         type="number"
61         id="rate-limit"
62         className="form-control col-12"
63         min={0}
64         value={rateLimitValue}
65         onInput={handleRateLimit}
66       />
67       <label className="col-12 col-form-label" htmlFor="rate-limit-per-second">
68         {i18n.t("per_second")}
69       </label>
70       <input
71         type="number"
72         id="rate-limit-per-second"
73         className="form-control col-12"
74         min={0}
75         value={rateLimitPerSecondValue}
76         onInput={handleRateLimitPerSecond}
77       />
78     </div>
79   );
80 }
81
82 function handleRateLimitChange(
83   { rateLimitType, ctx }: { rateLimitType: string; ctx: RateLimitsForm },
84   event: any
85 ) {
86   ctx.setState(prev => ({
87     ...prev,
88     form: {
89       ...prev.form,
90       [rateLimitType]: Number(event.target.value),
91     },
92   }));
93 }
94
95 function handlePerSecondChange(
96   { rateLimitType, ctx }: { rateLimitType: string; ctx: RateLimitsForm },
97   event: any
98 ) {
99   ctx.setState(prev => ({
100     ...prev,
101     form: {
102       ...prev.form,
103       [`${rateLimitType}_per_second`]: Number(event.target.value),
104     },
105   }));
106 }
107
108 function submitRateLimitForm(i: RateLimitsForm, event: any) {
109   event.preventDefault();
110   const auth = myAuth() ?? "TODO";
111   const form: EditSite = Object.entries(i.state.form).reduce(
112     (acc, [key, val]) => {
113       acc[`rate_limit_${key}`] = val;
114       return acc;
115     },
116     { auth, application_question: i.props.applicationQuestion }
117   );
118
119   i.setState({ loading: true });
120
121   WebSocketService.Instance.send(wsClient.editSite(form));
122 }
123
124 export default class RateLimitsForm extends Component<
125   RateLimitFormProps,
126   RateLimitFormState
127 > {
128   state: RateLimitFormState = {
129     loading: false,
130     form: {},
131   };
132   constructor(props: RateLimitFormProps, context) {
133     super(props, context);
134
135     const {
136       comment,
137       comment_per_second,
138       image,
139       image_per_second,
140       message,
141       message_per_second,
142       post,
143       post_per_second,
144       register,
145       register_per_second,
146       search,
147       search_per_second,
148     } = props.localSiteRateLimit;
149
150     this.state = {
151       ...this.state,
152       form: {
153         comment,
154         comment_per_second,
155         image,
156         image_per_second,
157         message,
158         message_per_second,
159         post,
160         post_per_second,
161         register,
162         register_per_second,
163         search,
164         search_per_second,
165       },
166     };
167   }
168
169   render() {
170     return (
171       <form onSubmit={linkEvent(this, submitRateLimitForm)}>
172         <h5>{i18n.t("rate_limit_header")}</h5>
173         <Tabs
174           tabs={rateLimitTypes.map(rateLimitType => ({
175             key: rateLimitType,
176             label: i18n.t(`rate_limit_${rateLimitType}`),
177             getNode: () => (
178               <RateLimits
179                 handleRateLimit={linkEvent(
180                   { rateLimitType, ctx: this },
181                   handleRateLimitChange
182                 )}
183                 handleRateLimitPerSecond={linkEvent(
184                   { rateLimitType, ctx: this },
185                   handlePerSecondChange
186                 )}
187                 rateLimitValue={this.state.form[rateLimitType]}
188                 rateLimitPerSecondValue={
189                   this.state.form[`${rateLimitType}_per_second`]
190                 }
191               />
192             ),
193           }))}
194         />
195         <div className="form-group row">
196           <div className="col-12">
197             <button
198               type="submit"
199               className="btn btn-secondary mr-2"
200               disabled={this.state.loading}
201             >
202               {this.state.loading ? (
203                 <Spinner />
204               ) : (
205                 capitalizeFirstLetter(i18n.t("save"))
206               )}
207             </button>
208           </div>
209         </div>
210       </form>
211     );
212   }
213
214   componentDidUpdate({ localSiteRateLimit }: RateLimitFormProps) {
215     if (
216       this.state.loading &&
217       Object.entries(localSiteRateLimit).some(
218         ([key, val]) => this.state.form[key] !== val
219       )
220     ) {
221       this.setState({ loading: false });
222     }
223   }
224 }