diff --git a/src/front/Api/BaseApiService.ts b/src/front/Api/BaseApiService.ts index 999ae0f0..198141b2 100644 --- a/src/front/Api/BaseApiService.ts +++ b/src/front/Api/BaseApiService.ts @@ -138,11 +138,16 @@ export default abstract class BaseApiService { } } else { // Handle error response + const responseCopy = response.clone(); try { const responseJson = await response.json(); return Promise.reject(responseJson); } catch (err) { - return Promise.reject(err); + const responseText = await responseCopy.text(); + return Promise.reject({ + http_status: response.status, + message: responseText, + }); } } diff --git a/src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss b/src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss new file mode 100644 index 00000000..2fd71d0d --- /dev/null +++ b/src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss @@ -0,0 +1,49 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + flex-direction: column; + max-width: 530px; + margin: auto; + margin-top: 220px; + + .title { + margin-bottom: 32px; + text-align: left; + + @media (max-width: $screen-s) { + font-family: 48px; + } + } + + .logo { + margin-top: 32px; + cursor: pointer; + } + + .what_is_france_connect { + color: var(--light-text-action-high-blue-france, #000091); + /* 2.Corps de texte/SM - Texte détail/Desktop & Mobile - Regular */ + font-family: Marianne; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 24px; /* 171.429% */ + margin-top: 12px; + } + + .or { + margin-top: 32px; + } + .forget-password { + margin-top: 32px; + margin-bottom: 8px; + } + + .form { + margin-top: 32px; + .submit_button { + margin-top: 32px; + } + } +} diff --git a/src/front/Components/Layouts/LoginCustomer/StepEmail/index.tsx b/src/front/Components/Layouts/LoginCustomer/StepEmail/index.tsx new file mode 100644 index 00000000..63607abe --- /dev/null +++ b/src/front/Components/Layouts/LoginCustomer/StepEmail/index.tsx @@ -0,0 +1,91 @@ +import React, { useCallback, useState } 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 = { + setPartialPhoneNumber: (phoneNumber: string) => void; + setStep: (step: LoginStep) => void; +}; + +export default function StepEmail(props: IProps) { + const { setPartialPhoneNumber, setStep } = props; + const [validationError, setValidationError] = useState([]); + const router = useRouter(); + const redirectCustomerOnConnection = useCallback(() => { + async function getCustomer() { + try { + const loginRes = await Customers.getInstance().login(); + router.push(loginRes.enrollment.franceConnectUrl); + } catch (e) { + console.error(e); + } + } + getCustomer(); + }, [router]); + + const onSubmitHandler = useCallback( + async (e: React.FormEvent | 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 ( +
+ +
Identifiez-vous
+
+ Pour accéder à votre espace de dépôt des documents, veuillez vous identifier. + france-connect +
Qu'est ce que FranceConnect ?
+ + Ou + +
+ error.property === "email")} + /> + + + {/* +
Vous n'arrivez pas à vous connecter ?
+
+ + + */} +
+ ); +} diff --git a/src/front/Components/Layouts/LoginCustomer/StepTotp/classes.module.scss b/src/front/Components/Layouts/LoginCustomer/StepTotp/classes.module.scss new file mode 100644 index 00000000..efbcd6ad --- /dev/null +++ b/src/front/Components/Layouts/LoginCustomer/StepTotp/classes.module.scss @@ -0,0 +1,24 @@ +@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; + .submit_button { + margin-top: 32px; + } + } +} diff --git a/src/front/Components/Layouts/LoginCustomer/StepTotp/index.tsx b/src/front/Components/Layouts/LoginCustomer/StepTotp/index.tsx new file mode 100644 index 00000000..421ea78f --- /dev/null +++ b/src/front/Components/Layouts/LoginCustomer/StepTotp/index.tsx @@ -0,0 +1,67 @@ +import React, { useCallback, useState } 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; + partialPhoneNumber: string; +}; + +export default function StepTotp(props: IProps) { + const { setStep, setTotpCode, partialPhoneNumber } = props; + const [validationError, setValidationError] = useState([]); + const router = useRouter(); + const onSubmitHandler = useCallback( + async (e: React.FormEvent | 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], + ); + + return ( +
+ +
Votre code a été envoyé par SMS au ** ** ** {partialPhoneNumber}
+
+
+ error.property === "code")} + /> + + +
+ ); +} diff --git a/src/front/Components/Layouts/LoginCustomer/classes.module.scss b/src/front/Components/Layouts/LoginCustomer/classes.module.scss index 2fd71d0d..f68b3ab0 100644 --- a/src/front/Components/Layouts/LoginCustomer/classes.module.scss +++ b/src/front/Components/Layouts/LoginCustomer/classes.module.scss @@ -1,49 +1,4 @@ @import "@Themes/constants.scss"; .root { - display: flex; - flex-direction: column; - max-width: 530px; - margin: auto; - margin-top: 220px; - - .title { - margin-bottom: 32px; - text-align: left; - - @media (max-width: $screen-s) { - font-family: 48px; - } - } - - .logo { - margin-top: 32px; - cursor: pointer; - } - - .what_is_france_connect { - color: var(--light-text-action-high-blue-france, #000091); - /* 2.Corps de texte/SM - Texte détail/Desktop & Mobile - Regular */ - font-family: Marianne; - font-size: 14px; - font-style: normal; - font-weight: 400; - line-height: 24px; /* 171.429% */ - margin-top: 12px; - } - - .or { - margin-top: 32px; - } - .forget-password { - margin-top: 32px; - margin-bottom: 8px; - } - - .form { - margin-top: 32px; - .submit_button { - margin-top: 32px; - } - } } diff --git a/src/front/Components/Layouts/LoginCustomer/index.tsx b/src/front/Components/Layouts/LoginCustomer/index.tsx index 384f59fd..16901f60 100644 --- a/src/front/Components/Layouts/LoginCustomer/index.tsx +++ b/src/front/Components/Layouts/LoginCustomer/index.tsx @@ -1,37 +1,28 @@ -import franceConnectLogo from "./france-connect.svg"; -import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; -import Image from "next/image"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; -import Customers from "@Front/Api/Auth/Id360/Customers/Customers"; + import classes from "./classes.module.scss"; import LandingImage from "./landing-connect.jpeg"; import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; -import Form from "@Front/Components/DesignSystem/Form"; -import TextField from "@Front/Components/DesignSystem/Form/TextField"; -import Module from "@Front/Config/Module"; -import { ValidationError } from "class-validator"; -import Auth from "@Front/Api/Auth/Customer/Auth"; +import StepEmail from "./StepEmail"; +import StepTotp from "./StepTotp"; +export enum LoginStep { + EMAIL, + TOTP, + NEW_PASSWORD, +} export default function Login() { const router = useRouter(); const error = router.query["error"]; - const [validationError, setValidationError] = useState([]); + const [isErrorModalOpen, setIsErrorModalOpen] = useState(false); - const redirectCustomerOnConnection = useCallback(() => { - async function getCustomer() { - try { - const loginRes = await Customers.getInstance().login(); - router.push(loginRes.enrollment.franceConnectUrl); - } catch (e) { - console.error(e); - } - } - getCustomer(); - }, [router]); + const [step, setStep] = useState(LoginStep.EMAIL); + const [totpCode, setTotpCode] = useState(""); + const [partialPhoneNumber, setPartialPhoneNumber] = useState(""); const openErrorModal = useCallback(() => { setIsErrorModalOpen(true); @@ -45,53 +36,13 @@ export default function Login() { if (error === "1") openErrorModal(); }, [error, openErrorModal]); - const onSubmitHandler = useCallback( - async (e: React.FormEvent | null, values: { [key: string]: string }) => { - try { - console.log(values); - if (!values["email"]) return; - const phoneNumber = await Auth.getInstance().mailVerifySms({ email: values["email"] }); - /* router.push( - Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path.replace("[uid]", "1"), - ); */ - } catch (validationErrors: Array | any) { - console.log(validationErrors); - if (validationErrors.length > 0) { - setValidationError(validationErrors as ValidationError[]); - } - return; - } - }, - [router], - ); return (
- -
Identifiez-vous
-
- Pour accéder à votre espace de dépôt des documents, veuillez vous identifier. - france-connect -
Qu'est ce que FranceConnect ?
- - Ou - -
- error.property === "email")} - /> - - - {/* -
Vous n'arrivez pas à vous connecter ?
-
- - - */} + {step === LoginStep.EMAIL && } + {step === LoginStep.TOTP && ( + + )}