Move password reset form to separate route, view (#1390)
* rework password reset form * make self-suggested changes * cleaning * validate in handlePasswordReset as well * update submodule * partially make suggested changes * make suggested changes * resolve merge conflicts * resolve merge conflicts * resolve merge conflicts --------- Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
This commit is contained in:
parent
6edbb027f1
commit
921cd976a4
4 changed files with 149 additions and 22 deletions
|
@ -5,6 +5,7 @@ export default async ({ res }: { res: Response }) => {
|
|||
|
||||
res.send(`User-Agent: *
|
||||
Disallow: /login
|
||||
Disallow: /login_reset
|
||||
Disallow: /settings
|
||||
Disallow: /create_community
|
||||
Disallow: /create_post
|
||||
|
|
138
src/shared/components/home/login-reset.tsx
Normal file
138
src/shared/components/home/login-reset.tsx
Normal file
|
@ -0,0 +1,138 @@
|
|||
import { setIsoData } from "@utils/app";
|
||||
import { capitalizeFirstLetter, validEmail } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { GetSiteResponse } from "lemmy-js-client";
|
||||
import { HttpService, I18NextService, UserService } from "../../services";
|
||||
import { toast } from "../../toast";
|
||||
import { HtmlTags } from "../common/html-tags";
|
||||
import { Spinner } from "../common/icon";
|
||||
|
||||
interface State {
|
||||
form: {
|
||||
email: string;
|
||||
loading: boolean;
|
||||
};
|
||||
siteRes: GetSiteResponse;
|
||||
}
|
||||
|
||||
export class LoginReset extends Component<any, State> {
|
||||
private isoData = setIsoData(this.context);
|
||||
|
||||
state: State = {
|
||||
form: {
|
||||
email: "",
|
||||
loading: false,
|
||||
},
|
||||
siteRes: this.isoData.site_res,
|
||||
};
|
||||
|
||||
constructor(props: any, context: any) {
|
||||
super(props, context);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (UserService.Instance.myUserInfo) {
|
||||
this.context.router.history.push("/");
|
||||
}
|
||||
}
|
||||
|
||||
get documentTitle(): string {
|
||||
return `${capitalizeFirstLetter(
|
||||
I18NextService.i18n.t("forgot_password")
|
||||
)} - ${this.state.siteRes.site_view.site.name}`;
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="container-lg">
|
||||
<HtmlTags
|
||||
title={this.documentTitle}
|
||||
path={this.context.router.route.match.url}
|
||||
/>
|
||||
<div className="col-12 col-lg-6 col-md-8 m-auto">
|
||||
{this.loginResetForm()}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
loginResetForm() {
|
||||
return (
|
||||
<form onSubmit={linkEvent(this, this.handlePasswordReset)}>
|
||||
<h5>
|
||||
{capitalizeFirstLetter(I18NextService.i18n.t("forgot_password"))}
|
||||
</h5>
|
||||
|
||||
<div className="form-group row">
|
||||
<label className="col-form-label">
|
||||
{I18NextService.i18n.t("no_password_reset")}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="form-group row mt-2">
|
||||
<label
|
||||
className="col-sm-2 col-form-label"
|
||||
htmlFor="login-reset-email"
|
||||
>
|
||||
{I18NextService.i18n.t("email")}
|
||||
</label>
|
||||
|
||||
<div className="col-sm-10">
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
id="login-reset-email"
|
||||
value={this.state.form.email}
|
||||
onInput={linkEvent(this, this.handleEmailInputChange)}
|
||||
autoComplete="email"
|
||||
required
|
||||
minLength={3}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="form-group row mt-3">
|
||||
<div className="col-sm-10">
|
||||
<button
|
||||
type="button"
|
||||
onClick={linkEvent(this, this.handlePasswordReset)}
|
||||
className="btn btn-secondary"
|
||||
disabled={
|
||||
!validEmail(this.state.form.email) || this.state.form.loading
|
||||
}
|
||||
>
|
||||
{this.state.form.loading ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
I18NextService.i18n.t("reset_password")
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
handleEmailInputChange(i: LoginReset, event: any) {
|
||||
i.setState(s => ((s.form.email = event.target.value.trim()), s));
|
||||
}
|
||||
|
||||
async handlePasswordReset(i: LoginReset, event: any) {
|
||||
event.preventDefault();
|
||||
|
||||
const email = i.state.form.email;
|
||||
|
||||
if (email && validEmail(email)) {
|
||||
i.setState(s => ((s.form.loading = true), s));
|
||||
|
||||
const res = await HttpService.client.passwordReset({ email });
|
||||
|
||||
if (res.state == "success") {
|
||||
toast(I18NextService.i18n.t("reset_password_mail_sent"));
|
||||
i.context.router.history.push("/login");
|
||||
}
|
||||
|
||||
i.setState(s => ((s.form.loading = false), s));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import { myAuth, setIsoData } from "@utils/app";
|
||||
import { isBrowser } from "@utils/browser";
|
||||
import { validEmail } from "@utils/helpers";
|
||||
import { Component, linkEvent } from "inferno";
|
||||
import { NavLink } from "inferno-router";
|
||||
import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
|
||||
import { I18NextService, UserService } from "../../services";
|
||||
import { HttpService, RequestState } from "../../services/HttpService";
|
||||
|
@ -105,18 +105,12 @@ export class Login extends Component<any, State> {
|
|||
required
|
||||
maxLength={60}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={linkEvent(this, this.handlePasswordReset)}
|
||||
className="btn p-0 btn-link d-inline-block float-right text-muted small fw-bold pointer-events not-allowed"
|
||||
disabled={
|
||||
!!this.state.form.username_or_email &&
|
||||
!validEmail(this.state.form.username_or_email)
|
||||
}
|
||||
title={I18NextService.i18n.t("no_password_reset")}
|
||||
<NavLink
|
||||
className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold pointer-events not-allowed"
|
||||
to="/login_reset"
|
||||
>
|
||||
{I18NextService.i18n.t("forgot_password")}
|
||||
</button>
|
||||
</NavLink>
|
||||
</div>
|
||||
</div>
|
||||
{this.state.showTotp && (
|
||||
|
@ -214,15 +208,4 @@ export class Login extends Component<any, State> {
|
|||
i.state.form.password = event.target.value;
|
||||
i.setState(i.state);
|
||||
}
|
||||
|
||||
async handlePasswordReset(i: Login, event: any) {
|
||||
event.preventDefault();
|
||||
const email = i.state.form.username_or_email;
|
||||
if (email) {
|
||||
const res = await HttpService.client.passwordReset({ email });
|
||||
if (res.state == "success") {
|
||||
toast(I18NextService.i18n.t("reset_password_mail_sent"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Home } from "./components/home/home";
|
|||
import { Instances } from "./components/home/instances";
|
||||
import { Legal } from "./components/home/legal";
|
||||
import { Login } from "./components/home/login";
|
||||
import { LoginReset } from "./components/home/login-reset";
|
||||
import { Setup } from "./components/home/setup";
|
||||
import { Signup } from "./components/home/signup";
|
||||
import { Modlog } from "./components/modlog";
|
||||
|
@ -38,6 +39,10 @@ export const routes: IRoutePropsWithFetch<Record<string, any>>[] = [
|
|||
path: `/login`,
|
||||
component: Login,
|
||||
},
|
||||
{
|
||||
path: `/login_reset`,
|
||||
component: LoginReset,
|
||||
},
|
||||
{
|
||||
path: `/signup`,
|
||||
component: Signup,
|
||||
|
|
Loading…
Reference in a new issue