mirror of
https://github.com/LemmyNet/lemmy-ui.git
synced 2024-11-30 00:01:15 +00:00
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
aee7e4d45b
commit
96cf021105
4 changed files with 149 additions and 22 deletions
|
@ -5,6 +5,7 @@ export default async ({ res }: { res: Response }) => {
|
||||||
|
|
||||||
res.send(`User-Agent: *
|
res.send(`User-Agent: *
|
||||||
Disallow: /login
|
Disallow: /login
|
||||||
|
Disallow: /login_reset
|
||||||
Disallow: /settings
|
Disallow: /settings
|
||||||
Disallow: /create_community
|
Disallow: /create_community
|
||||||
Disallow: /create_post
|
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 { myAuth, setIsoData } from "@utils/app";
|
||||||
import { isBrowser } from "@utils/browser";
|
import { isBrowser } from "@utils/browser";
|
||||||
import { validEmail } from "@utils/helpers";
|
|
||||||
import { Component, linkEvent } from "inferno";
|
import { Component, linkEvent } from "inferno";
|
||||||
|
import { NavLink } from "inferno-router";
|
||||||
import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
|
import { GetSiteResponse, LoginResponse } from "lemmy-js-client";
|
||||||
import { I18NextService, UserService } from "../../services";
|
import { I18NextService, UserService } from "../../services";
|
||||||
import { HttpService, RequestState } from "../../services/HttpService";
|
import { HttpService, RequestState } from "../../services/HttpService";
|
||||||
|
@ -105,18 +105,12 @@ export class Login extends Component<any, State> {
|
||||||
required
|
required
|
||||||
maxLength={60}
|
maxLength={60}
|
||||||
/>
|
/>
|
||||||
<button
|
<NavLink
|
||||||
type="button"
|
className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold pointer-events not-allowed"
|
||||||
onClick={linkEvent(this, this.handlePasswordReset)}
|
to="/login_reset"
|
||||||
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")}
|
|
||||||
>
|
>
|
||||||
{I18NextService.i18n.t("forgot_password")}
|
{I18NextService.i18n.t("forgot_password")}
|
||||||
</button>
|
</NavLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{this.state.showTotp && (
|
{this.state.showTotp && (
|
||||||
|
@ -214,15 +208,4 @@ export class Login extends Component<any, State> {
|
||||||
i.state.form.password = event.target.value;
|
i.state.form.password = event.target.value;
|
||||||
i.setState(i.state);
|
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 { Instances } from "./components/home/instances";
|
||||||
import { Legal } from "./components/home/legal";
|
import { Legal } from "./components/home/legal";
|
||||||
import { Login } from "./components/home/login";
|
import { Login } from "./components/home/login";
|
||||||
|
import { LoginReset } from "./components/home/login-reset";
|
||||||
import { Setup } from "./components/home/setup";
|
import { Setup } from "./components/home/setup";
|
||||||
import { Signup } from "./components/home/signup";
|
import { Signup } from "./components/home/signup";
|
||||||
import { Modlog } from "./components/modlog";
|
import { Modlog } from "./components/modlog";
|
||||||
|
@ -38,6 +39,10 @@ export const routes: IRoutePropsWithFetch<Record<string, any>>[] = [
|
||||||
path: `/login`,
|
path: `/login`,
|
||||||
component: Login,
|
component: Login,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: `/login_reset`,
|
||||||
|
component: LoginReset,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: `/signup`,
|
path: `/signup`,
|
||||||
component: Signup,
|
component: Signup,
|
||||||
|
|
Loading…
Reference in a new issue