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