]> Untitled Git - lemmy-ui.git/blob - src/shared/components/home/login.tsx
Adding option types 2 (#689)
[lemmy-ui.git] / src / shared / components / home / login.tsx
1 import { None } from "@sniptt/monads";
2 import { Component, linkEvent } from "inferno";
3 import {
4   GetSiteResponse,
5   Login as LoginForm,
6   LoginResponse,
7   PasswordReset,
8   UserOperation,
9   wsJsonToRes,
10   wsUserOp,
11 } from "lemmy-js-client";
12 import { Subscription } from "rxjs";
13 import { i18n } from "../../i18next";
14 import { UserService, WebSocketService } from "../../services";
15 import {
16   auth,
17   isBrowser,
18   setIsoData,
19   toast,
20   validEmail,
21   wsClient,
22   wsSubscribe,
23 } from "../../utils";
24 import { HtmlTags } from "../common/html-tags";
25 import { Spinner } from "../common/icon";
26
27 interface State {
28   loginForm: LoginForm;
29   loginLoading: boolean;
30   siteRes: GetSiteResponse;
31 }
32
33 export class Login extends Component<any, State> {
34   private isoData = setIsoData(this.context);
35   private subscription: Subscription;
36
37   emptyState: State = {
38     loginForm: new LoginForm({
39       username_or_email: undefined,
40       password: undefined,
41     }),
42     loginLoading: false,
43     siteRes: this.isoData.site_res,
44   };
45
46   constructor(props: any, context: any) {
47     super(props, context);
48
49     this.state = this.emptyState;
50
51     this.parseMessage = this.parseMessage.bind(this);
52     this.subscription = wsSubscribe(this.parseMessage);
53
54     if (isBrowser()) {
55       WebSocketService.Instance.send(wsClient.getCaptcha());
56     }
57   }
58
59   componentDidMount() {
60     // Navigate to home if already logged in
61     if (UserService.Instance.myUserInfo.isSome()) {
62       this.context.router.history.push("/");
63     }
64   }
65
66   componentWillUnmount() {
67     if (isBrowser()) {
68       this.subscription.unsubscribe();
69     }
70   }
71
72   get documentTitle(): string {
73     return this.state.siteRes.site_view.match({
74       some: siteView => `${i18n.t("login")} - ${siteView.site.name}`,
75       none: "",
76     });
77   }
78
79   get isLemmyMl(): boolean {
80     return isBrowser() && window.location.hostname == "lemmy.ml";
81   }
82
83   render() {
84     return (
85       <div class="container">
86         <HtmlTags
87           title={this.documentTitle}
88           path={this.context.router.route.match.url}
89           description={None}
90           image={None}
91         />
92         <div class="row">
93           <div class="col-12 col-lg-6 offset-lg-3">{this.loginForm()}</div>
94         </div>
95       </div>
96     );
97   }
98
99   loginForm() {
100     return (
101       <div>
102         <form onSubmit={linkEvent(this, this.handleLoginSubmit)}>
103           <h5>{i18n.t("login")}</h5>
104           <div class="form-group row">
105             <label
106               class="col-sm-2 col-form-label"
107               htmlFor="login-email-or-username"
108             >
109               {i18n.t("email_or_username")}
110             </label>
111             <div class="col-sm-10">
112               <input
113                 type="text"
114                 class="form-control"
115                 id="login-email-or-username"
116                 value={this.state.loginForm.username_or_email}
117                 onInput={linkEvent(this, this.handleLoginUsernameChange)}
118                 autoComplete="email"
119                 required
120                 minLength={3}
121               />
122             </div>
123           </div>
124           <div class="form-group row">
125             <label class="col-sm-2 col-form-label" htmlFor="login-password">
126               {i18n.t("password")}
127             </label>
128             <div class="col-sm-10">
129               <input
130                 type="password"
131                 id="login-password"
132                 value={this.state.loginForm.password}
133                 onInput={linkEvent(this, this.handleLoginPasswordChange)}
134                 class="form-control"
135                 autoComplete="current-password"
136                 required
137                 maxLength={60}
138               />
139               <button
140                 type="button"
141                 onClick={linkEvent(this, this.handlePasswordReset)}
142                 className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold pointer-events not-allowed"
143                 disabled={!validEmail(this.state.loginForm.username_or_email)}
144                 title={i18n.t("no_password_reset")}
145               >
146                 {i18n.t("forgot_password")}
147               </button>
148             </div>
149           </div>
150           <div class="form-group row">
151             <div class="col-sm-10">
152               <button type="submit" class="btn btn-secondary">
153                 {this.state.loginLoading ? <Spinner /> : i18n.t("login")}
154               </button>
155             </div>
156           </div>
157         </form>
158       </div>
159     );
160   }
161
162   handleLoginSubmit(i: Login, event: any) {
163     event.preventDefault();
164     i.state.loginLoading = true;
165     i.setState(i.state);
166     WebSocketService.Instance.send(wsClient.login(i.state.loginForm));
167   }
168
169   handleLoginUsernameChange(i: Login, event: any) {
170     i.state.loginForm.username_or_email = event.target.value;
171     i.setState(i.state);
172   }
173
174   handleLoginPasswordChange(i: Login, event: any) {
175     i.state.loginForm.password = event.target.value;
176     i.setState(i.state);
177   }
178
179   handlePasswordReset(i: Login, event: any) {
180     event.preventDefault();
181     let resetForm = new PasswordReset({
182       email: i.state.loginForm.username_or_email,
183     });
184     WebSocketService.Instance.send(wsClient.passwordReset(resetForm));
185   }
186
187   parseMessage(msg: any) {
188     let op = wsUserOp(msg);
189     console.log(msg);
190     if (msg.error) {
191       toast(i18n.t(msg.error), "danger");
192       this.state = this.emptyState;
193       this.setState(this.state);
194       return;
195     } else {
196       if (op == UserOperation.Login) {
197         let data = wsJsonToRes<LoginResponse>(msg, LoginResponse);
198         this.state = this.emptyState;
199         this.setState(this.state);
200         UserService.Instance.login(data);
201         WebSocketService.Instance.send(
202           wsClient.userJoin({
203             auth: auth().unwrap(),
204           })
205         );
206         toast(i18n.t("logged_in"));
207         this.props.history.push("/");
208       } else if (op == UserOperation.PasswordReset) {
209         toast(i18n.t("reset_password_mail_sent"));
210       } else if (op == UserOperation.GetSite) {
211         let data = wsJsonToRes<GetSiteResponse>(msg, GetSiteResponse);
212         this.state.siteRes = data;
213         this.setState(this.state);
214       }
215     }
216   }
217 }