]> Untitled Git - lemmy-ui.git/blob - src/shared/components/person/registration-applications.tsx
Merge branch 'browser_popup'
[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 = {
79         ...this.state,
80         listRegistrationApplicationsResponse: Some(
81           this.isoData.routeData[0] as ListRegistrationApplicationsResponse
82         ),
83         loading: false,
84       };
85     } else {
86       this.refetch();
87     }
88   }
89
90   componentDidMount() {
91     setupTippy();
92   }
93
94   componentWillUnmount() {
95     if (isBrowser()) {
96       this.subscription.unsubscribe();
97     }
98   }
99
100   get documentTitle(): string {
101     return this.state.siteRes.site_view.match({
102       some: siteView =>
103         UserService.Instance.myUserInfo.match({
104           some: mui =>
105             `@${mui.local_user_view.person.name} ${i18n.t(
106               "registration_applications"
107             )} - ${siteView.site.name}`,
108           none: "",
109         }),
110       none: "",
111     });
112   }
113
114   render() {
115     return (
116       <div className="container-lg">
117         {this.state.loading ? (
118           <h5>
119             <Spinner large />
120           </h5>
121         ) : (
122           <div className="row">
123             <div className="col-12">
124               <HtmlTags
125                 title={this.documentTitle}
126                 path={this.context.router.route.match.url}
127                 description={None}
128                 image={None}
129               />
130               <h5 className="mb-2">{i18n.t("registration_applications")}</h5>
131               {this.selects()}
132               {this.applicationList()}
133               <Paginator
134                 page={this.state.page}
135                 onChange={this.handlePageChange}
136               />
137             </div>
138           </div>
139         )}
140       </div>
141     );
142   }
143
144   unreadOrAllRadios() {
145     return (
146       <div className="btn-group btn-group-toggle flex-wrap mb-2">
147         <label
148           className={`btn btn-outline-secondary pointer
149             ${this.state.unreadOrAll == UnreadOrAll.Unread && "active"}
150           `}
151         >
152           <input
153             type="radio"
154             value={UnreadOrAll.Unread}
155             checked={this.state.unreadOrAll == UnreadOrAll.Unread}
156             onChange={linkEvent(this, this.handleUnreadOrAllChange)}
157           />
158           {i18n.t("unread")}
159         </label>
160         <label
161           className={`btn btn-outline-secondary pointer
162             ${this.state.unreadOrAll == UnreadOrAll.All && "active"}
163           `}
164         >
165           <input
166             type="radio"
167             value={UnreadOrAll.All}
168             checked={this.state.unreadOrAll == UnreadOrAll.All}
169             onChange={linkEvent(this, this.handleUnreadOrAllChange)}
170           />
171           {i18n.t("all")}
172         </label>
173       </div>
174     );
175   }
176
177   selects() {
178     return (
179       <div className="mb-2">
180         <span className="mr-3">{this.unreadOrAllRadios()}</span>
181       </div>
182     );
183   }
184
185   applicationList() {
186     return this.state.listRegistrationApplicationsResponse.match({
187       some: res => (
188         <div>
189           {res.registration_applications.map(ra => (
190             <>
191               <hr />
192               <RegistrationApplication
193                 key={ra.registration_application.id}
194                 application={ra}
195               />
196             </>
197           ))}
198         </div>
199       ),
200       none: <></>,
201     });
202   }
203
204   handleUnreadOrAllChange(i: RegistrationApplications, event: any) {
205     i.setState({ unreadOrAll: Number(event.target.value), page: 1 });
206     i.refetch();
207   }
208
209   handlePageChange(page: number) {
210     this.setState({ page });
211     this.refetch();
212   }
213
214   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
215     let promises: Promise<any>[] = [];
216
217     let form = new ListRegistrationApplications({
218       unread_only: Some(true),
219       page: Some(1),
220       limit: Some(fetchLimit),
221       auth: req.auth.unwrap(),
222     });
223     promises.push(req.client.listRegistrationApplications(form));
224
225     return promises;
226   }
227
228   refetch() {
229     let unread_only = this.state.unreadOrAll == UnreadOrAll.Unread;
230     let form = new ListRegistrationApplications({
231       unread_only: Some(unread_only),
232       page: Some(this.state.page),
233       limit: Some(fetchLimit),
234       auth: auth().unwrap(),
235     });
236     WebSocketService.Instance.send(wsClient.listRegistrationApplications(form));
237   }
238
239   parseMessage(msg: any) {
240     let op = wsUserOp(msg);
241     console.log(msg);
242     if (msg.error) {
243       toast(i18n.t(msg.error), "danger");
244       return;
245     } else if (msg.reconnect) {
246       this.refetch();
247     } else if (op == UserOperation.ListRegistrationApplications) {
248       let data = wsJsonToRes<ListRegistrationApplicationsResponse>(
249         msg,
250         ListRegistrationApplicationsResponse
251       );
252       this.setState({
253         listRegistrationApplicationsResponse: Some(data),
254         loading: false,
255       });
256       window.scrollTo(0, 0);
257     } else if (op == UserOperation.ApproveRegistrationApplication) {
258       let data = wsJsonToRes<RegistrationApplicationResponse>(
259         msg,
260         RegistrationApplicationResponse
261       );
262       updateRegistrationApplicationRes(
263         data.registration_application,
264         this.state.listRegistrationApplicationsResponse
265           .map(r => r.registration_applications)
266           .unwrapOr([])
267       );
268       let uacs = UserService.Instance.unreadApplicationCountSub;
269       // Minor bug, where if the application switches from deny to approve, the count will still go down
270       uacs.next(uacs.getValue() - 1);
271       this.setState(this.state);
272     }
273   }
274 }