✨ 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": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.23.4",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
|
||||||
"integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==",
|
"integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/highlight": "^7.23.4",
|
"@babel/highlight": "^7.23.4",
|
||||||
"chalk": "^2.4.2"
|
"chalk": "^2.4.2"
|
||||||
@ -223,9 +223,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.23.4",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.5.tgz",
|
||||||
"integrity": "sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==",
|
"integrity": "sha512-NdUTHcPe4C99WxPub+K9l9tK5/lV4UXIoaHSYgzco9BCyjKAAwzdBI+wWtYqHt7LJdbo74ZjRPJgzVweq1sz0w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
},
|
},
|
||||||
@ -234,9 +234,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.23.4",
|
"version": "7.23.5",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.5.tgz",
|
||||||
"integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==",
|
"integrity": "sha512-ON5kSOJwVO6xXVRTvOI0eOnWe7VdUcIpsovGo9U/Br4Ie4UVFQTboO2cYnDhAGU6Fp+UxSiT+pMft0SMHfuq6w==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.23.4",
|
"@babel/helper-string-parser": "^7.23.4",
|
||||||
"@babel/helper-validator-identifier": "^7.22.20",
|
"@babel/helper-validator-identifier": "^7.22.20",
|
||||||
|
@ -32,6 +32,10 @@ export type ILoginParams = {
|
|||||||
totpCode: string;
|
totpCode: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type IAskNewPasswordParams = {
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
|
|
||||||
export default class Auth extends BaseApiService {
|
export default class Auth extends BaseApiService {
|
||||||
private static instance: Auth;
|
private static instance: Auth;
|
||||||
protected readonly namespaceUrl = this.getBaseUrl().concat("/customer");
|
protected readonly namespaceUrl = this.getBaseUrl().concat("/customer");
|
||||||
@ -80,4 +84,14 @@ export default class Auth extends BaseApiService {
|
|||||||
return Promise.reject(err);
|
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 TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import { ValidationError } from "class-validator";
|
import { ValidationError } from "class-validator";
|
||||||
import Link from "next/link";
|
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
||||||
type IProps = {
|
type IProps = {
|
||||||
onSubmit: (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => void;
|
onSubmit: (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => void;
|
||||||
validationErrors: ValidationError[];
|
validationErrors: ValidationError[];
|
||||||
|
onPasswordForgotClicked: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function StepPassword(props: IProps) {
|
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 (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
@ -26,15 +41,29 @@ export default function StepPassword(props: IProps) {
|
|||||||
validationError={validationErrors.find((error) => error.property === "password")}
|
validationError={validationErrors.find((error) => error.property === "password")}
|
||||||
password
|
password
|
||||||
/>
|
/>
|
||||||
<Link href="/forgot-password">
|
<div onClick={openModal}>
|
||||||
<Typography typo={ITypo.P_16} className={classes["forgot-password"]}>
|
<Typography typo={ITypo.P_16} className={classes["forgot-password"]}>
|
||||||
Mot de passe oublié ?
|
Mot de passe oublié ?
|
||||||
</Typography>
|
</Typography>
|
||||||
</Link>
|
</div>
|
||||||
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
||||||
Valider
|
Valider
|
||||||
</Button>
|
</Button>
|
||||||
</Form>
|
</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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,14 @@ import StepNewPassword from "./StepNewPassword";
|
|||||||
import CustomerStore from "@Front/Stores/CustomerStore";
|
import CustomerStore from "@Front/Stores/CustomerStore";
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { TotpCodesReasons } from "le-coffre-resources/dist/Customer/TotpCodes";
|
import { TotpCodesReasons } from "le-coffre-resources/dist/Customer/TotpCodes";
|
||||||
|
import PasswordForgotten from "./PasswordForgotten";
|
||||||
|
|
||||||
export enum LoginStep {
|
export enum LoginStep {
|
||||||
EMAIL,
|
EMAIL,
|
||||||
TOTP,
|
TOTP,
|
||||||
PASSWORD,
|
PASSWORD,
|
||||||
NEW_PASSWORD,
|
NEW_PASSWORD,
|
||||||
|
PASSWORD_FORGOTTEN,
|
||||||
}
|
}
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -85,6 +87,8 @@ export default function Login() {
|
|||||||
|
|
||||||
// If it's first connection, show the form for first connection
|
// If it's first connection, show the form for first connection
|
||||||
if (res.reason === TotpCodesReasons.FIRST_LOGIN) setStep(LoginStep.NEW_PASSWORD);
|
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 just login normally
|
||||||
else setStep(LoginStep.PASSWORD);
|
else setStep(LoginStep.PASSWORD);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
@ -105,7 +109,6 @@ export default function Login() {
|
|||||||
const onNewPasswordSubmit = useCallback(
|
const onNewPasswordSubmit = useCallback(
|
||||||
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||||
try {
|
try {
|
||||||
console.log(values);
|
|
||||||
if (!values["password"] || !values["confirm_password"]) return;
|
if (!values["password"] || !values["confirm_password"]) return;
|
||||||
if (values["password"] !== values["confirm_password"]) {
|
if (values["password"] !== values["confirm_password"]) {
|
||||||
setValidationErrors([
|
setValidationErrors([
|
||||||
@ -159,6 +162,21 @@ export default function Login() {
|
|||||||
[email, router, totpCode],
|
[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 (
|
return (
|
||||||
<DefaultDoubleSidePage title={"Login"} image={LandingImage}>
|
<DefaultDoubleSidePage title={"Login"} image={LandingImage}>
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
@ -166,8 +184,17 @@ export default function Login() {
|
|||||||
{step === LoginStep.TOTP && (
|
{step === LoginStep.TOTP && (
|
||||||
<StepTotp onSubmit={onSmsCodeSubmit} validationErrors={validationErrors} partialPhoneNumber={partialPhoneNumber} />
|
<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.NEW_PASSWORD && <StepNewPassword onSubmit={onNewPasswordSubmit} validationErrors={validationErrors} />}
|
||||||
|
{step === LoginStep.PASSWORD_FORGOTTEN && (
|
||||||
|
<PasswordForgotten onSubmit={onNewPasswordSubmit} validationErrors={validationErrors} />
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Confirm
|
<Confirm
|
||||||
isOpen={isErrorModalOpen}
|
isOpen={isErrorModalOpen}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user