]> Untitled Git - lemmy-ui.git/blob - src/shared/components/person/registration-applications.tsx
Adding option types 2 (#689)
[lemmy-ui.git] / src / shared / components / person / registration-applications.tsx
1 import { None, Option, Some } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
3 import {
4   GetSiteResponse,
5   ListRegistrationApplications,
6   ListRegistrationApplicationsResponse,
7   RegistrationApplicationResponse,
8   UserOperation,
9   wsJsonToRes,
10   wsUserOp,
11 } from "lemmy-js-client";
12 import { Subscription } from "rxjs";
13 import { i18n } from "../../i18next";
14 import { InitialFetchRequest } from "../../interfaces";
15 import { UserService, WebSocketService } from "../../services";
16 import {
17   auth,
18   fetchLimit,
19   isBrowser,
20   setIsoData,
21   setupTippy,
22   toast,
23   updateRegistrationApplicationRes,
24   wsClient,
25   wsSubscribe,
26 } from "../../utils";
27 import { HtmlTags } from "../common/html-tags";
28 import { Spinner } from "../common/icon";
29 import { Paginator } from "../common/paginator";
30 import { RegistrationApplication } from "../common/registration-application";
31
32 enum UnreadOrAll {
33   Unread,
34   All,
35 }
36
37 interface RegistrationApplicationsState {
38   listRegistrationApplicationsResponse: Option<ListRegistrationApplicationsResponse>;
39   siteRes: GetSiteResponse;
40   unreadOrAll: UnreadOrAll;
41   page: number;
42   loading: boolean;
43 }
44
45 export class RegistrationApplications extends Component<
46   any,
47   RegistrationApplicationsState
48 > {
49   private isoData = setIsoData(
50     this.context,
51     ListRegistrationApplicationsResponse
52   );
53   private subscription: Subscription;
54   private emptyState: RegistrationApplicationsState = {
55     listRegistrationApplicationsResponse: None,
56     siteRes: this.isoData.site_res,
57     unreadOrAll: UnreadOrAll.Unread,
58     page: 1,
59     loading: true,
60   };
61
62   constructor(props: any, context: any) {
63     super(props, context);
64
65     this.state = this.emptyState;
66     this.handlePageChange = this.handlePageChange.bind(this);
67
68     if (UserService.Instance.myUserInfo.isNone() && isBrowser()) {
69       toast(i18n.t("not_logged_in"), "danger");
70       this.context.router.history.push(`/login`);
71     }
72
73     this.parseMessage = this.parseMessage.bind(this);
74     this.subscription = wsSubscribe(this.parseMessage);
75
76     // Only fetch the data if coming from another route
77     if (this.isoData.path == this.context.router.route.match.url) {
78       this.state.listRegistrationApplicationsResponse = Some(
79         this.isoData.routeData[0] as ListRegistrationApplicationsResponse
80       );
81       this.state.loading = false;
82     } else {
83       this.refetch();
84     }
85   }
86
87   componentDidMount() {
88     setupTippy();
89   }
90
91   componentWillUnmount() {
92     if (isBrowser()) {
93       this.subscription.unsubscribe();
94     }
95   }
96
97   get documentTitle(): string {
98     return this.state.siteRes.site_view.match({
99       some: siteView =>
100         UserService.Instance.myUserInfo.match({
101           some: mui =>
102             `@${mui.local_user_view.person.name} ${i18n.t(
103               "registration_applications"
104             )} - ${siteView.site.name}`,
105           none: "",
106         }),
107       none: "",
108     });
109   }
110
111   render() {
112     return (
113       <div class="container">
114         {this.state.loading ? (
115           <h5>
116             <Spinner large />
117           </h5>
118         ) : (
119           <div class="row">
120             <div class="col-12">
121               <HtmlTags
122                 title={this.documentTitle}
123                 path={this.context.router.route.match.url}
124                 description={None}
125                 image={None}
126               />
127               <h5 class="mb-2">{i18n.t("registration_applications")}</h5>
128               {this.selects()}
129               {this.applicationList()}
130               <Paginator
131                 page={this.state.page}
132                 onChange={this.handlePageChange}
133               />
134             </div>
135           </div>
136         )}
137       </div>
138     );
139   }
140
141   unreadOrAllRadios() {
142     return (
143       <div class="btn-group btn-group-toggle flex-wrap mb-2">
144         <label
145           className={`btn btn-outline-secondary pointer
146             ${this.state.unreadOrAll == UnreadOrAll.Unread && "active"}
147           `}
148         >
149           <input
150             type="radio"
151             value={UnreadOrAll.Unread}
152             checked={this.state.unreadOrAll == UnreadOrAll.Unread}
153             onChange={linkEvent(this, this.handleUnreadOrAllChange)}
154           />
155           {i18n.t("unread")}
156         </label>
157         <label
158           className={`btn btn-outline-secondary pointer
159             ${this.state.unreadOrAll == UnreadOrAll.All && "active"}
160           `}
161         >
162           <input
163             type="radio"
164             value={UnreadOrAll.All}
165             checked={this.state.unreadOrAll == UnreadOrAll.All}
166             onChange={linkEvent(this, this.handleUnreadOrAllChange)}
167           />
168           {i18n.t("all")}
169         </label>
170       </div>
171     );
172   }
173
174   selects() {
175     return (
176       <div className="mb-2">
177         <span class="mr-3">{this.unreadOrAllRadios()}</span>
178       </div>
179     );
180   }
181
182   applicationList() {
183     return this.state.listRegistrationApplicationsResponse.match({
184       some: res => (
185         <div>
186           {res.registration_applications.map(ra => (
187             <>
188               <hr />
189               <RegistrationApplication
190                 key={ra.registration_application.id}
191                 application={ra}
192               />
193             </>
194           ))}
195         </div>
196       ),
197       none: <></>,
198     });
199   }
200
201   handleUnreadOrAllChange(i: RegistrationApplications, event: any) {
202     i.state.unreadOrAll = Number(event.target.value);
203     i.state.page = 1;
204     i.setState(i.state);
205     i.refetch();
206   }
207
208   handlePageChange(page: number) {
209     this.setState({ page });
210     this.refetch();
211   }
212
213   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
214     let promises: Promise<any>[] = [];
215
216     let form = new ListRegistrationApplications({
217       unread_only: Some(true),
218       page: Some(1),
219       limit: Some(fetchLimit),
220       auth: req.auth.unwrap(),
221     });
222     promises.push(req.client.listRegistrationApplications(form));
223
224     return promises;
225   }
226
227   refetch() {
228     let unread_only = this.state.unreadOrAll == UnreadOrAll.Unread;
229     let form = new ListRegistrationApplications({
230       unread_only: Some(unread_only),
231       page: Some(this.state.page),
232       limit: Some(fetchLimit),
233       auth: auth().unwrap(),
234     });
235     WebSocketService.Instance.send(wsClient.listRegistrationApplications(form));
236   }
237
238   parseMessage(msg: any) {
239     let op = wsUserOp(msg);
240     console.log(msg);
241     if (msg.error) {
242       toast(i18n.t(msg.error), "danger");
243       return;
244     } else if (msg.reconnect) {
245       this.refetch();
246     } else if (op == UserOperation.ListRegistrationApplications) {
247       let data = wsJsonToRes<ListRegistrationApplicationsResponse>(
248         msg,
249         ListRegistrationApplicationsResponse
250       );
251       this.state.listRegistrationApplicationsResponse = Some(data);
252       this.state.loading = false;
253       window.scrollTo(0, 0);
254       this.setState(this.state);
255     } else if (op == UserOperation.ApproveRegistrationApplication) {
256       let data = wsJsonToRes<RegistrationApplicationResponse>(
257         msg,
258         RegistrationApplicationResponse
259       );
260       updateRegistrationApplicationRes(
261         data.registration_application,
262         this.state.listRegistrationApplicationsResponse
263           .map(r => r.registration_applications)
264           .unwrapOr([])
265       );
266       let uacs = UserService.Instance.unreadApplicationCountSub;
267       // Minor bug, where if the application switches from deny to approve, the count will still go down
268       uacs.next(uacs.getValue() - 1);
269       this.setState(this.state);
270     }
271   }
272 }