]> Untitled Git - lemmy.git/blob - ui/src/components/login.tsx
Merge branch 'master' into master
[lemmy.git] / ui / src / components / login.tsx
1 import { Component, linkEvent } from 'inferno';
2 import { Subscription } from 'rxjs';
3 import { retryWhen, delay, take } from 'rxjs/operators';
4 import {
5   LoginForm,
6   RegisterForm,
7   LoginResponse,
8   UserOperation,
9 } from '../interfaces';
10 import { WebSocketService, UserService } from '../services';
11 import { msgOp } from '../utils';
12 import { i18n } from '../i18next';
13 import { T } from 'inferno-i18next';
14
15 interface State {
16   loginForm: LoginForm;
17   registerForm: RegisterForm;
18   loginLoading: boolean;
19   registerLoading: boolean;
20 }
21
22 export class Login extends Component<any, State> {
23   private subscription: Subscription;
24
25   emptyState: State = {
26     loginForm: {
27       username_or_email: undefined,
28       password: undefined,
29     },
30     registerForm: {
31       username: undefined,
32       password: undefined,
33       password_verify: undefined,
34       admin: false,
35       show_nsfw: false,
36     },
37     loginLoading: false,
38     registerLoading: false,
39   };
40
41   constructor(props: any, context: any) {
42     super(props, context);
43
44     this.state = this.emptyState;
45
46     this.subscription = WebSocketService.Instance.subject
47       .pipe(
48         retryWhen(errors =>
49           errors.pipe(
50             delay(3000),
51             take(10)
52           )
53         )
54       )
55       .subscribe(
56         msg => this.parseMessage(msg),
57         err => console.error(err),
58         () => console.log('complete')
59       );
60   }
61
62   componentWillUnmount() {
63     this.subscription.unsubscribe();
64   }
65
66   componentDidMount() {
67     document.title = `${i18n.t('login')} - ${
68       WebSocketService.Instance.site.name
69     }`;
70   }
71
72   render() {
73     return (
74       <div class="container">
75         <div class="row">
76           <div class="col-12 col-lg-6 mb-4">{this.loginForm()}</div>
77           <div class="col-12 col-lg-6">{this.registerForm()}</div>
78         </div>
79       </div>
80     );
81   }
82
83   loginForm() {
84     return (
85       <div>
86         <form onSubmit={linkEvent(this, this.handleLoginSubmit)}>
87           <h5>Login</h5>
88           <div class="form-group row">
89             <label class="col-sm-2 col-form-label">
90               <T i18nKey="email_or_username">#</T>
91             </label>
92             <div class="col-sm-10">
93               <input
94                 type="text"
95                 class="form-control"
96                 value={this.state.loginForm.username_or_email}
97                 onInput={linkEvent(this, this.handleLoginUsernameChange)}
98                 required
99                 minLength={3}
100               />
101             </div>
102           </div>
103           <div class="form-group row">
104             <label class="col-sm-2 col-form-label">
105               <T i18nKey="password">#</T>
106             </label>
107             <div class="col-sm-10">
108               <input
109                 type="password"
110                 value={this.state.loginForm.password}
111                 onInput={linkEvent(this, this.handleLoginPasswordChange)}
112                 class="form-control"
113                 required
114               />
115             </div>
116           </div>
117           <div class="form-group row">
118             <div class="col-sm-10">
119               <button type="submit" class="btn btn-secondary">
120                 {this.state.loginLoading ? (
121                   <svg class="icon icon-spinner spin">
122                     <use xlinkHref="#icon-spinner"></use>
123                   </svg>
124                 ) : (
125                   i18n.t('login')
126                 )}
127               </button>
128             </div>
129           </div>
130         </form>
131       </div>
132     );
133   }
134   registerForm() {
135     return (
136       <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
137         <h5>
138           <T i18nKey="sign_up">#</T>
139         </h5>
140         <div class="form-group row">
141           <label class="col-sm-2 col-form-label">
142             <T i18nKey="username">#</T>
143           </label>
144           <div class="col-sm-10">
145             <input
146               type="text"
147               class="form-control"
148               value={this.state.registerForm.username}
149               onInput={linkEvent(this, this.handleRegisterUsernameChange)}
150               required
151               minLength={3}
152               maxLength={20}
153               pattern="[a-zA-Z0-9_]+"
154             />
155           </div>
156         </div>
157         <div class="form-group row">
158           <label class="col-sm-2 col-form-label">
159             <T i18nKey="email">#</T>
160           </label>
161           <div class="col-sm-10">
162             <input
163               type="email"
164               class="form-control"
165               placeholder={i18n.t('optional')}
166               value={this.state.registerForm.email}
167               onInput={linkEvent(this, this.handleRegisterEmailChange)}
168               minLength={3}
169             />
170           </div>
171         </div>
172         <div class="form-group row">
173           <label class="col-sm-2 col-form-label">
174             <T i18nKey="password">#</T>
175           </label>
176           <div class="col-sm-10">
177             <input
178               type="password"
179               value={this.state.registerForm.password}
180               onInput={linkEvent(this, this.handleRegisterPasswordChange)}
181               class="form-control"
182               required
183             />
184           </div>
185         </div>
186         <div class="form-group row">
187           <label class="col-sm-2 col-form-label">
188             <T i18nKey="verify_password">#</T>
189           </label>
190           <div class="col-sm-10">
191             <input
192               type="password"
193               value={this.state.registerForm.password_verify}
194               onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
195               class="form-control"
196               required
197             />
198           </div>
199         </div>
200         <div class="form-group row">
201           <div class="col-sm-10">
202             <div class="form-check">
203               <input
204                 class="form-check-input"
205                 type="checkbox"
206                 checked={this.state.registerForm.show_nsfw}
207                 onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
208               />
209               <label class="form-check-label">
210                 <T i18nKey="show_nsfw">#</T>
211               </label>
212             </div>
213           </div>
214         </div>
215         <div class="form-group row">
216           <div class="col-sm-10">
217             <button type="submit" class="btn btn-secondary">
218               {this.state.registerLoading ? (
219                 <svg class="icon icon-spinner spin">
220                   <use xlinkHref="#icon-spinner"></use>
221                 </svg>
222               ) : (
223                 i18n.t('sign_up')
224               )}
225             </button>
226           </div>
227         </div>
228       </form>
229     );
230   }
231
232   handleLoginSubmit(i: Login, event: any) {
233     event.preventDefault();
234     i.state.loginLoading = true;
235     i.setState(i.state);
236     WebSocketService.Instance.login(i.state.loginForm);
237   }
238
239   handleLoginUsernameChange(i: Login, event: any) {
240     i.state.loginForm.username_or_email = event.target.value;
241     i.setState(i.state);
242   }
243
244   handleLoginPasswordChange(i: Login, event: any) {
245     i.state.loginForm.password = event.target.value;
246     i.setState(i.state);
247   }
248
249   handleRegisterSubmit(i: Login, event: any) {
250     event.preventDefault();
251     i.state.registerLoading = true;
252     i.setState(i.state);
253
254     WebSocketService.Instance.register(i.state.registerForm);
255   }
256
257   handleRegisterUsernameChange(i: Login, event: any) {
258     i.state.registerForm.username = event.target.value;
259     i.setState(i.state);
260   }
261
262   handleRegisterEmailChange(i: Login, event: any) {
263     i.state.registerForm.email = event.target.value;
264     i.setState(i.state);
265   }
266
267   handleRegisterPasswordChange(i: Login, event: any) {
268     i.state.registerForm.password = event.target.value;
269     i.setState(i.state);
270   }
271
272   handleRegisterPasswordVerifyChange(i: Login, event: any) {
273     i.state.registerForm.password_verify = event.target.value;
274     i.setState(i.state);
275   }
276
277   handleRegisterShowNsfwChange(i: Login, event: any) {
278     i.state.registerForm.show_nsfw = event.target.checked;
279     i.setState(i.state);
280   }
281
282   parseMessage(msg: any) {
283     let op: UserOperation = msgOp(msg);
284     if (msg.error) {
285       alert(i18n.t(msg.error));
286       this.state = this.emptyState;
287       this.setState(this.state);
288       return;
289     } else {
290       if (op == UserOperation.Login) {
291         this.state = this.emptyState;
292         this.setState(this.state);
293         let res: LoginResponse = msg;
294         UserService.Instance.login(res);
295         this.props.history.push('/');
296       } else if (op == UserOperation.Register) {
297         this.state = this.emptyState;
298         this.setState(this.state);
299         let res: LoginResponse = msg;
300         UserService.Instance.login(res);
301         this.props.history.push('/communities');
302       }
303     }
304   }
305 }