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