]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/setup.tsx
Make sure user is logged in for site creation. Fixes #838 (#858)
[lemmy-ui.git] / src / shared / components / home / setup.tsx
1 import { None, Some } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
3 import { Helmet } from "inferno-helmet";
4 import {
5   GetSiteResponse,
6   LoginResponse,
7   Register,
8   toUndefined,
9   UserOperation,
10   wsJsonToRes,
11   wsUserOp,
12 } from "lemmy-js-client";
13 import { Subscription } from "rxjs";
14 import { delay, retryWhen, take } from "rxjs/operators";
15 import { i18n } from "../../i18next";
16 import { UserService, WebSocketService } from "../../services";
17 import { setIsoData, toast, wsClient } from "../../utils";
18 import { Spinner } from "../common/icon";
19 import { SiteForm } from "./site-form";
20
21 interface State {
22   userForm: Register;
23   doneRegisteringUser: boolean;
24   userLoading: boolean;
25   siteRes: GetSiteResponse;
26 }
27
28 export class Setup extends Component<any, State> {
29   private subscription: Subscription;
30   private isoData = setIsoData(this.context);
31
32   private emptyState: State = {
33     userForm: new Register({
34       username: undefined,
35       password: undefined,
36       password_verify: undefined,
37       show_nsfw: true,
38       // The first admin signup doesn't need a captcha
39       captcha_uuid: None,
40       captcha_answer: None,
41       email: None,
42       honeypot: None,
43       answer: None,
44     }),
45     doneRegisteringUser: UserService.Instance.myUserInfo.isSome(),
46     userLoading: false,
47     siteRes: this.isoData.site_res,
48   };
49
50   constructor(props: any, context: any) {
51     super(props, context);
52
53     this.state = this.emptyState;
54
55     this.subscription = WebSocketService.Instance.subject
56       .pipe(retryWhen(errors => errors.pipe(delay(3000), take(10))))
57       .subscribe(
58         msg => this.parseMessage(msg),
59         err => console.error(err),
60         () => console.log("complete")
61       );
62   }
63
64   componentWillUnmount() {
65     this.subscription.unsubscribe();
66   }
67
68   get documentTitle(): string {
69     return `${i18n.t("setup")} - Lemmy`;
70   }
71
72   render() {
73     return (
74       <div className="container-lg">
75         <Helmet title={this.documentTitle} />
76         <div className="row">
77           <div className="col-12 offset-lg-3 col-lg-6">
78             <h3>{i18n.t("lemmy_instance_setup")}</h3>
79             {!this.state.doneRegisteringUser ? (
80               this.registerUser()
81             ) : (
82               <SiteForm siteRes={this.state.siteRes} showLocal />
83             )}
84           </div>
85         </div>
86       </div>
87     );
88   }
89
90   registerUser() {
91     return (
92       <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
93         <h5>{i18n.t("setup_admin")}</h5>
94         <div className="form-group row">
95           <label className="col-sm-2 col-form-label" htmlFor="username">
96             {i18n.t("username")}
97           </label>
98           <div className="col-sm-10">
99             <input
100               type="text"
101               className="form-control"
102               id="username"
103               value={this.state.userForm.username}
104               onInput={linkEvent(this, this.handleRegisterUsernameChange)}
105               required
106               minLength={3}
107               pattern="[a-zA-Z0-9_]+"
108             />
109           </div>
110         </div>
111         <div className="form-group row">
112           <label className="col-sm-2 col-form-label" htmlFor="email">
113             {i18n.t("email")}
114           </label>
115
116           <div className="col-sm-10">
117             <input
118               type="email"
119               id="email"
120               className="form-control"
121               placeholder={i18n.t("optional")}
122               value={toUndefined(this.state.userForm.email)}
123               onInput={linkEvent(this, this.handleRegisterEmailChange)}
124               minLength={3}
125             />
126           </div>
127         </div>
128         <div className="form-group row">
129           <label className="col-sm-2 col-form-label" htmlFor="password">
130             {i18n.t("password")}
131           </label>
132           <div className="col-sm-10">
133             <input
134               type="password"
135               id="password"
136               value={this.state.userForm.password}
137               onInput={linkEvent(this, this.handleRegisterPasswordChange)}
138               className="form-control"
139               required
140               autoComplete="new-password"
141               minLength={10}
142               maxLength={60}
143             />
144           </div>
145         </div>
146         <div className="form-group row">
147           <label className="col-sm-2 col-form-label" htmlFor="verify-password">
148             {i18n.t("verify_password")}
149           </label>
150           <div className="col-sm-10">
151             <input
152               type="password"
153               id="verify-password"
154               value={this.state.userForm.password_verify}
155               onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
156               className="form-control"
157               required
158               autoComplete="new-password"
159               minLength={10}
160               maxLength={60}
161             />
162           </div>
163         </div>
164         <div className="form-group row">
165           <div className="col-sm-10">
166             <button type="submit" className="btn btn-secondary">
167               {this.state.userLoading ? <Spinner /> : i18n.t("sign_up")}
168             </button>
169           </div>
170         </div>
171       </form>
172     );
173   }
174
175   handleRegisterSubmit(i: Setup, event: any) {
176     event.preventDefault();
177     i.setState({ userLoading: true });
178     event.preventDefault();
179     WebSocketService.Instance.send(wsClient.register(i.state.userForm));
180   }
181
182   handleRegisterUsernameChange(i: Setup, event: any) {
183     i.state.userForm.username = event.target.value;
184     i.setState(i.state);
185   }
186
187   handleRegisterEmailChange(i: Setup, event: any) {
188     i.state.userForm.email = Some(event.target.value);
189     i.setState(i.state);
190   }
191
192   handleRegisterPasswordChange(i: Setup, event: any) {
193     i.state.userForm.password = event.target.value;
194     i.setState(i.state);
195   }
196
197   handleRegisterPasswordVerifyChange(i: Setup, event: any) {
198     i.state.userForm.password_verify = event.target.value;
199     i.setState(i.state);
200   }
201
202   parseMessage(msg: any) {
203     let op = wsUserOp(msg);
204     if (msg.error) {
205       toast(i18n.t(msg.error), "danger");
206       this.setState({ userLoading: false });
207       return;
208     } else if (op == UserOperation.Register) {
209       let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
210       this.setState({ userLoading: false });
211       UserService.Instance.login(data);
212       if (UserService.Instance.jwtInfo.isSome()) {
213         this.setState({ doneRegisteringUser: true });
214       }
215     } else if (op == UserOperation.CreateSite) {
216       window.location.href = "/";
217     }
218   }
219 }