Merge branch 'dev' into staging

This commit is contained in:
Maxime Lalo 2023-07-26 15:29:31 +02:00
commit d7b67007c1
7 changed files with 214 additions and 99 deletions

View File

@ -1,10 +1,11 @@
import React from "react"; import InfoIcon from "@Assets/Icons/info.svg";
import classes from "./classes.module.scss";
import Image from "next/image";
import NotificationIcon from "@Assets/Icons/notification.svg"; import NotificationIcon from "@Assets/Icons/notification.svg";
import Toasts, { IToast } from "@Front/Stores/Toasts"; import Toasts, { IToast } from "@Front/Stores/Toasts";
import Image from "next/image";
import React from "react";
import classes from "./classes.module.scss";
import NotificationModal from "./NotificationModal"; import NotificationModal from "./NotificationModal";
import InfoIcon from "@Assets/Icons/info.svg";
type IProps = { type IProps = {
isModalOpen: boolean; isModalOpen: boolean;

View File

@ -20,7 +20,14 @@ export default class ProfileModal extends React.Component<IProps, IState> {
<div className={classes["background"]} onClick={this.props.closeModal} /> <div className={classes["background"]} onClick={this.props.closeModal} />
<div className={classes["root"]}> <div className={classes["root"]}>
<NavigationLink path={Module.getInstance().get().modules.pages.MyAccount.props.path} text="Mon compte" /> <NavigationLink path={Module.getInstance().get().modules.pages.MyAccount.props.path} text="Mon compte" />
<NavigationLink path={Module.getInstance().get().modules.pages.Roles.props.path} text="Gestion des rôles" /> <NavigationLink
path={Module.getInstance().get().modules.pages.Roles.props.path}
text="Gestion des rôles"
routesActive={[
Module.getInstance().get().modules.pages.Roles.props.path,
Module.getInstance().get().modules.pages.Roles.pages.RolesInformations.props.path,
]}
/>
<NavigationLink <NavigationLink
path={Module.getInstance().get().modules.pages.DeedTypes.props.path} path={Module.getInstance().get().modules.pages.DeedTypes.props.path}
text="Paramétrage des listes de pièces" text="Paramétrage des listes de pièces"
@ -29,6 +36,10 @@ export default class ProfileModal extends React.Component<IProps, IState> {
Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path, Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path,
Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path, Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path,
Module.getInstance().get().modules.pages.DeedTypes.pages.Edit.props.path, Module.getInstance().get().modules.pages.DeedTypes.pages.Edit.props.path,
Module.getInstance().get().modules.pages.DocumentTypes.pages.Edit.props.path,
Module.getInstance().get().modules.pages.DocumentTypes.pages.Create.props.path,
Module.getInstance().get().modules.pages.DocumentTypes.pages.DocumentTypesInformations.props.path,
Module.getInstance().get().modules.pages.DocumentTypes.props.path,
]} ]}
/> />
<NavigationLink <NavigationLink

View File

@ -0,0 +1,37 @@
.root {
display: flex;
gap: 16px;
cursor: pointer;
width: fit-content;
.switch-container {
position: relative;
width: 46px;
height: 24px;
background-color: var(--grey-medium);
border-radius: 64px;
transition: all 200ms ease-in-out;
&[data-checked="true"] {
background-color: var(--turquoise-flash);
.round {
left: 24px;
}
}
.checkbox {
display: none;
}
.round {
transition: all 200ms ease-in-out;
width: 20px;
height: 20px;
border-radius: 100px;
position: absolute;
top: 2px;
left: 2px;
background: white;
}
}
}

View File

@ -0,0 +1,33 @@
import { useCallback, useEffect, useState } from "react";
import classes from "./classes.module.scss";
import Typography, { ITypo, ITypoColor } from "../Typography";
type IProps = {
onChange?: (checked: boolean) => void;
checked?: boolean;
label: string;
};
export default function Switch({ onChange, checked, label }: IProps) {
const [isChecked, setIsChecked] = useState<boolean>(checked ? checked : false);
useEffect(() => {
setIsChecked(checked ? checked : false);
}, [checked]);
const handleChange = useCallback(() => {
setIsChecked(!isChecked);
onChange?.(!isChecked);
}, [isChecked, onChange]);
return (
<div className={classes["root"]} onClick={handleChange}>
<div className={classes["switch-container"]} data-checked={isChecked.toString()}>
<div className={classes["round"]} />
</div>
<Typography typo={ITypo.P_ERR_16} color={ITypoColor.BLACK}>
{label}
</Typography>
</div>
);
}

View File

@ -3,9 +3,9 @@ import OfficeRoles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles";
import Roles from "@Front/Api/LeCoffreApi/Admin/Roles/Roles"; import Roles from "@Front/Api/LeCoffreApi/Admin/Roles/Roles";
import Users from "@Front/Api/LeCoffreApi/Admin/Users/Users"; import Users from "@Front/Api/LeCoffreApi/Admin/Users/Users";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField"; import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import Switch from "@Front/Components/DesignSystem/Switch";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultCollaboratorDashboard from "@Front/Components/LayoutTemplates/DefaultCollaboratorDashboard"; import DefaultCollaboratorDashboard from "@Front/Components/LayoutTemplates/DefaultCollaboratorDashboard";
import Module from "@Front/Config/Module"; import Module from "@Front/Config/Module";
@ -26,9 +26,16 @@ export default function CollaboratorInformations(props: IProps) {
const [roleModalOpened, setRoleModalOpened] = useState<boolean>(false); const [roleModalOpened, setRoleModalOpened] = useState<boolean>(false);
const [adminModalOpened, setAdminModalOpened] = useState<boolean>(false); const [adminModalOpened, setAdminModalOpened] = useState<boolean>(false);
const [adminRoleType, setAdminRoleType] = useState<"add" | "remove">("add");
const [selectedOption, setSelectedOption] = useState<IOption | null>(null); const [selectedOption, setSelectedOption] = useState<IOption | null>(null);
const [isAdminChecked, setIsAdminChecked] = useState<boolean>(false);
useEffect(() => {
if (!userSelected) return;
setIsAdminChecked(userSelected.role?.name === "admin" && !userSelected.office_role);
}, [userSelected]);
const handleRoleChange = useCallback((option: IOption) => { const handleRoleChange = useCallback((option: IOption) => {
setSelectedOption(option); setSelectedOption(option);
setRoleModalOpened(true); setRoleModalOpened(true);
@ -56,31 +63,43 @@ export default function CollaboratorInformations(props: IProps) {
}, [selectedOption, userSelected]); }, [selectedOption, userSelected]);
const changeAdmin = useCallback(async () => { const changeAdmin = useCallback(async () => {
const adminRole = await Roles.getInstance().getOne({ try {
where: { if (adminRoleType === "add") {
name: "admin", const adminRole = await Roles.getInstance().getOne({
}, where: {
}); name: "admin",
},
});
if (!adminRole) return; if (!adminRole) return;
await Users.getInstance().put( await Users.getInstance().put(
userSelected?.uid as string, userSelected?.uid as string,
User.hydrate<User>({ User.hydrate<User>({
uid: userSelected?.uid as string, uid: userSelected?.uid as string,
office_role: undefined, office_role: undefined,
role: adminRole, role: adminRole,
}), }),
); );
setRoleModalOpened(false); } else {
}, [userSelected]); // retirer rôle admin
}
setAdminModalOpened(false);
} catch (e) {
console.error(e);
}
}, [adminRoleType, userSelected]);
const openAdminModal = useCallback(() => { const openAdminModal = useCallback((checked: boolean) => {
setIsAdminChecked(checked);
if (checked) setAdminRoleType("add");
else setAdminRoleType("remove");
setAdminModalOpened(true); setAdminModalOpened(true);
}, []); }, []);
const closeAdminModal = useCallback(() => { const closeAdminModal = useCallback(() => {
setIsAdminChecked(userSelected?.role?.name === "admin" && !userSelected.office_role);
setAdminModalOpened(false); setAdminModalOpened(false);
}, []); }, [userSelected]);
useEffect(() => { useEffect(() => {
async function getUser() { async function getUser() {
@ -167,15 +186,7 @@ export default function CollaboratorInformations(props: IProps) {
</div> </div>
{userSelected?.role?.name !== "super-admin" && ( {userSelected?.role?.name !== "super-admin" && (
<div className={classes["third-line"]}> <div className={classes["third-line"]}>
<CheckBox <Switch checked={isAdminChecked} label="Administrateur de l'office" onChange={openAdminModal} />
onChange={openAdminModal}
option={{
value: "1",
label: "Nommer administrateur de l'office",
}}
toolTip="blabla"
checked={userSelected?.role?.name === "admin" && !userSelected.office_role}
/>
</div> </div>
)} )}
</div> </div>
@ -189,7 +200,7 @@ export default function CollaboratorInformations(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"]}>
Attributer le rôle de <span className={classes["role-name"]}>{selectedOption?.label}</span> à{" "} Attribuer le rôle de <span className={classes["role-name"]}>{selectedOption?.label}</span> à{" "}
{userSelected?.contact?.first_name} {userSelected?.contact?.last_name} ? {userSelected?.contact?.first_name} {userSelected?.contact?.last_name} ?
</Typography> </Typography>
</div> </div>
@ -204,7 +215,8 @@ export default function CollaboratorInformations(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"]}>
Attributer le rôle d'administrateur à {userSelected?.contact?.first_name} {userSelected?.contact?.last_name} ? {adminRoleType === "add" ? "Attribuer" : "Retirer"} le rôle d'administrateur à{" "}
{userSelected?.contact?.first_name} {userSelected?.contact?.last_name} ?
</Typography> </Typography>
</div> </div>
</Confirm> </Confirm>

View File

@ -1,8 +1,8 @@
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultCollaboratorDashboard from "@Front/Components/LayoutTemplates/DefaultCollaboratorDashboard";
import BasePage from "../Base"; import BasePage from "../Base";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import DefaultCollaboratorDashboard from "@Front/Components/LayoutTemplates/DefaultCollaboratorDashboard";
type IProps = {}; type IProps = {};
type IState = {}; type IState = {};
@ -12,7 +12,7 @@ export default class Collaborators extends BasePage<IProps, IState> {
<DefaultCollaboratorDashboard title={"Dossier"} mobileBackText={"Liste des collaborateurs"}> <DefaultCollaboratorDashboard title={"Dossier"} mobileBackText={"Liste des collaborateurs"}>
<div className={classes["root"]}> <div className={classes["root"]}>
<div className={classes["no-folder-selected"]}> <div className={classes["no-folder-selected"]}>
<Typography typo={ITypo.H1Bis}>Informations du collaboraeur</Typography> <Typography typo={ITypo.H1Bis}>Informations du collaborateur</Typography>
<div className={classes["choose-a-folder"]}> <div className={classes["choose-a-folder"]}>
<Typography typo={ITypo.P_18} color={ITypoColor.GREY}> <Typography typo={ITypo.P_18} color={ITypoColor.GREY}>
Sélectionnez un collaborateur Sélectionnez un collaborateur

View File

@ -1,15 +1,16 @@
import WarningIcon from "@Assets/images/warning.png"; import WarningIcon from "@Assets/images/warning.png";
import OfficeRoles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles"; import OfficeRoles from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles";
import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users"; import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField"; import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import Switch from "@Front/Components/DesignSystem/Switch";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultUserDashboard from "@Front/Components/LayoutTemplates/DefaultUserDashboard"; import DefaultUserDashboard from "@Front/Components/LayoutTemplates/DefaultUserDashboard";
import Toasts from "@Front/Stores/Toasts";
import User from "le-coffre-resources/dist/Notary"; import User from "le-coffre-resources/dist/Notary";
import Image from "next/image"; import Image from "next/image";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
@ -21,42 +22,82 @@ export default function UserInformations(props: IProps) {
const [userSelected, setUserSelected] = useState<User | null>(null); const [userSelected, setUserSelected] = useState<User | null>(null);
const [availableRoles, setAvailableRoles] = useState<IOption[]>([]); const [availableRoles, setAvailableRoles] = useState<IOption[]>([]);
const [addSuperAdminModalOpened, setAddSuperAdminModalOpened] = useState<boolean>(false); const [isSuperAdminModalOpened, setIsSuperAdminModalOpened] = useState<boolean>(false);
const [removeSuperAdminModalOpened, setRemoveSuperAdminModalOpened] = useState<boolean>(false); const [superAdminModalType, setSuperAdminModalType] = useState<"add" | "remove">("add");
const [adminModalType, setAdminModalType] = useState<"add" | "remove">("add");
const openAddSuperAdminModal = () => { const [isSuperAdminChecked, setIsSuperAdminChecked] = useState<boolean>(false);
setAddSuperAdminModalOpened(true); const [isAdminChecked, setIsAdminChecked] = useState<boolean>(false);
const [isAdminModalOpened, setIsAdminModalOpened] = useState<boolean>(false);
/** Functions for the admin modal */
const openAdminModal = () => {
setIsAdminModalOpened(true);
}; };
const closeAddSuperAdminModal = () => { const closeAdminModal = useCallback(() => {
setAddSuperAdminModalOpened(false); setIsAdminModalOpened(false);
setIsAdminChecked(userSelected?.role?.name === "admin" && !userSelected.office_role);
}, [userSelected]);
const handleAdminChanged = (checked: boolean) => {
setIsAdminChecked(checked);
setAdminModalType(checked ? "add" : "remove");
openAdminModal();
}; };
const openRemoveSuperAdminModal = () => { const handleAdminModalAccepted = useCallback(async () => {
setRemoveSuperAdminModalOpened(true); if (!userSelected) return;
}; if (adminModalType === "add") {
// add super admin
const closeRemoveSuperAdminModal = () => {
setRemoveSuperAdminModalOpened(false);
};
const handleCheckboxAdminChanged = (e: React.ChangeEvent<HTMLInputElement>) => {
const checked = e.target.checked;
if (checked) {
openAddSuperAdminModal();
} else { } else {
openRemoveSuperAdminModal(); // remove super admin
} }
setIsAdminModalOpened(false);
}, [userSelected, adminModalType]);
/** Functions for the super admin modal */
const openSuperAdminModal = () => {
setIsSuperAdminModalOpened(true);
}; };
const addSuperAdmin = async () => { const closeSuperAdminModal = useCallback(() => {
closeAddSuperAdminModal(); setIsSuperAdminModalOpened(false);
setIsSuperAdminChecked(userSelected?.role?.name === "super-admin" && !userSelected.office_role);
}, [userSelected]);
const handleSuperAdminChanged = (checked: boolean) => {
setIsSuperAdminChecked(checked);
setSuperAdminModalType(checked ? "add" : "remove");
openSuperAdminModal();
}; };
const removeSuperAdmin = async () => { const handleSuperAdminModalAccepted = useCallback(async () => {
closeRemoveSuperAdminModal(); if (!userSelected) return;
}; if (superAdminModalType === "add") {
Toasts.getInstance().open({
title: "Vote attribué",
text: "Vous avez voté pour attribuer le titre de Super Admin à " + userSelected.contact?.first_name,
});
// add super admin
} else {
Toasts.getInstance().open({
title: "Vote attribué",
text: "Vous avez voté pour supprimer le titre de Super Admin à " + userSelected.contact?.first_name,
});
// remove super admin
}
setIsSuperAdminModalOpened(false);
}, [userSelected, superAdminModalType]);
/** Reset switch state when userSelect change */
useEffect(() => {
if (!userSelected) return;
setIsSuperAdminChecked(userSelected.role?.name === "super-admin");
setIsAdminChecked(userSelected.role?.name === "admin" && !userSelected.office_role);
}, [userSelected]);
/** When page change, get the user of the page */
useEffect(() => { useEffect(() => {
async function getUser() { async function getUser() {
if (!userUid) return; if (!userUid) return;
@ -137,23 +178,8 @@ export default function UserInformations(props: IProps) {
<Typography typo={ITypo.P_SB_18}>Attribuer un titre</Typography> <Typography typo={ITypo.P_SB_18}>Attribuer un titre</Typography>
</div> </div>
<div className={classes["second-line"]}> <div className={classes["second-line"]}>
<CheckBox <Switch label="Admin de son office" checked={isAdminChecked} onChange={handleAdminChanged} />
option={{ <Switch label="Super-admin LeCoffre.io" checked={isSuperAdminChecked} onChange={handleSuperAdminChanged} />
label: "Nommer admin de son office",
value: "title",
}}
name="admin"
toolTip="tooltip"
/>
<CheckBox
onChange={handleCheckboxAdminChanged}
option={{
label: "Nommer super admin LEcoffre.io",
value: "title",
}}
name="superadmin"
toolTip="tooltip"
/>
<div className={classes["votes-block"]}> <div className={classes["votes-block"]}>
<div className={classes["left"]}> <div className={classes["left"]}>
<Image src={WarningIcon} alt="warning" width={28} height={28} /> <Image src={WarningIcon} alt="warning" width={28} height={28} />
@ -174,38 +200,33 @@ export default function UserInformations(props: IProps) {
</div> </div>
</div> </div>
<Confirm <Confirm
isOpen={addSuperAdminModalOpened} isOpen={isSuperAdminModalOpened}
onClose={closeAddSuperAdminModal} onClose={closeSuperAdminModal}
onAccept={addSuperAdmin} onAccept={handleSuperAdminModalAccepted}
closeBtn closeBtn
header={`Souhaitez-vous attribuer un vote à ${ header={`Souhaitez-vous attribuer un vote à ${
userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name
} pour devenir Super Administrateur ?`} } pour ${superAdminModalType === "add" ? "devenir" : "retirer son rôle de"} Super Administrateur ?`}
confirmText={"Attribuer un vote"} confirmText={"Attribuer un vote"}
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"]}>
Nommer une personne Super Administrateur nécessite 3 votes de super administrateurs existants. Souhaitez-vous {superAdminModalType === "add" ? "Nommer" : "Retirer"} une personne Super Administrateur nécessite 3 votes de
attribuer un vote ? super administrateurs existants. Souhaitez-vous attribuer un vote ?
</Typography> </Typography>
</div> </div>
</Confirm> </Confirm>
<Confirm <Confirm
isOpen={removeSuperAdminModalOpened} isOpen={isAdminModalOpened}
onClose={closeRemoveSuperAdminModal} onClose={closeAdminModal}
onAccept={removeSuperAdmin} onAccept={handleAdminModalAccepted}
closeBtn closeBtn
header={`Souhaitez-vous retirer ${ header={`Souhaitez-vous ${adminModalType === "add" ? "ajouter" : "retirer"} ${
userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name userSelected?.contact?.first_name + " " + userSelected?.contact?.last_name
} de la liste des Super Administrateurs ?`} } aux administrateurs de son office ?`}
confirmText={"Attribuer un vote"} confirmText={adminModalType === "add" ? "Ajouter" : "Retirer"}
cancelText={"Annuler"}> cancelText={"Annuler"}>
<div className={classes["modal-content"]}> <div className={classes["modal-content"]}></div>
<Typography typo={ITypo.P_16} className={classes["text"]}>
Retirer un collaborateur du rôle de Super Administrateur nécessite 3 votes de super administrateurs existants.
Souhaitez-vous attribuer un vote ?
</Typography>
</div>
</Confirm> </Confirm>
</div> </div>
</DefaultUserDashboard> </DefaultUserDashboard>