Merge Dev in Staging

This commit is contained in:
Arnaud D. Natali 2023-10-10 15:22:10 +02:00 committed by GitHub
commit a7b2792f80
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 391 additions and 209 deletions

View File

@ -32,10 +32,12 @@
} }
.notification-subheader { .notification-subheader {
width: 100%; display: flex;
display: inline-flex; align-items: center;
justify-content: space-between; gap: 8px;
text-decoration: underline; text-decoration: underline;
text-underline-offset: 2px;
color: var(--pink-flash);
cursor: pointer; cursor: pointer;
} }

View File

@ -5,6 +5,7 @@ import CloseIcon from "@Assets/Icons/cross.svg";
import Image from "next/image"; import Image from "next/image";
import ToastHandler from "@Front/Components/DesignSystem/Toasts/ToastsHandler"; import ToastHandler from "@Front/Components/DesignSystem/Toasts/ToastsHandler";
import Toasts, { IToast } from "@Front/Stores/Toasts"; import Toasts, { IToast } from "@Front/Stores/Toasts";
import Check from "@Front/Components/Elements/Icons/Check";
type IProps = { type IProps = {
isOpen: boolean; isOpen: boolean;
@ -23,6 +24,7 @@ export default class NotificationModal extends React.Component<IProps, IState> {
toastList: Toasts.getInstance().toasts, toastList: Toasts.getInstance().toasts,
}; };
this.handleToastChange = this.handleToastChange.bind(this); this.handleToastChange = this.handleToastChange.bind(this);
this.readAllNotifications = this.readAllNotifications.bind(this);
} }
public override render(): JSX.Element | null { public override render(): JSX.Element | null {
@ -38,7 +40,10 @@ export default class NotificationModal extends React.Component<IProps, IState> {
</div> </div>
</div> </div>
<div className={classes["notification-subheader"]} onClick={this.readAllNotifications}> <div className={classes["notification-subheader"]} onClick={this.readAllNotifications}>
<Typography typo={ITypo.CAPTION_14}>Tout marquer comme lu</Typography> <Typography typo={ITypo.CAPTION_14} color={ITypoColor.PINK_FLASH}>
Tout marquer comme lu
</Typography>
<Check color={ITypoColor.PINK_FLASH} />
</div> </div>
<div className={classes["notification-body"]}> <div className={classes["notification-body"]}>
<> <>
@ -68,6 +73,7 @@ export default class NotificationModal extends React.Component<IProps, IState> {
private readAllNotifications() { private readAllNotifications() {
Toasts.getInstance().closeAll(); Toasts.getInstance().closeAll();
this.props.closeModal();
} }
private handleToastChange(toastList: IToast[] | null) { private handleToastChange(toastList: IToast[] | null) {

View File

@ -54,7 +54,8 @@
.content { .content {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 64px; column-gap: 64px;
row-gap: 16px;
margin-top: 32px; margin-top: 32px;
@media (max-width: $screen-s) { @media (max-width: $screen-s) {
@ -63,7 +64,7 @@
flex-direction: column; flex-direction: column;
} }
.documents-asked{ .documents-asked {
order: -1; order: -1;
} }
@ -73,7 +74,7 @@
gap: 32px; gap: 32px;
margin-top: 16px; margin-top: 16px;
@media(max-width: $screen-s){ @media (max-width: $screen-s) {
order: -1; order: -1;
} }
} }

View File

@ -26,6 +26,7 @@ type IProps = {
isOpened: boolean; isOpened: boolean;
onChange: (id: string) => void; onChange: (id: string) => void;
anchorStatus: AnchorStatus; anchorStatus: AnchorStatus;
getFolderCallback: () => Promise<void>;
}; };
type IState = { type IState = {
isOpenDeletionModal: boolean; isOpenDeletionModal: boolean;
@ -95,6 +96,9 @@ export default class UserFolder extends React.Component<IProps, IState> {
<DocumentList <DocumentList
documents={documentsAsked} documents={documentsAsked}
title="Documents demandés" title="Documents demandés"
subtitle={
documentsAsked && documentsAsked?.length === 0 ? "Vous n'avez pas encore demandé de documents" : ""
}
openDeletionModal={this.openDeletionModal} openDeletionModal={this.openDeletionModal}
folderUid={this.props.folder.uid!} folderUid={this.props.folder.uid!}
className={classes["documents-asked"]} className={classes["documents-asked"]}
@ -142,7 +146,7 @@ export default class UserFolder extends React.Component<IProps, IState> {
private async deleteAskedDocument() { private async deleteAskedDocument() {
try { try {
await Documents.getInstance().delete(this.state.selectedDocumentToDelete); await Documents.getInstance().delete(this.state.selectedDocumentToDelete);
window.location.reload(); await this.props.getFolderCallback();
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }

View File

@ -0,0 +1,19 @@
import { ITypoColor } from "@Front/Components/DesignSystem/Typography";
type IProps = {
color?: ITypoColor;
};
export default function Check(props: IProps) {
return (
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M15 4.5L6.75 12.75L3 9"
stroke={`var(--${props.color ?? "white"})`}
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}

View File

@ -10,13 +10,14 @@ import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Module from "@Front/Config/Module"; import Module from "@Front/Config/Module";
import { ECivility } from "le-coffre-resources/dist/Customer/Contact"; import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
import { Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary";
import Link from "next/link"; import Link from "next/link";
import { NextRouter, useRouter } from "next/router"; import { NextRouter, useRouter } from "next/router";
import BasePage from "../../Base"; import BasePage from "../../Base";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import TextField from "@Front/Components/DesignSystem/Form/TextField"; import TextField from "@Front/Components/DesignSystem/Form/TextField";
import { ValidationError } from "class-validator";
enum ESelectedOption { enum ESelectedOption {
EXISTING_CUSTOMER = "existing_customer", EXISTING_CUSTOMER = "existing_customer",
@ -29,6 +30,7 @@ type IState = {
selectedCustomers: readonly IOption[]; selectedCustomers: readonly IOption[];
existingCustomers: IOption[]; existingCustomers: IOption[];
isLoaded: boolean; isLoaded: boolean;
validationError: ValidationError[];
}; };
type IPropsClass = IProps & { type IPropsClass = IProps & {
@ -44,6 +46,7 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
selectedCustomers: [], selectedCustomers: [],
existingCustomers: [], existingCustomers: [],
isLoaded: false, isLoaded: false,
validationError: [],
}; };
this.onExistingClientSelected = this.onExistingClientSelected.bind(this); this.onExistingClientSelected = this.onExistingClientSelected.bind(this);
this.onNewClientSelected = this.onNewClientSelected.bind(this); this.onNewClientSelected = this.onNewClientSelected.bind(this);
@ -105,10 +108,28 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
{this.state.selectedOption === "new_customer" && ( {this.state.selectedOption === "new_customer" && (
<div className={classes["new-client"]}> <div className={classes["new-client"]}>
<TextField name="last_name" placeholder="Nom" /> <TextField
<TextField name="first_name" placeholder="Prénom" /> name="last_name"
<TextField name="email" placeholder="E-mail" /> placeholder="Nom"
<TextField name="cell_phone_number" placeholder="Numéro de téléphone" /> validationError={this.state.validationError.find((error) => error.property === "last_name")}
/>
<TextField
name="first_name"
placeholder="Prénom"
validationError={this.state.validationError.find((error) => error.property === "first_name")}
/>
<TextField
name="email"
placeholder="E-mail"
validationError={this.state.validationError.find((error) => error.property === "email")}
/>
<TextField
name="cell_phone_number"
placeholder="Numéro de téléphone"
validationError={this.state.validationError.find(
(error) => error.property === "cell_phone_number",
)}
/>
<div className={classes["button-container"]}> <div className={classes["button-container"]}>
<Link href={backwardPath} className={classes["cancel-button"]}> <Link href={backwardPath} className={classes["cancel-button"]}>
<Button variant={EButtonVariant.GHOST}>Annuler</Button> <Button variant={EButtonVariant.GHOST}>Annuler</Button>
@ -207,11 +228,29 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
}) as Partial<Customer>[]; }) as Partial<Customer>[];
if (this.state.selectedOption === "new_customer") { if (this.state.selectedOption === "new_customer") {
try {
const contactToCreate = Contact.hydrate<Customer>(values);
await contactToCreate.validateOrReject?.({ groups: ["createCustomer"], forbidUnknownValues: false });
} catch (validationErrors) {
console.log(validationErrors);
this.setState({
validationError: validationErrors as ValidationError[],
});
return;
}
try {
const customer: Customer = await Customers.getInstance().post({ const customer: Customer = await Customers.getInstance().post({
contact: values, contact: values,
}); });
if (!customer.uid) return; if (!customer.uid) return;
customersToLink?.push({ uid: customer.uid } as Partial<Customer>); customersToLink?.push({ uid: customer.uid } as Partial<Customer>);
} catch (backError) {
if (!Array.isArray(backError)) return;
this.setState({
validationError: backError as ValidationError[],
});
}
} }
if (customersToLink) { if (customersToLink) {

View File

@ -13,6 +13,7 @@ import { AnchorStatus } from "..";
type IProps = { type IProps = {
folder: OfficeFolder; folder: OfficeFolder;
anchorStatus: AnchorStatus; anchorStatus: AnchorStatus;
getFolderCallback: () => Promise<void>;
}; };
type IState = { type IState = {
openedCustomer: string; openedCustomer: string;
@ -76,6 +77,7 @@ export default class ClientSection extends React.Component<IProps, IState> {
isOpened={this.state.openedCustomer === customer.uid} isOpened={this.state.openedCustomer === customer.uid}
onChange={this.changeUserFolder} onChange={this.changeUserFolder}
anchorStatus={this.props.anchorStatus} anchorStatus={this.props.anchorStatus}
getFolderCallback={this.props.getFolderCallback}
/> />
); );
}); });

View File

@ -37,6 +37,7 @@ type IPropsClass = IProps & {
isLoading: boolean; isLoading: boolean;
selectedFolder: OfficeFolder | null; selectedFolder: OfficeFolder | null;
getAnchoringStatus: () => Promise<void>; getAnchoringStatus: () => Promise<void>;
getFolderCallback: () => Promise<void>;
}; };
type IState = { type IState = {
@ -115,12 +116,20 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
/> />
</div> </div>
{this.doesFolderHaveCustomer() && ( {this.doesFolderHaveCustomer() && (
<ClientSection folder={this.props.selectedFolder} anchorStatus={this.props.isAnchored} /> <ClientSection
folder={this.props.selectedFolder}
anchorStatus={this.props.isAnchored}
getFolderCallback={this.props.getFolderCallback}
/>
)} )}
</div> </div>
{!this.doesFolderHaveCustomer() && ( {!this.doesFolderHaveCustomer() && (
<ClientSection folder={this.props.selectedFolder} anchorStatus={this.props.isAnchored} /> <ClientSection
folder={this.props.selectedFolder}
anchorStatus={this.props.isAnchored}
getFolderCallback={this.props.getFolderCallback}
/>
)} )}
<div className={classes["button-container"]}> <div className={classes["button-container"]}>
@ -209,7 +218,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
onAccept={this.closePreventArchiveModal} onAccept={this.closePreventArchiveModal}
onClose={this.closePreventArchiveModal} onClose={this.closePreventArchiveModal}
closeBtn closeBtn
header={"Vous devez valider et certifier un dossier avant de pouvoir l'archiver"} header={"Vous devez valider et ancrer un dossier avant de pouvoir l'archiver"}
cancelText={"Annuler"} cancelText={"Annuler"}
confirmText={"J'ai compris"}> confirmText={"J'ai compris"}>
<div className={classes["modal-title"]}> <div className={classes["modal-title"]}>
@ -374,7 +383,7 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
} }
private openArchivedModal(): void { private openArchivedModal(): void {
if (this.everyDocumentValidated() && this.props.isAnchored) { if (this.everyDocumentValidated() && this.props.isAnchored === AnchorStatus.VERIFIED_ON_CHAIN) {
this.setState({ isArchivedModalOpen: true }); this.setState({ isArchivedModalOpen: true });
} else { } else {
this.setState({ isPreventArchiveModalOpen: true }); this.setState({ isPreventArchiveModalOpen: true });
@ -471,6 +480,7 @@ export default function FolderInformation(props: IProps) {
isLoading={isLoading} isLoading={isLoading}
selectedFolder={selectedFolder} selectedFolder={selectedFolder}
getAnchoringStatus={getAnchoringStatus} getAnchoringStatus={getAnchoringStatus}
getFolderCallback={getFolder}
/> />
); );
} }

View File

@ -14,6 +14,8 @@ import { ChangeEvent } from "react";
import BasePage from "../../Base"; import BasePage from "../../Base";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import { Address } from "le-coffre-resources/dist/Customer";
import { ValidationError } from "class-validator";
type IProps = {}; type IProps = {};
@ -34,6 +36,7 @@ type IState = {
inputAddress: string; inputAddress: string;
folder: OfficeFolder | null; folder: OfficeFolder | null;
customer: Customer | null; customer: Customer | null;
validationError: ValidationError[];
}; };
class UpdateClientClass extends BasePage<IPropsClass, IState> { class UpdateClientClass extends BasePage<IPropsClass, IState> {
constructor(props: IPropsClass) { constructor(props: IPropsClass) {
@ -50,6 +53,7 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
inputAddress: "", inputAddress: "",
folder: null, folder: null,
customer: null, customer: null,
validationError: [],
}; };
this.onSelectedFolder = this.onSelectedFolder.bind(this); this.onSelectedFolder = this.onSelectedFolder.bind(this);
this.onChangeNameInput = this.onChangeNameInput.bind(this); this.onChangeNameInput = this.onChangeNameInput.bind(this);
@ -83,24 +87,28 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
placeholder="Nom" placeholder="Nom"
onChange={this.onChangeNameInput} onChange={this.onChangeNameInput}
defaultValue={this.state.customer?.contact?.first_name} defaultValue={this.state.customer?.contact?.first_name}
validationError={this.state.validationError.find((error) => error.property === "first_name")}
/> />
<TextField <TextField
name="last_name" name="last_name"
placeholder="Prénom" placeholder="Prénom"
onChange={this.onChangeFirstNameInput} onChange={this.onChangeFirstNameInput}
defaultValue={this.state.customer?.contact?.last_name} defaultValue={this.state.customer?.contact?.last_name}
validationError={this.state.validationError.find((error) => error.property === "last_name")}
/> />
<TextField <TextField
name="email" name="email"
placeholder="E-mail" placeholder="E-mail"
onChange={this.onChangeEmailInput} onChange={this.onChangeEmailInput}
defaultValue={this.state.customer?.contact?.email} defaultValue={this.state.customer?.contact?.email}
validationError={this.state.validationError.find((error) => error.property === "email")}
/> />
<TextField <TextField
name="cell_phone_number" name="cell_phone_number"
placeholder="Numéro de téléphone" placeholder="Numéro de téléphone"
onChange={this.onChangePhoneNumberInput} onChange={this.onChangePhoneNumberInput}
defaultValue={this.state.customer?.contact?.cell_phone_number ?? ""} defaultValue={this.state.customer?.contact?.cell_phone_number ?? ""}
validationError={this.state.validationError.find((error) => error.property === "cell_phone_number")}
/> />
<TextField <TextField
name="birthdate" name="birthdate"
@ -108,6 +116,7 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
required={false} required={false}
onChange={this.onChangeBirthDateInput} onChange={this.onChangeBirthDateInput}
defaultValue={this.state.customer?.contact?.birthdate?.toString() ?? ""} defaultValue={this.state.customer?.contact?.birthdate?.toString() ?? ""}
validationError={this.state.validationError.find((error) => error.property === "birthdate")}
/> />
<TextField <TextField
name="address" name="address"
@ -167,25 +176,33 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
[key: string]: string; [key: string]: string;
}, },
) { ) {
const contact = { const contact = Contact.hydrate<Contact>({
first_name: values["first_name"], first_name: values["first_name"],
last_name: values["last_name"], last_name: values["last_name"],
email: values["email"], email: values["email"],
cell_phone_number: values["cell_phone_number"], cell_phone_number: values["cell_phone_number"],
birthdate: values["birthdate"] === "" ? null : values["birthdate"], birthdate: values["birthdate"] === "" ? null : new Date(values["birthdate"]!),
address: address: values["address"] ? Address.hydrate<Address>({ address: values["address"] }) : undefined,
values["address"] === "" });
? null
: { try {
address: values["address"], await contact.validateOrReject?.({ groups: ["createCustomer"], forbidUnknownValues: false });
}, } catch (validationErrors) {
} as Contact; console.log(validationErrors);
this.setState({
validationError: validationErrors as ValidationError[],
});
return;
}
try { try {
await Customers.getInstance().put(this.props.customerUid, { contact }); await Customers.getInstance().put(this.props.customerUid, { contact });
this.props.router.push(this.backwardPath); this.props.router.push(this.backwardPath);
} catch (e) { } catch (backError) {
console.error(e); if (!Array.isArray(backError)) return;
this.setState({
validationError: backError as ValidationError[],
});
} }
} }

View File

@ -8,6 +8,7 @@ import { AnchorStatus } from "@Front/Components/Layouts/Folder/FolderInformation
type IProps = { type IProps = {
folder: OfficeFolder; folder: OfficeFolder;
anchorStatus: AnchorStatus; anchorStatus: AnchorStatus;
getFolderCallback: () => Promise<void>;
}; };
type IState = { type IState = {
openedCustomer: string; openedCustomer: string;
@ -53,6 +54,7 @@ export default class ClientSection extends React.Component<IProps, IState> {
onChange={this.changeUserFolder} onChange={this.changeUserFolder}
anchorStatus={this.props.anchorStatus} anchorStatus={this.props.anchorStatus}
isArchived isArchived
getFolderCallback={this.props.getFolderCallback}
/> />
); );
}); });

View File

@ -26,6 +26,7 @@ type IPropsClass = IProps & {
isLoading: boolean; isLoading: boolean;
selectedFolder: OfficeFolder | null; selectedFolder: OfficeFolder | null;
isAnchored: AnchorStatus; isAnchored: AnchorStatus;
getFolderCallback: () => Promise<void>;
}; };
type IState = { type IState = {
@ -94,10 +95,22 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
<div className={classes["progress-bar"]}> <div className={classes["progress-bar"]}>
<QuantityProgressBar title="Complétion du dossier" total={100} currentNumber={0} /> <QuantityProgressBar title="Complétion du dossier" total={100} currentNumber={0} />
</div> </div>
{this.doesFolderHaveCustomer() && <ClientSection folder={this.state.selectedFolder} anchorStatus={this.props.isAnchored} />} {this.doesFolderHaveCustomer() && (
<ClientSection
folder={this.state.selectedFolder}
anchorStatus={this.props.isAnchored}
getFolderCallback={this.props.getFolderCallback}
/>
)}
</div> </div>
{!this.doesFolderHaveCustomer() && <ClientSection folder={this.state.selectedFolder} anchorStatus={this.props.isAnchored} />} {!this.doesFolderHaveCustomer() && (
<ClientSection
folder={this.state.selectedFolder}
anchorStatus={this.props.isAnchored}
getFolderCallback={this.props.getFolderCallback}
/>
)}
<div className={classes["button-container"]}> <div className={classes["button-container"]}>
<Button variant={EButtonVariant.GHOST} onClick={this.restoreFolder}> <Button variant={EButtonVariant.GHOST} onClick={this.restoreFolder}>
@ -181,7 +194,7 @@ export default function FolderInformation(props: IProps) {
folderUid = folderUid as string; folderUid = folderUid as string;
const getAnchoringStatus = useCallback(async () => { const getAnchoringStatus = useCallback(async () => {
if(!folderUid) return; if (!folderUid) return;
setIsLoading(true); setIsLoading(true);
try { try {
const anchorStatus = await OfficeFolderAnchors.getInstance().getByUid(folderUid as string); const anchorStatus = await OfficeFolderAnchors.getInstance().getByUid(folderUid as string);
@ -237,5 +250,15 @@ export default function FolderInformation(props: IProps) {
getFolder(); getFolder();
}, [getFolder]); }, [getFolder]);
return <FolderInformationClass {...props} selectedFolderUid={folderUid} selectedFolder={selectedFolder} router={router} isLoading={isLoading} isAnchored={isAnchored} />; return (
<FolderInformationClass
{...props}
selectedFolderUid={folderUid}
selectedFolder={selectedFolder}
router={router}
isLoading={isLoading}
isAnchored={isAnchored}
getFolderCallback={getFolder}
/>
);
} }

View File

@ -5,15 +5,19 @@ 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 Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useCallback } from "react"; import { useCallback, useEffect, useState } from "react";
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 { FrontendVariables } from "@Front/Config/VariablesFront"; import { FrontendVariables } from "@Front/Config/VariablesFront";
import Link from "next/link"; import Link from "next/link";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
export default function Login() { export default function Login() {
const router = useRouter(); const router = useRouter();
const error = router.query["error"];
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
const redirectUserOnConnection = useCallback(() => { const redirectUserOnConnection = useCallback(() => {
const variables = FrontendVariables.getInstance(); const variables = FrontendVariables.getInstance();
@ -24,6 +28,18 @@ export default function Login() {
); );
}, [router]); }, [router]);
const openErrorModal = useCallback(() => {
setIsErrorModalOpen(true);
}, []);
const closeErrorModal = useCallback(() => {
setIsErrorModalOpen(false);
}, []);
useEffect(() => {
if (error === "1") openErrorModal();
}, [error, openErrorModal]);
return ( return (
<DefaultDoubleSidePage title={"Login"} image={LandingImage}> <DefaultDoubleSidePage title={"Login"} image={LandingImage}>
<div className={classes["root"]}> <div className={classes["root"]}>
@ -41,6 +57,20 @@ export default function Login() {
<Button variant={EButtonVariant.LINE}>Contacter l'administrateur</Button> <Button variant={EButtonVariant.LINE}>Contacter l'administrateur</Button>
</Link> </Link>
</div> </div>
<Confirm
isOpen={isErrorModalOpen}
onClose={closeErrorModal}
showCancelButton={false}
onAccept={closeErrorModal}
closeBtn
header={"Erreur"}
confirmText={"OK"}>
<div className={classes["modal-content"]}>
<Typography typo={ITypo.P_16} className={classes["text"]}>
Une erreur est survenue lors de la connexion. Veuillez réessayer.
</Typography>
</div>
</Confirm>
</DefaultDoubleSidePage> </DefaultDoubleSidePage>
); );
} }

View File

@ -26,7 +26,7 @@ export default function LoginCallBack() {
await UserStore.instance.connect(token.accessToken, token.refreshToken); await UserStore.instance.connect(token.accessToken, token.refreshToken);
return router.push(Module.getInstance().get().modules.pages.Folder.props.path); return router.push(Module.getInstance().get().modules.pages.Folder.props.path);
} catch (e) { } catch (e) {
console.error(e); router.push(Module.getInstance().get().modules.pages.Login.props.path + "?error=1");
return; return;
} }
} }

View File

@ -83,3 +83,15 @@
.remove-my-vote { .remove-my-vote {
margin-top: 16px; margin-top: 16px;
} }
.loader-container {
display: flex;
flex: 1;
align-items: center;
justify-content: center;
height: 100%;
.loader {
width: 40px;
height: 40px;
}
}

View File

@ -18,6 +18,7 @@ import { useCallback, useEffect, useState } from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import OfficeRoles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles"; import OfficeRoles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles";
import Loader from "@Front/Components/DesignSystem/Loader";
type IProps = {}; type IProps = {};
export default function UserInformations(props: IProps) { export default function UserInformations(props: IProps) {
@ -36,10 +37,12 @@ export default function UserInformations(props: IProps) {
const [currentAppointment, setCurrentAppointment] = useState<Appointment | null>(null); const [currentAppointment, setCurrentAppointment] = useState<Appointment | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(true);
/** When page change, get the user of the page */ /** When page change, get the user of the page */
const getUser = useCallback(async () => { const getUser = useCallback(async () => {
if (!userUid) return; if (!userUid) return;
setIsLoading(true);
const user = await Users.getInstance().getByUid(userUid as string, { const user = await Users.getInstance().getByUid(userUid as string, {
q: { q: {
contact: true, contact: true,
@ -66,6 +69,7 @@ export default function UserInformations(props: IProps) {
}, },
}); });
if (!roles) return; if (!roles) return;
setIsLoading(false);
setUserSelected(user); setUserSelected(user);
}, [userUid]); }, [userUid]);
@ -201,9 +205,12 @@ export default function UserInformations(props: IProps) {
return ( return (
<DefaultUserDashboard mobileBackText={"Liste des utilisateurs"}> <DefaultUserDashboard mobileBackText={"Liste des utilisateurs"}>
{!isLoading && (
<div className={classes["root"]}> <div className={classes["root"]}>
<div className={classes["header"]}> <div className={classes["header"]}>
<Typography typo={ITypo.H1Bis}>{userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name}</Typography> <Typography typo={ITypo.H1Bis}>
{userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name}
</Typography>
<Typography typo={ITypo.H3} color={ITypoColor.GREY}> <Typography typo={ITypo.H3} color={ITypoColor.GREY}>
Office {userSelected?.office_membership?.name.toLocaleUpperCase()} Office {userSelected?.office_membership?.name.toLocaleUpperCase()}
</Typography> </Typography>
@ -306,8 +313,8 @@ export default function UserInformations(props: IProps) {
cancelText={"Annuler"}> cancelText={"Annuler"}>
<div className={classes["modal-content"]}> <div className={classes["modal-content"]}>
<Typography typo={ITypo.P_16} className={classes["text"]}> <Typography typo={ITypo.P_16} className={classes["text"]}>
{superAdminModalType === "add" ? "Nommer" : "Retirer"} une personne Super Administrateur nécessite 3 votes de {superAdminModalType === "add" ? "Nommer" : "Retirer"} une personne Super Administrateur nécessite 3 votes
super administrateurs existants. Souhaitez-vous attribuer un vote ? de super administrateurs existants. Souhaitez-vous attribuer un vote ?
</Typography> </Typography>
</div> </div>
</Confirm> </Confirm>
@ -330,6 +337,14 @@ export default function UserInformations(props: IProps) {
<div className={classes["modal-content"]}></div> <div className={classes["modal-content"]}></div>
</Confirm> </Confirm>
</div> </div>
)}
{isLoading && (
<div className={classes["loader-container"]}>
<div className={classes["loader"]}>
<Loader />
</div>
</div>
)}
</DefaultUserDashboard> </DefaultUserDashboard>
); );
} }