Merge branch 'dev' into staging

This commit is contained in:
Maxime Lalo 2024-07-29 11:54:55 +02:00
commit 71a8a1e18c
21 changed files with 175 additions and 1225 deletions

View File

@ -1,6 +1,7 @@
@import "@Themes/constants.scss"; @import "@Themes/constants.scss";
.root { .root {
width: 336px; width: 336px;
min-width: 336px;
height: 100%; height: 100%;
max-height: 100%; max-height: 100%;

View File

@ -7,7 +7,7 @@ import Button from "../Button";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import DropdownNavigation from "./DropdownNavigation"; import DropdownNavigation from "./DropdownNavigation";
type IProps = { export type ISearchBlockListProps = {
blocks: IBlock[]; blocks: IBlock[];
onSelectedBlock: (block: IBlock) => void; onSelectedBlock: (block: IBlock) => void;
bottomButton?: { bottomButton?: {
@ -15,7 +15,7 @@ type IProps = {
link: string; link: string;
}; };
}; };
export default function SearchBlockList(props: IProps) { export default function SearchBlockList(props: ISearchBlockListProps) {
const { blocks, onSelectedBlock, bottomButton } = props; const { blocks, onSelectedBlock, bottomButton } = props;
const [selectedBlock, setSelectedBlock] = useState<IBlock | null>(null); const [selectedBlock, setSelectedBlock] = useState<IBlock | null>(null);

View File

@ -1,23 +0,0 @@
@import "@Themes/constants.scss";
.root {
width: calc(100vh - 83px);
display: flex;
flex-direction: column;
justify-content: space-between;
.header {
flex: 1;
}
.searchbar {
padding: 40px 24px 24px 24px;
}
.folderlist-container {
max-height: calc(100vh - 215px);
height: 100%;
border-right: 1px solid var(--color-neutral-200);
overflow: auto;
}
}

View File

@ -1,44 +0,0 @@
import React, { useCallback } from "react";
import classes from "./classes.module.scss";
import User from "le-coffre-resources/dist/Notary";
import { useRouter } from "next/router";
import Module from "@Front/Config/Module";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
type IProps = {
collaborators: User[];
onSelectedCollaborator?: (user: User) => void;
onCloseLeftSide?: () => void;
};
export default function CollaboratorListContainer(props: IProps) {
const router = useRouter();
const { collaboratorUid } = router.query;
const onSelectedBlock = useCallback(
(block: IBlock) => {
props.onCloseLeftSide && props.onCloseLeftSide();
const redirectPath = Module.getInstance().get().modules.pages.Collaborators.pages.CollaboratorInformations.props.path;
router.push(redirectPath.replace("[uid]", block.id));
},
[props, router],
);
return (
<div className={classes["root"]}>
<SearchBlockList
blocks={props.collaborators.map((user) => {
return {
primaryText: user.contact?.first_name + " " + user.contact?.last_name,
id: user.uid!,
isActive: user.uid === collaboratorUid,
};
})}
onSelectedBlock={onSelectedBlock}
/>
</div>
);
}

View File

@ -1,116 +0,0 @@
@import "@Themes/constants.scss";
@keyframes growWidth {
0% {
width: 100%;
}
100% {
width: 200%;
}
}
.root {
.content {
display: flex;
overflow: hidden;
height: calc(100vh - var(--header-height));
.overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--color-generic-white);
opacity: 0.5;
z-index: 2;
transition: all 0.3s $custom-easing;
}
.left-side {
background-color: var(--color-generic-white);
z-index: 3;
display: flex;
width: 336px;
min-width: 336px;
transition: all 0.3s $custom-easing;
overflow: hidden;
@media (max-width: ($screen-m - 1px)) {
width: 56px;
min-width: 56px;
transform: translateX(-389px);
&.opened {
transform: translateX(0px);
width: 336px;
min-width: 336px;
}
}
@media (max-width: $screen-s) {
width: 0px;
min-width: 0px;
&.opened {
width: 100vw;
min-width: 100vw;
}
}
}
.closable-left-side {
position: absolute;
background-color: var(--color-generic-white);
z-index: 0;
display: flex;
justify-content: center;
min-width: 56px;
max-width: 56px;
height: calc(100vh - var(--header-height));
border-right: 1px var(--color-neutral-200) solid;
@media (min-width: $screen-m) {
display: none;
}
.chevron-icon {
margin-top: 21px;
transform: rotate(180deg);
cursor: pointer;
}
@media (max-width: $screen-s) {
display: none;
}
}
.right-side {
min-width: calc(100vw - 389px);
padding: 24px;
overflow-y: auto;
@media (max-width: ($screen-m - 1px)) {
min-width: calc(100vw - 56px);
}
@media (max-width: $screen-s) {
flex: 1;
min-width: unset;
}
.back-arrow-mobile {
display: none;
@media (max-width: $screen-s) {
display: block;
margin-bottom: 24px;
}
}
.back-arrow-desktop {
@media (max-width: $screen-s) {
display: none;
}
}
}
}
}

View File

@ -1,93 +1,20 @@
import ChevronIcon from "@Assets/Icons/chevron.svg"; import React, { useEffect } from "react";
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/Admin/Users/Users";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import { useRouter } from "next/router";
import Header from "@Front/Components/DesignSystem/Header"; import Module from "@Front/Config/Module";
import Version from "@Front/Components/DesignSystem/Version"; import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultDashboardWithList, { IPropsDashboardWithList } from "../DefaultDashboardWithList";
import User from "le-coffre-resources/dist/Notary";
import JwtService from "@Front/Services/JwtService/JwtService"; import JwtService from "@Front/Services/JwtService/JwtService";
import WindowStore from "@Front/Stores/WindowStore"; import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/Admin/Users/Users";
import classNames from "classnames";
import User from "le-coffre-resources/dist/Admin";
import Image from "next/image";
import React, { ReactNode } from "react";
import classes from "./classes.module.scss"; type IProps = IPropsDashboardWithList;
import CollaboratorListContainer from "./CollaboratorListContainer";
import { ChevronLeftIcon } from "@heroicons/react/24/solid";
type IProps = { export default function DefaultCollaboratorDashboard(props: IProps) {
title: string; const [collaborators, setCollaborators] = React.useState<User[] | null>(null);
children?: ReactNode; const router = useRouter();
onSelectedUser: (user: User) => void; const { collaboratorUid } = router.query;
hasBackArrow: boolean; useEffect(() => {
backArrowUrl?: string;
mobileBackText?: string;
};
type IState = {
collaborators: User[] | null;
isLeftSideOpen: boolean;
leftSideCanBeClosed: boolean;
};
export default class DefaultCollaboratorDashboard extends React.Component<IProps, IState> {
private onWindowResize = () => {};
public static defaultProps: Partial<IProps> = {
hasBackArrow: false,
};
public constructor(props: IProps) {
super(props);
this.state = {
collaborators: null,
isLeftSideOpen: false,
leftSideCanBeClosed: typeof window !== "undefined" ? window.innerWidth < 1024 : false,
};
this.onOpenLeftSide = this.onOpenLeftSide.bind(this);
this.onCloseLeftSide = this.onCloseLeftSide.bind(this);
}
public override render(): JSX.Element {
return (
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
{this.state.isLeftSideOpen && <div className={classes["overlay"]} onClick={this.onCloseLeftSide} />}
<div className={classNames(classes["left-side"], this.state.isLeftSideOpen && classes["opened"])}>
{this.state.collaborators && (
<CollaboratorListContainer collaborators={this.state.collaborators} onCloseLeftSide={this.onCloseLeftSide} />
)}
</div>
<div className={classNames(classes["closable-left-side"])}>
<Image alt="open side menu" src={ChevronIcon} className={classes["chevron-icon"]} onClick={this.onOpenLeftSide} />
</div>
<div className={classes["right-side"]}>
{this.props.hasBackArrow && (
<div className={classes["back-arrow-desktop"]}>
<BackArrow url={this.props.backArrowUrl ?? ""} />
</div>
)}
{this.props.mobileBackText && (
<div className={classes["back-arrow-mobile"]}>
<Button
leftIcon={<ChevronLeftIcon />}
variant={EButtonVariant.PRIMARY}
styletype={EButtonstyletype.TEXT}
onClick={this.onOpenLeftSide}>
{this.props.mobileBackText ?? "Retour"}
</Button>
</div>
)}
{this.props.children}
</div>
</div>
<Version />
</div>
);
}
public override async componentDidMount() {
this.onWindowResize = WindowStore.getInstance().onResize((window) => this.onResize(window));
const jwt = JwtService.getInstance().decodeJwt(); const jwt = JwtService.getInstance().decodeJwt();
if (!jwt) return; if (!jwt) return;
const query: IGetUsersparams = { const query: IGetUsersparams = {
@ -102,27 +29,31 @@ export default class DefaultCollaboratorDashboard extends React.Component<IProps
}, },
}; };
const collaborators = await Users.getInstance().get(query); Users.getInstance()
this.setState({ collaborators }); .get(query)
} .then((users) => setCollaborators(users));
public override componentWillUnmount() { }, []);
this.onWindowResize();
}
private onOpenLeftSide() { const onSelectedBlock = (block: IBlock) => {
this.setState({ isLeftSideOpen: true }); router.push(
} Module.getInstance().get().modules.pages.Collaborators.pages.CollaboratorInformations.props.path.replace("[uid]", block.id),
);
};
private onCloseLeftSide() { return (
if (!this.state.leftSideCanBeClosed) return; <DefaultDashboardWithList
this.setState({ isLeftSideOpen: false }); {...props}
} onSelectedBlock={onSelectedBlock}
blocks={
private onResize(window: Window) { collaborators
if (window.innerWidth > 1023) { ? collaborators.map((collaborator) => ({
if (!this.state.leftSideCanBeClosed) return; id: collaborator.uid!,
this.setState({ leftSideCanBeClosed: false }); primaryText: collaborator.contact?.first_name + " " + collaborator.contact?.last_name,
} isActive: collaborator.uid === collaboratorUid,
this.setState({ leftSideCanBeClosed: true }); secondaryText: collaborator.contact?.email,
} }))
: []
}
/>
);
} }

View File

@ -4,8 +4,7 @@ import BackArrow from "@Front/Components/Elements/BackArrow";
import React, { ReactNode } from "react"; import React, { ReactNode } from "react";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block"; import SearchBlockList, { ISearchBlockListProps } from "@Front/Components/DesignSystem/SearchBlockList";
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
export type IPropsDashboardWithList = { export type IPropsDashboardWithList = {
title?: string; title?: string;
@ -14,22 +13,19 @@ export type IPropsDashboardWithList = {
hasBackArrow?: boolean; hasBackArrow?: boolean;
backArrowUrl?: string; backArrowUrl?: string;
mobileBackText?: string; mobileBackText?: string;
};
type IProps = IPropsDashboardWithList & {
blocksList: IBlock[];
onSelectedBlock: (block: IBlock) => void;
headerConnected?: boolean; headerConnected?: boolean;
}; };
type IProps = IPropsDashboardWithList & ISearchBlockListProps;
export default function DefaultDashboardWithList(props: IProps) { export default function DefaultDashboardWithList(props: IProps) {
const { hasBackArrow, backArrowUrl, children, blocksList, onSelectedBlock, headerConnected = true } = props; const { hasBackArrow, backArrowUrl, children, blocks, onSelectedBlock, headerConnected = true, bottomButton } = props;
return ( return (
<div className={classes["root"]}> <div className={classes["root"]}>
<Header isUserConnected={headerConnected} /> <Header isUserConnected={headerConnected} />
<div className={classes["content"]}> <div className={classes["content"]}>
<SearchBlockList blocks={blocksList} onSelectedBlock={onSelectedBlock} /> <SearchBlockList blocks={blocks} onSelectedBlock={onSelectedBlock} bottomButton={bottomButton} />
<div className={classes["right-side"]}> <div className={classes["right-side"]}>
{hasBackArrow && ( {hasBackArrow && (
<div className={classes["back-arrow-desktop"]}> <div className={classes["back-arrow-desktop"]}>

View File

@ -1,32 +0,0 @@
@import "@Themes/constants.scss";
.root {
width: calc(100vh - 83px);
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
.header {
flex: 1;
}
.searchbar {
padding: 40px 24px 24px 24px;
}
.folderlist-container {
max-height: calc(100vh - 290px);
height: calc(100vh - 290px);
overflow: auto;
border-right: 1px solid var(--color-neutral-200);
}
.create-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}

View File

@ -1,48 +0,0 @@
import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
import Module from "@Front/Config/Module";
import { DeedType } from "le-coffre-resources/dist/Admin";
import { useRouter } from "next/router";
import React, { useCallback } from "react";
import classes from "./classes.module.scss";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
type IProps = {
deedTypes: DeedType[];
onSelectedDeed?: (deed: DeedTypes) => void;
onCloseLeftSide?: () => void;
};
export default function DeedListContainer(props: IProps) {
const router = useRouter();
const { deedTypeUid } = router.query;
const onSelectedBlock = useCallback(
(block: IBlock) => {
props.onCloseLeftSide && props.onCloseLeftSide();
const redirectPath = Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path;
router.push(redirectPath.replace("[uid]", block.id));
},
[props, router],
);
return (
<div className={classes["root"]}>
<SearchBlockList
blocks={props.deedTypes.map((deed) => {
return {
primaryText: deed.name,
id: deed.uid!,
isActive: deedTypeUid === deed.uid,
};
})}
onSelectedBlock={onSelectedBlock}
bottomButton={{
link: Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path,
text: "Créer un type d'acte",
}}
/>
</div>
);
}

View File

@ -1,116 +0,0 @@
@import "@Themes/constants.scss";
@keyframes growWidth {
0% {
width: 100%;
}
100% {
width: 200%;
}
}
.root {
.content {
display: flex;
overflow: hidden;
height: calc(100vh - var(--header-height));
.overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--color-generic-white);
opacity: 0.5;
z-index: 2;
transition: all 0.3s $custom-easing;
}
.left-side {
background-color: var(--color-generic-white);
z-index: 3;
display: flex;
width: 336px;
min-width: 336px;
transition: all 0.3s $custom-easing;
overflow: hidden;
@media (max-width: ($screen-m - 1px)) {
width: 56px;
min-width: 56px;
transform: translateX(-389px);
&.opened {
transform: translateX(0px);
width: 336px;
min-width: 336px;
}
}
@media (max-width: $screen-s) {
width: 0px;
min-width: 0px;
&.opened {
width: 100vw;
min-width: 100vw;
}
}
}
.closable-left-side {
position: absolute;
background-color: var(--color-generic-white);
z-index: 0;
display: flex;
justify-content: center;
min-width: 56px;
max-width: 56px;
height: calc(100vh - var(--header-height));
border-right: 1px var(--color-neutral-200) solid;
@media (min-width: $screen-m) {
display: none;
}
.chevron-icon {
margin-top: 21px;
transform: rotate(180deg);
cursor: pointer;
}
@media (max-width: $screen-s) {
display: none;
}
}
.right-side {
min-width: calc(100vw - 389px);
padding: 24px;
overflow-y: auto;
@media (max-width: ($screen-m - 1px)) {
min-width: calc(100vw - 56px);
}
@media (max-width: $screen-s) {
flex: 1;
min-width: unset;
}
.back-arrow-mobile {
display: none;
@media (max-width: $screen-s) {
display: block;
margin-bottom: 24px;
}
}
.back-arrow-desktop {
@media (max-width: $screen-s) {
display: none;
}
}
}
}
}

View File

@ -1,92 +1,19 @@
import ChevronIcon from "@Assets/Icons/chevron.svg"; import React, { useEffect } from "react";
import { useRouter } from "next/router";
import Module from "@Front/Config/Module";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import DefaultDashboardWithList, { IPropsDashboardWithList } from "../DefaultDashboardWithList";
import { DeedType } from "le-coffre-resources/dist/Notary";
import DeedTypes, { IGetDeedTypesParams } from "@Front/Api/LeCoffreApi/Notary/DeedTypes/DeedTypes"; import DeedTypes, { IGetDeedTypesParams } from "@Front/Api/LeCoffreApi/Notary/DeedTypes/DeedTypes";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Header from "@Front/Components/DesignSystem/Header";
import Version from "@Front/Components/DesignSystem/Version";
import BackArrow from "@Front/Components/Elements/BackArrow";
import WindowStore from "@Front/Stores/WindowStore";
import classNames from "classnames";
import { Deed, DeedType } from "le-coffre-resources/dist/Notary";
import Image from "next/image";
import React, { ReactNode } from "react";
import classes from "./classes.module.scss"; type IProps = IPropsDashboardWithList;
import DeedListContainer from "./DeedTypeListContainer";
import { ChevronLeftIcon } from "@heroicons/react/24/solid";
type IProps = { export default function DefaultDeedTypeDashboard(props: IProps) {
title: string; const [deedTypes, setDeedTypes] = React.useState<DeedType[] | null>(null);
children?: ReactNode; const router = useRouter();
onSelectedDeed: (deed: Deed) => void; const { deedTypeUid } = router.query;
hasBackArrow: boolean; useEffect(() => {
backArrowUrl?: string;
mobileBackText?: string;
};
type IState = {
deedTypes: DeedType[] | null;
isLeftSideOpen: boolean;
leftSideCanBeClosed: boolean;
};
export default class DefaultDeedTypesDashboard extends React.Component<IProps, IState> {
private onWindowResize = () => {};
public static defaultProps: Partial<IProps> = {
hasBackArrow: false,
};
public constructor(props: IProps) {
super(props);
this.state = {
deedTypes: null,
isLeftSideOpen: false,
leftSideCanBeClosed: typeof window !== "undefined" ? window.innerWidth < 1024 : false,
};
this.onOpenLeftSide = this.onOpenLeftSide.bind(this);
this.onCloseLeftSide = this.onCloseLeftSide.bind(this);
}
public override render(): JSX.Element {
return (
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
{this.state.isLeftSideOpen && <div className={classes["overlay"]} onClick={this.onCloseLeftSide} />}
<div className={classNames(classes["left-side"], this.state.isLeftSideOpen && classes["opened"])}>
{this.state.deedTypes && (
<DeedListContainer deedTypes={this.state.deedTypes} onCloseLeftSide={this.onCloseLeftSide} />
)}
</div>
<div className={classNames(classes["closable-left-side"])}>
<Image alt="open side menu" src={ChevronIcon} className={classes["chevron-icon"]} onClick={this.onOpenLeftSide} />
</div>
<div className={classes["right-side"]}>
{this.props.hasBackArrow && (
<div className={classes["back-arrow-desktop"]}>
<BackArrow url={this.props.backArrowUrl ?? ""} />
</div>
)}
{this.props.mobileBackText && (
<div className={classes["back-arrow-mobile"]}>
<Button
leftIcon={<ChevronLeftIcon />}
variant={EButtonVariant.PRIMARY}
styletype={EButtonstyletype.TEXT}
onClick={this.onOpenLeftSide}>
{this.props.mobileBackText ?? "Retour"}
</Button>
</div>
)}
{this.props.children}
</div>
</div>
<Version />
</div>
);
}
public override async componentDidMount() {
this.onWindowResize = WindowStore.getInstance().onResize((window) => this.onResize(window));
const query: IGetDeedTypesParams = { const query: IGetDeedTypesParams = {
where: { where: {
archived_at: null, archived_at: null,
@ -96,28 +23,32 @@ export default class DefaultDeedTypesDashboard extends React.Component<IProps, I
}, },
}; };
const deedTypes = await DeedTypes.getInstance().get(query); DeedTypes.getInstance()
this.setState({ deedTypes }); .get(query)
} .then((deedTypes) => setDeedTypes(deedTypes));
}, []);
public override componentWillUnmount() { const onSelectedBlock = (block: IBlock) => {
this.onWindowResize(); router.push(Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path.replace("[uid]", block.id));
} };
private onOpenLeftSide() { return (
this.setState({ isLeftSideOpen: true }); <DefaultDashboardWithList
} {...props}
onSelectedBlock={onSelectedBlock}
private onCloseLeftSide() { blocks={
if (!this.state.leftSideCanBeClosed) return; deedTypes
this.setState({ isLeftSideOpen: false }); ? deedTypes.map((deedTypes) => ({
} id: deedTypes.uid!,
primaryText: deedTypes.name,
private onResize(window: Window) { isActive: deedTypes.uid === deedTypeUid,
if (window.innerWidth > 1023) { }))
if (!this.state.leftSideCanBeClosed) return; : []
this.setState({ leftSideCanBeClosed: false }); }
} bottomButton={{
this.setState({ leftSideCanBeClosed: true }); link: Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path,
} text: "Créer une liste de pièces",
}}
/>
);
} }

View File

@ -1,30 +0,0 @@
@import "@Themes/constants.scss";
.root {
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
.header {
flex: 1;
}
.searchbar {
padding: 40px 24px 24px 24px;
}
.folderlist-container {
max-height: calc(100vh - 290px);
height: calc(100vh - 290px);
overflow: auto;
border-right: 1px solid var(--color-neutral-200);
}
.create-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}

View File

@ -1,48 +0,0 @@
import Module from "@Front/Config/Module";
import { DocumentType } from "le-coffre-resources/dist/SuperAdmin";
import { useRouter } from "next/router";
import React, { useCallback } from "react";
import classes from "./classes.module.scss";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
type IProps = {
documentTypes: DocumentType[];
onSelectedDocumentType?: (documentType: DocumentType) => void;
onCloseLeftSide?: () => void;
};
export default function DocumentTypeListContainer(props: IProps) {
const router = useRouter();
const { documentTypeUid } = router.query;
const onSelectedBlock = useCallback(
(block: IBlock) => {
props.onCloseLeftSide && props.onCloseLeftSide();
const redirectPath = Module.getInstance().get().modules.pages.DocumentTypes.pages.DocumentTypesInformations.props.path;
router.push(redirectPath.replace("[uid]", block.id));
},
[props, router],
);
return (
<div className={classes["root"]}>
<SearchBlockList
blocks={props.documentTypes.map((documentType) => {
return {
primaryText: documentType.name,
id: documentType.uid!,
isActive: documentType.uid === documentTypeUid,
};
})}
onSelectedBlock={onSelectedBlock}
bottomButton={{
link: Module.getInstance().get().modules.pages.DocumentTypes.pages.Create.props.path,
text: "Créer un type de document",
}}
/>
</div>
);
}

View File

@ -1,116 +0,0 @@
@import "@Themes/constants.scss";
@keyframes growWidth {
0% {
width: 100%;
}
100% {
width: 200%;
}
}
.root {
.content {
display: flex;
overflow: hidden;
height: calc(100vh - var(--header-height));
.overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--color-generic-white);
opacity: 0.5;
z-index: 2;
transition: all 0.3s $custom-easing;
}
.left-side {
background-color: var(--color-generic-white);
z-index: 3;
display: flex;
width: 336px;
min-width: 336px;
transition: all 0.3s $custom-easing;
overflow: hidden;
@media (max-width: ($screen-m - 1px)) {
width: 56px;
min-width: 56px;
transform: translateX(-389px);
&.opened {
transform: translateX(0px);
width: 336px;
min-width: 336px;
}
}
@media (max-width: $screen-s) {
width: 0px;
min-width: 0px;
&.opened {
width: 100vw;
min-width: 100vw;
}
}
}
.closable-left-side {
position: absolute;
background-color: var(--color-generic-white);
z-index: 0;
display: flex;
justify-content: center;
min-width: 56px;
max-width: 56px;
height: calc(100vh - var(--header-height));
border-right: 1px var(--color-neutral-200) solid;
@media (min-width: $screen-m) {
display: none;
}
.chevron-icon {
margin-top: 21px;
transform: rotate(180deg);
cursor: pointer;
}
@media (max-width: $screen-s) {
display: none;
}
}
.right-side {
min-width: calc(100vw - 389px);
padding: 24px;
overflow-y: auto;
@media (max-width: ($screen-m - 1px)) {
min-width: calc(100vw - 56px);
}
@media (max-width: $screen-s) {
flex: 1;
min-width: unset;
}
.back-arrow-mobile {
display: none;
@media (max-width: $screen-s) {
display: block;
margin-bottom: 24px;
}
}
.back-arrow-desktop {
@media (max-width: $screen-s) {
display: none;
}
}
}
}
}

View File

@ -1,124 +1,57 @@
import ChevronIcon from "@Assets/Icons/chevron.svg"; import React, { useEffect } from "react";
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import { useRouter } from "next/router";
import Header from "@Front/Components/DesignSystem/Header"; import Module from "@Front/Config/Module";
import Version from "@Front/Components/DesignSystem/Version"; import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultDashboardWithList, { IPropsDashboardWithList } from "../DefaultDashboardWithList";
import JwtService from "@Front/Services/JwtService/JwtService"; import JwtService from "@Front/Services/JwtService/JwtService";
import WindowStore from "@Front/Stores/WindowStore"; import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
import classNames from "classnames";
import { DocumentType } from "le-coffre-resources/dist/Notary"; import { DocumentType } from "le-coffre-resources/dist/Notary";
import Image from "next/image";
import React, { ReactNode } from "react";
import classes from "./classes.module.scss"; type IProps = IPropsDashboardWithList;
import DocumentTypeListContainer from "./DocumentTypeListContainer";
import { ChevronLeftIcon } from "@heroicons/react/24/solid";
type IProps = { export default function DefaultDocumentTypeDashboard(props: IProps) {
title: string; const [documentTypes, setDocumentTypes] = React.useState<DocumentType[] | null>(null);
children?: ReactNode; const router = useRouter();
onSelectedDocumentType: (documentType: DocumentType) => void; const { documentTypeUid } = router.query;
hasBackArrow: boolean; useEffect(() => {
backArrowUrl?: string;
mobileBackText?: string;
};
type IState = {
documentTypes: DocumentType[] | null;
isLeftSideOpen: boolean;
leftSideCanBeClosed: boolean;
};
export default class DefaultDocumentTypesDashboard extends React.Component<IProps, IState> {
private onWindowResize = () => {};
public static defaultProps: Partial<IProps> = {
hasBackArrow: false,
};
public constructor(props: IProps) {
super(props);
this.state = {
documentTypes: null,
isLeftSideOpen: false,
leftSideCanBeClosed: typeof window !== "undefined" ? window.innerWidth < 1024 : false,
};
this.onOpenLeftSide = this.onOpenLeftSide.bind(this);
this.onCloseLeftSide = this.onCloseLeftSide.bind(this);
}
public override render(): JSX.Element {
return (
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
{this.state.isLeftSideOpen && <div className={classes["overlay"]} onClick={this.onCloseLeftSide} />}
<div className={classNames(classes["left-side"], this.state.isLeftSideOpen && classes["opened"])}>
{this.state.documentTypes && (
<DocumentTypeListContainer documentTypes={this.state.documentTypes} onCloseLeftSide={this.onCloseLeftSide} />
)}
</div>
<div className={classNames(classes["closable-left-side"])}>
<Image alt="open side menu" src={ChevronIcon} className={classes["chevron-icon"]} onClick={this.onOpenLeftSide} />
</div>
<div className={classes["right-side"]}>
{this.props.hasBackArrow && (
<div className={classes["back-arrow-desktop"]}>
<BackArrow url={this.props.backArrowUrl ?? ""} />
</div>
)}
{this.props.mobileBackText && (
<div className={classes["back-arrow-mobile"]}>
<Button
leftIcon={<ChevronLeftIcon />}
variant={EButtonVariant.PRIMARY}
styletype={EButtonstyletype.TEXT}
onClick={this.onOpenLeftSide}>
{this.props.mobileBackText ?? "Retour"}
</Button>
</div>
)}
{this.props.children}
</div>
</div>
<Version />
</div>
);
}
public override async componentDidMount() {
this.onWindowResize = WindowStore.getInstance().onResize((window) => this.onResize(window));
const jwt = JwtService.getInstance().decodeJwt(); const jwt = JwtService.getInstance().decodeJwt();
if (!jwt) return; if (!jwt) return;
const documentTypes = await DocumentTypes.getInstance().get({ DocumentTypes.getInstance()
where: { .get({
office_uid: jwt.office_Id, where: {
}, office_uid: jwt.office_Id,
orderBy: { },
name: "asc", orderBy: {
}, name: "asc",
}); },
this.setState({ documentTypes }); })
} .then((documentTypes) => setDocumentTypes(documentTypes));
}, []);
public override componentWillUnmount() { const onSelectedBlock = (block: IBlock) => {
this.onWindowResize(); router.push(
} Module.getInstance().get().modules.pages.DocumentTypes.pages.DocumentTypesInformations.props.path.replace("[uid]", block.id),
);
};
private onOpenLeftSide() { return (
this.setState({ isLeftSideOpen: true }); <DefaultDashboardWithList
} {...props}
onSelectedBlock={onSelectedBlock}
private onCloseLeftSide() { blocks={
if (!this.state.leftSideCanBeClosed) return; documentTypes
this.setState({ isLeftSideOpen: false }); ? documentTypes.map((documentType) => ({
} id: documentType.uid!,
primaryText: documentType.name,
private onResize(window: Window) { isActive: documentType.uid === documentTypeUid,
if (window.innerWidth > 1023) { }))
if (!this.state.leftSideCanBeClosed) return; : []
this.setState({ leftSideCanBeClosed: false }); }
} bottomButton={{
this.setState({ leftSideCanBeClosed: true }); link: Module.getInstance().get().modules.pages.DocumentTypes.pages.Create.props.path,
} text: "Créer un type de document",
}}
/>
);
} }

View File

@ -27,7 +27,7 @@ export default function DefaultOfficeDashboard(props: IProps) {
<DefaultDashboardWithList <DefaultDashboardWithList
{...props} {...props}
onSelectedBlock={onSelectedBlock} onSelectedBlock={onSelectedBlock}
blocksList={ blocks={
offices offices
? offices.map((office) => ({ ? offices.map((office) => ({
id: office.uid!, id: office.uid!,

View File

@ -1,32 +0,0 @@
@import "@Themes/constants.scss";
.root {
width: calc(100vh - 83px);
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
.header {
flex: 1;
}
.searchbar {
padding: 40px 24px 24px 24px;
}
.folderlist-container {
max-height: calc(100vh - 215px);
height: calc(100vh - 215px);
overflow: auto;
border-right: 1px solid var(--color-neutral-200);
}
.create-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
}
}

View File

@ -1,53 +0,0 @@
import Module from "@Front/Config/Module";
import { OfficeRole } from "le-coffre-resources/dist/Admin";
import { useRouter } from "next/router";
import React, { useCallback } from "react";
import classes from "./classes.module.scss";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
type IProps = {
roles: OfficeRole[];
onSelectedRole?: (role: OfficeRole) => void;
onCloseLeftSide?: () => void;
};
export default function RoleListContainer(props: IProps) {
const router = useRouter();
const { roleUid } = router.query;
const onSelectedBlock = useCallback(
(block: IBlock) => {
props.onCloseLeftSide && props.onCloseLeftSide();
const redirectPath = Module.getInstance().get().modules.pages.Roles.pages.RolesInformations.props.path;
router.push(redirectPath.replace("[uid]", block.id));
},
[props, router],
);
return (
<div className={classes["root"]}>
<SearchBlockList
blocks={props.roles
.filter((role) => {
if (role.name === "admin") return false;
return true;
})
.map((role) => {
return {
primaryText: role.name,
id: role.uid!,
isActive: role.uid === roleUid,
};
})}
onSelectedBlock={onSelectedBlock}
bottomButton={{
link: Module.getInstance().get().modules.pages.Roles.pages.Create.props.path,
text: "Créer un rôle",
}}
/>
</div>
);
}

View File

@ -1,116 +0,0 @@
@import "@Themes/constants.scss";
@keyframes growWidth {
0% {
width: 100%;
}
100% {
width: 200%;
}
}
.root {
.content {
display: flex;
overflow: hidden;
height: calc(100vh - var(--header-height));
.overlay {
position: absolute;
width: 100%;
height: 100%;
background-color: var(--color-generic-white);
opacity: 0.5;
z-index: 2;
transition: all 0.3s $custom-easing;
}
.left-side {
background-color: var(--color-generic-white);
z-index: 3;
display: flex;
width: 336px;
min-width: 336px;
transition: all 0.3s $custom-easing;
overflow: hidden;
@media (max-width: ($screen-m - 1px)) {
width: 56px;
min-width: 56px;
transform: translateX(-389px);
&.opened {
transform: translateX(0px);
width: 336px;
min-width: 336px;
}
}
@media (max-width: $screen-s) {
width: 0px;
min-width: 0px;
&.opened {
width: 100vw;
min-width: 100vw;
}
}
}
.closable-left-side {
position: absolute;
background-color: var(--color-generic-white);
z-index: 0;
display: flex;
justify-content: center;
min-width: 56px;
max-width: 56px;
height: calc(100vh - var(--header-height));
border-right: 1px var(--color-neutral-200) solid;
@media (min-width: $screen-m) {
display: none;
}
.chevron-icon {
margin-top: 21px;
transform: rotate(180deg);
cursor: pointer;
}
@media (max-width: $screen-s) {
display: none;
}
}
.right-side {
min-width: calc(100vw - 389px);
padding: 24px;
overflow-y: auto;
@media (max-width: ($screen-m - 1px)) {
min-width: calc(100vw - 56px);
}
@media (max-width: $screen-s) {
flex: 1;
min-width: unset;
}
.back-arrow-mobile {
display: none;
@media (max-width: $screen-s) {
display: block;
margin-bottom: 24px;
}
}
.back-arrow-desktop {
@media (max-width: $screen-s) {
display: none;
}
}
}
}
}

View File

@ -1,117 +1,49 @@
import ChevronIcon from "@Assets/Icons/chevron.svg"; import React, { useEffect } from "react";
import { useRouter } from "next/router";
import Module from "@Front/Config/Module";
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
import DefaultDashboardWithList, { IPropsDashboardWithList } from "../DefaultDashboardWithList";
import { OfficeRole } from "le-coffre-resources/dist/Notary";
import OfficeRoles, { IGetRolesParams } from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles"; import OfficeRoles, { IGetRolesParams } from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Header from "@Front/Components/DesignSystem/Header";
import Version from "@Front/Components/DesignSystem/Version";
import BackArrow from "@Front/Components/Elements/BackArrow";
import WindowStore from "@Front/Stores/WindowStore";
import classNames from "classnames";
import { OfficeRole } from "le-coffre-resources/dist/Admin";
import Image from "next/image";
import React, { ReactNode } from "react";
import classes from "./classes.module.scss"; type IProps = IPropsDashboardWithList;
import RoleListContainer from "./RoleListContainer";
import { ChevronLeftIcon } from "@heroicons/react/24/outline";
type IProps = { export default function DefaultRoleDashboard(props: IProps) {
title: string; const [roles, setRoles] = React.useState<OfficeRole[] | null>(null);
children?: ReactNode; const router = useRouter();
onSelectedRole: (role: OfficeRole) => void; const { roleUid } = router.query;
hasBackArrow: boolean; useEffect(() => {
backArrowUrl?: string;
mobileBackText?: string;
};
type IState = {
roles: OfficeRole[] | null;
isLeftSideOpen: boolean;
leftSideCanBeClosed: boolean;
};
export default class DefaultRoleDashboard extends React.Component<IProps, IState> {
private onWindowResize = () => {};
public static defaultProps: Partial<IProps> = {
hasBackArrow: false,
};
public constructor(props: IProps) {
super(props);
this.state = {
roles: null,
isLeftSideOpen: false,
leftSideCanBeClosed: typeof window !== "undefined" ? window.innerWidth < 1024 : false,
};
this.onOpenLeftSide = this.onOpenLeftSide.bind(this);
this.onCloseLeftSide = this.onCloseLeftSide.bind(this);
}
public override render(): JSX.Element {
return (
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
{this.state.isLeftSideOpen && <div className={classes["overlay"]} onClick={this.onCloseLeftSide} />}
<div className={classNames(classes["left-side"], this.state.isLeftSideOpen && classes["opened"])}>
{this.state.roles && <RoleListContainer roles={this.state.roles} onCloseLeftSide={this.onCloseLeftSide} />}
</div>
<div className={classNames(classes["closable-left-side"])}>
<Image alt="open side menu" src={ChevronIcon} className={classes["chevron-icon"]} onClick={this.onOpenLeftSide} />
</div>
<div className={classes["right-side"]}>
{this.props.hasBackArrow && (
<div className={classes["back-arrow-desktop"]}>
<BackArrow url={this.props.backArrowUrl ?? ""} />
</div>
)}
{this.props.mobileBackText && (
<div className={classes["back-arrow-mobile"]}>
<Button
leftIcon={<ChevronLeftIcon />}
variant={EButtonVariant.PRIMARY}
styletype={EButtonstyletype.TEXT}
onClick={this.onOpenLeftSide}>
{this.props.mobileBackText ?? "Retour"}
</Button>
</div>
)}
{this.props.children}
</div>
</div>
<Version />
</div>
);
}
public override async componentDidMount() {
this.onWindowResize = WindowStore.getInstance().onResize((window) => this.onResize(window));
const query: IGetRolesParams = { const query: IGetRolesParams = {
include: { rules: true }, include: { rules: true },
}; };
const roles = await OfficeRoles.getInstance().get(query); OfficeRoles.getInstance()
.get(query)
.then((roles) => setRoles(roles));
}, []);
this.setState({ roles }); const onSelectedBlock = (block: IBlock) => {
} router.push(Module.getInstance().get().modules.pages.Roles.pages.RolesInformations.props.path.replace("[uid]", block.id));
};
public override componentWillUnmount() { return (
this.onWindowResize(); <DefaultDashboardWithList
} {...props}
onSelectedBlock={onSelectedBlock}
private onOpenLeftSide() { blocks={
this.setState({ isLeftSideOpen: true }); roles
} ? roles.map((role) => ({
id: role.uid!,
private onCloseLeftSide() { primaryText: role.name,
if (!this.state.leftSideCanBeClosed) return; isActive: role.uid === roleUid,
this.setState({ isLeftSideOpen: false }); }))
} : []
}
private onResize(window: Window) { bottomButton={{
if (window.innerWidth > 1023) { link: Module.getInstance().get().modules.pages.Roles.pages.Create.props.path,
if (!this.state.leftSideCanBeClosed) return; text: "Créer un rôle",
this.setState({ leftSideCanBeClosed: false }); }}
} />
this.setState({ leftSideCanBeClosed: true }); );
}
} }

View File

@ -31,7 +31,7 @@ export default function DefaultUserDashboard(props: IProps) {
<DefaultDashboardWithList <DefaultDashboardWithList
{...props} {...props}
onSelectedBlock={onSelectedBlock} onSelectedBlock={onSelectedBlock}
blocksList={ blocks={
users users
? users.map((user) => ({ ? users.map((user) => ({
id: user.uid!, id: user.uid!,