]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/admin-settings.tsx
3a2238ba14f4b348351b461611fa08612f5431d1
[lemmy-ui.git] / src / shared / components / home / admin-settings.tsx
1 import autosize from "autosize";
2 import { Component, linkEvent } from "inferno";
3 import {
4   BannedPersonsResponse,
5   GetBannedPersons,
6   GetFederatedInstancesResponse,
7   GetSiteResponse,
8   PersonView,
9   SiteResponse,
10   UserOperation,
11   wsJsonToRes,
12   wsUserOp,
13 } from "lemmy-js-client";
14 import { Subscription } from "rxjs";
15 import { i18n } from "../../i18next";
16 import { InitialFetchRequest } from "../../interfaces";
17 import { WebSocketService } from "../../services";
18 import {
19   capitalizeFirstLetter,
20   isBrowser,
21   myAuth,
22   randomStr,
23   setIsoData,
24   showLocal,
25   toast,
26   wsClient,
27   wsSubscribe,
28 } from "../../utils";
29 import { HtmlTags } from "../common/html-tags";
30 import { Spinner } from "../common/icon";
31 import Tabs from "../common/tabs";
32 import { PersonListing } from "../person/person-listing";
33 import { EmojiForm } from "./emojis-form";
34 import { SiteForm } from "./site-form";
35 import { TaglineForm } from "./tagline-form";
36
37 interface AdminSettingsState {
38   siteRes: GetSiteResponse;
39   instancesRes?: GetFederatedInstancesResponse;
40   banned: PersonView[];
41   loading: boolean;
42   leaveAdminTeamLoading: boolean;
43 }
44
45 export class AdminSettings extends Component<any, AdminSettingsState> {
46   private siteConfigTextAreaId = `site-config-${randomStr()}`;
47   private isoData = setIsoData(this.context);
48   private subscription?: Subscription;
49   state: AdminSettingsState = {
50     siteRes: this.isoData.site_res,
51     banned: [],
52     loading: true,
53     leaveAdminTeamLoading: false,
54   };
55
56   constructor(props: any, context: any) {
57     super(props, context);
58
59     this.parseMessage = this.parseMessage.bind(this);
60     this.subscription = wsSubscribe(this.parseMessage);
61
62     // Only fetch the data if coming from another route
63     if (this.isoData.path == this.context.router.route.match.url) {
64       this.state = {
65         ...this.state,
66         banned: (this.isoData.routeData[0] as BannedPersonsResponse).banned,
67         instancesRes: this.isoData
68           .routeData[1] as GetFederatedInstancesResponse,
69         loading: false,
70       };
71     } else {
72       let cAuth = myAuth();
73       if (cAuth) {
74         WebSocketService.Instance.send(
75           wsClient.getBannedPersons({
76             auth: cAuth,
77           })
78         );
79         WebSocketService.Instance.send(
80           wsClient.getFederatedInstances({ auth: cAuth })
81         );
82       }
83     }
84   }
85
86   static fetchInitialData(req: InitialFetchRequest): Promise<any>[] {
87     let promises: Promise<any>[] = [];
88
89     let auth = req.auth;
90     if (auth) {
91       let bannedPersonsForm: GetBannedPersons = { auth };
92       promises.push(req.client.getBannedPersons(bannedPersonsForm));
93       promises.push(req.client.getFederatedInstances({ auth }));
94     }
95
96     return promises;
97   }
98
99   componentDidMount() {
100     if (isBrowser()) {
101       var textarea: any = document.getElementById(this.siteConfigTextAreaId);
102       autosize(textarea);
103     }
104   }
105
106   componentWillUnmount() {
107     if (isBrowser()) {
108       this.subscription?.unsubscribe();
109     }
110   }
111
112   get documentTitle(): string {
113     return `${i18n.t("admin_settings")} - ${
114       this.state.siteRes.site_view.site.name
115     }`;
116   }
117
118   render() {
119     return (
120       <div className="container-lg">
121         <HtmlTags
122           title={this.documentTitle}
123           path={this.context.router.route.match.url}
124         />
125         {this.state.loading ? (
126           <h5>
127             <Spinner large />
128           </h5>
129         ) : (
130           <Tabs
131             tabs={[
132               {
133                 key: "site",
134                 label: i18n.t("site"),
135                 getNode: () => (
136                   <div className="row">
137                     <div className="col-12 col-md-6">
138                       <SiteForm
139                         siteRes={this.state.siteRes}
140                         instancesRes={this.state.instancesRes}
141                         showLocal={showLocal(this.isoData)}
142                       />
143                     </div>
144                     <div className="col-12 col-md-6">
145                       {this.admins()}
146                       {this.bannedUsers()}
147                     </div>
148                   </div>
149                 ),
150               },
151               {
152                 key: "taglines",
153                 label: i18n.t("taglines"),
154                 getNode: () => (
155                   <div className="row">
156                     <TaglineForm siteRes={this.state.siteRes} />
157                   </div>
158                 ),
159               },
160               {
161                 key: "emojis",
162                 label: i18n.t("emojis"),
163                 getNode: () => (
164                   <div className="row">
165                     <EmojiForm />
166                   </div>
167                 ),
168               },
169             ]}
170           />
171         )}
172       </div>
173     );
174   }
175
176   admins() {
177     return (
178       <>
179         <h5>{capitalizeFirstLetter(i18n.t("admins"))}</h5>
180         <ul className="list-unstyled">
181           {this.state.siteRes.admins.map(admin => (
182             <li key={admin.person.id} className="list-inline-item">
183               <PersonListing person={admin.person} />
184             </li>
185           ))}
186         </ul>
187         {this.leaveAdmin()}
188       </>
189     );
190   }
191
192   leaveAdmin() {
193     return (
194       <button
195         onClick={linkEvent(this, this.handleLeaveAdminTeam)}
196         className="btn btn-danger mb-2"
197       >
198         {this.state.leaveAdminTeamLoading ? (
199           <Spinner />
200         ) : (
201           i18n.t("leave_admin_team")
202         )}
203       </button>
204     );
205   }
206
207   bannedUsers() {
208     return (
209       <>
210         <h5>{i18n.t("banned_users")}</h5>
211         <ul className="list-unstyled">
212           {this.state.banned.map(banned => (
213             <li key={banned.person.id} className="list-inline-item">
214               <PersonListing person={banned.person} />
215             </li>
216           ))}
217         </ul>
218       </>
219     );
220   }
221
222   handleLeaveAdminTeam(i: AdminSettings) {
223     let auth = myAuth();
224     if (auth) {
225       i.setState({ leaveAdminTeamLoading: true });
226       WebSocketService.Instance.send(wsClient.leaveAdmin({ auth }));
227     }
228   }
229
230   parseMessage(msg: any) {
231     let op = wsUserOp(msg);
232     console.log(msg);
233     if (msg.error) {
234       toast(i18n.t(msg.error), "danger");
235       this.context.router.history.push("/");
236       this.setState({ loading: false });
237       return;
238     } else if (op == UserOperation.EditSite) {
239       let data = wsJsonToRes<SiteResponse>(msg);
240       this.setState(s => ((s.siteRes.site_view = data.site_view), s));
241       toast(i18n.t("site_saved"));
242     } else if (op == UserOperation.GetBannedPersons) {
243       let data = wsJsonToRes<BannedPersonsResponse>(msg);
244       this.setState({ banned: data.banned, loading: false });
245     } else if (op == UserOperation.LeaveAdmin) {
246       let data = wsJsonToRes<GetSiteResponse>(msg);
247       this.setState(s => ((s.siteRes.site_view = data.site_view), s));
248       this.setState({ leaveAdminTeamLoading: false });
249       toast(i18n.t("left_admin_team"));
250       this.context.router.history.push("/");
251     } else if (op == UserOperation.GetFederatedInstances) {
252       let data = wsJsonToRes<GetFederatedInstancesResponse>(msg);
253       this.setState({ instancesRes: data });
254     }
255   }
256 }