diff --git a/src/front/Components/DesignSystem/Typography/index.tsx b/src/front/Components/DesignSystem/Typography/index.tsx index 0f81e46e..30a5551e 100644 --- a/src/front/Components/DesignSystem/Typography/index.tsx +++ b/src/front/Components/DesignSystem/Typography/index.tsx @@ -147,6 +147,8 @@ export enum ETypoColor { INPUT_LABEL = "--input-label", INPUT_ERROR = "--input-error", + + TEXT_ACCENT = "--text-accent", } export default function Typography(props: IProps) { diff --git a/src/front/Components/Layouts/LoginCustomer/PasswordForgotten/classes.module.scss b/src/front/Components/Layouts/Login/PasswordForgotten/classes.module.scss similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/PasswordForgotten/classes.module.scss rename to src/front/Components/Layouts/Login/PasswordForgotten/classes.module.scss diff --git a/src/front/Components/Layouts/LoginCustomer/PasswordForgotten/index.tsx b/src/front/Components/Layouts/Login/PasswordForgotten/index.tsx similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/PasswordForgotten/index.tsx rename to src/front/Components/Layouts/Login/PasswordForgotten/index.tsx diff --git a/src/front/Components/Layouts/Login/StepEmail/classes.module.scss b/src/front/Components/Layouts/Login/StepEmail/classes.module.scss new file mode 100644 index 00000000..2826c0af --- /dev/null +++ b/src/front/Components/Layouts/Login/StepEmail/classes.module.scss @@ -0,0 +1,32 @@ +.root { + width: 472px; + margin: auto; + margin-top: 80px; + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + .header { + display: flex; + flex-direction: column; + gap: var(--spacing-sm, 8px); + } + + .content { + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + .section { + .section-title { + margin-bottom: var(--spacing-xl, 32px); + } + + > form { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + } + } + } +} diff --git a/src/front/Components/Layouts/Login/StepEmail/index.tsx b/src/front/Components/Layouts/Login/StepEmail/index.tsx new file mode 100644 index 00000000..68d351d2 --- /dev/null +++ b/src/front/Components/Layouts/Login/StepEmail/index.tsx @@ -0,0 +1,194 @@ +import React, { useCallback, useEffect, useState } from "react"; +import classes from "./classes.module.scss"; +import Typography, { ETypo, ETypoColor } 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 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 Image from "next/image"; +import LogoSmallBlue from "@Assets/logo_small_blue.svg"; + +import idNoteLogo from "@Assets/Icons/id-note-logo.svg"; +import { useRouter } from "next/router"; +import { FrontendVariables } from "@Front/Config/VariablesFront"; +import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; + +type IProps = { + onSubmit: (e: React.FormEvent | null, values: { [key: string]: string }) => void; + validationErrors: ValidationError[]; +}; + +export default function StepEmail(props: IProps) { + const { onSubmit, validationErrors } = props; + const [isErrorModalOpen, setIsErrorModalOpen] = useState(0); + /* 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 router = useRouter(); + const error = router.query["error"]; + const redirectUserOnConnection = useCallback(() => { + const variables = FrontendVariables.getInstance(); + router.push( + `${variables.IDNOT_BASE_URL + variables.IDNOT_AUTHORIZE_ENDPOINT}?client_id=${variables.IDNOT_CLIENT_ID}&redirect_uri=${ + variables.FRONT_APP_HOST + }/authorized-client&scope=openid,profile&response_type=code`, + ); + }, [router]); + + const openErrorModal = useCallback((index: number) => { + setIsErrorModalOpen(index); + }, []); + + const closeErrorModal = useCallback(() => { + setIsErrorModalOpen(0); + }, []); + + const closeNoEmailModal = useCallback(() => { + setIsErrorModalOpen(0); + router.push("https://connexion.idnot.fr/"); + }, [router]); + + const closeContactAdminModal = () => { + setIsErrorModalOpen(0); + window.open("https://www.lecoffre.io/contact", "_blank"); + }; + + useEffect(() => { + openErrorModal(parseInt(error as string)); + }, [error, openErrorModal]); + + return ( +
+
+ Logo small blue + + Bienvenue ! + + Connectez-vous pour accéder à votre espace sécurisé. +
+
+
+ + Pour les notaires : + + +
+
+ + Pour les clients : + +
+ err.property === "email")} + /> + + +
+
+ +
+ + Vous ne disposez pas d'un abonnement, veuillez contacter l'administrateur de votre office. + +
+
+ +
+ + Veuillez vous reconnecter. + +
+
+ +
+ + Votre compte ID.not doit être associé à une adresse email @notaires.fr (onglet Mettre à jour mes données + professionnelles) + +
+
+ +
+ + L'accès à la version bêta de lecoffre.io est limité à un groupe restreint d'utilisateurs autorisés. + +
    +
  • + + Si vous êtes intéressé par la participation à notre programme de bêta-test, veuillez nous compléter le + formulaire :{" "} + + https://www.lecoffre.io/contact + + +
  • +
    +
  • + + Si vous avez déjà un compte bêta-testeur, veuillez vous connecter sur{" "} + + https://compte.idnot.fr/home + {" "} + et vérifier que l'adresse mail renseignée sur votre espace est identique à celle que vous nous avez + communiquée. + +
  • +
+
+
+
+ ); +} diff --git a/src/front/Components/Layouts/LoginCustomer/StepNewPassword/classes.module.scss b/src/front/Components/Layouts/Login/StepNewPassword/classes.module.scss similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/StepNewPassword/classes.module.scss rename to src/front/Components/Layouts/Login/StepNewPassword/classes.module.scss diff --git a/src/front/Components/Layouts/LoginCustomer/StepNewPassword/index.tsx b/src/front/Components/Layouts/Login/StepNewPassword/index.tsx similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/StepNewPassword/index.tsx rename to src/front/Components/Layouts/Login/StepNewPassword/index.tsx diff --git a/src/front/Components/Layouts/LoginCustomer/StepPassword/classes.module.scss b/src/front/Components/Layouts/Login/StepPassword/classes.module.scss similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/StepPassword/classes.module.scss rename to src/front/Components/Layouts/Login/StepPassword/classes.module.scss diff --git a/src/front/Components/Layouts/LoginCustomer/StepPassword/index.tsx b/src/front/Components/Layouts/Login/StepPassword/index.tsx similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/StepPassword/index.tsx rename to src/front/Components/Layouts/Login/StepPassword/index.tsx diff --git a/src/front/Components/Layouts/LoginCustomer/StepTotp/classes.module.scss b/src/front/Components/Layouts/Login/StepTotp/classes.module.scss similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/StepTotp/classes.module.scss rename to src/front/Components/Layouts/Login/StepTotp/classes.module.scss diff --git a/src/front/Components/Layouts/LoginCustomer/StepTotp/index.tsx b/src/front/Components/Layouts/Login/StepTotp/index.tsx similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/StepTotp/index.tsx rename to src/front/Components/Layouts/Login/StepTotp/index.tsx diff --git a/src/front/Components/Layouts/Login/classes.module.scss b/src/front/Components/Layouts/Login/classes.module.scss index 794913a1..f68b3ab0 100644 --- a/src/front/Components/Layouts/Login/classes.module.scss +++ b/src/front/Components/Layouts/Login/classes.module.scss @@ -1,25 +1,4 @@ @import "@Themes/constants.scss"; .root { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - height: 100%; - max-width: 530px; - margin: auto; - - .title { - margin: 32px 0; - text-align: center; - - @media (max-width: $screen-s) { - font-family: 48px; - } - } - - .forget-password { - margin-top: 32px; - margin-bottom: 8px; - } } diff --git a/src/front/Components/Layouts/LoginCustomer/france-connect.svg b/src/front/Components/Layouts/Login/france-connect.svg similarity index 100% rename from src/front/Components/Layouts/LoginCustomer/france-connect.svg rename to src/front/Components/Layouts/Login/france-connect.svg diff --git a/src/front/Components/Layouts/Login/index.tsx b/src/front/Components/Layouts/Login/index.tsx index 94dbbe78..3b4a7670 100644 --- a/src/front/Components/Layouts/Login/index.tsx +++ b/src/front/Components/Layouts/Login/index.tsx @@ -1,77 +1,240 @@ -import CoffreIcon from "@Assets/Icons/coffre.svg"; -import idNoteLogo from "@Assets/Icons/id-note-logo.svg"; -import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Typography, { ETypo } 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 classes from "./classes.module.scss"; import LandingImage from "./landing-connect.jpeg"; -import { FrontendVariables } from "@Front/Config/VariablesFront"; -import Link from "next/link"; import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; +import StepEmail from "./StepEmail"; +import StepTotp from "./StepTotp"; +import Auth from "@Front/Api/Auth/Customer/Auth"; +import { ValidationError } from "class-validator"; +import StepPassword from "./StepPassword"; +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(); - const error = router.query["error"]; - const [isErrorModalOpen, setIsErrorModalOpen] = useState(0); + const [isErrorModalOpen, setIsErrorModalOpen] = useState(false); - const redirectUserOnConnection = useCallback(() => { - const variables = FrontendVariables.getInstance(); - router.push( - `${variables.IDNOT_BASE_URL + variables.IDNOT_AUTHORIZE_ENDPOINT}?client_id=${variables.IDNOT_CLIENT_ID}&redirect_uri=${ - variables.FRONT_APP_HOST - }/authorized-client&scope=openid,profile&response_type=code`, - ); - }, [router]); + const [step, setStep] = useState(LoginStep.EMAIL); + const [totpCodeUid, setTotpCodeUid] = useState(""); + const [totpCode, setTotpCode] = useState(""); + const [email, setEmail] = useState(""); + const [partialPhoneNumber, setPartialPhoneNumber] = useState(""); + const [validationErrors, setValidationErrors] = useState([]); - const openErrorModal = useCallback((index: number) => { - setIsErrorModalOpen(index); + const openErrorModal = useCallback(() => { + setIsErrorModalOpen(true); }, []); const closeErrorModal = useCallback(() => { - setIsErrorModalOpen(0); + setIsErrorModalOpen(false); }, []); - const closeNoEmailModal = useCallback(() => { - setIsErrorModalOpen(0); - router.push("https://connexion.idnot.fr/"); - }, [router]); - - const closeContactAdminModal = () => { - setIsErrorModalOpen(0); - window.open("https://www.lecoffre.io/contact", "_blank"); - }; - useEffect(() => { - openErrorModal(parseInt(error as string)); + if (error === "1") openErrorModal(); }, [error, openErrorModal]); + const onEmailFormSubmit = useCallback(async (e: React.FormEvent | null, values: { [key: string]: string }) => { + try { + if (!values["email"]) return; + setEmail(values["email"]); + const res = await Auth.getInstance().mailVerifySms({ email: values["email"] }); + setPartialPhoneNumber(res.partialPhoneNumber); + setTotpCodeUid(res.totpCodeUid); + setStep(LoginStep.TOTP); + setValidationErrors([]); + } catch (error: any) { + setValidationErrors([ + { + property: "email", + constraints: { + [error.http_status]: error.message, + }, + }, + ]); + return; + } + }, []); + + const onSmsCodeSubmit = useCallback( + async (e: React.FormEvent | null, values: { [key: string]: string }) => { + try { + if (!values["totpCode"]) return; + const res = await Auth.getInstance().verifyTotpCode({ totpCode: values["totpCode"], email }); + + // If the code is valid setting it in state + if (res.validCode) setTotpCode(values["totpCode"]); + + setValidationErrors([]); + // 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) { + setValidationErrors([ + { + property: "totpCode", + constraints: { + [error.http_status]: error.message, + }, + }, + ]); + return; + } + }, + [email, setStep], + ); + + const onNewPasswordSubmit = useCallback( + async (e: React.FormEvent | null, values: { [key: string]: string }) => { + try { + if (!values["password"] || !values["confirm_password"]) return; + if (values["password"] !== values["confirm_password"]) { + setValidationErrors([ + { + property: "confirm_password", + constraints: { + "400": "Les mots de passe ne correspondent pas.", + }, + }, + ]); + return; + } + + const passwordRegex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d@$!%*?&_\\-]{8,}$/); + if (!passwordRegex.test(values["password"])) { + setValidationErrors([ + { + property: "password", + constraints: { + "400": "Le mot de passe doit contenir au moins 8 caractères dont 1 majuscule, 1 minuscule et 1 chiffre.", + }, + }, + ]); + return; + } + const token = await Auth.getInstance().setPassword({ totpCode, email, password: values["password"] }); + CustomerStore.instance.connect(token.accessToken, token.refreshToken); + setValidationErrors([]); + router.push(Module.getInstance().get().modules.pages.Folder.pages.Select.props.path); + // If set password worked, setting the token and redirecting + } catch (error: any) { + setValidationErrors([ + { + property: "password", + constraints: { + [error.http_status]: error.message, + }, + }, + ]); + return; + } + }, + [totpCode, email, router], + ); + + const onPasswordSubmit = useCallback( + async (e: React.FormEvent | null, values: { [key: string]: string }) => { + try { + if (!values["password"]) return; + const token = await Auth.getInstance().login({ totpCode, email, password: values["password"] }); + CustomerStore.instance.connect(token.accessToken, token.refreshToken); + setValidationErrors([]); + router.push(Module.getInstance().get().modules.pages.Folder.pages.Select.props.path); + } catch (error: any) { + setValidationErrors([ + { + property: "password", + constraints: { + [error.http_status]: error.message, + }, + }, + ]); + return; + } + }, + [email, router, totpCode], + ); + + const onPasswordForgotClicked = useCallback(async () => { + try { + const res = await Auth.getInstance().askNewPassword({ email }); + setPartialPhoneNumber(res.partialPhoneNumber); + setValidationErrors([]); + 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]); + + const onSendAnotherCode = useCallback(async () => { + try { + const res = await Auth.getInstance().sendAnotherCode({ email, totpCodeUid }); + + setValidationErrors([]); + setPartialPhoneNumber(res.partialPhoneNumber); + setTotpCodeUid(res.totpCodeUid); + } catch (error: any) { + setValidationErrors([ + { + property: "totpCode", + constraints: { + [error.http_status]: error.message, + }, + }, + ]); + return; + } + }, [email, totpCodeUid]); + return (
- coffre - -
Connexion espace professionnel
-
- - -
Vous n'arrivez pas à vous connecter ?
-
- - - + {step === LoginStep.EMAIL && } + {step === LoginStep.TOTP && ( + + )} + {step === LoginStep.PASSWORD && ( + + )} + {step === LoginStep.NEW_PASSWORD && } + {step === LoginStep.PASSWORD_FORGOTTEN && ( + + )}
- Vous ne disposez pas d'un abonnement, veuillez contacter l'administrateur de votre office. + Une erreur est survenue lors de la connexion. Veuillez réessayer.
- -
- - Veuillez vous reconnecter. - -
-
- -
- - Votre compte ID.not doit être associé à une adresse email @notaires.fr (onglet Mettre à jour mes données - professionnelles) - -
-
- -
- - L'accès à la version bêta de lecoffre.io est limité à un groupe restreint d'utilisateurs autorisés. - -
    -
  • - - Si vous êtes intéressé par la participation à notre programme de bêta-test, veuillez nous compléter le - formulaire :{" "} - - https://www.lecoffre.io/contact - - -
  • -
    -
  • - - Si vous avez déjà un compte bêta-testeur, veuillez vous connecter sur{" "} - - https://compte.idnot.fr/home - {" "} - et vérifier que l'adresse mail renseignée sur votre espace est identique à celle que vous nous avez - communiquée. - -
  • -
-
-
); } diff --git a/src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss b/src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss deleted file mode 100644 index 2fd71d0d..00000000 --- a/src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss +++ /dev/null @@ -1,49 +0,0 @@ -@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 deleted file mode 100644 index 64c15e5c..00000000 --- a/src/front/Components/Layouts/LoginCustomer/StepEmail/index.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from "react"; -import classes from "./classes.module.scss"; -import Typography, { ETypo } 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"; -type IProps = { - onSubmit: (e: React.FormEvent | null, values: { [key: string]: string }) => void; - validationErrors: ValidationError[]; -}; - -export default function StepEmail(props: IProps) { - const { onSubmit, validationErrors } = props; - /* 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]); */ - - 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 - */} - - Pour accéder à votre espace de dépôt des documents, veuillez vous identifier.{" "} - -
- error.property === "email")} - /> - - - {/* -
Vous n'arrivez pas à vous connecter ?
-
- - - */} -
- ); -} diff --git a/src/front/Components/Layouts/LoginCustomer/classes.module.scss b/src/front/Components/Layouts/LoginCustomer/classes.module.scss deleted file mode 100644 index f68b3ab0..00000000 --- a/src/front/Components/Layouts/LoginCustomer/classes.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -@import "@Themes/constants.scss"; - -.root { -} diff --git a/src/front/Components/Layouts/LoginCustomer/index.tsx b/src/front/Components/Layouts/LoginCustomer/index.tsx deleted file mode 100644 index 3b4a7670..00000000 --- a/src/front/Components/Layouts/LoginCustomer/index.tsx +++ /dev/null @@ -1,252 +0,0 @@ -import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; -import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; -import { useRouter } from "next/router"; -import { useCallback, useEffect, useState } from "react"; - -import classes from "./classes.module.scss"; -import LandingImage from "./landing-connect.jpeg"; -import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; -import StepEmail from "./StepEmail"; -import StepTotp from "./StepTotp"; -import Auth from "@Front/Api/Auth/Customer/Auth"; -import { ValidationError } from "class-validator"; -import StepPassword from "./StepPassword"; -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(); - const error = router.query["error"]; - - const [isErrorModalOpen, setIsErrorModalOpen] = useState(false); - - const [step, setStep] = useState(LoginStep.EMAIL); - const [totpCodeUid, setTotpCodeUid] = useState(""); - const [totpCode, setTotpCode] = useState(""); - const [email, setEmail] = useState(""); - const [partialPhoneNumber, setPartialPhoneNumber] = useState(""); - const [validationErrors, setValidationErrors] = useState([]); - - const openErrorModal = useCallback(() => { - setIsErrorModalOpen(true); - }, []); - - const closeErrorModal = useCallback(() => { - setIsErrorModalOpen(false); - }, []); - - useEffect(() => { - if (error === "1") openErrorModal(); - }, [error, openErrorModal]); - - const onEmailFormSubmit = useCallback(async (e: React.FormEvent | null, values: { [key: string]: string }) => { - try { - if (!values["email"]) return; - setEmail(values["email"]); - const res = await Auth.getInstance().mailVerifySms({ email: values["email"] }); - setPartialPhoneNumber(res.partialPhoneNumber); - setTotpCodeUid(res.totpCodeUid); - setStep(LoginStep.TOTP); - setValidationErrors([]); - } catch (error: any) { - setValidationErrors([ - { - property: "email", - constraints: { - [error.http_status]: error.message, - }, - }, - ]); - return; - } - }, []); - - const onSmsCodeSubmit = useCallback( - async (e: React.FormEvent | null, values: { [key: string]: string }) => { - try { - if (!values["totpCode"]) return; - const res = await Auth.getInstance().verifyTotpCode({ totpCode: values["totpCode"], email }); - - // If the code is valid setting it in state - if (res.validCode) setTotpCode(values["totpCode"]); - - setValidationErrors([]); - // 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) { - setValidationErrors([ - { - property: "totpCode", - constraints: { - [error.http_status]: error.message, - }, - }, - ]); - return; - } - }, - [email, setStep], - ); - - const onNewPasswordSubmit = useCallback( - async (e: React.FormEvent | null, values: { [key: string]: string }) => { - try { - if (!values["password"] || !values["confirm_password"]) return; - if (values["password"] !== values["confirm_password"]) { - setValidationErrors([ - { - property: "confirm_password", - constraints: { - "400": "Les mots de passe ne correspondent pas.", - }, - }, - ]); - return; - } - - const passwordRegex = new RegExp(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[A-Za-z\d@$!%*?&_\\-]{8,}$/); - if (!passwordRegex.test(values["password"])) { - setValidationErrors([ - { - property: "password", - constraints: { - "400": "Le mot de passe doit contenir au moins 8 caractères dont 1 majuscule, 1 minuscule et 1 chiffre.", - }, - }, - ]); - return; - } - const token = await Auth.getInstance().setPassword({ totpCode, email, password: values["password"] }); - CustomerStore.instance.connect(token.accessToken, token.refreshToken); - setValidationErrors([]); - router.push(Module.getInstance().get().modules.pages.Folder.pages.Select.props.path); - // If set password worked, setting the token and redirecting - } catch (error: any) { - setValidationErrors([ - { - property: "password", - constraints: { - [error.http_status]: error.message, - }, - }, - ]); - return; - } - }, - [totpCode, email, router], - ); - - const onPasswordSubmit = useCallback( - async (e: React.FormEvent | null, values: { [key: string]: string }) => { - try { - if (!values["password"]) return; - const token = await Auth.getInstance().login({ totpCode, email, password: values["password"] }); - CustomerStore.instance.connect(token.accessToken, token.refreshToken); - setValidationErrors([]); - router.push(Module.getInstance().get().modules.pages.Folder.pages.Select.props.path); - } catch (error: any) { - setValidationErrors([ - { - property: "password", - constraints: { - [error.http_status]: error.message, - }, - }, - ]); - return; - } - }, - [email, router, totpCode], - ); - - const onPasswordForgotClicked = useCallback(async () => { - try { - const res = await Auth.getInstance().askNewPassword({ email }); - setPartialPhoneNumber(res.partialPhoneNumber); - setValidationErrors([]); - 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]); - - const onSendAnotherCode = useCallback(async () => { - try { - const res = await Auth.getInstance().sendAnotherCode({ email, totpCodeUid }); - - setValidationErrors([]); - setPartialPhoneNumber(res.partialPhoneNumber); - setTotpCodeUid(res.totpCodeUid); - } catch (error: any) { - setValidationErrors([ - { - property: "totpCode", - constraints: { - [error.http_status]: error.message, - }, - }, - ]); - return; - } - }, [email, totpCodeUid]); - - return ( - -
- {step === LoginStep.EMAIL && } - {step === LoginStep.TOTP && ( - - )} - {step === LoginStep.PASSWORD && ( - - )} - {step === LoginStep.NEW_PASSWORD && } - {step === LoginStep.PASSWORD_FORGOTTEN && ( - - )} -
- -
- - Une erreur est survenue lors de la connexion. Veuillez réessayer. - -
-
-
- ); -} diff --git a/src/front/Components/Layouts/LoginCustomer/landing-connect.jpeg b/src/front/Components/Layouts/LoginCustomer/landing-connect.jpeg deleted file mode 100644 index 789e0ef3..00000000 Binary files a/src/front/Components/Layouts/LoginCustomer/landing-connect.jpeg and /dev/null differ diff --git a/src/front/Components/Layouts/LoginHome/classes.module.scss b/src/front/Components/Layouts/LoginHome/classes.module.scss deleted file mode 100644 index 6fbad4c2..00000000 --- a/src/front/Components/Layouts/LoginHome/classes.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -.root { - padding: 64px; - - .content { - display: flex; - gap: 48px; - flex-direction: column; - margin-top: 48px; - - .section { - display: flex; - flex-direction: column; - gap: 24px; - } - .separator { - height: 1px; - background-color: var(--color-neutral-200); - } - } - .bottom { - margin-top: 48px; - } -} diff --git a/src/front/Components/Layouts/LoginHome/index.tsx b/src/front/Components/Layouts/LoginHome/index.tsx deleted file mode 100644 index 64cfe38d..00000000 --- a/src/front/Components/Layouts/LoginHome/index.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; - -import classes from "./classes.module.scss"; -import LandingImage from "../Login/landing-connect.jpeg"; -import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import Link from "next/link"; -import Module from "@Front/Config/Module"; - -export default function LoginHome() { - return ( - -
- -
Connectez-vous à votre plateforme LEcoffre.io
-
-
-
- - Je suis un notaire / collaborateur - - - - -
-
-
- - Je suis un client - - - - -
-
-
- -
Vous n'arrivez pas à vous connecter ?
-
- - - -
-
- - ); -} diff --git a/src/pages/customer-login.tsx b/src/pages/customer-login.tsx index 785decd1..40f96abe 100644 --- a/src/pages/customer-login.tsx +++ b/src/pages/customer-login.tsx @@ -1,5 +1,5 @@ -import LoginCustomer from "@Front/Components/Layouts/LoginCustomer"; +import Login from "@Front/Components/Layouts/Login"; export default function Route() { - return ; + return ; } diff --git a/src/pages/customers/login.tsx b/src/pages/customers/login.tsx index 785decd1..40f96abe 100644 --- a/src/pages/customers/login.tsx +++ b/src/pages/customers/login.tsx @@ -1,5 +1,5 @@ -import LoginCustomer from "@Front/Components/Layouts/LoginCustomer"; +import Login from "@Front/Components/Layouts/Login"; export default function Route() { - return ; + return ; } diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 790c8a7c..40f96abe 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,5 +1,5 @@ -import LoginHome from "@Front/Components/Layouts/LoginHome"; +import Login from "@Front/Components/Layouts/Login"; export default function Route() { - return ; + return ; }