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