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