diff --git a/src/front/Components/DesignSystem/Alert/index.tsx b/src/front/Components/DesignSystem/Alert/index.tsx index a00022bc..64d70a5c 100644 --- a/src/front/Components/DesignSystem/Alert/index.tsx +++ b/src/front/Components/DesignSystem/Alert/index.tsx @@ -49,7 +49,7 @@ export default function Alert(props: IProps) { {title} - + {description} diff --git a/src/front/Components/DesignSystem/BlockList/index.tsx b/src/front/Components/DesignSystem/BlockList/index.tsx deleted file mode 100644 index e733a3ac..00000000 --- a/src/front/Components/DesignSystem/BlockList/index.tsx +++ /dev/null @@ -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) => { - onSelectedBlock && onSelectedBlock(blocks.find((folder) => folder.id === e.currentTarget.id)!); - }, - [blocks, onSelectedBlock], - ); - - return ( -
- {blocks.map((folder) => { - return ( -
-
-
- {folder.name} -
-
- {folder.hasFlag && } - {folder.rightIcon} - chevron -
-
-
- ); - })} -
- ); -} diff --git a/src/front/Components/DesignSystem/FolderArchivedListContainer/index.tsx b/src/front/Components/DesignSystem/FolderArchivedListContainer/index.tsx index 19797c52..30f9824b 100644 --- a/src/front/Components/DesignSystem/FolderArchivedListContainer/index.tsx +++ b/src/front/Components/DesignSystem/FolderArchivedListContainer/index.tsx @@ -1,16 +1,12 @@ import Module from "@Front/Config/Module"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document"; -import Link from "next/link"; import { NextRouter, useRouter } from "next/router"; import React from "react"; -import BlockList, { IBlock } from "../BlockList"; -import Button from "../Button"; -import SearchBar from "../SearchBar"; import classes from "./classes.module.scss"; -import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; -import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule"; +import { IBlock } from "../SearchBlockList/BlockList/Block"; +import SearchBlockList from "../SearchBlockList"; type IProps = { folders: OfficeFolder[]; @@ -44,33 +40,9 @@ class FolderArchivedListContainerClass extends React.Component -
-
- -
-
- -
-
- {!this.props.isArchived && ( -
- - - - - -
- )} + ); } @@ -106,9 +78,10 @@ class FolderArchivedListContainerClass extends React.Component { return { id: folder.uid!, - name: folder.folder_number! + " - " + folder.name!, - selected: this.props.selectedFolder === folder.uid, - hasFlag: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED), + primaryText: folder.name, + isActive: this.props.selectedFolder === folder.uid, + secondaryText: folder.folder_number, + showAlert: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED), }; }); } diff --git a/src/front/Components/DesignSystem/FolderListContainer/index.tsx b/src/front/Components/DesignSystem/FolderListContainer/index.tsx index 0ac30339..53df5b74 100644 --- a/src/front/Components/DesignSystem/FolderListContainer/index.tsx +++ b/src/front/Components/DesignSystem/FolderListContainer/index.tsx @@ -1,16 +1,12 @@ import Module from "@Front/Config/Module"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document"; -import Link from "next/link"; -import { NextRouter, useRouter } from "next/router"; -import React from "react"; +import { useRouter } from "next/router"; +import React, { useCallback, useEffect } from "react"; -import BlockList, { IBlock } from "../BlockList"; -import Button from "../Button"; -import SearchBar from "../SearchBar"; import classes from "./classes.module.scss"; -import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; -import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule"; +import { IBlock } from "../SearchBlockList/BlockList/Block"; +import SearchBlockList from "../SearchBlockList"; type IProps = { folders: OfficeFolder[]; @@ -19,132 +15,77 @@ type IProps = { onCloseLeftSide?: () => void; }; -type IPropsClass = IProps & { - router: NextRouter; - selectedFolder: string; -}; - -type IState = { - filteredFolders: OfficeFolder[]; - blocks: IBlock[]; -}; - -class FolderListContainerClass extends React.Component { - 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.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 navigatePath = Module.getInstance().get().modules.pages.Folder.pages.CreateFolder.props.path; - return ( -
-
-
- -
-
- -
-
- {!this.props.isArchived && ( -
- - - - - -
- )} -
- ); - } - - public override componentDidUpdate(prevProps: Readonly, prevState: Readonly, 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 - .filter((folder) => { - const pendingDocuments = (folder.documents ?? []).filter( - (document) => document.document_status === EDocumentStatus.DEPOSITED, - ); - return pendingDocuments.length >= 1; - }) - .sort((folder1, folder2) => { - return folder1.created_at! > folder2.created_at! ? -1 : 1; - }); - - const otherFolders = folders - .filter((folder) => { - const pendingDocuments = (folder.documents ?? []).filter( - (document) => document.document_status === EDocumentStatus.DEPOSITED, - ); - return pendingDocuments.length === 0; - }) - .sort((folder1, folder2) => { - return folder1.created_at! > folder2.created_at! ? -1 : 1; - }); - - return [...pendingFolders, ...otherFolders].map((folder) => { - return { - id: folder.uid!, - name: folder.folder_number! + " - " + folder.name!, - selected: this.props.selectedFolder === folder.uid, - hasFlag: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED), - }; - }); - } - - private onSelectedFolder(block: IBlock) { - const folder = this.props.folders.find((folder) => folder.uid === block.id); - if (!folder) return; - this.props.onSelectedFolder && this.props.onSelectedFolder(folder); - const path = this.redirectPath.replace("[folderUid]", folder.uid ?? ""); - this.props.router.push(path); - } - - private filterFolders(value: string): void { - const filteredFolders: OfficeFolder[] = this.props.folders.filter((folder) => { - const name = folder.name.toLowerCase(); - 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 name.includes(value) || number.includes(value); - }); - - this.setState({ filteredFolders, blocks: this.getBlocks(filteredFolders) }); - } -} - export default function FolderListContainer(props: IProps) { const router = useRouter(); const { folderUid } = router.query; - return ; + const { folders, isArchived } = props; + + const redirectPath: string = isArchived + ? Module.getInstance().get().modules.pages.Folder.pages.FolderArchived.pages.FolderInformation.props.path + : Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path; + + const getBlocks = useCallback( + (folders: OfficeFolder[]): IBlock[] => { + const pendingFolders = folders + .filter((folder) => { + const pendingDocuments = (folder.documents ?? []).filter( + (document) => document.document_status === EDocumentStatus.DEPOSITED, + ); + return pendingDocuments.length >= 1; + }) + .sort((folder1, folder2) => { + return folder1.created_at! > folder2.created_at! ? -1 : 1; + }); + + const otherFolders = folders + .filter((folder) => { + const pendingDocuments = (folder.documents ?? []).filter( + (document) => document.document_status === EDocumentStatus.DEPOSITED, + ); + return pendingDocuments.length === 0; + }) + .sort((folder1, folder2) => { + return folder1.created_at! > folder2.created_at! ? -1 : 1; + }); + + return [...pendingFolders, ...otherFolders].map((folder) => { + return { + id: folder.uid!, + primaryText: folder.name, + secondaryText: folder.folder_number, + isActive: folderUid === folder.uid, + showAlert: folder.documents?.some((document) => document.document_status === EDocumentStatus.DEPOSITED), + }; + }); + }, + [folderUid], + ); + + const [blocks, setBlocks] = React.useState(getBlocks(folders)); + + const onSelectedFolder = (block: IBlock) => { + props.onCloseLeftSide && props.onCloseLeftSide(); + const folder = folders.find((folder) => folder.uid === block.id); + if (!folder) return; + props.onSelectedFolder && props.onSelectedFolder(folder); + const path = redirectPath.replace("[folderUid]", folder.uid ?? ""); + router.push(path); + }; + + useEffect(() => { + setBlocks(getBlocks(folders)); + }, [folders, getBlocks]); + + return ( +
+ +
+ ); } diff --git a/src/front/Components/DesignSystem/Footer/classes.module.scss b/src/front/Components/DesignSystem/Footer/classes.module.scss new file mode 100644 index 00000000..f9a12433 --- /dev/null +++ b/src/front/Components/DesignSystem/Footer/classes.module.scss @@ -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: "|"; + } + } +} diff --git a/src/front/Components/DesignSystem/Footer/desktop.tsx b/src/front/Components/DesignSystem/Footer/desktop.tsx new file mode 100644 index 00000000..d0eb1772 --- /dev/null +++ b/src/front/Components/DesignSystem/Footer/desktop.tsx @@ -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 ( + + ); +} diff --git a/src/front/Components/DesignSystem/Footer/index.tsx b/src/front/Components/DesignSystem/Footer/index.tsx new file mode 100644 index 00000000..8867ec7f --- /dev/null +++ b/src/front/Components/DesignSystem/Footer/index.tsx @@ -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 ( +
+ + + +
+ ); +} diff --git a/src/front/Components/DesignSystem/Footer/mobile.tsx b/src/front/Components/DesignSystem/Footer/mobile.tsx new file mode 100644 index 00000000..12f962bd --- /dev/null +++ b/src/front/Components/DesignSystem/Footer/mobile.tsx @@ -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 ( +
+ © Lecoffre 2024 + + Juridiques + + Cookies +
+ ); +} diff --git a/src/front/Components/DesignSystem/Footer/tablet.tsx b/src/front/Components/DesignSystem/Footer/tablet.tsx new file mode 100644 index 00000000..adec78f9 --- /dev/null +++ b/src/front/Components/DesignSystem/Footer/tablet.tsx @@ -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 ( + + ); +} diff --git a/src/front/Components/DesignSystem/SearchBar/classes.module.scss b/src/front/Components/DesignSystem/SearchBar/classes.module.scss index 326e7950..bfb3e58c 100644 --- a/src/front/Components/DesignSystem/SearchBar/classes.module.scss +++ b/src/front/Components/DesignSystem/SearchBar/classes.module.scss @@ -2,30 +2,67 @@ .root { display: flex; - align-items: center; - padding-left: 24px; - background-color: var(--color-generic-white); - border: 1px solid var(--color-neutral-200); - position: relative; + padding: var(--spacing-2, 16px) var(--spacing-sm, 8px); + align-items: flex-start; + gap: var(--spacing-2, 16px); - .fake-placeholder { - position: absolute; - left: 47px; - top: 24px; - color: var(--color-neutral-500); - pointer-events: none; + border-radius: var(--input-radius, 0px); + border: 1px solid var(--input-main-border-default, #d7dce0); + background: var(--input-background, #fff); + + &:hover { + border-radius: var(--input-radius, 0px); + border: 1px solid var(--input-main-border-hovered, #b4bec5); + background: var(--input-background, #fff); } - .input { - border: 0; - margin-left: 8px; - padding: 24px 0; - width: 100%; - font-family: "Inter", sans-serif; - font-style: normal; - font-weight: 400; - font-size: 18px; - line-height: 22px; - color: var(--color-neutral-500); + &[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 { + flex: 1; + border: none; + + color: var(--input-placeholder-filled, #24282e); + + /* text/md/semibold */ + font-family: var(--font-text-family, Poppins); + font-size: 16px; + font-style: normal; + font-weight: var(--font-text-weight-semibold, 600); + line-height: normal; + letter-spacing: 0.08px; + 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; + } } } diff --git a/src/front/Components/DesignSystem/SearchBar/index.tsx b/src/front/Components/DesignSystem/SearchBar/index.tsx index 8c16ee0c..57a7af19 100644 --- a/src/front/Components/DesignSystem/SearchBar/index.tsx +++ b/src/front/Components/DesignSystem/SearchBar/index.tsx @@ -1,54 +1,45 @@ -import LoopIcon from "@Assets/Icons/loop.svg"; -import Image from "next/image"; -import React from "react"; +import React, { useCallback } from "react"; -import Typography, { ETypo, ETypoColor } from "../Typography"; import classes from "./classes.module.scss"; +import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline"; type IProps = { onChange?: (input: string) => void; placeholder?: string; }; -type IState = { - hasValue: boolean; -}; +export default function SearchBar({ onChange, placeholder = "Rechercher" }: IProps) { + const [isFocused, setIsFocused] = React.useState(false); + const [value, setValue] = React.useState(""); -export default class SearchBar extends React.Component { - static defaultProps = { - placeholder: "Search", - }; + const changeValue = useCallback( + (value: string) => { + setValue(value); + onChange && onChange(value); + }, + [onChange], + ); - 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 ( -
- Loop icon - {!this.state.hasValue && ( - -
{this.props.placeholder}
-
- )} - + const handleOnChange = (event: React.ChangeEvent) => changeValue(event.target.value); + const handleFocus = () => setIsFocused(true); + const handleBlur = () => setIsFocused(false); + const clearValue = () => changeValue(""); + + return ( + + ); } diff --git a/src/front/Components/DesignSystem/SearchBlockList/BlockList/Block/classes.module.scss b/src/front/Components/DesignSystem/SearchBlockList/BlockList/Block/classes.module.scss new file mode 100644 index 00000000..f775beaf --- /dev/null +++ b/src/front/Components/DesignSystem/SearchBlockList/BlockList/Block/classes.module.scss @@ -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); + } +} diff --git a/src/front/Components/DesignSystem/SearchBlockList/BlockList/Block/index.tsx b/src/front/Components/DesignSystem/SearchBlockList/BlockList/Block/index.tsx new file mode 100644 index 00000000..19ec5787 --- /dev/null +++ b/src/front/Components/DesignSystem/SearchBlockList/BlockList/Block/index.tsx @@ -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 ( +
+
+
+ + {secondaryText} + + + {primaryText} + +
+ {showAlert && ( + + )} + +
+ {hasSeparator &&
} +
+ ); +} diff --git a/src/front/Components/DesignSystem/BlockList/classes.module.scss b/src/front/Components/DesignSystem/SearchBlockList/BlockList/classes.module.scss similarity index 100% rename from src/front/Components/DesignSystem/BlockList/classes.module.scss rename to src/front/Components/DesignSystem/SearchBlockList/BlockList/classes.module.scss diff --git a/src/front/Components/DesignSystem/SearchBlockList/BlockList/index.tsx b/src/front/Components/DesignSystem/SearchBlockList/BlockList/index.tsx new file mode 100644 index 00000000..ef103838 --- /dev/null +++ b/src/front/Components/DesignSystem/SearchBlockList/BlockList/index.tsx @@ -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 ( +
+ {blocks.map((block) => { + return ; + })} +
+ ); +} diff --git a/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss b/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss new file mode 100644 index 00000000..e7bcaa27 --- /dev/null +++ b/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss @@ -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; + } +} diff --git a/src/front/Components/DesignSystem/SearchBlockList/index.tsx b/src/front/Components/DesignSystem/SearchBlockList/index.tsx new file mode 100644 index 00000000..3dd43a52 --- /dev/null +++ b/src/front/Components/DesignSystem/SearchBlockList/index.tsx @@ -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(blocks); + const bottomButtonRef = useRef(null); + const searchBarRef = useRef(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 ( +
+
+ +
+
+ +
+ {bottomButton && ( +
+ +
+ )} +
+ ); +} diff --git a/src/front/Components/DesignSystem/Typography/index.tsx b/src/front/Components/DesignSystem/Typography/index.tsx index 8c5e87b1..fd0d019f 100644 --- a/src/front/Components/DesignSystem/Typography/index.tsx +++ b/src/front/Components/DesignSystem/Typography/index.tsx @@ -28,25 +28,25 @@ export enum ETypo { TEXT_LG_SEMIBOLD = "text-lg-semibold", TEXT_LG_REGULAR = "text-lg-regular", 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_SEMIBOLD = "text-md-semibold", TEXT_MD_REGULAR = "text-md-regular", 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_SEMIBOLD = "text-sm-semibold", TEXT_SM_REGULAR = "text-sm-regular", 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_SEMIBOLD = "text-xs-semibold", TEXT_XS_REGULAR = "text-xs-regular", TEXT_XS_UPPERCASE = "text-xs-uppercase", - TEXT_XS_light = "text-xs-light", + TEXT_XS_LIGHT = "text-xs-light", CAPTION_BOLD = "caption-bold", CAPTION_SEMIBOLD = "caption-semibold", @@ -153,6 +153,8 @@ export enum ETypoColor { CONTRAST_DEFAULT = "--contrast-default", CONTRAST_HOVERED = "--contrast-hovered", 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) { diff --git a/src/front/Components/Elements/Tabs/HorizontalTab/classes.module.scss b/src/front/Components/Elements/Tabs/HorizontalTab/classes.module.scss index cfbbe33c..871a4a8a 100644 --- a/src/front/Components/Elements/Tabs/HorizontalTab/classes.module.scss +++ b/src/front/Components/Elements/Tabs/HorizontalTab/classes.module.scss @@ -6,6 +6,9 @@ border-bottom: 1px solid var(--tabs-stroke, #d7dce0); cursor: pointer; + display: flex; + align-items: center; + gap: var(--spacing-1-5, 12px); &[data-is-selected="true"] { border-bottom: 2px solid var(--tabs-contrast-actived, #24282e); } diff --git a/src/front/Components/Elements/Tabs/HorizontalTab/index.tsx b/src/front/Components/Elements/Tabs/HorizontalTab/index.tsx index 990e6238..0f6cced0 100644 --- a/src/front/Components/Elements/Tabs/HorizontalTab/index.tsx +++ b/src/front/Components/Elements/Tabs/HorizontalTab/index.tsx @@ -3,6 +3,7 @@ import classes from "./classes.module.scss"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import useHoverable from "@Front/Hooks/useHoverable"; import { ITabValue } from ".."; +import { ExclamationCircleIcon } from "@heroicons/react/24/outline"; export type ITab = { label: React.ReactNode; }; @@ -11,6 +12,7 @@ export type IProps = { onSelect: (value: ITabValue) => void; value: ITabValue; isSelected: boolean; + hasWarning?: boolean; } & ITab; export default function HorizontalTabs(props: IProps) { @@ -29,6 +31,7 @@ export default function HorizontalTabs(props: IProps) { color={!isHovered && !props.isSelected ? ETypoColor.TABS_CONTRAST_DEFAULT : ETypoColor.TABS_CONTRAST_ACTIVATED}> {props.label} + {props.hasWarning && }
); } diff --git a/src/front/Components/Elements/Tabs/index.tsx b/src/front/Components/Elements/Tabs/index.tsx index 7906b750..c90dbc36 100644 --- a/src/front/Components/Elements/Tabs/index.tsx +++ b/src/front/Components/Elements/Tabs/index.tsx @@ -8,11 +8,12 @@ import useOpenable from "@Front/Hooks/useOpenable"; export type ITabValue = T & { id: unknown; -} +}; type ITabInternal = ITab & { key?: string; value: ITabValue; + hasWarning?: boolean; }; type IProps = { @@ -100,6 +101,7 @@ export default function Tabs({ onSelect, tabs: propsTabs }: IProps) { value={element.value} onSelect={handleSelect} isSelected={element.value.id === selectedTab.id} + hasWarning={element.hasWarning} /> ))}
@@ -112,6 +114,7 @@ export default function Tabs({ onSelect, tabs: propsTabs }: IProps) { value={element.value} onSelect={handleSelect} isSelected={element.value.id === selectedTab.id} + hasWarning={element.hasWarning} /> ))} diff --git a/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/CollaboratorListContainer/index.tsx b/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/CollaboratorListContainer/index.tsx index 792c377e..eee22e10 100644 --- a/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/CollaboratorListContainer/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/CollaboratorListContainer/index.tsx @@ -1,11 +1,11 @@ -import React, { useCallback, useState } from "react"; +import React, { useCallback } from "react"; import classes from "./classes.module.scss"; -import SearchBar from "@Front/Components/DesignSystem/SearchBar"; import User from "le-coffre-resources/dist/Notary"; -import BlockList, { IBlock } from "@Front/Components/DesignSystem/BlockList"; 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[]; @@ -14,22 +14,9 @@ type IProps = { }; export default function CollaboratorListContainer(props: IProps) { - const [filteredUsers, setFilteredUsers] = useState(props.collaborators); const router = useRouter(); 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( (block: IBlock) => { @@ -42,35 +29,16 @@ export default function CollaboratorListContainer(props: IProps) { return (
-
-
- -
-
- { - return { - name: user.contact?.first_name + " " + user.contact?.last_name, - id: user.uid!, - selected: user.uid === collaboratorUid, - rightIcon: user.seats?.some((seat) => new Date(seat.subscription!.end_date) >= new Date()) ? ( -
- ) : ( - <> - ), - }; - })} - onSelectedBlock={onSelectedBlock} - /> -
-
+ { + return { + primaryText: user.contact?.first_name + " " + user.contact?.last_name, + id: user.uid!, + isActive: user.uid === collaboratorUid, + }; + })} + onSelectedBlock={onSelectedBlock} + />
); } diff --git a/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/DeedTypeListContainer/index.tsx b/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/DeedTypeListContainer/index.tsx index a4889258..fd94a36d 100644 --- a/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/DeedTypeListContainer/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/DeedTypeListContainer/index.tsx @@ -1,14 +1,12 @@ 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 { DeedType } from "le-coffre-resources/dist/Admin"; -import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useCallback, useState } from "react"; +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[]; @@ -17,20 +15,9 @@ type IProps = { }; export default function DeedListContainer(props: IProps) { - const [filteredUsers, setFilteredUsers] = useState(props.deedTypes); const router = useRouter(); 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( (block: IBlock) => { props.onCloseLeftSide && props.onCloseLeftSide(); @@ -42,28 +29,20 @@ export default function DeedListContainer(props: IProps) { return (
-
-
- -
-
- { - return { - name: deed.name, - id: deed.uid!, - selected: deedTypeUid === deed.uid, - }; - })} - onSelectedBlock={onSelectedBlock} - /> -
-
-
- - - -
+ { + 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", + }} + />
); } diff --git a/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/DocumentTypeListContainer/index.tsx b/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/DocumentTypeListContainer/index.tsx index ada6b7a7..da7fb26f 100644 --- a/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/DocumentTypeListContainer/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/DocumentTypeListContainer/index.tsx @@ -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 { DocumentType } from "le-coffre-resources/dist/SuperAdmin"; -import Link from "next/link"; import { useRouter } from "next/router"; -import React, { useCallback, useState } from "react"; +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[]; @@ -16,19 +14,9 @@ type IProps = { }; export default function DocumentTypeListContainer(props: IProps) { - const [filteredDocumentTypes, setFilteredDocumentTypes] = useState(props.documentTypes); const router = useRouter(); 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( (block: IBlock) => { @@ -41,28 +29,20 @@ export default function DocumentTypeListContainer(props: IProps) { return (
-
-
- -
-
- { - return { - name: documentType.name, - id: documentType.uid!, - selected: documentType.uid === documentTypeUid, - }; - })} - onSelectedBlock={onSelectedBlock} - /> -
-
-
- - - -
+ { + 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", + }} + />
); } diff --git a/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/OfficeListContainer/index.tsx b/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/OfficeListContainer/index.tsx index fec898d0..b3c92662 100644 --- a/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/OfficeListContainer/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/OfficeListContainer/index.tsx @@ -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 { Office } from "le-coffre-resources/dist/SuperAdmin"; import { useRouter } from "next/router"; -import React, { useCallback, useState } from "react"; +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 = { offices: Office[]; @@ -14,21 +14,9 @@ type IProps = { }; export default function OfficeListContainer(props: IProps) { - const [filteredOffices, setFilteredOffices] = useState(props.offices); const router = useRouter(); 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( (block: IBlock) => { @@ -41,23 +29,16 @@ export default function OfficeListContainer(props: IProps) { return (
-
-
- -
-
- { - return { - name: office.crpcen + " - " + office.name, - id: office.uid!, - selected: office.uid === officeUid, - }; - })} - onSelectedBlock={onSelectedBlock} - /> -
-
+ { + return { + primaryText: office.crpcen + " - " + office.name, + id: office.uid!, + isActive: office.uid === officeUid, + }; + })} + onSelectedBlock={onSelectedBlock} + />
); } diff --git a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx index 1f52f6fb..b02309c9 100644 --- a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/RoleListContainer/index.tsx @@ -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 { OfficeRole } from "le-coffre-resources/dist/Admin"; import { useRouter } from "next/router"; -import React, { useCallback, useState } from "react"; +import React, { useCallback } from "react"; import classes from "./classes.module.scss"; -import Link from "next/link"; -import Button from "@Front/Components/DesignSystem/Button"; +import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block"; +import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList"; type IProps = { roles: OfficeRole[]; @@ -16,21 +14,10 @@ type IProps = { }; export default function RoleListContainer(props: IProps) { - const [filteredRoles, setFilteredRoles] = useState(props.roles); const router = useRouter(); 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( (block: IBlock) => { props.onCloseLeftSide && props.onCloseLeftSide(); @@ -42,33 +29,25 @@ export default function RoleListContainer(props: IProps) { return (
-
-
- -
-
- { - if (role.name === "admin") return false; - return true; - }) - .map((role) => { - return { - name: role.name, - id: role.uid!, - selected: role.uid === roleUid, - }; - })} - onSelectedBlock={onSelectedBlock} - /> -
-
-
- - - -
+ { + 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", + }} + />
); } diff --git a/src/front/Components/LayoutTemplates/DefaultUserDashboard/UserListContainer/index.tsx b/src/front/Components/LayoutTemplates/DefaultUserDashboard/UserListContainer/index.tsx index 8128b38d..0842539d 100644 --- a/src/front/Components/LayoutTemplates/DefaultUserDashboard/UserListContainer/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultUserDashboard/UserListContainer/index.tsx @@ -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 User from "le-coffre-resources/dist/Notary"; import { useRouter } from "next/router"; -import React, { useCallback, useState } from "react"; +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 = { users: User[]; @@ -14,22 +14,9 @@ type IProps = { }; export default function UserListContainer(props: IProps) { - const [filteredUsers, setFilteredUsers] = useState(props.users); const router = useRouter(); 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( (block: IBlock) => { @@ -42,23 +29,16 @@ export default function UserListContainer(props: IProps) { return (
-
-
- -
-
- { - return { - name: user.contact?.first_name + " " + user.contact?.last_name, - id: user.uid!, - selected: user.uid === userUid, - }; - })} - onSelectedBlock={onSelectedBlock} - /> -
-
+ { + return { + primaryText: user.contact?.first_name + " " + user.contact?.last_name, + id: user.uid!, + isActive: user.uid === userUid, + }; + })} + onSelectedBlock={onSelectedBlock} + />
); } diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 4152498b..4da7b128 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -14,6 +14,7 @@ import NumberPicker from "@Front/Components/Elements/NumberPicker"; import Tabs from "@Front/Components/Elements/Tabs"; import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; import useOpenable from "@Front/Hooks/useOpenable"; +import Footer from "@Front/Components/DesignSystem/Footer"; import { ArchiveBoxIcon, ArrowLongLeftIcon, @@ -797,6 +798,7 @@ export default function DesignSystem() { variant={EAlertVariant.NEUTRAL} />
+