]> Untitled Git - lemmy-ui.git/blob - src/shared/components/person/registration-applications.tsx
ES-Lint tweak (#2001)
[lemmy-ui.git] / src / shared / components / person / registration-applications.tsx
1 import {
2   editRegistrationApplication,
3   myAuthRequired,
4   setIsoData,
5 } from "@utils/app";
6 import { randomStr } from "@utils/helpers";
7 import { RouteDataResponse } from "@utils/types";
8 import classNames from "classnames";
9 import { Component, linkEvent } from "inferno";
10 import {
11   ApproveRegistrationApplication,
12   GetSiteResponse,
13   ListRegistrationApplicationsResponse,
14   RegistrationApplicationView,
15 } from "lemmy-js-client";
16 import { fetchLimit } from "../../config";
17 import { InitialFetchRequest } from "../../interfaces";
18 import { FirstLoadService, I18NextService, UserService } from "../../services";
19 import { HttpService, RequestState } from "../../services/HttpService";
20 import { setupTippy } from "../../tippy";
21 import { HtmlTags } from "../common/html-tags";
22 import { Spinner } from "../common/icon";
23 import { Paginator } from "../common/paginator";
24 import { RegistrationApplication } from "../common/registration-application";
25
26 enum UnreadOrAll {
27   Unread,
28   All,
29 }
30
31 type RegistrationApplicationsData = RouteDataResponse<{
32   listRegistrationApplicationsResponse: ListRegistrationApplicationsResponse;
33 }>;
34
35 interface RegistrationApplicationsState {
36   appsRes: RequestState<ListRegistrationApplicationsResponse>;
37   siteRes: GetSiteResponse;
38   unreadOrAll: UnreadOrAll;
39   page: number;
40   isIsomorphic: boolean;
41 }
42
43 export class RegistrationApplications extends Component<
44   any,
45   RegistrationApplicationsState
46 > {
47   private isoData = setIsoData<RegistrationApplicationsData>(this.context);
48   state: RegistrationApplicationsState = {
49     appsRes: { state: "empty" },
50     siteRes: this.isoData.site_res,
51     unreadOrAll: UnreadOrAll.Unread,
52     page: 1,
53     isIsomorphic: false,
54   };
55
56   constructor(props: any, context: any) {
57     super(props, context);
58
59     this.handlePageChange = this.handlePageChange.bind(this);
60     this.handleApproveApplication = this.handleApproveApplication.bind(this);
61
62     // Only fetch the data if coming from another route
63     if (FirstLoadService.isFirstLoad) {
64       this.state = {
65         ...this.state,
66         appsRes: this.isoData.routeData.listRegistrationApplicationsResponse,
67         isIsomorphic: true,
68       };
69     }
70   }
71
72   async componentDidMount() {
73     if (!this.state.isIsomorphic) {
74       await this.refetch();
75     }
76     setupTippy();
77   }
78
79   get documentTitle(): string {
80     const mui = UserService.Instance.myUserInfo;
81     return mui
82       ? `@${mui.local_user_view.person.name} ${I18NextService.i18n.t(
83           "registration_applications"
84         )} - ${this.state.siteRes.site_view.site.name}`
85       : "";
86   }
87
88   renderApps() {
89     switch (this.state.appsRes.state) {
90       case "loading":
91         return (
92           <h5>
93             <Spinner large />
94           </h5>
95         );
96       case "success": {
97         const apps = this.state.appsRes.data.registration_applications;
98         return (
99           <div className="row">
100             <div className="col-12">
101               <HtmlTags
102                 title={this.documentTitle}
103                 path={this.context.router.route.match.url}
104               />
105               <h1 className="h4 mb-4">
106                 {I18NextService.i18n.t("registration_applications")}
107               </h1>
108               {this.selects()}
109               {this.applicationList(apps)}
110               <Paginator
111                 page={this.state.page}
112                 onChange={this.handlePageChange}
113               />
114             </div>
115           </div>
116         );
117       }
118     }
119   }
120
121   render() {
122     return (
123       <div className="registration-applications container-lg">
124         {this.renderApps()}
125       </div>
126     );
127   }
128
129   unreadOrAllRadios() {
130     const radioId = randomStr();
131
132     return (
133       <div className="btn-group btn-group-toggle flex-wrap mb-2" role="group">
134         <input
135           id={`${radioId}-unread`}
136           type="radio"
137           className="btn-check"
138           value={UnreadOrAll.Unread}
139           checked={this.state.unreadOrAll === UnreadOrAll.Unread}
140           onChange={linkEvent(this, this.handleUnreadOrAllChange)}
141         />
142         <label
143           htmlFor={`${radioId}-unread`}
144           className={classNames("btn btn-outline-secondary pointer", {
145             active: this.state.unreadOrAll === UnreadOrAll.Unread,
146           })}
147         >
148           {I18NextService.i18n.t("unread")}
149         </label>
150
151         <input
152           id={`${radioId}-all`}
153           type="radio"
154           className="btn-check"
155           value={UnreadOrAll.All}
156           checked={this.state.unreadOrAll === UnreadOrAll.All}
157           onChange={linkEvent(this, this.handleUnreadOrAllChange)}
158         />
159         <label
160           htmlFor={`${radioId}-all`}
161           className={classNames("btn btn-outline-secondary pointer", {
162             active: this.state.unreadOrAll === UnreadOrAll.All,
163           })}
164         >
165           {I18NextService.i18n.t("all")}
166         </label>
167       </div>
168     );
169   }
170
171   selects() {
172     return (
173       <div className="mb-2">
174         <span className="me-3">{this.unreadOrAllRadios()}</span>
175       </div>
176     );
177   }
178
179   applicationList(apps: RegistrationApplicationView[]) {
180     return (
181       <div>
182         {apps.map(ra => (
183           <>
184             <hr />
185             <RegistrationApplication
186               key={ra.registration_application.id}
187               application={ra}
188               onApproveApplication={this.handleApproveApplication}
189             />
190           </>
191         ))}
192       </div>
193     );
194   }
195
196   handleUnreadOrAllChange(i: RegistrationApplications, event: any) {
197     i.setState({ unreadOrAll: Number(event.target.value), page: 1 });
198     i.refetch();
199   }
200
201   handlePageChange(page: number) {
202     this.setState({ page });
203     this.refetch();
204   }
205
206   static async fetchInitialData({
207     auth,
208     client,
209   }: InitialFetchRequest): Promise<RegistrationApplicationsData> {
210     return {
211       listRegistrationApplicationsResponse: auth
212         ? await client.listRegistrationApplications({
213             unread_only: true,
214             page: 1,
215             limit: fetchLimit,
216             auth: auth as string,
217           })
218         : { state: "empty" },
219     };
220   }
221
222   async refetch() {
223     const unread_only = this.state.unreadOrAll === UnreadOrAll.Unread;
224     this.setState({
225       appsRes: { state: "loading" },
226     });
227     this.setState({
228       appsRes: await HttpService.client.listRegistrationApplications({
229         unread_only: unread_only,
230         page: this.state.page,
231         limit: fetchLimit,
232         auth: myAuthRequired(),
233       }),
234     });
235   }
236
237   async handleApproveApplication(form: ApproveRegistrationApplication) {
238     const approveRes = await HttpService.client.approveRegistrationApplication(
239       form
240     );
241     this.setState(s => {
242       if (s.appsRes.state === "success" && approveRes.state === "success") {
243         s.appsRes.data.registration_applications = editRegistrationApplication(
244           approveRes.data.registration_application,
245           s.appsRes.data.registration_applications
246         );
247       }
248       return s;
249     });
250   }
251 }