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