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