✨ Two first steps working
This commit is contained in:
parent
81731b72d8
commit
386ba6c32e
@ -8,6 +8,15 @@ export type IMailVerifyReturn = {
|
||||
partialPhoneNumber: string;
|
||||
};
|
||||
|
||||
export type IVerifyTotpCodeParams = {
|
||||
totpCode: string;
|
||||
email: string;
|
||||
};
|
||||
|
||||
export type IVerifyTotpCodeReturn = {
|
||||
validCode: boolean;
|
||||
};
|
||||
|
||||
export default class Auth extends BaseApiService {
|
||||
private static instance: Auth;
|
||||
protected readonly namespaceUrl = this.getBaseUrl().concat("/customer");
|
||||
@ -26,4 +35,14 @@ export default class Auth extends BaseApiService {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
|
||||
public async verifyTotpCode(body: IVerifyTotpCodeParams): Promise<IVerifyTotpCodeReturn> {
|
||||
const url = new URL(this.baseURl.concat("/verify-totp-code"));
|
||||
try {
|
||||
return this.postRequest<IVerifyTotpCodeReturn>(url, body);
|
||||
} catch (err) {
|
||||
this.onError(err);
|
||||
return Promise.reject(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import React, { useCallback } from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||
import Image from "next/image";
|
||||
@ -9,16 +9,13 @@ import franceConnectLogo from "../france-connect.svg";
|
||||
import { useRouter } from "next/router";
|
||||
import Customers from "@Front/Api/Auth/Id360/Customers/Customers";
|
||||
import { ValidationError } from "class-validator";
|
||||
import { LoginStep } from "..";
|
||||
import Auth from "@Front/Api/Auth/Customer/Auth";
|
||||
type IProps = {
|
||||
setPartialPhoneNumber: (phoneNumber: string) => void;
|
||||
setStep: (step: LoginStep) => void;
|
||||
onSubmit: (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => void;
|
||||
validationErrors: ValidationError[];
|
||||
};
|
||||
|
||||
export default function StepEmail(props: IProps) {
|
||||
const { setPartialPhoneNumber, setStep } = props;
|
||||
const [validationError, setValidationError] = useState<ValidationError[]>([]);
|
||||
const { onSubmit, validationErrors } = props;
|
||||
const router = useRouter();
|
||||
const redirectCustomerOnConnection = useCallback(() => {
|
||||
async function getCustomer() {
|
||||
@ -32,33 +29,6 @@ export default function StepEmail(props: IProps) {
|
||||
getCustomer();
|
||||
}, [router]);
|
||||
|
||||
const onSubmitHandler = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||
try {
|
||||
if (!values["email"]) return;
|
||||
const res = await Auth.getInstance().mailVerifySms({ email: values["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;
|
||||
}
|
||||
setValidationError([
|
||||
{
|
||||
property: "email",
|
||||
constraints: {
|
||||
[error.http_status]: error.message,
|
||||
},
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
},
|
||||
[setPartialPhoneNumber, setStep],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
<Typography typo={ITypo.H1}>
|
||||
@ -70,11 +40,11 @@ export default function StepEmail(props: IProps) {
|
||||
<Typography className={classes["or"]} typo={ITypo.P_16}>
|
||||
Ou
|
||||
</Typography>
|
||||
<Form className={classes["form"]} onSubmit={onSubmitHandler}>
|
||||
<Form className={classes["form"]} onSubmit={onSubmit}>
|
||||
<TextField
|
||||
placeholder="E-mail"
|
||||
name="email"
|
||||
validationError={validationError.find((error) => error.property === "email")}
|
||||
validationError={validationErrors.find((error) => error.property === "email")}
|
||||
/>
|
||||
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
||||
Suivant
|
||||
|
@ -1,62 +1,29 @@
|
||||
import React, { useCallback, useState } from "react";
|
||||
import React from "react";
|
||||
import classes from "./classes.module.scss";
|
||||
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||
import Image from "next/image";
|
||||
import Form from "@Front/Components/DesignSystem/Form";
|
||||
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
||||
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||
import franceConnectLogo from "./france-connect.svg";
|
||||
import { useRouter } from "next/router";
|
||||
import Customers from "@Front/Api/Auth/Id360/Customers/Customers";
|
||||
import { ValidationError } from "class-validator";
|
||||
import { LoginStep } from "..";
|
||||
import Auth from "@Front/Api/Auth/Customer/Auth";
|
||||
type IProps = {
|
||||
setStep: (step: LoginStep) => void;
|
||||
setTotpCode: (code: string) => void;
|
||||
onSubmit: (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => void;
|
||||
validationErrors: ValidationError[];
|
||||
partialPhoneNumber: string;
|
||||
};
|
||||
|
||||
export default function StepTotp(props: IProps) {
|
||||
const { setStep, setTotpCode, partialPhoneNumber } = props;
|
||||
const [validationError, setValidationError] = useState<ValidationError[]>([]);
|
||||
const router = useRouter();
|
||||
const onSubmitHandler = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||
try {
|
||||
if (!values["email"]) return;
|
||||
const res = await Auth.getInstance().mailVerifySms({ email: values["email"] });
|
||||
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;
|
||||
}
|
||||
setValidationError([
|
||||
{
|
||||
property: "code",
|
||||
constraints: {
|
||||
[error.http_status]: error.message,
|
||||
},
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
},
|
||||
[setStep],
|
||||
);
|
||||
const { onSubmit, validationErrors, partialPhoneNumber } = props;
|
||||
|
||||
return (
|
||||
<div className={classes["root"]}>
|
||||
<Typography typo={ITypo.H1}>
|
||||
<div className={classes["title"]}>Votre code a été envoyé par SMS au ** ** ** {partialPhoneNumber}</div>
|
||||
</Typography>
|
||||
<Form className={classes["form"]} onSubmit={onSubmitHandler}>
|
||||
<Form className={classes["form"]} onSubmit={onSubmit}>
|
||||
<TextField
|
||||
placeholder="Code à usage unique"
|
||||
name="email"
|
||||
validationError={validationError.find((error) => error.property === "code")}
|
||||
name="totpCode"
|
||||
validationError={validationErrors.find((error) => error.property === "totpCode")}
|
||||
/>
|
||||
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
||||
Suivant
|
||||
|
@ -8,6 +8,8 @@ import LandingImage from "./landing-connect.jpeg";
|
||||
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
||||
import StepEmail from "./StepEmail";
|
||||
import StepTotp from "./StepTotp";
|
||||
import Auth from "@Front/Api/Auth/Customer/Auth";
|
||||
import { ValidationError } from "class-validator";
|
||||
|
||||
export enum LoginStep {
|
||||
EMAIL,
|
||||
@ -22,8 +24,9 @@ export default function Login() {
|
||||
|
||||
const [step, setStep] = useState<LoginStep>(LoginStep.EMAIL);
|
||||
const [totpCode, setTotpCode] = useState<string>("");
|
||||
const [email, setEmail] = useState<string>("");
|
||||
const [partialPhoneNumber, setPartialPhoneNumber] = useState<string>("");
|
||||
|
||||
const [validationErrors, setValidationErrors] = useState<ValidationError[]>([]);
|
||||
const openErrorModal = useCallback(() => {
|
||||
setIsErrorModalOpen(true);
|
||||
}, []);
|
||||
@ -36,12 +39,66 @@ export default function Login() {
|
||||
if (error === "1") openErrorModal();
|
||||
}, [error, openErrorModal]);
|
||||
|
||||
const onEmailFormSubmit = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||
try {
|
||||
if (!values["email"]) return;
|
||||
const res = await Auth.getInstance().mailVerifySms({ email: values["email"] });
|
||||
setPartialPhoneNumber(res.partialPhoneNumber);
|
||||
setEmail(values["email"]);
|
||||
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;
|
||||
}
|
||||
setValidationErrors([
|
||||
{
|
||||
property: "email",
|
||||
constraints: {
|
||||
[error.http_status]: error.message,
|
||||
},
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
},
|
||||
[setEmail, setPartialPhoneNumber, setStep],
|
||||
);
|
||||
|
||||
const onSmsCodeSubmit = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => {
|
||||
try {
|
||||
if (!values["totpCode"]) return;
|
||||
const res = await Auth.getInstance().verifyTotpCode({ totpCode: values["totpCode"], email });
|
||||
if (res.validCode) {
|
||||
setTotpCode(values["totpCode"]);
|
||||
setStep(LoginStep.NEW_PASSWORD);
|
||||
}
|
||||
} catch (error: any) {
|
||||
setValidationErrors([
|
||||
{
|
||||
property: "totpCode",
|
||||
constraints: {
|
||||
[error.http_status]: error.message,
|
||||
},
|
||||
},
|
||||
]);
|
||||
return;
|
||||
}
|
||||
},
|
||||
[email, setStep],
|
||||
);
|
||||
return (
|
||||
<DefaultDoubleSidePage title={"Login"} image={LandingImage}>
|
||||
<div className={classes["root"]}>
|
||||
{step === LoginStep.EMAIL && <StepEmail setPartialPhoneNumber={setPartialPhoneNumber} setStep={setStep} />}
|
||||
{step === LoginStep.EMAIL && <StepEmail onSubmit={onEmailFormSubmit} validationErrors={validationErrors} />}
|
||||
{step === LoginStep.TOTP && (
|
||||
<StepTotp setStep={setStep} setTotpCode={setTotpCode} partialPhoneNumber={partialPhoneNumber} />
|
||||
<StepTotp onSubmit={onSmsCodeSubmit} validationErrors={validationErrors} partialPhoneNumber={partialPhoneNumber} />
|
||||
)}
|
||||
{step === LoginStep.NEW_PASSWORD && (
|
||||
<StepTotp onSubmit={onSmsCodeSubmit} validationErrors={validationErrors} partialPhoneNumber={partialPhoneNumber} />
|
||||
)}
|
||||
</div>
|
||||
<Confirm
|
||||
|
Loading…
x
Reference in New Issue
Block a user