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