]> Untitled Git - lemmy.git/blob - ui/src/components/login.tsx
Fixing create_post, create_community, and login pages.
[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   PasswordResetForm,
10   GetSiteResponse,
11 } from '../interfaces';
12 import { WebSocketService, UserService } from '../services';
13 import { msgOp, validEmail } from '../utils';
14 import { i18n } from '../i18next';
15 import { T } from 'inferno-i18next';
16
17 interface State {
18   loginForm: LoginForm;
19   registerForm: RegisterForm;
20   loginLoading: boolean;
21   registerLoading: boolean;
22   enable_nsfw: boolean;
23 }
24
25 export class Login extends Component<any, State> {
26   private subscription: Subscription;
27
28   emptyState: State = {
29     loginForm: {
30       username_or_email: undefined,
31       password: undefined,
32     },
33     registerForm: {
34       username: undefined,
35       password: undefined,
36       password_verify: undefined,
37       admin: false,
38       show_nsfw: false,
39     },
40     loginLoading: false,
41     registerLoading: false,
42     enable_nsfw: undefined,
43   };
44
45   constructor(props: any, context: any) {
46     super(props, context);
47
48     this.state = this.emptyState;
49
50     this.subscription = WebSocketService.Instance.subject
51       .pipe(
52         retryWhen(errors =>
53           errors.pipe(
54             delay(3000),
55             take(10)
56           )
57         )
58       )
59       .subscribe(
60         msg => this.parseMessage(msg),
61         err => console.error(err),
62         () => console.log('complete')
63       );
64
65     WebSocketService.Instance.getSite();
66   }
67
68   componentWillUnmount() {
69     this.subscription.unsubscribe();
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               <button
116                 disabled={!validEmail(this.state.loginForm.username_or_email)}
117                 onClick={linkEvent(this, this.handlePasswordReset)}
118                 className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold"
119               >
120                 <T i18nKey="forgot_password">#</T>
121               </button>
122             </div>
123           </div>
124           <div class="form-group row">
125             <div class="col-sm-10">
126               <button type="submit" class="btn btn-secondary">
127                 {this.state.loginLoading ? (
128                   <svg class="icon icon-spinner spin">
129                     <use xlinkHref="#icon-spinner"></use>
130                   </svg>
131                 ) : (
132                   i18n.t('login')
133                 )}
134               </button>
135             </div>
136           </div>
137         </form>
138       </div>
139     );
140   }
141   registerForm() {
142     return (
143       <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
144         <h5>
145           <T i18nKey="sign_up">#</T>
146         </h5>
147         <div class="form-group row">
148           <label class="col-sm-2 col-form-label">
149             <T i18nKey="username">#</T>
150           </label>
151           <div class="col-sm-10">
152             <input
153               type="text"
154               class="form-control"
155               value={this.state.registerForm.username}
156               onInput={linkEvent(this, this.handleRegisterUsernameChange)}
157               required
158               minLength={3}
159               maxLength={20}
160               pattern="[a-zA-Z0-9_]+"
161             />
162           </div>
163         </div>
164         <div class="form-group row">
165           <label class="col-sm-2 col-form-label">
166             <T i18nKey="email">#</T>
167           </label>
168           <div class="col-sm-10">
169             <input
170               type="email"
171               class="form-control"
172               placeholder={i18n.t('optional')}
173               value={this.state.registerForm.email}
174               onInput={linkEvent(this, this.handleRegisterEmailChange)}
175               minLength={3}
176             />
177           </div>
178         </div>
179         <div class="form-group row">
180           <label class="col-sm-2 col-form-label">
181             <T i18nKey="password">#</T>
182           </label>
183           <div class="col-sm-10">
184             <input
185               type="password"
186               value={this.state.registerForm.password}
187               onInput={linkEvent(this, this.handleRegisterPasswordChange)}
188               class="form-control"
189               required
190             />
191           </div>
192         </div>
193         <div class="form-group row">
194           <label class="col-sm-2 col-form-label">
195             <T i18nKey="verify_password">#</T>
196           </label>
197           <div class="col-sm-10">
198             <input
199               type="password"
200               value={this.state.registerForm.password_verify}
201               onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
202               class="form-control"
203               required
204             />
205           </div>
206         </div>
207         {this.state.enable_nsfw && (
208           <div class="form-group row">
209             <div class="col-sm-10">
210               <div class="form-check">
211                 <input
212                   class="form-check-input"
213                   type="checkbox"
214                   checked={this.state.registerForm.show_nsfw}
215                   onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
216                 />
217                 <label class="form-check-label">
218                   <T i18nKey="show_nsfw">#</T>
219                 </label>
220               </div>
221             </div>
222           </div>
223         )}
224         <div class="form-group row">
225           <div class="col-sm-10">
226             <button type="submit" class="btn btn-secondary">
227               {this.state.registerLoading ? (
228                 <svg class="icon icon-spinner spin">
229                   <use xlinkHref="#icon-spinner"></use>
230                 </svg>
231               ) : (
232                 i18n.t('sign_up')
233               )}
234             </button>
235           </div>
236         </div>
237       </form>
238     );
239   }
240
241   handleLoginSubmit(i: Login, event: any) {
242     event.preventDefault();
243     i.state.loginLoading = true;
244     i.setState(i.state);
245     WebSocketService.Instance.login(i.state.loginForm);
246   }
247
248   handleLoginUsernameChange(i: Login, event: any) {
249     i.state.loginForm.username_or_email = event.target.value;
250     i.setState(i.state);
251   }
252
253   handleLoginPasswordChange(i: Login, event: any) {
254     i.state.loginForm.password = event.target.value;
255     i.setState(i.state);
256   }
257
258   handleRegisterSubmit(i: Login, event: any) {
259     event.preventDefault();
260     i.state.registerLoading = true;
261     i.setState(i.state);
262
263     WebSocketService.Instance.register(i.state.registerForm);
264   }
265
266   handleRegisterUsernameChange(i: Login, event: any) {
267     i.state.registerForm.username = event.target.value;
268     i.setState(i.state);
269   }
270
271   handleRegisterEmailChange(i: Login, event: any) {
272     i.state.registerForm.email = event.target.value;
273     if (i.state.registerForm.email == '') {
274       i.state.registerForm.email = undefined;
275     }
276     i.setState(i.state);
277   }
278
279   handleRegisterPasswordChange(i: Login, event: any) {
280     i.state.registerForm.password = event.target.value;
281     i.setState(i.state);
282   }
283
284   handleRegisterPasswordVerifyChange(i: Login, event: any) {
285     i.state.registerForm.password_verify = event.target.value;
286     i.setState(i.state);
287   }
288
289   handleRegisterShowNsfwChange(i: Login, event: any) {
290     i.state.registerForm.show_nsfw = event.target.checked;
291     i.setState(i.state);
292   }
293
294   handlePasswordReset(i: Login) {
295     event.preventDefault();
296     let resetForm: PasswordResetForm = {
297       email: i.state.loginForm.username_or_email,
298     };
299     WebSocketService.Instance.passwordReset(resetForm);
300   }
301
302   parseMessage(msg: any) {
303     let op: UserOperation = msgOp(msg);
304     if (msg.error) {
305       alert(i18n.t(msg.error));
306       this.state = this.emptyState;
307       this.setState(this.state);
308       return;
309     } else {
310       if (op == UserOperation.Login) {
311         this.state = this.emptyState;
312         this.setState(this.state);
313         let res: LoginResponse = msg;
314         UserService.Instance.login(res);
315         this.props.history.push('/');
316       } else if (op == UserOperation.Register) {
317         this.state = this.emptyState;
318         this.setState(this.state);
319         let res: LoginResponse = msg;
320         UserService.Instance.login(res);
321         this.props.history.push('/communities');
322       } else if (op == UserOperation.PasswordReset) {
323         alert(i18n.t('reset_password_mail_sent'));
324       } else if (op == UserOperation.GetSite) {
325         let res: GetSiteResponse = msg;
326         this.state.enable_nsfw = res.site.enable_nsfw;
327         this.setState(this.state);
328         document.title = `${i18n.t('login')} - ${
329           WebSocketService.Instance.site.name
330         }`;
331       }
332     }
333   }
334 }