diff --git a/package-lock.json b/package-lock.json index 4554bcda..b1029407 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,6 @@ "react-toastify": "^9.1.3", "sass": "^1.59.2", "sharp": "^0.32.1", - "ts-pattern": "^4.3.0", "typescript": "4.9.5", "uuidv4": "^6.2.13" } @@ -4911,11 +4910,6 @@ "node": ">=8.0" } }, - "node_modules/ts-pattern": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ts-pattern/-/ts-pattern-4.3.0.tgz", - "integrity": "sha512-pefrkcd4lmIVR0LA49Imjf9DYLK8vtWhqBPA3Ya1ir8xCW0O2yjL9dsCVvI7pCodLC5q7smNpEtDR2yVulQxOg==" - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", diff --git a/package.json b/package.json index 870848ea..e1bfc963 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev", + "dev": "PORT=5005 next dev", "build": "next build", "start": "next start", "lint": "next lint", diff --git a/src/front/Components/Layouts/LoginCustomer/PasswordForgotten/classes.module.scss b/src/front/Components/Layouts/Login/PasswordForgotten/classes.module.scss similarity index 86% rename from src/front/Components/Layouts/LoginCustomer/PasswordForgotten/classes.module.scss rename to src/front/Components/Layouts/Login/PasswordForgotten/classes.module.scss index e0a34824..c44eb8ee 100644 --- a/src/front/Components/Layouts/LoginCustomer/PasswordForgotten/classes.module.scss +++ b/src/front/Components/Layouts/Login/PasswordForgotten/classes.module.scss @@ -3,9 +3,6 @@ .root { display: flex; flex-direction: column; - max-width: 530px; - margin: auto; - margin-top: 220px; .title { text-align: left; 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/LoginCustomer/StepEmail/classes.module.scss b/src/front/Components/Layouts/Login/StepEmail/classes.module.scss similarity index 93% rename from src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss rename to src/front/Components/Layouts/Login/StepEmail/classes.module.scss index 2fd71d0d..082074f2 100644 --- a/src/front/Components/Layouts/LoginCustomer/StepEmail/classes.module.scss +++ b/src/front/Components/Layouts/Login/StepEmail/classes.module.scss @@ -3,9 +3,6 @@ .root { display: flex; flex-direction: column; - max-width: 530px; - margin: auto; - margin-top: 220px; .title { margin-bottom: 32px; diff --git a/src/front/Components/Layouts/LoginCustomer/StepEmail/index.tsx b/src/front/Components/Layouts/Login/StepEmail/index.tsx similarity index 90% rename from src/front/Components/Layouts/LoginCustomer/StepEmail/index.tsx rename to src/front/Components/Layouts/Login/StepEmail/index.tsx index a9348265..6a798ae5 100644 --- a/src/front/Components/Layouts/LoginCustomer/StepEmail/index.tsx +++ b/src/front/Components/Layouts/Login/StepEmail/index.tsx @@ -31,16 +31,13 @@ export default function StepEmail(props: IProps) { return (
- -
Identifiez-vous
-
+ Connectez-vous en tant que client {/* 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.
(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(1); + }, []); + + const closeErrorModal = useCallback(() => { + setIsErrorModalOpen(0); + }, []); + + 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]); + const redirectUserOnConnection = useCallback(() => { const variables = FrontendVariables.getInstance(); router.push( @@ -28,14 +218,6 @@ export default function Login() { ); }, [router]); - const openErrorModal = useCallback((index: number) => { - setIsErrorModalOpen(index); - }, []); - - const closeErrorModal = useCallback(() => { - setIsErrorModalOpen(0); - }, []); - const closeNoEmailModal = useCallback(() => { setIsErrorModalOpen(0); router.push("https://connexion.idnot.fr/"); @@ -47,25 +229,49 @@ export default function Login() { }; useEffect(() => { - openErrorModal(parseInt(error as string)); + if (error === "1") openErrorModal(); }, [error, openErrorModal]); return (
- coffre - -
Connexion espace professionnel
-
- - -
Vous n'arrivez pas à vous connecter ?
-
- - - + {step === LoginStep.EMAIL && ( +
+ + Connectez vous en tant que notaire + + + + Vous n'arrivez pas à vous connecter ? + + + + +
+
+ )} + {step === LoginStep.EMAIL && } + {step === LoginStep.TOTP && ( + + )} + {step === LoginStep.PASSWORD && ( + + )} + {step === LoginStep.NEW_PASSWORD && } + {step === LoginStep.PASSWORD_FORGOTTEN && ( + + )}
(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/Subscription/Manage/SubscriptionManageCollaborators/index.tsx b/src/front/Components/Layouts/Subscription/Manage/SubscriptionManageCollaborators/index.tsx index c0f06dbb..435157bf 100644 --- a/src/front/Components/Layouts/Subscription/Manage/SubscriptionManageCollaborators/index.tsx +++ b/src/front/Components/Layouts/Subscription/Manage/SubscriptionManageCollaborators/index.tsx @@ -71,7 +71,7 @@ export default function SubscriptionManageCollaborators() { useEffect(() => { loadSubscription(); loadCollaborators(); - }, [loadSubscription]); + }, [loadCollaborators, loadSubscription]); return ( 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..fe395216 100644 --- a/src/pages/customers/login.tsx +++ b/src/pages/customers/login.tsx @@ -1,4 +1,4 @@ -import LoginCustomer from "@Front/Components/Layouts/LoginCustomer"; +import LoginCustomer from "@Front/Components/Layouts/Login"; export default function Route() { return ; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 40f96abe..3def80ce 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,4 +1,4 @@ -import Login from "@Front/Components/Layouts/Login"; +import Login from "./login"; export default function Route() { return ;