]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/rate-limit-form.tsx
Merge branch 'main' into expand-video-embeds-to-fullwidth
[lemmy-ui.git] / src / shared / components / home / rate-limit-form.tsx
1 import classNames from "classnames";
2 import { Component, FormEventHandler, linkEvent } from "inferno";
3 import { EditSite, LocalSiteRateLimit } from "lemmy-js-client";
4 import { i18n } from "../../i18next";
5 import { capitalizeFirstLetter, myAuthRequired } 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   className?: string;
24 }
25
26 interface RateLimitFormProps {
27   rateLimits: LocalSiteRateLimit;
28   onSaveSite(form: EditSite): void;
29   loading: boolean;
30 }
31
32 interface RateLimitFormState {
33   form: {
34     message?: number;
35     message_per_second?: number;
36     post?: number;
37     post_per_second?: number;
38     comment?: number;
39     comment_per_second?: number;
40     image?: number;
41     image_per_second?: number;
42     search?: number;
43     search_per_second?: number;
44     register?: number;
45     register_per_second?: number;
46   };
47 }
48
49 function RateLimits({
50   handleRateLimit,
51   handleRateLimitPerSecond,
52   rateLimitPerSecondValue,
53   rateLimitValue,
54   className,
55 }: RateLimitsProps) {
56   return (
57     <div role="tabpanel" className={classNames("mb-3 row", className)}>
58       <div className="col-md-6">
59         <label htmlFor="rate-limit">{i18n.t("rate_limit")}</label>
60         <input
61           type="number"
62           id="rate-limit"
63           className="form-control"
64           min={0}
65           value={rateLimitValue}
66           onInput={handleRateLimit}
67         />
68       </div>
69       <div className="col-md-6">
70         <label htmlFor="rate-limit-per-second">{i18n.t("per_second")}</label>
71         <input
72           type="number"
73           id="rate-limit-per-second"
74           className="form-control"
75           min={0}
76           value={rateLimitPerSecondValue}
77           onInput={handleRateLimitPerSecond}
78         />
79       </div>
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 = myAuthRequired();
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     {
119       auth,
120     }
121   );
122
123   i.props.onSaveSite(form);
124 }
125
126 export default class RateLimitsForm extends Component<
127   RateLimitFormProps,
128   RateLimitFormState
129 > {
130   state: RateLimitFormState = {
131     form: this.props.rateLimits,
132   };
133   constructor(props: RateLimitFormProps, context: any) {
134     super(props, context);
135   }
136
137   render() {
138     return (
139       <form
140         className="rate-limit-form"
141         onSubmit={linkEvent(this, submitRateLimitForm)}
142       >
143         <h5>{i18n.t("rate_limit_header")}</h5>
144         <Tabs
145           tabs={rateLimitTypes.map(rateLimitType => ({
146             key: rateLimitType,
147             label: i18n.t(`rate_limit_${rateLimitType}`),
148             getNode: isSelected => (
149               <RateLimits
150                 className={classNames("tab-pane show", {
151                   active: isSelected,
152                 })}
153                 handleRateLimit={linkEvent(
154                   { rateLimitType, ctx: this },
155                   handleRateLimitChange
156                 )}
157                 handleRateLimitPerSecond={linkEvent(
158                   { rateLimitType, ctx: this },
159                   handlePerSecondChange
160                 )}
161                 rateLimitValue={this.state.form[rateLimitType]}
162                 rateLimitPerSecondValue={
163                   this.state.form[`${rateLimitType}_per_second`]
164                 }
165               />
166             ),
167           }))}
168         />
169         <div className="col-12 mb-3">
170           <button
171             type="submit"
172             className="btn btn-secondary me-2"
173             disabled={this.props.loading}
174           >
175             {this.props.loading ? (
176               <Spinner />
177             ) : (
178               capitalizeFirstLetter(i18n.t("save"))
179             )}
180           </button>
181         </div>
182       </form>
183     );
184   }
185 }