1 import { myAuth, setIsoData } from "@utils/app";
2 import { isBrowser } from "@utils/browser";
3 import { Component, linkEvent } from "inferno";
4 import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
5 import { I18NextService, UserService } from "../../services";
6 import { HttpService, RequestState } from "../../services/HttpService";
7 import { toast } from "../../toast";
8 import { HtmlTags } from "../common/html-tags";
9 import { Spinner } from "../common/icon";
10 import PasswordInput from "../common/password-input";
13 loginRes: RequestState<LoginResponse>;
15 username_or_email?: string;
17 totp_2fa_token?: string;
20 siteRes: GetSiteResponse;
23 export class Login extends Component<any, State> {
24 private isoData = setIsoData(this.context);
27 loginRes: { state: "empty" },
30 siteRes: this.isoData.site_res,
33 constructor(props: any, context: any) {
34 super(props, context);
38 // Navigate to home if already logged in
39 if (UserService.Instance.myUserInfo) {
40 this.context.router.history.push("/");
44 get documentTitle(): string {
45 return `${I18NextService.i18n.t("login")} - ${
46 this.state.siteRes.site_view.site.name
50 get isLemmyMl(): boolean {
51 return isBrowser() && window.location.hostname == "lemmy.ml";
56 <div className="login container-lg">
58 title={this.documentTitle}
59 path={this.context.router.route.match.url}
62 <div className="col-12 col-lg-6 offset-lg-3">{this.loginForm()}</div>
71 <form onSubmit={linkEvent(this, this.handleLoginSubmit)}>
72 <h1 className="h4 mb-4">{I18NextService.i18n.t("login")}</h1>
73 <div className="mb-3 row">
75 className="col-sm-2 col-form-label"
76 htmlFor="login-email-or-username"
78 {I18NextService.i18n.t("email_or_username")}
80 <div className="col-sm-10">
83 className="form-control"
84 id="login-email-or-username"
85 value={this.state.form.username_or_email}
86 onInput={linkEvent(this, this.handleLoginUsernameChange)}
93 <div className="mb-3">
96 value={this.state.form.password}
97 onInput={linkEvent(this, this.handleLoginPasswordChange)}
98 label={I18NextService.i18n.t("password")}
102 {this.state.showTotp && (
103 <div className="mb-3 row">
105 className="col-sm-6 col-form-label"
106 htmlFor="login-totp-token"
108 {I18NextService.i18n.t("two_factor_token")}
110 <div className="col-sm-6">
114 className="form-control"
115 id="login-totp-token"
117 autoComplete="one-time-code"
118 value={this.state.form.totp_2fa_token}
119 onInput={linkEvent(this, this.handleLoginTotpChange)}
124 <div className="mb-3 row">
125 <div className="col-sm-10">
126 <button type="submit" className="btn btn-secondary">
127 {this.state.loginRes.state == "loading" ? (
130 I18NextService.i18n.t("login")
140 async handleLoginSubmit(i: Login, event: any) {
141 event.preventDefault();
142 const { password, totp_2fa_token, username_or_email } = i.state.form;
144 if (username_or_email && password) {
145 i.setState({ loginRes: { state: "loading" } });
147 const loginRes = await HttpService.client.login({
152 switch (loginRes.state) {
154 if (loginRes.msg === "missing_totp_token") {
155 i.setState({ showTotp: true });
156 toast(I18NextService.i18n.t("enter_two_factor_code"), "info");
158 if (loginRes.msg === "incorrect_login") {
159 toast(I18NextService.i18n.t("incorrect_login"), "danger");
162 i.setState({ loginRes: { state: "failed", msg: loginRes.msg } });
167 UserService.Instance.login({
170 const site = await HttpService.client.getSite({
174 if (site.state === "success") {
175 UserService.Instance.myUserInfo = site.data.my_user;
178 i.props.history.action === "PUSH"
179 ? i.props.history.back()
180 : i.props.history.replace("/");
188 handleLoginUsernameChange(i: Login, event: any) {
189 i.state.form.username_or_email = event.target.value.trim();
193 handleLoginTotpChange(i: Login, event: any) {
194 i.state.form.totp_2fa_token = event.target.value;
198 handleLoginPasswordChange(i: Login, event: any) {
199 i.state.form.password = event.target.value;