Merge branch 'staging' into preprod
This commit is contained in:
commit
6c43cdb9b6
@ -49,7 +49,7 @@ export default function Alert(props: IProps) {
|
|||||||
<Typography typo={ETypo.TEXT_LG_SEMIBOLD} color={ETypoColor.COLOR_NEUTRAL_950}>
|
<Typography typo={ETypo.TEXT_LG_SEMIBOLD} color={ETypoColor.COLOR_NEUTRAL_950}>
|
||||||
{title}
|
{title}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography typo={ETypo.TEXT_MD_light} color={ETypoColor.COLOR_NEUTRAL_700}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT} color={ETypoColor.COLOR_NEUTRAL_700}>
|
||||||
{description}
|
{description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
import React, { useCallback } from "react";
|
|
||||||
import classes from "./classes.module.scss";
|
|
||||||
import Typography, { ETypo } from "../Typography";
|
|
||||||
import ChevronIcon from "@Assets/Icons/chevron.svg";
|
|
||||||
import Image from "next/image";
|
|
||||||
import WarningBadge from "../WarningBadge";
|
|
||||||
|
|
||||||
export type IBlock = {
|
|
||||||
name: string;
|
|
||||||
id: string;
|
|
||||||
selected: boolean;
|
|
||||||
rightIcon?: JSX.Element;
|
|
||||||
hasFlag?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
type IProps = {
|
|
||||||
blocks: IBlock[];
|
|
||||||
onSelectedBlock: (block: IBlock) => void;
|
|
||||||
};
|
|
||||||
export default function BlockList({ blocks, onSelectedBlock }: IProps) {
|
|
||||||
const selectBlock = useCallback(
|
|
||||||
(e: React.MouseEvent<HTMLDivElement>) => {
|
|
||||||
onSelectedBlock && onSelectedBlock(blocks.find((folder) => folder.id === e.currentTarget.id)!);
|
|
||||||
},
|
|
||||||
[blocks, onSelectedBlock],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{blocks.map((folder) => {
|
|
||||||
return (
|
|
||||||
<div onClick={selectBlock} key={folder.id} id={folder.id}>
|
|
||||||
<div className={classes["root"]} data-selected={folder.selected.toString()}>
|
|
||||||
<div className={classes["left-side"]}>
|
|
||||||
<Typography typo={ETypo.TEXT_MD_REGULAR}>{folder.name}</Typography>
|
|
||||||
</div>
|
|
||||||
<div className={classes["right-side"]}>
|
|
||||||
{folder.hasFlag && <WarningBadge />}
|
|
||||||
{folder.rightIcon}
|
|
||||||
<Image alt="chevron" src={ChevronIcon} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,16 +1,12 @@
|
|||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
|
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
|
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
|
||||||
import Link from "next/link";
|
|
||||||
import { NextRouter, useRouter } from "next/router";
|
import { NextRouter, useRouter } from "next/router";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
import BlockList, { IBlock } from "../BlockList";
|
|
||||||
import Button from "../Button";
|
|
||||||
import SearchBar from "../SearchBar";
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import Rules, { RulesMode } from "@Front/Components/Elements/Rules";
|
import { IBlock } from "../SearchBlockList/BlockList/Block";
|
||||||
import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule";
|
import SearchBlockList from "../SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
folders: OfficeFolder[];
|
folders: OfficeFolder[];
|
||||||
@ -44,33 +40,9 @@ class FolderArchivedListContainerClass extends React.Component<IPropsClass, ISta
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
const navigatePath = Module.getInstance().get().modules.pages.Folder.pages.CreateFolder.props.path;
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<SearchBlockList blocks={this.state.blocks} onSelectedBlock={this.onSelectedFolder} />
|
||||||
<div className={classes["searchbar"]}>
|
|
||||||
<SearchBar onChange={this.filterFolders} placeholder="Chercher un dossier" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList blocks={this.state.blocks} onSelectedBlock={this.onSelectedFolder} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{!this.props.isArchived && (
|
|
||||||
<div>
|
|
||||||
<Rules
|
|
||||||
mode={RulesMode.NECESSARY}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
action: AppRuleActions.create,
|
|
||||||
name: AppRuleNames.officeFolders,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Link href={navigatePath}>
|
|
||||||
<Button fullwidth={true}>Créer un dossier</Button>
|
|
||||||
</Link>
|
|
||||||
</Rules>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -106,9 +78,10 @@ class FolderArchivedListContainerClass extends React.Component<IPropsClass, ISta
|
|||||||
return [...pendingFolders, ...otherFolders].map((folder) => {
|
return [...pendingFolders, ...otherFolders].map((folder) => {
|
||||||
return {
|
return {
|
||||||
id: folder.uid!,
|
id: folder.uid!,
|
||||||
name: folder.folder_number! + " - " + folder.name!,
|
primaryText: folder.name,
|
||||||
selected: this.props.selectedFolder === folder.uid,
|
isActive: this.props.selectedFolder === folder.uid,
|
||||||
hasFlag: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED),
|
secondaryText: folder.folder_number,
|
||||||
|
showAlert: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,12 @@
|
|||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
|
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
|
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
|
||||||
import Link from "next/link";
|
import { useRouter } from "next/router";
|
||||||
import { NextRouter, useRouter } from "next/router";
|
import React, { useCallback, useEffect } from "react";
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import BlockList, { IBlock } from "../BlockList";
|
|
||||||
import Button from "../Button";
|
|
||||||
import SearchBar from "../SearchBar";
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import Rules, { RulesMode } from "@Front/Components/Elements/Rules";
|
import { IBlock } from "../SearchBlockList/BlockList/Block";
|
||||||
import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule";
|
import SearchBlockList from "../SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
folders: OfficeFolder[];
|
folders: OfficeFolder[];
|
||||||
@ -19,68 +15,17 @@ type IProps = {
|
|||||||
onCloseLeftSide?: () => void;
|
onCloseLeftSide?: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IPropsClass = IProps & {
|
export default function FolderListContainer(props: IProps) {
|
||||||
router: NextRouter;
|
const router = useRouter();
|
||||||
selectedFolder: string;
|
const { folderUid } = router.query;
|
||||||
};
|
const { folders, isArchived } = props;
|
||||||
|
|
||||||
type IState = {
|
const redirectPath: string = isArchived
|
||||||
filteredFolders: OfficeFolder[];
|
|
||||||
blocks: IBlock[];
|
|
||||||
};
|
|
||||||
|
|
||||||
class FolderListContainerClass extends React.Component<IPropsClass, IState> {
|
|
||||||
private redirectPath: string = this.props.isArchived
|
|
||||||
? Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.pages.FolderInformation.props.path
|
? Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.pages.FolderInformation.props.path
|
||||||
: Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path;
|
: Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path;
|
||||||
public constructor(props: IPropsClass) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
filteredFolders: this.props.folders,
|
|
||||||
blocks: this.getBlocks(this.props.folders),
|
|
||||||
};
|
|
||||||
this.filterFolders = this.filterFolders.bind(this);
|
|
||||||
this.onSelectedFolder = this.onSelectedFolder.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
const getBlocks = useCallback(
|
||||||
const navigatePath = Module.getInstance().get().modules.pages.Folder.pages.CreateFolder.props.path;
|
(folders: OfficeFolder[]): IBlock[] => {
|
||||||
return (
|
|
||||||
<div className={classes["root"]}>
|
|
||||||
<div className={classes["header"]}>
|
|
||||||
<div className={classes["searchbar"]}>
|
|
||||||
<SearchBar onChange={this.filterFolders} placeholder="Chercher un dossier" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList blocks={this.state.blocks} onSelectedBlock={this.onSelectedFolder} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{!this.props.isArchived && (
|
|
||||||
<div>
|
|
||||||
<Rules
|
|
||||||
mode={RulesMode.NECESSARY}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
action: AppRuleActions.create,
|
|
||||||
name: AppRuleNames.officeFolders,
|
|
||||||
},
|
|
||||||
]}>
|
|
||||||
<Link href={navigatePath}>
|
|
||||||
<Button fullwidth={true}>Créer un dossier</Button>
|
|
||||||
</Link>
|
|
||||||
</Rules>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override componentDidUpdate(prevProps: Readonly<IPropsClass>, prevState: Readonly<IState>, snapshot?: any): void {
|
|
||||||
if (prevProps.selectedFolder !== this.props.selectedFolder) {
|
|
||||||
this.setState({ filteredFolders: this.props.folders, blocks: this.getBlocks(this.props.folders) });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private getBlocks(folders: OfficeFolder[]): IBlock[] {
|
|
||||||
const pendingFolders = folders
|
const pendingFolders = folders
|
||||||
.filter((folder) => {
|
.filter((folder) => {
|
||||||
const pendingDocuments = (folder.documents ?? []).filter(
|
const pendingDocuments = (folder.documents ?? []).filter(
|
||||||
@ -106,45 +51,41 @@ class FolderListContainerClass extends React.Component<IPropsClass, IState> {
|
|||||||
return [...pendingFolders, ...otherFolders].map((folder) => {
|
return [...pendingFolders, ...otherFolders].map((folder) => {
|
||||||
return {
|
return {
|
||||||
id: folder.uid!,
|
id: folder.uid!,
|
||||||
name: folder.folder_number! + " - " + folder.name!,
|
primaryText: folder.name,
|
||||||
selected: this.props.selectedFolder === folder.uid,
|
secondaryText: folder.folder_number,
|
||||||
hasFlag: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED),
|
isActive: folderUid === folder.uid,
|
||||||
|
showAlert: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
[folderUid],
|
||||||
|
);
|
||||||
|
|
||||||
private onSelectedFolder(block: IBlock) {
|
const [blocks, setBlocks] = React.useState<IBlock[]>(getBlocks(folders));
|
||||||
const folder = this.props.folders.find((folder) => folder.uid === block.id);
|
|
||||||
|
const onSelectedFolder = (block: IBlock) => {
|
||||||
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
|
const folder = folders.find((folder) => folder.uid === block.id);
|
||||||
if (!folder) return;
|
if (!folder) return;
|
||||||
this.props.onSelectedFolder && this.props.onSelectedFolder(folder);
|
props.onSelectedFolder && props.onSelectedFolder(folder);
|
||||||
const path = this.redirectPath.replace("[folderUid]", folder.uid ?? "");
|
const path = redirectPath.replace("[folderUid]", folder.uid ?? "");
|
||||||
this.props.router.push(path);
|
router.push(path);
|
||||||
}
|
};
|
||||||
|
|
||||||
private filterFolders(value: string): void {
|
useEffect(() => {
|
||||||
const filteredFolders: OfficeFolder[] = this.props.folders.filter((folder) => {
|
setBlocks(getBlocks(folders));
|
||||||
const name = folder.name.toLowerCase();
|
}, [folders, getBlocks]);
|
||||||
const number = folder.folder_number.toLowerCase();
|
|
||||||
value = value.toLowerCase();
|
|
||||||
if (folder.customers) {
|
|
||||||
const customerNames = folder.customers
|
|
||||||
.map((customer) => {
|
|
||||||
return `${customer.contact?.first_name.toLowerCase()} ${customer.contact?.last_name.toLowerCase()}`;
|
|
||||||
})
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
return name.includes(value) || number.includes(value) || customerNames.includes(value);
|
return (
|
||||||
}
|
<div className={classes["root"]}>
|
||||||
|
<SearchBlockList
|
||||||
return name.includes(value) || number.includes(value);
|
blocks={blocks}
|
||||||
});
|
onSelectedBlock={onSelectedFolder}
|
||||||
|
bottomButton={{
|
||||||
this.setState({ filteredFolders, blocks: this.getBlocks(filteredFolders) });
|
link: Module.getInstance().get().modules.pages.Folder.pages.CreateFolder.props.path,
|
||||||
}
|
text: "Créer un dossier",
|
||||||
}
|
}}
|
||||||
|
/>
|
||||||
export default function FolderListContainer(props: IProps) {
|
</div>
|
||||||
const router = useRouter();
|
);
|
||||||
const { folderUid } = router.query;
|
|
||||||
return <FolderListContainerClass {...props} router={router} selectedFolder={folderUid as string} />;
|
|
||||||
}
|
}
|
||||||
|
48
src/front/Components/DesignSystem/Footer/classes.module.scss
Normal file
48
src/front/Components/DesignSystem/Footer/classes.module.scss
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
@import "@Themes/constants.scss";
|
||||||
|
|
||||||
|
.root {
|
||||||
|
border-top: 1px solid var(--footer-border, #d7dce0);
|
||||||
|
background: var(--footer-background, #fff);
|
||||||
|
padding: var(--spacing-1-5) 0;
|
||||||
|
font-family: var(--font-title-family, Poppins);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: var(--font-text-weight-regular, 400);
|
||||||
|
letter-spacing: 0.06px;
|
||||||
|
|
||||||
|
.sub-root {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--Radius-lg, 16px);
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 360px;
|
||||||
|
//make it sticky
|
||||||
|
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 660px) or (min-width: 768px) {
|
||||||
|
.tablet {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 660px) {
|
||||||
|
.mobile {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 769px) {
|
||||||
|
.desktop {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
&::before {
|
||||||
|
content: "|";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/front/Components/DesignSystem/Footer/desktop.tsx
Normal file
20
src/front/Components/DesignSystem/Footer/desktop.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from "react";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Desktop({ className }: IProps) {
|
||||||
|
return (
|
||||||
|
<div className={[classes["sub-root"], className].join(" ")}>
|
||||||
|
<span>© Copyright lecoffre 2024</span>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/terms">Conditions d'utilisation</a>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/privacy">Politique de confidentialité</a>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/cookies">Politique des cookies</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
19
src/front/Components/DesignSystem/Footer/index.tsx
Normal file
19
src/front/Components/DesignSystem/Footer/index.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import React from "react";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import Mobile from "./mobile";
|
||||||
|
import Desktop from "./desktop";
|
||||||
|
import Tablet from "./tablet";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Footer({ className }: IProps) {
|
||||||
|
return (
|
||||||
|
<footer className={[classes["root"], className].join(" ")}>
|
||||||
|
<Mobile className={classes["mobile"]} />
|
||||||
|
<Tablet className={classes["tablet"]} />
|
||||||
|
<Desktop className={classes["desktop"]} />
|
||||||
|
</footer>
|
||||||
|
);
|
||||||
|
}
|
18
src/front/Components/DesignSystem/Footer/mobile.tsx
Normal file
18
src/front/Components/DesignSystem/Footer/mobile.tsx
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
import React from "react";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Mobile({ className }: IProps) {
|
||||||
|
return (
|
||||||
|
<div className={[classes["sub-root"], className].join(" ")}>
|
||||||
|
<span>© Lecoffre 2024</span>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/terms">Juridiques</a>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/cookies">Cookies</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
20
src/front/Components/DesignSystem/Footer/tablet.tsx
Normal file
20
src/front/Components/DesignSystem/Footer/tablet.tsx
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import React from "react";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Tablet({ className }: IProps) {
|
||||||
|
return (
|
||||||
|
<div className={[classes["sub-root"], className].join(" ")}>
|
||||||
|
<span>© Lecoffre 2024</span>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/terms">Conditions d'utilisation</a>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/privacy">Politique de confidentialité</a>
|
||||||
|
<span className={classes["separator"]} />
|
||||||
|
<a href="/cookies">Politique des cookies</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -2,30 +2,67 @@
|
|||||||
|
|
||||||
.root {
|
.root {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
padding: var(--spacing-2, 16px) var(--spacing-sm, 8px);
|
||||||
padding-left: 24px;
|
align-items: flex-start;
|
||||||
background-color: var(--color-generic-white);
|
gap: var(--spacing-2, 16px);
|
||||||
border: 1px solid var(--color-neutral-200);
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.fake-placeholder {
|
border-radius: var(--input-radius, 0px);
|
||||||
position: absolute;
|
border: 1px solid var(--input-main-border-default, #d7dce0);
|
||||||
left: 47px;
|
background: var(--input-background, #fff);
|
||||||
top: 24px;
|
|
||||||
color: var(--color-neutral-500);
|
&:hover {
|
||||||
pointer-events: none;
|
border-radius: var(--input-radius, 0px);
|
||||||
|
border: 1px solid var(--input-main-border-hovered, #b4bec5);
|
||||||
|
background: var(--input-background, #fff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[data-has-value="true"] {
|
||||||
|
border-radius: var(--input-radius, 0px);
|
||||||
|
border: 1px solid var(--input-main-border-filled, #6d7e8a);
|
||||||
|
background: var(--input-background, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-is-focused="true"] {
|
||||||
|
border-radius: var(--input-radius, 0px);
|
||||||
|
border: 1px solid var(--input-main-border-focused, #005bcb);
|
||||||
|
background: var(--input-background, #fff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-container {
|
||||||
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 0px var(--spacing-2, 16px);
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
border: 0;
|
flex: 1;
|
||||||
margin-left: 8px;
|
border: none;
|
||||||
padding: 24px 0;
|
|
||||||
width: 100%;
|
color: var(--input-placeholder-filled, #24282e);
|
||||||
font-family: "Inter", sans-serif;
|
|
||||||
|
/* text/md/semibold */
|
||||||
|
font-family: var(--font-text-family, Poppins);
|
||||||
|
font-size: 16px;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: var(--font-text-weight-semibold, 600);
|
||||||
font-size: 18px;
|
line-height: normal;
|
||||||
line-height: 22px;
|
letter-spacing: 0.08px;
|
||||||
color: var(--color-neutral-500);
|
width: 100%;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--input-placeholder-empty, #6d7e8a);
|
||||||
|
/* text/md/regular */
|
||||||
|
font-family: var(--font-text-family, Poppins);
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: var(--font-text-weight-regular, 400);
|
||||||
|
line-height: normal;
|
||||||
|
letter-spacing: 0.08px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cross {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,45 @@
|
|||||||
import LoopIcon from "@Assets/Icons/loop.svg";
|
import React, { useCallback } from "react";
|
||||||
import Image from "next/image";
|
|
||||||
import React from "react";
|
|
||||||
|
|
||||||
import Typography, { ETypo, ETypoColor } from "../Typography";
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
onChange?: (input: string) => void;
|
onChange?: (input: string) => void;
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IState = {
|
export default function SearchBar({ onChange, placeholder = "Rechercher" }: IProps) {
|
||||||
hasValue: boolean;
|
const [isFocused, setIsFocused] = React.useState(false);
|
||||||
};
|
const [value, setValue] = React.useState("");
|
||||||
|
|
||||||
export default class SearchBar extends React.Component<IProps, IState> {
|
const changeValue = useCallback(
|
||||||
static defaultProps = {
|
(value: string) => {
|
||||||
placeholder: "Search",
|
setValue(value);
|
||||||
};
|
onChange && onChange(value);
|
||||||
|
},
|
||||||
|
[onChange],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOnChange = (event: React.ChangeEvent<HTMLInputElement>) => changeValue(event.target.value);
|
||||||
|
const handleFocus = () => setIsFocused(true);
|
||||||
|
const handleBlur = () => setIsFocused(false);
|
||||||
|
const clearValue = () => changeValue("");
|
||||||
|
|
||||||
public constructor(props: IProps) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
hasValue: false,
|
|
||||||
};
|
|
||||||
this.doesInputHaveValue = this.doesInputHaveValue.bind(this);
|
|
||||||
this.onChange = this.onChange.bind(this);
|
|
||||||
}
|
|
||||||
public override render(): JSX.Element {
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<label className={classes["root"]} data-is-focused={isFocused} data-has-value={value !== ""}>
|
||||||
<Image src={LoopIcon} alt="Loop icon" />
|
<div className={classes["input-container"]}>
|
||||||
{!this.state.hasValue && (
|
<MagnifyingGlassIcon width="24" height="24" />
|
||||||
<Typography typo={ETypo.TEXT_LG_REGULAR} color={ETypoColor.COLOR_ERROR_600}>
|
<input
|
||||||
<div className={classes["fake-placeholder"]}>{this.props.placeholder}</div>
|
type="text"
|
||||||
</Typography>
|
value={value}
|
||||||
)}
|
placeholder={placeholder}
|
||||||
<input type="text" placeholder="" className={classes["input"]} onChange={this.onChange} />
|
className={classes["input"]}
|
||||||
|
onChange={handleOnChange}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
/>
|
||||||
|
{value !== "" && <XMarkIcon width="24" height="24" className={classes["cross"]} onClick={clearValue} />}
|
||||||
</div>
|
</div>
|
||||||
|
</label>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private onChange(event: React.ChangeEvent<HTMLInputElement>) {
|
|
||||||
const hasValue = event.target.value.length > 0;
|
|
||||||
this.doesInputHaveValue(hasValue);
|
|
||||||
if (!this.props.onChange) return;
|
|
||||||
this.props.onChange(event.target.value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private doesInputHaveValue(hasValue: boolean) {
|
|
||||||
this.setState({ hasValue });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
.root {
|
||||||
|
background: var(--navigation-button-background-default, #f7f8f8);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background: var(--navigation-button-background-actived, #edeff1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-is-active="true"] {
|
||||||
|
border-left: 3px solid var(--navigation-border, #005bcb);
|
||||||
|
background: var(--navigation-button-background-actived, #edeff1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
padding: var(--spacing-md, 16px) var(--spacing-lg, 24px);
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-sm, 8px);
|
||||||
|
|
||||||
|
.text-container {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.separator {
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--separator-stroke-light, #d7dce0);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import { ChevronRightIcon } from "@heroicons/react/24/outline";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { ExclamationCircleIcon } from "@heroicons/react/20/solid";
|
||||||
|
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
|
|
||||||
|
export type IBlock = {
|
||||||
|
id: string;
|
||||||
|
primaryText: string;
|
||||||
|
secondaryText?: string;
|
||||||
|
showAlert?: boolean;
|
||||||
|
isActive?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IProps = IBlock & {
|
||||||
|
hasSeparator?: boolean;
|
||||||
|
onClick?: (id: string) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function Block(props: IProps) {
|
||||||
|
const { primaryText, secondaryText, showAlert = false, hasSeparator = true, isActive = false, onClick } = props;
|
||||||
|
|
||||||
|
const handleOnClick = useCallback(() => onClick && onClick(props.id), [onClick, props.id]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes["root"]} data-is-active={isActive} onClick={handleOnClick}>
|
||||||
|
<div className={classes["content"]}>
|
||||||
|
<div className={classes["text-container"]}>
|
||||||
|
<Typography typo={ETypo.TEXT_MD_LIGHT} color={ETypoColor.NAVIGATION_BUTTON_CONTRAST_DEFAULT}>
|
||||||
|
{secondaryText}
|
||||||
|
</Typography>
|
||||||
|
<Typography
|
||||||
|
typo={ETypo.TEXT_MD_BOLD}
|
||||||
|
color={isActive ? ETypoColor.NAVIGATION_BUTTON_CONTRAST_ACTIVE : ETypoColor.NAVIGATION_BUTTON_CONTRAST_DEFAULT}>
|
||||||
|
{primaryText}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
{showAlert && (
|
||||||
|
<ExclamationCircleIcon width="24" height="24" className={classes["icon"]} color={"var(--warning-default-base)"} />
|
||||||
|
)}
|
||||||
|
<ChevronRightIcon width="24" height="24" className={classes["icon"]} color={"var(--button-icon-button-default-default)"} />
|
||||||
|
</div>
|
||||||
|
{hasSeparator && <div className={classes["separator"]} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
import React, { useCallback } from "react";
|
||||||
|
import Block, { IBlock } from "./Block";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
blocks: IBlock[];
|
||||||
|
onSelectedBlock: (block: IBlock) => void;
|
||||||
|
};
|
||||||
|
export default function BlockList({ blocks, onSelectedBlock }: IProps) {
|
||||||
|
const selectBlock = useCallback(
|
||||||
|
(id: string) => {
|
||||||
|
onSelectedBlock && onSelectedBlock(blocks.find((folder) => folder.id === id)!);
|
||||||
|
},
|
||||||
|
[blocks, onSelectedBlock],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{blocks.map((block) => {
|
||||||
|
return <Block {...block} hasSeparator onClick={selectBlock} key={block.id} />;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
.root {
|
||||||
|
width: 336px;
|
||||||
|
height: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
|
||||||
|
border-radius: var(--navigation-radius, 0px);
|
||||||
|
background: var(--navigation-button-background-default, #f7f8f8);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
.block-list {
|
||||||
|
overflow-y: auto;
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
-ms-overflow-style: none; /* IE and Edge */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
|
||||||
|
.searchbar {
|
||||||
|
padding: var(--spacing-md, 16px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-container {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
|
}
|
78
src/front/Components/DesignSystem/SearchBlockList/index.tsx
Normal file
78
src/front/Components/DesignSystem/SearchBlockList/index.tsx
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
import BlockList from "./BlockList";
|
||||||
|
import { IBlock } from "./BlockList/Block";
|
||||||
|
import classes from "./classes.module.scss";
|
||||||
|
import SearchBar from "../SearchBar";
|
||||||
|
import Button from "../Button";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
blocks: IBlock[];
|
||||||
|
onSelectedBlock: (block: IBlock) => void;
|
||||||
|
bottomButton?: {
|
||||||
|
text: string;
|
||||||
|
link: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
export default function SearchBlockList(props: IProps) {
|
||||||
|
const { blocks, onSelectedBlock, bottomButton } = props;
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const [blocksShowing, setBlocksShowing] = useState<IBlock[]>(blocks);
|
||||||
|
const bottomButtonRef = useRef<HTMLAnchorElement>(null);
|
||||||
|
const searchBarRef = useRef<HTMLDivElement>(null);
|
||||||
|
const handleSearchChange = useCallback(
|
||||||
|
(value: string) => {
|
||||||
|
const filteredBlocks = blocks.filter((block) => {
|
||||||
|
const name = block.primaryText.toLowerCase();
|
||||||
|
const number = block.secondaryText?.toLowerCase();
|
||||||
|
value = value.toLowerCase();
|
||||||
|
return name.includes(value) || number?.includes(value);
|
||||||
|
});
|
||||||
|
setBlocksShowing(filteredBlocks);
|
||||||
|
},
|
||||||
|
[blocks],
|
||||||
|
);
|
||||||
|
|
||||||
|
const getHeight = useCallback(() => {
|
||||||
|
let heightToSubstract = 0;
|
||||||
|
if (bottomButton && bottomButtonRef.current) {
|
||||||
|
heightToSubstract += bottomButtonRef.current.clientHeight;
|
||||||
|
}
|
||||||
|
if (searchBarRef.current) {
|
||||||
|
heightToSubstract += searchBarRef.current.clientHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
maxHeight: `calc(100% - ${heightToSubstract}px)`,
|
||||||
|
};
|
||||||
|
}, [bottomButton]);
|
||||||
|
|
||||||
|
const redirectOnBottomButtonClick = useCallback(() => {
|
||||||
|
if (!bottomButton) return;
|
||||||
|
router.push(bottomButton.link);
|
||||||
|
}, [bottomButton, router]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setBlocksShowing(blocks);
|
||||||
|
}, [blocks]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classes["root"]}>
|
||||||
|
<div className={classes["searchbar"]} ref={searchBarRef}>
|
||||||
|
<SearchBar placeholder="Chercher" onChange={handleSearchChange} />
|
||||||
|
</div>
|
||||||
|
<div className={classes["block-list"]} style={getHeight()}>
|
||||||
|
<BlockList blocks={blocksShowing} onSelectedBlock={onSelectedBlock} />
|
||||||
|
</div>
|
||||||
|
{bottomButton && (
|
||||||
|
<div className={classes["bottom-container"]}>
|
||||||
|
<Button fullwidth onClick={redirectOnBottomButtonClick}>
|
||||||
|
{bottomButton.text}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -28,25 +28,25 @@ export enum ETypo {
|
|||||||
TEXT_LG_SEMIBOLD = "text-lg-semibold",
|
TEXT_LG_SEMIBOLD = "text-lg-semibold",
|
||||||
TEXT_LG_REGULAR = "text-lg-regular",
|
TEXT_LG_REGULAR = "text-lg-regular",
|
||||||
TEXT_LG_UPPERCASE = "text-lg-uppercase",
|
TEXT_LG_UPPERCASE = "text-lg-uppercase",
|
||||||
TEXT_LG_light = "text-lg-light",
|
TEXT_LG_LIGHT = "text-lg-light",
|
||||||
|
|
||||||
TEXT_MD_BOLD = "text-md-bold",
|
TEXT_MD_BOLD = "text-md-bold",
|
||||||
TEXT_MD_SEMIBOLD = "text-md-semibold",
|
TEXT_MD_SEMIBOLD = "text-md-semibold",
|
||||||
TEXT_MD_REGULAR = "text-md-regular",
|
TEXT_MD_REGULAR = "text-md-regular",
|
||||||
TEXT_MD_UPPERCASE = "text-md-uppercase",
|
TEXT_MD_UPPERCASE = "text-md-uppercase",
|
||||||
TEXT_MD_light = "text-md-light",
|
TEXT_MD_LIGHT = "text-md-light",
|
||||||
|
|
||||||
TEXT_SM_BOLD = "text-sm-bold",
|
TEXT_SM_BOLD = "text-sm-bold",
|
||||||
TEXT_SM_SEMIBOLD = "text-sm-semibold",
|
TEXT_SM_SEMIBOLD = "text-sm-semibold",
|
||||||
TEXT_SM_REGULAR = "text-sm-regular",
|
TEXT_SM_REGULAR = "text-sm-regular",
|
||||||
TEXT_SM_UPPERCASE = "text-sm-uppercase",
|
TEXT_SM_UPPERCASE = "text-sm-uppercase",
|
||||||
TEXT_SM_light = "text-sm-light",
|
TEXT_SM_LIGHT = "text-sm-light",
|
||||||
|
|
||||||
TEXT_XS_BOLD = "text-xs-bold",
|
TEXT_XS_BOLD = "text-xs-bold",
|
||||||
TEXT_XS_SEMIBOLD = "text-xs-semibold",
|
TEXT_XS_SEMIBOLD = "text-xs-semibold",
|
||||||
TEXT_XS_REGULAR = "text-xs-regular",
|
TEXT_XS_REGULAR = "text-xs-regular",
|
||||||
TEXT_XS_UPPERCASE = "text-xs-uppercase",
|
TEXT_XS_UPPERCASE = "text-xs-uppercase",
|
||||||
TEXT_XS_light = "text-xs-light",
|
TEXT_XS_LIGHT = "text-xs-light",
|
||||||
|
|
||||||
CAPTION_BOLD = "caption-bold",
|
CAPTION_BOLD = "caption-bold",
|
||||||
CAPTION_SEMIBOLD = "caption-semibold",
|
CAPTION_SEMIBOLD = "caption-semibold",
|
||||||
@ -153,6 +153,8 @@ export enum ETypoColor {
|
|||||||
CONTRAST_DEFAULT = "--contrast-default",
|
CONTRAST_DEFAULT = "--contrast-default",
|
||||||
CONTRAST_HOVERED = "--contrast-hovered",
|
CONTRAST_HOVERED = "--contrast-hovered",
|
||||||
ERROR_WEAK_CONTRAST = "--error-weak-contrast",
|
ERROR_WEAK_CONTRAST = "--error-weak-contrast",
|
||||||
|
NAVIGATION_BUTTON_CONTRAST_DEFAULT = "--navigation-button-contrast-default",
|
||||||
|
NAVIGATION_BUTTON_CONTRAST_ACTIVE = "--navigation-button-contrast-active",
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Typography(props: IProps) {
|
export default function Typography(props: IProps) {
|
||||||
|
@ -6,6 +6,9 @@
|
|||||||
border-bottom: 1px solid var(--tabs-stroke, #d7dce0);
|
border-bottom: 1px solid var(--tabs-stroke, #d7dce0);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--spacing-1-5, 12px);
|
||||||
&[data-is-selected="true"] {
|
&[data-is-selected="true"] {
|
||||||
border-bottom: 2px solid var(--tabs-contrast-actived, #24282e);
|
border-bottom: 2px solid var(--tabs-contrast-actived, #24282e);
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import classes from "./classes.module.scss";
|
|||||||
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
import useHoverable from "@Front/Hooks/useHoverable";
|
import useHoverable from "@Front/Hooks/useHoverable";
|
||||||
import { ITabValue } from "..";
|
import { ITabValue } from "..";
|
||||||
|
import { ExclamationCircleIcon } from "@heroicons/react/24/outline";
|
||||||
export type ITab = {
|
export type ITab = {
|
||||||
label: React.ReactNode;
|
label: React.ReactNode;
|
||||||
};
|
};
|
||||||
@ -11,6 +12,7 @@ export type IProps<T> = {
|
|||||||
onSelect: (value: ITabValue<T>) => void;
|
onSelect: (value: ITabValue<T>) => void;
|
||||||
value: ITabValue<T>;
|
value: ITabValue<T>;
|
||||||
isSelected: boolean;
|
isSelected: boolean;
|
||||||
|
hasWarning?: boolean;
|
||||||
} & ITab;
|
} & ITab;
|
||||||
|
|
||||||
export default function HorizontalTabs<T>(props: IProps<T>) {
|
export default function HorizontalTabs<T>(props: IProps<T>) {
|
||||||
@ -29,6 +31,7 @@ export default function HorizontalTabs<T>(props: IProps<T>) {
|
|||||||
color={!isHovered && !props.isSelected ? ETypoColor.TABS_CONTRAST_DEFAULT : ETypoColor.TABS_CONTRAST_ACTIVATED}>
|
color={!isHovered && !props.isSelected ? ETypoColor.TABS_CONTRAST_DEFAULT : ETypoColor.TABS_CONTRAST_ACTIVATED}>
|
||||||
{props.label}
|
{props.label}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
{props.hasWarning && <ExclamationCircleIcon width="24" height="24" color="var(--tabs-contrast-warning)" />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,12 @@ import useOpenable from "@Front/Hooks/useOpenable";
|
|||||||
|
|
||||||
export type ITabValue<T> = T & {
|
export type ITabValue<T> = T & {
|
||||||
id: unknown;
|
id: unknown;
|
||||||
}
|
};
|
||||||
|
|
||||||
type ITabInternal<T> = ITab & {
|
type ITabInternal<T> = ITab & {
|
||||||
key?: string;
|
key?: string;
|
||||||
value: ITabValue<T>;
|
value: ITabValue<T>;
|
||||||
|
hasWarning?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IProps<T> = {
|
type IProps<T> = {
|
||||||
@ -100,6 +101,7 @@ export default function Tabs<T>({ onSelect, tabs: propsTabs }: IProps<T>) {
|
|||||||
value={element.value}
|
value={element.value}
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
isSelected={element.value.id === selectedTab.id}
|
isSelected={element.value.id === selectedTab.id}
|
||||||
|
hasWarning={element.hasWarning}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -112,6 +114,7 @@ export default function Tabs<T>({ onSelect, tabs: propsTabs }: IProps<T>) {
|
|||||||
value={element.value}
|
value={element.value}
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
isSelected={element.value.id === selectedTab.id}
|
isSelected={element.value.id === selectedTab.id}
|
||||||
|
hasWarning={element.hasWarning}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback } from "react";
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
|
||||||
import User from "le-coffre-resources/dist/Notary";
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
|
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
|
||||||
|
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
collaborators: User[];
|
collaborators: User[];
|
||||||
@ -14,22 +14,9 @@ type IProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function CollaboratorListContainer(props: IProps) {
|
export default function CollaboratorListContainer(props: IProps) {
|
||||||
const [filteredUsers, setFilteredUsers] = useState<User[]>(props.collaborators);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { collaboratorUid } = router.query;
|
const { collaboratorUid } = router.query;
|
||||||
const filterUsers = useCallback(
|
|
||||||
(input: string) => {
|
|
||||||
const filteredUsers = props.collaborators.filter((user) => {
|
|
||||||
return (
|
|
||||||
user.contact?.first_name?.toLowerCase().includes(input.toLowerCase()) ||
|
|
||||||
user.contact?.last_name?.toLowerCase().includes(input.toLowerCase())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
setFilteredUsers(filteredUsers);
|
|
||||||
},
|
|
||||||
[props.collaborators],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onSelectedBlock = useCallback(
|
const onSelectedBlock = useCallback(
|
||||||
(block: IBlock) => {
|
(block: IBlock) => {
|
||||||
@ -42,35 +29,16 @@ export default function CollaboratorListContainer(props: IProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<SearchBlockList
|
||||||
<div className={classes["searchbar"]}>
|
blocks={props.collaborators.map((user) => {
|
||||||
<SearchBar onChange={filterUsers} placeholder="Chercher un collaborateur" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList
|
|
||||||
blocks={filteredUsers.map((user) => {
|
|
||||||
return {
|
return {
|
||||||
name: user.contact?.first_name + " " + user.contact?.last_name,
|
primaryText: user.contact?.first_name + " " + user.contact?.last_name,
|
||||||
id: user.uid!,
|
id: user.uid!,
|
||||||
selected: user.uid === collaboratorUid,
|
isActive: user.uid === collaboratorUid,
|
||||||
rightIcon: user.seats?.some((seat) => new Date(seat.subscription!.end_date) >= new Date()) ? (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
height: "12px",
|
|
||||||
width: "12px",
|
|
||||||
borderRadius: "100px",
|
|
||||||
backgroundColor: "var(--color-success-600)",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
onSelectedBlock={onSelectedBlock}
|
onSelectedBlock={onSelectedBlock}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,12 @@
|
|||||||
import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
|
import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
|
||||||
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
|
||||||
import Button from "@Front/Components/DesignSystem/Button";
|
|
||||||
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { DeedType } from "le-coffre-resources/dist/Admin";
|
import { DeedType } from "le-coffre-resources/dist/Admin";
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback } 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 from "@Front/Components/DesignSystem/SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
deedTypes: DeedType[];
|
deedTypes: DeedType[];
|
||||||
@ -17,20 +15,9 @@ type IProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function DeedListContainer(props: IProps) {
|
export default function DeedListContainer(props: IProps) {
|
||||||
const [filteredUsers, setFilteredUsers] = useState<DeedType[]>(props.deedTypes);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { deedTypeUid } = router.query;
|
const { deedTypeUid } = router.query;
|
||||||
|
|
||||||
const filterDeeds = useCallback(
|
|
||||||
(input: string) => {
|
|
||||||
const filteredUsers = props.deedTypes.filter((deedType) => {
|
|
||||||
return deedType.name?.toLowerCase().includes(input.toLowerCase());
|
|
||||||
});
|
|
||||||
setFilteredUsers(filteredUsers);
|
|
||||||
},
|
|
||||||
[props.deedTypes],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onSelectedBlock = useCallback(
|
const onSelectedBlock = useCallback(
|
||||||
(block: IBlock) => {
|
(block: IBlock) => {
|
||||||
props.onCloseLeftSide && props.onCloseLeftSide();
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
@ -42,28 +29,20 @@ export default function DeedListContainer(props: IProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<SearchBlockList
|
||||||
<div className={classes["searchbar"]}>
|
blocks={props.deedTypes.map((deed) => {
|
||||||
<SearchBar onChange={filterDeeds} placeholder="Chercher un type d'acte" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList
|
|
||||||
blocks={filteredUsers.map((deed) => {
|
|
||||||
return {
|
return {
|
||||||
name: deed.name,
|
primaryText: deed.name,
|
||||||
id: deed.uid!,
|
id: deed.uid!,
|
||||||
selected: deedTypeUid === deed.uid,
|
isActive: deedTypeUid === deed.uid,
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
onSelectedBlock={onSelectedBlock}
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
bottomButton={{
|
||||||
|
link: Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path,
|
||||||
|
text: "Créer un type d'acte",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className={classes["create-container"]}>
|
|
||||||
<Link href={Module.getInstance().get().modules.pages.DeedTypes.pages.Create.props.path}>
|
|
||||||
<Button fullwidth={true}>Créer un type d'acte</Button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
|
||||||
import Button from "@Front/Components/DesignSystem/Button";
|
|
||||||
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { DocumentType } from "le-coffre-resources/dist/SuperAdmin";
|
import { DocumentType } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
import Link from "next/link";
|
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback } 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 from "@Front/Components/DesignSystem/SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
documentTypes: DocumentType[];
|
documentTypes: DocumentType[];
|
||||||
@ -16,19 +14,9 @@ type IProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function DocumentTypeListContainer(props: IProps) {
|
export default function DocumentTypeListContainer(props: IProps) {
|
||||||
const [filteredDocumentTypes, setFilteredDocumentTypes] = useState<DocumentType[]>(props.documentTypes);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { documentTypeUid } = router.query;
|
const { documentTypeUid } = router.query;
|
||||||
const filterDocumentTypes = useCallback(
|
|
||||||
(input: string) => {
|
|
||||||
const filteredDocumentTypes = props.documentTypes.filter((documentType) => {
|
|
||||||
return documentType.name.toLowerCase().includes(input.toLowerCase());
|
|
||||||
});
|
|
||||||
setFilteredDocumentTypes(filteredDocumentTypes);
|
|
||||||
},
|
|
||||||
[props.documentTypes],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onSelectedBlock = useCallback(
|
const onSelectedBlock = useCallback(
|
||||||
(block: IBlock) => {
|
(block: IBlock) => {
|
||||||
@ -41,28 +29,20 @@ export default function DocumentTypeListContainer(props: IProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<SearchBlockList
|
||||||
<div className={classes["searchbar"]}>
|
blocks={props.documentTypes.map((documentType) => {
|
||||||
<SearchBar onChange={filterDocumentTypes} placeholder="Chercher un document" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList
|
|
||||||
blocks={filteredDocumentTypes.map((documentType) => {
|
|
||||||
return {
|
return {
|
||||||
name: documentType.name,
|
primaryText: documentType.name,
|
||||||
id: documentType.uid!,
|
id: documentType.uid!,
|
||||||
selected: documentType.uid === documentTypeUid,
|
isActive: documentType.uid === documentTypeUid,
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
onSelectedBlock={onSelectedBlock}
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
bottomButton={{
|
||||||
|
link: Module.getInstance().get().modules.pages.DocumentTypes.pages.Create.props.path,
|
||||||
|
text: "Créer un type de document",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className={classes["create-container"]}>
|
|
||||||
<Link href={Module.getInstance().get().modules.pages.DocumentTypes.pages.Create.props.path}>
|
|
||||||
<Button fullwidth={true}>Créer un type de document</Button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
|
||||||
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { Office } from "le-coffre-resources/dist/SuperAdmin";
|
import { Office } from "le-coffre-resources/dist/SuperAdmin";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback } 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 from "@Front/Components/DesignSystem/SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
offices: Office[];
|
offices: Office[];
|
||||||
@ -14,21 +14,9 @@ type IProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function OfficeListContainer(props: IProps) {
|
export default function OfficeListContainer(props: IProps) {
|
||||||
const [filteredOffices, setFilteredOffices] = useState<Office[]>(props.offices);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { officeUid } = router.query;
|
const { officeUid } = router.query;
|
||||||
const filterOffices = useCallback(
|
|
||||||
(input: string) => {
|
|
||||||
const filteredOffices = props.offices.filter((office) => {
|
|
||||||
return (
|
|
||||||
office.name.toLowerCase().includes(input.toLowerCase()) || office.crpcen?.toLowerCase().includes(input.toLowerCase())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
setFilteredOffices(filteredOffices);
|
|
||||||
},
|
|
||||||
[props.offices],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onSelectedBlock = useCallback(
|
const onSelectedBlock = useCallback(
|
||||||
(block: IBlock) => {
|
(block: IBlock) => {
|
||||||
@ -41,23 +29,16 @@ export default function OfficeListContainer(props: IProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<SearchBlockList
|
||||||
<div className={classes["searchbar"]}>
|
blocks={props.offices.map((office) => {
|
||||||
<SearchBar onChange={filterOffices} placeholder="Chercher un office" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList
|
|
||||||
blocks={filteredOffices.map((office) => {
|
|
||||||
return {
|
return {
|
||||||
name: office.crpcen + " - " + office.name,
|
primaryText: office.crpcen + " - " + office.name,
|
||||||
id: office.uid!,
|
id: office.uid!,
|
||||||
selected: office.uid === officeUid,
|
isActive: office.uid === officeUid,
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
onSelectedBlock={onSelectedBlock}
|
onSelectedBlock={onSelectedBlock}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,11 @@
|
|||||||
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
|
||||||
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { OfficeRole } from "le-coffre-resources/dist/Admin";
|
import { OfficeRole } from "le-coffre-resources/dist/Admin";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback } from "react";
|
||||||
|
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import Link from "next/link";
|
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
|
||||||
import Button from "@Front/Components/DesignSystem/Button";
|
import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
roles: OfficeRole[];
|
roles: OfficeRole[];
|
||||||
@ -16,21 +14,10 @@ type IProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function RoleListContainer(props: IProps) {
|
export default function RoleListContainer(props: IProps) {
|
||||||
const [filteredRoles, setFilteredRoles] = useState<OfficeRole[]>(props.roles);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { roleUid } = router.query;
|
const { roleUid } = router.query;
|
||||||
|
|
||||||
const filterRoles = useCallback(
|
|
||||||
(input: string) => {
|
|
||||||
const filteredRoles = props.roles.filter((role) => {
|
|
||||||
return role.name?.toLowerCase().includes(input.toLowerCase());
|
|
||||||
});
|
|
||||||
setFilteredRoles(filteredRoles);
|
|
||||||
},
|
|
||||||
[props.roles],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onSelectedBlock = useCallback(
|
const onSelectedBlock = useCallback(
|
||||||
(block: IBlock) => {
|
(block: IBlock) => {
|
||||||
props.onCloseLeftSide && props.onCloseLeftSide();
|
props.onCloseLeftSide && props.onCloseLeftSide();
|
||||||
@ -42,33 +29,25 @@ export default function RoleListContainer(props: IProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<SearchBlockList
|
||||||
<div className={classes["searchbar"]}>
|
blocks={props.roles
|
||||||
<SearchBar onChange={filterRoles} placeholder="Chercher un rôle" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList
|
|
||||||
blocks={filteredRoles
|
|
||||||
.filter((role) => {
|
.filter((role) => {
|
||||||
if (role.name === "admin") return false;
|
if (role.name === "admin") return false;
|
||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.map((role) => {
|
.map((role) => {
|
||||||
return {
|
return {
|
||||||
name: role.name,
|
primaryText: role.name,
|
||||||
id: role.uid!,
|
id: role.uid!,
|
||||||
selected: role.uid === roleUid,
|
isActive: role.uid === roleUid,
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
onSelectedBlock={onSelectedBlock}
|
onSelectedBlock={onSelectedBlock}
|
||||||
|
bottomButton={{
|
||||||
|
link: Module.getInstance().get().modules.pages.Roles.pages.Create.props.path,
|
||||||
|
text: "Créer un rôle",
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className={classes["create-container"]}>
|
|
||||||
<Link href={Module.getInstance().get().modules.pages.Roles.pages.Create.props.path}>
|
|
||||||
<Button fullwidth={true}>Créer un rôle</Button>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
|
||||||
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
|
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import User from "le-coffre-resources/dist/Notary";
|
import User from "le-coffre-resources/dist/Notary";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import React, { useCallback, useState } from "react";
|
import React, { useCallback } 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 from "@Front/Components/DesignSystem/SearchBlockList";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
users: User[];
|
users: User[];
|
||||||
@ -14,22 +14,9 @@ type IProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function UserListContainer(props: IProps) {
|
export default function UserListContainer(props: IProps) {
|
||||||
const [filteredUsers, setFilteredUsers] = useState<User[]>(props.users);
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const { userUid } = router.query;
|
const { userUid } = router.query;
|
||||||
const filterUsers = useCallback(
|
|
||||||
(input: string) => {
|
|
||||||
const filteredUsers = props.users.filter((user) => {
|
|
||||||
return (
|
|
||||||
user.contact?.first_name?.toLowerCase().includes(input.toLowerCase()) ||
|
|
||||||
user.contact?.last_name?.toLowerCase().includes(input.toLowerCase())
|
|
||||||
);
|
|
||||||
});
|
|
||||||
setFilteredUsers(filteredUsers);
|
|
||||||
},
|
|
||||||
[props.users],
|
|
||||||
);
|
|
||||||
|
|
||||||
const onSelectedBlock = useCallback(
|
const onSelectedBlock = useCallback(
|
||||||
(block: IBlock) => {
|
(block: IBlock) => {
|
||||||
@ -42,23 +29,16 @@ export default function UserListContainer(props: IProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<div className={classes["header"]}>
|
<SearchBlockList
|
||||||
<div className={classes["searchbar"]}>
|
blocks={props.users.map((user) => {
|
||||||
<SearchBar onChange={filterUsers} placeholder="Chercher un utilisateur" />
|
|
||||||
</div>
|
|
||||||
<div className={classes["folderlist-container"]}>
|
|
||||||
<BlockList
|
|
||||||
blocks={filteredUsers.map((user) => {
|
|
||||||
return {
|
return {
|
||||||
name: user.contact?.first_name + " " + user.contact?.last_name,
|
primaryText: user.contact?.first_name + " " + user.contact?.last_name,
|
||||||
id: user.uid!,
|
id: user.uid!,
|
||||||
selected: user.uid === userUid,
|
isActive: user.uid === userUid,
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
onSelectedBlock={onSelectedBlock}
|
onSelectedBlock={onSelectedBlock}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import NumberPicker from "@Front/Components/Elements/NumberPicker";
|
|||||||
import Tabs from "@Front/Components/Elements/Tabs";
|
import Tabs from "@Front/Components/Elements/Tabs";
|
||||||
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
|
||||||
import useOpenable from "@Front/Hooks/useOpenable";
|
import useOpenable from "@Front/Hooks/useOpenable";
|
||||||
|
import Footer from "@Front/Components/DesignSystem/Footer";
|
||||||
import {
|
import {
|
||||||
ArchiveBoxIcon,
|
ArchiveBoxIcon,
|
||||||
ArrowLongLeftIcon,
|
ArrowLongLeftIcon,
|
||||||
@ -797,6 +798,7 @@ export default function DesignSystem() {
|
|||||||
variant={EAlertVariant.NEUTRAL}
|
variant={EAlertVariant.NEUTRAL}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<Footer />
|
||||||
</div>
|
</div>
|
||||||
</DefaultTemplate>
|
</DefaultTemplate>
|
||||||
);
|
);
|
||||||
|
@ -24,7 +24,7 @@ export default function DeleteCustomerModal(props: IProps) {
|
|||||||
title={"Êtes-vous sûr de vouloir supprimer ce client du dossier ?"}
|
title={"Êtes-vous sûr de vouloir supprimer ce client du dossier ?"}
|
||||||
firstButton={{ children: "Annuler", onClick: onClose }}
|
firstButton={{ children: "Annuler", onClick: onClose }}
|
||||||
secondButton={{ children: "Supprimer le client", onClick: handleDelete }}>
|
secondButton={{ children: "Supprimer le client", onClick: handleDelete }}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
Cette action retirera le client de ce dossier. Vous ne pourrez plus récupérer les informations associées à ce client dans ce
|
Cette action retirera le client de ce dossier. Vous ne pourrez plus récupérer les informations associées à ce client dans ce
|
||||||
dossier une fois supprimées.
|
dossier une fois supprimées.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -131,7 +131,7 @@ export default function ClientBox(props: IProps) {
|
|||||||
onClose={closeErrorModal}
|
onClose={closeErrorModal}
|
||||||
title={"Suppression impossible"}
|
title={"Suppression impossible"}
|
||||||
secondButton={{ children: "Fermer", onClick: closeErrorModal, fullwidth: true }}>
|
secondButton={{ children: "Fermer", onClick: closeErrorModal, fullwidth: true }}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
Ce client ne peut pas être supprimé car des documents sont associés à son dossier. Veuillez d'abord gérer ou supprimer
|
Ce client ne peut pas être supprimé car des documents sont associés à son dossier. Veuillez d'abord gérer ou supprimer
|
||||||
ces documents avant de tenter de supprimer le client.
|
ces documents avant de tenter de supprimer le client.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -31,7 +31,7 @@ export default function DeleteAskedDocumentModal(props: IProps) {
|
|||||||
title={"Êtes-vous sûr de vouloir supprimer cette demande de document ?"}
|
title={"Êtes-vous sûr de vouloir supprimer cette demande de document ?"}
|
||||||
firstButton={{ children: "Annuler", onClick: onClose }}
|
firstButton={{ children: "Annuler", onClick: onClose }}
|
||||||
secondButton={{ children: "Supprimer la demande", onClick: onDelete }}>
|
secondButton={{ children: "Supprimer la demande", onClick: onDelete }}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>Cette action annulera la demande du document en cours.</Typography>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>Cette action annulera la demande du document en cours.</Typography>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ import Link from "next/link";
|
|||||||
import NoDocument from "./NoDocument";
|
import NoDocument from "./NoDocument";
|
||||||
import DocumentTables from "./DocumentTables";
|
import DocumentTables from "./DocumentTables";
|
||||||
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
|
||||||
|
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
folder: OfficeFolder;
|
folder: OfficeFolder;
|
||||||
@ -42,6 +43,9 @@ export default function ClientView(props: IProps) {
|
|||||||
label: `${customer.contact?.first_name} ${customer.contact?.last_name}`,
|
label: `${customer.contact?.first_name} ${customer.contact?.last_name}`,
|
||||||
key: customer.uid,
|
key: customer.uid,
|
||||||
value: customer,
|
value: customer,
|
||||||
|
hasWarning:
|
||||||
|
customer.documents &&
|
||||||
|
customer.documents.filter((document) => document.document_status === EDocumentStatus.DEPOSITED).length > 0,
|
||||||
})),
|
})),
|
||||||
[customers],
|
[customers],
|
||||||
);
|
);
|
||||||
|
@ -34,7 +34,7 @@ export default function DeleteFolderModal(props: IProps) {
|
|||||||
title={"Êtes-vous sûr de vouloir supprimer ce dossier ?"}
|
title={"Êtes-vous sûr de vouloir supprimer ce dossier ?"}
|
||||||
firstButton={{ children: "Annuler", onClick: onClose }}
|
firstButton={{ children: "Annuler", onClick: onClose }}
|
||||||
secondButton={{ children: "Supprimer le dossier", onClick: onDelete }}>
|
secondButton={{ children: "Supprimer le dossier", onClick: onDelete }}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
Cette action est irréversible. En supprimant ce dossier, toutes les informations associées seront définitivement perdues.
|
Cette action est irréversible. En supprimant ce dossier, toutes les informations associées seront définitivement perdues.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
@ -44,13 +44,13 @@ export default function AnchoringModal(props: IProps) {
|
|||||||
firstButton={!isAnchoring ? { children: "Non, Annuler", onClick: onClose } : undefined}
|
firstButton={!isAnchoring ? { children: "Non, Annuler", onClick: onClose } : undefined}
|
||||||
secondButton={!isAnchoring ? { children: "Oui, certifier et ancrer", onClick: anchor } : undefined}>
|
secondButton={!isAnchoring ? { children: "Oui, certifier et ancrer", onClick: anchor } : undefined}>
|
||||||
{!isAnchoring ? (
|
{!isAnchoring ? (
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
La certification et l'ancrage de ce dossier dans la blockchain sont des actions définitives et garantiront la sécurité
|
La certification et l'ancrage de ce dossier dans la blockchain sont des actions définitives et garantiront la sécurité
|
||||||
et l'authenticité de tous les documents. Veuillez confirmer que vous souhaitez continuer.
|
et l'authenticité de tous les documents. Veuillez confirmer que vous souhaitez continuer.
|
||||||
</Typography>
|
</Typography>
|
||||||
) : (
|
) : (
|
||||||
<div className={classes["anchoring"]}>
|
<div className={classes["anchoring"]}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
Vos documents sont en train d'être ancrés dans la blockchain. Cela peut prendre quelques instants. Merci de votre
|
Vos documents sont en train d'être ancrés dans la blockchain. Cela peut prendre quelques instants. Merci de votre
|
||||||
patience.
|
patience.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -37,7 +37,7 @@ export default function ArchiveModal(props: IProps) {
|
|||||||
firstButton={{ children: "Annuler", onClick: onClose }}
|
firstButton={{ children: "Annuler", onClick: onClose }}
|
||||||
secondButton={{ children: "Archiver le dossier", onClick: archive }}>
|
secondButton={{ children: "Archiver le dossier", onClick: archive }}>
|
||||||
<div className={classes["root"]}>
|
<div className={classes["root"]}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
Archiver ce dossier le déplacera dans la section des dossiers archivés. Vous pouvez ajouter une note de dossier avant
|
Archiver ce dossier le déplacera dans la section des dossiers archivés. Vous pouvez ajouter une note de dossier avant
|
||||||
d'archiver si vous le souhaitez.
|
d'archiver si vous le souhaitez.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -38,7 +38,7 @@ export default function DownloadAnchoringProofModal(props: IProps) {
|
|||||||
title={"Félicitations ! Dossier ancré avec succès"}
|
title={"Félicitations ! Dossier ancré avec succès"}
|
||||||
firstButton={{ children: "Fermer", onClick: onClose }}
|
firstButton={{ children: "Fermer", onClick: onClose }}
|
||||||
secondButton={{ children: "Télécharger la preuve d’ancrage", onClick: downloadAnchoringProof }}>
|
secondButton={{ children: "Télécharger la preuve d’ancrage", onClick: downloadAnchoringProof }}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
Votre dossier a été validé et ancré dans la blockchain. Vous pouvez maintenant télécharger la preuve d'ancrage pour vos
|
Votre dossier a été validé et ancré dans la blockchain. Vous pouvez maintenant télécharger la preuve d'ancrage pour vos
|
||||||
archives.
|
archives.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -23,7 +23,7 @@ export default function RequireAnchoringModal(props: IProps) {
|
|||||||
title={"Archiver le dossier, action requise : Ancrer et certifier le dossier"}
|
title={"Archiver le dossier, action requise : Ancrer et certifier le dossier"}
|
||||||
firstButton={{ children: "Annuler", onClick: onClose }}
|
firstButton={{ children: "Annuler", onClick: onClose }}
|
||||||
secondButton={{ children: "Ancrer le dossier", onClick: onAnchor }}>
|
secondButton={{ children: "Ancrer le dossier", onClick: onAnchor }}>
|
||||||
<Typography typo={ETypo.TEXT_MD_light}>
|
<Typography typo={ETypo.TEXT_MD_LIGHT}>
|
||||||
Pour archiver ce dossier, il est nécessaire de l'ancrer dans la blockchain afin de garantir la sécurité et l'authenticité
|
Pour archiver ce dossier, il est nécessaire de l'ancrer dans la blockchain afin de garantir la sécurité et l'authenticité
|
||||||
des documents. Veuillez procéder à l'ancrage avant de continuer.
|
des documents. Veuillez procéder à l'ancrage avant de continuer.
|
||||||
</Typography>
|
</Typography>
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders";
|
import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders";
|
||||||
import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList";
|
|
||||||
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
|
||||||
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
|
||||||
import JwtService from "@Front/Services/JwtService/JwtService";
|
import JwtService from "@Front/Services/JwtService/JwtService";
|
||||||
@ -9,6 +8,8 @@ import { useCallback, useEffect, useState } from "react";
|
|||||||
|
|
||||||
import LandingImage from "../Login/landing-connect.jpeg";
|
import LandingImage from "../Login/landing-connect.jpeg";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block";
|
||||||
|
import BlockList from "@Front/Components/DesignSystem/SearchBlockList/BlockList";
|
||||||
|
|
||||||
export default function SelectFolder() {
|
export default function SelectFolder() {
|
||||||
const [folders, setFolders] = useState<OfficeFolder[]>([]);
|
const [folders, setFolders] = useState<OfficeFolder[]>([]);
|
||||||
@ -66,7 +67,7 @@ export default function SelectFolder() {
|
|||||||
blocks={folders.map((folder) => {
|
blocks={folders.map((folder) => {
|
||||||
return {
|
return {
|
||||||
id: folder.uid!,
|
id: folder.uid!,
|
||||||
name: folder.name!,
|
primaryText: folder.name!,
|
||||||
selected: false,
|
selected: false,
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
|
@ -3,7 +3,7 @@ $screen-l: 1439px;
|
|||||||
$screen-ls: 1280px;
|
$screen-ls: 1280px;
|
||||||
$screen-m: 1023px;
|
$screen-m: 1023px;
|
||||||
$screen-s: 767px;
|
$screen-s: 767px;
|
||||||
// $screen-xs: 424px;
|
$screen-xs: 424px;
|
||||||
|
|
||||||
$custom-easing: cubic-bezier(0.645, 0.045, 0.355, 1);
|
$custom-easing: cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
@import "@Themes/constants.scss";
|
|
||||||
@import "@Themes/fonts.scss";
|
@import "@Themes/fonts.scss";
|
||||||
|
@import "@Themes/constants.scss";
|
||||||
@import "@Themes/variables.scss";
|
@import "@Themes/variables.scss";
|
||||||
|
|
||||||
* {
|
* {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
import "@Front/index.scss";
|
||||||
import { DefaultLayout } from "@Front/Components/LayoutTemplates/DefaultLayout";
|
import { DefaultLayout } from "@Front/Components/LayoutTemplates/DefaultLayout";
|
||||||
import { FrontendVariables } from "@Front/Config/VariablesFront";
|
import { FrontendVariables } from "@Front/Config/VariablesFront";
|
||||||
import "@Front/index.scss";
|
|
||||||
import type { NextPage } from "next";
|
import type { NextPage } from "next";
|
||||||
import type { AppType, AppProps } from "next/app";
|
import type { AppType, AppProps } from "next/app";
|
||||||
import { useEffect, type ReactElement, type ReactNode } from "react";
|
import { useEffect, type ReactElement, type ReactNode } from "react";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user