🚧 WIP login page
This commit is contained in:
parent
6017803cee
commit
81731b72d8
@ -138,11 +138,16 @@ export default abstract class BaseApiService {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Handle error response
|
// Handle error response
|
||||||
|
const responseCopy = response.clone();
|
||||||
try {
|
try {
|
||||||
const responseJson = await response.json();
|
const responseJson = await response.json();
|
||||||
return Promise.reject(responseJson);
|
return Promise.reject(responseJson);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return Promise.reject(err);
|
const responseText = await responseCopy.text();
|
||||||
|
return Promise.reject({
|
||||||
|
http_status: response.status,
|
||||||
|
message: responseText,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<ValidationError[]>([]);
|
||||||
|
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<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}>
|
||||||
|
<div className={classes["title"]}>Identifiez-vous</div>
|
||||||
|
</Typography>
|
||||||
|
<Typography typo={ITypo.P_16}>Pour accéder à votre espace de dépôt des documents, veuillez vous identifier.</Typography>
|
||||||
|
<Image alt="france-connect" src={franceConnectLogo} onClick={redirectCustomerOnConnection} className={classes["logo"]} />
|
||||||
|
<div className={classes["what_is_france_connect"]}>Qu'est ce que FranceConnect ?</div>
|
||||||
|
<Typography className={classes["or"]} typo={ITypo.P_16}>
|
||||||
|
Ou
|
||||||
|
</Typography>
|
||||||
|
<Form className={classes["form"]} onSubmit={onSubmitHandler}>
|
||||||
|
<TextField
|
||||||
|
placeholder="E-mail"
|
||||||
|
name="email"
|
||||||
|
validationError={validationError.find((error) => error.property === "email")}
|
||||||
|
/>
|
||||||
|
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
||||||
|
Suivant
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
{/* <Typography typo={ITypo.P_18}>
|
||||||
|
<div className={classes["forget-password"]}>Vous n'arrivez pas à vous connecter ?</div>
|
||||||
|
</Typography>
|
||||||
|
<Link href="mailto:g.texier@notaires.fr">
|
||||||
|
<Button variant={EButtonVariant.LINE}>Contacter l'administrateur</Button>
|
||||||
|
</Link> */}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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<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],
|
||||||
|
);
|
||||||
|
|
||||||
|
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}>
|
||||||
|
<TextField
|
||||||
|
placeholder="Code à usage unique"
|
||||||
|
name="email"
|
||||||
|
validationError={validationError.find((error) => error.property === "code")}
|
||||||
|
/>
|
||||||
|
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
||||||
|
Suivant
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -1,49 +1,4 @@
|
|||||||
@import "@Themes/constants.scss";
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
.root {
|
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -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 Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
||||||
import Image from "next/image";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import Customers from "@Front/Api/Auth/Id360/Customers/Customers";
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import LandingImage from "./landing-connect.jpeg";
|
import LandingImage from "./landing-connect.jpeg";
|
||||||
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
|
||||||
import Form from "@Front/Components/DesignSystem/Form";
|
import StepEmail from "./StepEmail";
|
||||||
import TextField from "@Front/Components/DesignSystem/Form/TextField";
|
import StepTotp from "./StepTotp";
|
||||||
import Module from "@Front/Config/Module";
|
|
||||||
import { ValidationError } from "class-validator";
|
|
||||||
import Auth from "@Front/Api/Auth/Customer/Auth";
|
|
||||||
|
|
||||||
|
export enum LoginStep {
|
||||||
|
EMAIL,
|
||||||
|
TOTP,
|
||||||
|
NEW_PASSWORD,
|
||||||
|
}
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const error = router.query["error"];
|
const error = router.query["error"];
|
||||||
const [validationError, setValidationError] = useState<ValidationError[]>([]);
|
|
||||||
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
|
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
|
||||||
|
|
||||||
const redirectCustomerOnConnection = useCallback(() => {
|
const [step, setStep] = useState<LoginStep>(LoginStep.EMAIL);
|
||||||
async function getCustomer() {
|
const [totpCode, setTotpCode] = useState<string>("");
|
||||||
try {
|
const [partialPhoneNumber, setPartialPhoneNumber] = useState<string>("");
|
||||||
const loginRes = await Customers.getInstance().login();
|
|
||||||
router.push(loginRes.enrollment.franceConnectUrl);
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getCustomer();
|
|
||||||
}, [router]);
|
|
||||||
|
|
||||||
const openErrorModal = useCallback(() => {
|
const openErrorModal = useCallback(() => {
|
||||||
setIsErrorModalOpen(true);
|
setIsErrorModalOpen(true);
|
||||||
@ -45,53 +36,13 @@ export default function Login() {
|
|||||||
if (error === "1") openErrorModal();
|
if (error === "1") openErrorModal();
|
||||||
}, [error, openErrorModal]);
|
}, [error, openErrorModal]);
|
||||||
|
|
||||||
const onSubmitHandler = useCallback(
|
|
||||||
async (e: React.FormEvent<HTMLFormElement> | 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<ValidationError> | any) {
|
|
||||||
console.log(validationErrors);
|
|
||||||
if (validationErrors.length > 0) {
|
|
||||||
setValidationError(validationErrors as ValidationError[]);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[router],
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<DefaultDoubleSidePage title={"Login"} image={LandingImage}>
|
<DefaultDoubleSidePage title={"Login"} image={LandingImage}>
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<Typography typo={ITypo.H1}>
|
{step === LoginStep.EMAIL && <StepEmail setPartialPhoneNumber={setPartialPhoneNumber} setStep={setStep} />}
|
||||||
<div className={classes["title"]}>Identifiez-vous</div>
|
{step === LoginStep.TOTP && (
|
||||||
</Typography>
|
<StepTotp setStep={setStep} setTotpCode={setTotpCode} partialPhoneNumber={partialPhoneNumber} />
|
||||||
<Typography typo={ITypo.P_16}>Pour accéder à votre espace de dépôt des documents, veuillez vous identifier.</Typography>
|
)}
|
||||||
<Image alt="france-connect" src={franceConnectLogo} onClick={redirectCustomerOnConnection} className={classes["logo"]} />
|
|
||||||
<div className={classes["what_is_france_connect"]}>Qu'est ce que FranceConnect ?</div>
|
|
||||||
<Typography className={classes["or"]} typo={ITypo.P_16}>
|
|
||||||
Ou
|
|
||||||
</Typography>
|
|
||||||
<Form className={classes["form"]} onSubmit={onSubmitHandler}>
|
|
||||||
<TextField
|
|
||||||
placeholder="E-mail"
|
|
||||||
name="email"
|
|
||||||
validationError={validationError.find((error) => error.property === "email")}
|
|
||||||
/>
|
|
||||||
<Button type="submit" variant={EButtonVariant.PRIMARY} className={classes["submit_button"]}>
|
|
||||||
Suivant
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
{/* <Typography typo={ITypo.P_18}>
|
|
||||||
<div className={classes["forget-password"]}>Vous n'arrivez pas à vous connecter ?</div>
|
|
||||||
</Typography>
|
|
||||||
<Link href="mailto:g.texier@notaires.fr">
|
|
||||||
<Button variant={EButtonVariant.LINE}>Contacter l'administrateur</Button>
|
|
||||||
</Link> */}
|
|
||||||
</div>
|
</div>
|
||||||
<Confirm
|
<Confirm
|
||||||
isOpen={isErrorModalOpen}
|
isOpen={isErrorModalOpen}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user