✨ Password forgotten working
This commit is contained in:
parent
7dcc4b2cb1
commit
07313fba82
18
package-lock.json
generated
18
package-lock.json
generated
@ -43,9 +43,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz",
|
||||
"integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==",
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
|
||||
"integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
|
||||
"dependencies": {
|
||||
"@babel/highlight": "^7.23.4",
|
||||
"chalk": "^2.4.2"
|
||||
@ -223,9 +223,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz",
|
||||
"integrity": "sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==",
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz",
|
||||
"integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
@ -234,9 +234,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.23.4",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz",
|
||||
"integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==",
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz",
|
||||
"integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.23.4",
|
||||
"@babel/helper-validator-identifier": "^7.22.20",
|
||||
|
@ -32,6 +32,10 @@ export type ILoginParams = {
|
||||
totpCode: string;
|
||||
};
|
||||
|
||||
export type IAskNewPasswordParams = {
|
||||
email: string;
|
||||
};
|
||||
|
||||
export default class Auth extends BaseApiService {
|
||||
private static instance: Auth;
|
||||
protected readonly namespaceUrl = this.getBaseUrl().concat("/customer");
|
||||
@ -80,4 +84,14 @@ export default class Auth extends BaseApiService {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
public async askNewPassword(body: IAskNewPasswordParams): Promise<IMailVerifyReturn> {
|
||||
const url = new URL(this.baseURl.concat("/ask-new-password"));
|
||||
try {
|
||||
return this.postRequest<IMailVerifyReturn>(url, body);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
@import "@Themes/constants.scss";
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-width: 530px;
|
||||
margin: auto;
|
||||
margin-top: 220px;
|
||||
|
||||
.title {
|
||||
text-align: left;
|
||||
|
||||
@media (max-width: $screen-s) {
|
||||
font-family: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
.form {
|
||||
margin-top: 32px;
|
||||
|
||||
.password_indication {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.submit_button {
|
||||
margin-top: 32px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||
import Form from "@Front/Components/DesignSystem/Form";
|
||||
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||
import { ValidationError } from "class-validator";
|
||||
type IProps = {
|
||||
onSubmit: (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => void;
|
||||
validationErrors: ValidationError[];
|
||||
};
|
||||
|
||||
export default function PasswordForgotten(props: IProps) {
|
||||
const { onSubmit, validationErrors } = props;
|
||||
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
<Typography typo={ITypo.H1}>
|
||||
<div className={classes["title"]}>Réinitialisez votre mot de passe</div>
|
||||
</Typography>
|
||||
<Form className={classes["form"]} onSubmit={onSubmit}>
|
||||
<TextField
|
||||
placeholder="Mot de passe"
|
||||
name="password"
|
||||
validationError={validationErrors.find((error) => error.property === "password")}
|
||||
password
|
||||
/>
|
||||
<Typography typo={ITypo.CAPTION_14} color={ITypoColor.GREY} className={classes["password_indication"]}>
|
||||
Au moins 8 caractères dont 1 majuscule, 1 minuscule et 1 chiffre.
|
||||
</Typography>
|
||||
<TextField
|
||||
placeholder="Confirmation du mot de passe"
|
||||
name="confirm_password"
|
||||
validationError={validationErrors.find((error) => error.property === "confirm_password")}
|
||||
password
|
||||
/>
|
||||
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
||||
Valider
|
||||
</Button>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -5,14 +5,29 @@ import Form from "@Front/Components/DesignSystem/Form";
|
||||
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||
import { ValidationError } from "class-validator";
|
||||
import Link from "next/link";
|
||||
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
||||
type IProps = {
|
||||
onSubmit: (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => void;
|
||||
validationErrors: ValidationError[];
|
||||
onPasswordForgotClicked: () => void;
|
||||
};
|
||||
|
||||
export default function StepPassword(props: IProps) {
|
||||
const { onSubmit, validationErrors } = props;
|
||||
const { onSubmit, validationErrors, onPasswordForgotClicked } = props;
|
||||
const [isModalOpened, setIsModalOpened] = React.useState(false);
|
||||
|
||||
const closeModal = () => {
|
||||
setIsModalOpened(false);
|
||||
};
|
||||
|
||||
const openModal = () => {
|
||||
setIsModalOpened(true);
|
||||
};
|
||||
|
||||
const onModalAccept = () => {
|
||||
onPasswordForgotClicked();
|
||||
setIsModalOpened(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
@ -26,15 +41,29 @@ export default function StepPassword(props: IProps) {
|
||||
validationError={validationErrors.find((error) => error.property === "password")}
|
||||
password
|
||||
/>
|
||||
<Link href="/forgot-password">
|
||||
<div onClick={openModal}>
|
||||
<Typography typo={ITypo.P_16} className={classes["forgot-password"]}>
|
||||
Mot de passe oublié ?
|
||||
</Typography>
|
||||
</Link>
|
||||
</div>
|
||||
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
||||
Valider
|
||||
</Button>
|
||||
</Form>
|
||||
<Confirm
|
||||
isOpen={isModalOpened}
|
||||
onClose={closeModal}
|
||||
showCancelButton={true}
|
||||
onAccept={onModalAccept}
|
||||
closeBtn
|
||||
header={"Mot de passe oublié ?"}
|
||||
confirmText={"Valider"}>
|
||||
<div className={classes["modal-content"]}>
|
||||
<Typography typo={ITypo.P_16} className={classes["text"]}>
|
||||
Un code à usage unique va vous être envoyé par sms pour réinitialiser votre mot de passe.
|
||||
</Typography>
|
||||
</div>
|
||||
</Confirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -15,12 +15,14 @@ import StepNewPassword from "./StepNewPassword";
|
||||
import CustomerStore from "@Front/Stores/CustomerStore";
|
||||
import Module from "@Front/Config/Module";
|
||||
import { TotpCodesReasons } from "le-coffre-resources/dist/Customer/TotpCodes";
|
||||
import PasswordForgotten from "./PasswordForgotten";
|
||||
|
||||
export enum LoginStep {
|
||||
EMAIL,
|
||||
TOTP,
|
||||
PASSWORD,
|
||||
NEW_PASSWORD,
|
||||
PASSWORD_FORGOTTEN,
|
||||
}
|
||||
export default function Login() {
|
||||
const router = useRouter();
|
||||
@ -85,6 +87,8 @@ export default function Login() {
|
||||
|
||||
// If it's first connection, show the form for first connection
|
||||
if (res.reason === TotpCodesReasons.FIRST_LOGIN) setStep(LoginStep.NEW_PASSWORD);
|
||||
// If it's password forgotten, show the form for password forgotten
|
||||
else if (res.reason === TotpCodesReasons.RESET_PASSWORD) setStep(LoginStep.PASSWORD_FORGOTTEN);
|
||||
// Else just login normally
|
||||
else setStep(LoginStep.PASSWORD);
|
||||
} catch (error: any) {
|
||||
@ -105,7 +109,6 @@ export default function Login() {
|
||||
const onNewPasswordSubmit = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||
try {
|
||||
console.log(values);
|
||||
if (!values["password"] || !values["confirm_password"]) return;
|
||||
if (values["password"] !== values["confirm_password"]) {
|
||||
setValidationErrors([
|
||||
@ -159,6 +162,21 @@ export default function Login() {
|
||||
[email, router, totpCode],
|
||||
);
|
||||
|
||||
const onPasswordForgotClicked = useCallback(async () => {
|
||||
try {
|
||||
const res = await Auth.getInstance().askNewPassword({ email });
|
||||
setPartialPhoneNumber(res.partialPhoneNumber);
|
||||
setStep(LoginStep.TOTP);
|
||||
} catch (error: any) {
|
||||
// If token already exists and is still valid redirect to the connect/register page
|
||||
if (error.http_status === 425) {
|
||||
setStep(LoginStep.TOTP);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}, [email]);
|
||||
|
||||
return (
|
||||
<DefaultDoubleSidePage title={"Login"} image={LandingImage}>
|
||||
<div className={classes["root"]}>
|
||||
@ -166,8 +184,17 @@ export default function Login() {
|
||||
{step === LoginStep.TOTP && (
|
||||
<StepTotp onSubmit={onSmsCodeSubmit} validationErrors={validationErrors} partialPhoneNumber={partialPhoneNumber} />
|
||||
)}
|
||||
{step === LoginStep.PASSWORD && <StepPassword onSubmit={onPasswordSubmit} validationErrors={validationErrors} />}
|
||||
{step === LoginStep.PASSWORD && (
|
||||
<StepPassword
|
||||
onSubmit={onPasswordSubmit}
|
||||
validationErrors={validationErrors}
|
||||
onPasswordForgotClicked={onPasswordForgotClicked}
|
||||
/>
|
||||
)}
|
||||
{step === LoginStep.NEW_PASSWORD && <StepNewPassword onSubmit={onNewPasswordSubmit} validationErrors={validationErrors} />}
|
||||
{step === LoginStep.PASSWORD_FORGOTTEN && (
|
||||
<PasswordForgotten onSubmit={onNewPasswordSubmit} validationErrors={validationErrors} />
|
||||
)}
|
||||
</div>
|
||||
<Confirm
|
||||
isOpen={isErrorModalOpen}
|
||||
|
Loading…
x
Reference in New Issue
Block a user