From 5efd8b37133d0f16ef30b75321a5db6dc79ef9d7 Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 25 Jul 2024 10:27:40 +0200 Subject: [PATCH 01/16] fix header height --- .../Header/BurgerMenu/BurgerModal/classes.module.scss | 2 +- src/front/Components/DesignSystem/Header/classes.module.scss | 2 +- src/front/Components/DesignSystem/Header/index.tsx | 3 +++ .../DefaultCollaboratorDashboard/classes.module.scss | 4 ++-- .../DefaultDeedTypeDashboard/classes.module.scss | 4 ++-- .../DefaultDocumentTypesDashboard/classes.module.scss | 4 ++-- .../LayoutTemplates/DefaultDoubleSidePage/classes.module.scss | 4 ++-- .../DefaultNotaryDashboard/classes.module.scss | 4 ++-- .../DefaultOfficeDashboard/classes.module.scss | 4 ++-- .../LayoutTemplates/DefaultRoleDashboard/classes.module.scss | 4 ++-- .../LayoutTemplates/DefaultUserDashboard/classes.module.scss | 4 ++-- 11 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss index da462747..870ae3a1 100644 --- a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss +++ b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss @@ -11,7 +11,7 @@ width: 100%; left: 0; text-align: center; - max-height: calc(100vh - 83px); + max-height: calc(100vh - var(--header-height)); overflow: auto; > *:not(:last-child) { margin-bottom: 24px; diff --git a/src/front/Components/DesignSystem/Header/classes.module.scss b/src/front/Components/DesignSystem/Header/classes.module.scss index 929a37be..ee508b5a 100644 --- a/src/front/Components/DesignSystem/Header/classes.module.scss +++ b/src/front/Components/DesignSystem/Header/classes.module.scss @@ -6,7 +6,7 @@ align-items: center; flex-shrink: 0; - height: 75px; + height: var(--header-height); padding: 0px var(--spacing-lg, 24px); border-bottom: 1px solid var(--menu-border, #d7dce0); diff --git a/src/front/Components/DesignSystem/Header/index.tsx b/src/front/Components/DesignSystem/Header/index.tsx index b0efedca..addada55 100644 --- a/src/front/Components/DesignSystem/Header/index.tsx +++ b/src/front/Components/DesignSystem/Header/index.tsx @@ -23,6 +23,8 @@ type IProps = { isUserConnected: boolean; }; +const headerHeight = 75; + export default function Header(props: IProps) { const { isUserConnected } = props; @@ -44,6 +46,7 @@ export default function Header(props: IProps) { }, []); useEffect(() => { + document.documentElement.style.setProperty("--header-height", `${headerHeight}px`); loadSubscription(); }, [loadSubscription]); diff --git a/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/classes.module.scss index c4e19f2a..f54563dd 100644 --- a/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultCollaboratorDashboard/classes.module.scss @@ -14,7 +14,7 @@ .content { display: flex; overflow: hidden; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); .overlay { position: absolute; @@ -66,7 +66,7 @@ justify-content: center; min-width: 56px; max-width: 56px; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); border-right: 1px var(--color-neutral-200) solid; @media (min-width: $screen-m) { diff --git a/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/classes.module.scss index c4e19f2a..f54563dd 100644 --- a/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultDeedTypeDashboard/classes.module.scss @@ -14,7 +14,7 @@ .content { display: flex; overflow: hidden; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); .overlay { position: absolute; @@ -66,7 +66,7 @@ justify-content: center; min-width: 56px; max-width: 56px; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); border-right: 1px var(--color-neutral-200) solid; @media (min-width: $screen-m) { diff --git a/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/classes.module.scss index c4e19f2a..f54563dd 100644 --- a/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultDocumentTypesDashboard/classes.module.scss @@ -14,7 +14,7 @@ .content { display: flex; overflow: hidden; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); .overlay { position: absolute; @@ -66,7 +66,7 @@ justify-content: center; min-width: 56px; max-width: 56px; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); border-right: 1px var(--color-neutral-200) solid; @media (min-width: $screen-m) { diff --git a/src/front/Components/LayoutTemplates/DefaultDoubleSidePage/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultDoubleSidePage/classes.module.scss index e99cca13..8d431201 100644 --- a/src/front/Components/LayoutTemplates/DefaultDoubleSidePage/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultDoubleSidePage/classes.module.scss @@ -5,7 +5,7 @@ .content { display: flex; .sides { - min-height: calc(100vh - 83px); + min-height: calc(100vh - var(--header-height)); width: 50%; @media (max-width: $screen-m) { width: 100%; @@ -31,7 +31,7 @@ width: 50vw; top: 83px; right: 0; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); @media (max-width: $screen-m) { display: none; } diff --git a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss index 69cef63d..4a8599a1 100644 --- a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss @@ -15,7 +15,7 @@ .content { display: flex; overflow: hidden; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); .overlay { position: absolute; @@ -67,7 +67,7 @@ justify-content: center; min-width: 56px; max-width: 56px; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); border-right: 1px var(--color-neutral-200) solid; @media (min-width: $screen-m) { diff --git a/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/classes.module.scss index c4e19f2a..f54563dd 100644 --- a/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultOfficeDashboard/classes.module.scss @@ -14,7 +14,7 @@ .content { display: flex; overflow: hidden; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); .overlay { position: absolute; @@ -66,7 +66,7 @@ justify-content: center; min-width: 56px; max-width: 56px; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); border-right: 1px var(--color-neutral-200) solid; @media (min-width: $screen-m) { diff --git a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/classes.module.scss index c4e19f2a..f54563dd 100644 --- a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/classes.module.scss @@ -14,7 +14,7 @@ .content { display: flex; overflow: hidden; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); .overlay { position: absolute; @@ -66,7 +66,7 @@ justify-content: center; min-width: 56px; max-width: 56px; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); border-right: 1px var(--color-neutral-200) solid; @media (min-width: $screen-m) { diff --git a/src/front/Components/LayoutTemplates/DefaultUserDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultUserDashboard/classes.module.scss index f4e58c6d..059853fe 100644 --- a/src/front/Components/LayoutTemplates/DefaultUserDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultUserDashboard/classes.module.scss @@ -14,7 +14,7 @@ .content { display: flex; overflow: hidden; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); .overlay { position: absolute; @@ -66,7 +66,7 @@ justify-content: center; min-width: 56px; max-width: 56px; - height: calc(100vh - 83px); + height: calc(100vh - var(--header-height)); border-right: 1px var(--color-neutral-200 solid); @media (min-width: $screen-m) { From a6bd2dad7b189ffd13802793dee0bf76e6122be3 Mon Sep 17 00:00:00 2001 From: Maxime Lalo Date: Thu, 25 Jul 2024 10:46:19 +0200 Subject: [PATCH 02/16] :sparkles: Sort customers that have warnings --- .../FolderInformation/ClientView/index.tsx | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index 264db94d..3ff52286 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -39,14 +39,17 @@ export default function ClientView(props: IProps) { const tabs = useMemo( () => - customers.map((customer) => ({ - label: `${customer.contact?.first_name} ${customer.contact?.last_name}`, - key: customer.uid, - value: customer, - hasWarning: - customer.documents && - customer.documents.filter((document) => document.document_status === EDocumentStatus.DEPOSITED).length > 0, - })), + customers + .map((customer) => ({ + label: `${customer.contact?.first_name} ${customer.contact?.last_name}`, + key: customer.uid, + value: customer, + hasWarning: + customer.documents && + customer.documents.filter((document) => document.document_status === EDocumentStatus.DEPOSITED).length > 0, + })) + // put every tabs that has warning first + .sort((a, b) => (a.hasWarning ? -1 : 1)), [customers], ); From 7d0e0a60107ef2b68c354219074e6b7ef9cf273d Mon Sep 17 00:00:00 2001 From: Maxime Lalo Date: Thu, 25 Jul 2024 10:51:19 +0200 Subject: [PATCH 03/16] :bug: fixing sort customers --- .../FolderInformation/ClientView/index.tsx | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index 3ff52286..3a02bd33 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -28,10 +28,17 @@ export default function ClientView(props: IProps) { const customers: ICustomer[] = useMemo( () => - folder?.customers?.map((customer) => ({ - id: customer.uid ?? "", - ...customer, - })) ?? [], + folder?.customers + ?.map((customer) => ({ + id: customer.uid ?? "", + ...customer, + })) + .sort((a, b) => { + return a.documents && + a.documents.filter((document) => document.document_status === EDocumentStatus.DEPOSITED).length > 0 + ? -1 + : 1; + }) ?? [], [folder], ); @@ -39,17 +46,14 @@ export default function ClientView(props: IProps) { const tabs = useMemo( () => - customers - .map((customer) => ({ - label: `${customer.contact?.first_name} ${customer.contact?.last_name}`, - key: customer.uid, - value: customer, - hasWarning: - customer.documents && - customer.documents.filter((document) => document.document_status === EDocumentStatus.DEPOSITED).length > 0, - })) - // put every tabs that has warning first - .sort((a, b) => (a.hasWarning ? -1 : 1)), + customers.map((customer) => ({ + label: `${customer.contact?.first_name} ${customer.contact?.last_name}`, + key: customer.uid, + value: customer, + hasWarning: + customer.documents && + customer.documents.filter((document) => document.document_status === EDocumentStatus.DEPOSITED).length > 0, + })), [customers], ); From 2883a71c3cffcc6b868b96605682e7634aff1dc9 Mon Sep 17 00:00:00 2001 From: Maxime Lalo Date: Thu, 25 Jul 2024 11:22:42 +0200 Subject: [PATCH 04/16] :bug: Fixing links opacity --- src/front/index.scss | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/front/index.scss b/src/front/index.scss index 3b8e1f7e..5b066837 100644 --- a/src/front/index.scss +++ b/src/front/index.scss @@ -46,13 +46,6 @@ a, a:visited { color: initial; text-decoration: none !important; - opacity: 1; - transition: opacity 0.15s ease-in-out; - will-change: opacity; -} - -a:hover { - opacity: 0.9; } .react-select__input-container { From fc720286112068c67cd9528cc7b927968be4296c Mon Sep 17 00:00:00 2001 From: Maxime Lalo Date: Thu, 25 Jul 2024 11:26:06 +0200 Subject: [PATCH 05/16] :sparkles: New favicon --- public/favicon.ico | Bin 0 -> 9662 bytes public/favicon.svg | 22 ------------------ .../Components/DesignSystem/Header/index.tsx | 2 +- .../LayoutTemplates/DefaultLayout.tsx | 2 +- 4 files changed, 2 insertions(+), 24 deletions(-) create mode 100644 public/favicon.ico delete mode 100644 public/favicon.svg diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..022a2b9345f36eeaff95abeff7bf314c037d2524 GIT binary patch literal 9662 zcmd6tzi(Vc5XaY|NQo<29ui2DF6rP;a8KcDpd~fUT|tdglIkqc&>+*Lyd-T<2$pnd*>t}?CH>|fu}R#quR4$QIwEhSAk@5!gKcq5PZoJZ!*}H8 zP=mVcnus|XjO%6?=dEFspOP`SEg#pWsEDgLIO$$JYCd z=Y~5Gqalj(8j?rDL31(n__dX-J!UaxTZ8?dvl5kF`u^jC>f4VB_0zba``hPtv;G^3 z?ZxU0w3V$rW`@^u@WeH3hq#nn{5oIxc=`dQY7+Ov`?h>F;>08E9wL+I0f+XB-Se z>Q0X^e2uxwDf;>Nu$4nf&&lTC*ScL0r^M878$W+?8fjcD$*UB`+*|YP!M!VGH^a{S z8+Y5eX`zjDL7av8gYypNh(6&?c>Q=zUT2S|Nf+ep^^;0XA=uLeaeCe-Z=})r*QeEs z<^2V_uQ_>uhu)@t{2ubYS@Dd%Lr6lXI7S-GBP@uysGs_xAw( z6!|<;`;ly>bs5Q8OOMkw>0^_7PA*;Kd*tlVw53Xan!na&TTn`r|G-@8n?L_{aNk(_ zdZEXA(?!_XcL~lZCVxip-nwhUPcO$rUr=+?vHptn;x&5Y5|jTdi1*fA8@3dFeEKsV zia&>CoA`bI`1tTg04xqn~**eSY}6Sj;

!|;8ByUpn8`MCFplY1*%J~Q|Izq5x7x98-L!sOrY z+CyN@9Z9LJeLl4nKN2ZU!QIx zCt^kfrXt3hT1&6}i$&z@29`%DtT~zRjc)*BF620evrB$Ua##zy<)s{sG#d9o>s=5r z2mPCiVa;**;WEv40eTsu6fbgk)|JcWSYz8~@xS_|FE`=e-%=h^`Q3QUbNRSDW}2@{ z^yElmXSh@OC_ZNbj$@5ejZ!1-Gh{OjbT)=rUnlmeO5Yn^hVU-@&k$aPFG9EjpXmP& z!2zxx|H8*1NL>aYynw$Rg3M%i#TTsagzyml$`zlm-U}h-h<8a7f+cV~MDFk|SSyb> aKg-+dV0BT6>N>6JwpiBD>S}df*8M-9=#6^- literal 0 HcmV?d00001 diff --git a/public/favicon.svg b/public/favicon.svg deleted file mode 100644 index 984d1ebe..00000000 --- a/public/favicon.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/front/Components/DesignSystem/Header/index.tsx b/src/front/Components/DesignSystem/Header/index.tsx index addada55..4e5c17bc 100644 --- a/src/front/Components/DesignSystem/Header/index.tsx +++ b/src/front/Components/DesignSystem/Header/index.tsx @@ -54,7 +54,7 @@ export default function Header(props: IProps) { <>

- +
diff --git a/src/front/Components/LayoutTemplates/DefaultLayout.tsx b/src/front/Components/LayoutTemplates/DefaultLayout.tsx index 322f5bd3..148fedf7 100644 --- a/src/front/Components/LayoutTemplates/DefaultLayout.tsx +++ b/src/front/Components/LayoutTemplates/DefaultLayout.tsx @@ -8,7 +8,7 @@ export const DefaultLayout = ({ children }: DefaultLayoutProps) => { <> LEcoffre - {/* */} + {/* */}
{children} From f59f7ad9db632b031b88f160e85cc486c45707e8 Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 25 Jul 2024 12:30:02 +0200 Subject: [PATCH 06/16] :sparkles: burger modal --- .../BurgerModalSubmenu/classes.module.scss | 18 - .../BurgerModal/BurgerModalSubmenu/index.tsx | 58 --- .../BurgerModal/classes.module.scss | 25 +- .../Header/BurgerMenu/BurgerModal/index.tsx | 336 ++++++++++-------- .../HeaderSubmenu/HeaderSubmenuLink/index.tsx | 39 -- .../Header/HeaderSubmenu/classes.module.scss | 44 --- .../Header/HeaderSubmenu/index.tsx | 57 --- .../DesignSystem/Header/Navigation/index.tsx | 3 +- .../Header/NavigationLink/classes.module.scss | 12 - .../Header/NavigationLink/index.tsx | 54 --- .../Profile/ProfileModal/classes.module.scss | 35 +- .../Header/Profile/ProfileModal/index.tsx | 28 +- .../DesignSystem/LogOutButton/index.tsx | 31 +- .../Menu/MenuItem/classes.module.scss | 25 +- .../DesignSystem/Menu/MenuItem/index.tsx | 89 ++++- .../Components/DesignSystem/Menu/index.tsx | 29 +- .../InformationSection/index.tsx | 3 +- 17 files changed, 355 insertions(+), 531 deletions(-) delete mode 100644 src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/classes.module.scss delete mode 100644 src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/index.tsx delete mode 100644 src/front/Components/DesignSystem/Header/HeaderSubmenu/HeaderSubmenuLink/index.tsx delete mode 100644 src/front/Components/DesignSystem/Header/HeaderSubmenu/classes.module.scss delete mode 100644 src/front/Components/DesignSystem/Header/HeaderSubmenu/index.tsx delete mode 100644 src/front/Components/DesignSystem/Header/NavigationLink/classes.module.scss delete mode 100644 src/front/Components/DesignSystem/Header/NavigationLink/index.tsx diff --git a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/classes.module.scss b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/classes.module.scss deleted file mode 100644 index 26b47c0f..00000000 --- a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/classes.module.scss +++ /dev/null @@ -1,18 +0,0 @@ -@import "@Themes/constants.scss"; - -.root { - .content { - display: flex; - gap: 8px; - align-items: center; - justify-content: center; - } - - .sub-menu { - padding: 24px; - text-align: center; - gap: 24px; - display: flex; - flex-direction: column; - } -} diff --git a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/index.tsx b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/index.tsx deleted file mode 100644 index 7b1adba8..00000000 --- a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/BurgerModalSubmenu/index.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import classNames from "classnames"; -import { useRouter } from "next/router"; -import React, { useEffect, useState } from "react"; -import classes from "./classes.module.scss"; -import { IAppRule } from "@Front/Api/Entities/rule"; -import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; -import { IHeaderLinkProps } from "../../../ButtonHeader"; -import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import HeaderSubmenuLink from "../../../HeaderSubmenu/HeaderSubmenuLink"; -import useToggle from "@Front/Hooks/useToggle"; -import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline"; - -type IProps = { - text: string | JSX.Element; - links: (IHeaderLinkProps & { - rules?: IAppRule[]; - })[]; -}; - -export default function HeaderSubmenu(props: IProps) { - const router = useRouter(); - const { pathname } = router; - const [isActive, setIsActive] = useState(true); - const { active: isSubmenuOpened, toggle } = useToggle(); - - useEffect(() => { - setIsActive(false); - if (props.links.some((link) => link.path === pathname)) setIsActive(true); - if (props.links.some((link) => link.routesActive?.some((routeActive) => pathname.includes(routeActive)))) setIsActive(true); - }, [isActive, pathname, props.links]); - - return ( - link.rules ?? [])}> -
-
-
- - {props.text} - - {isSubmenuOpened ? : } -
-
- {isSubmenuOpened && ( -
- {props.links.map((link) => ( - - - - ))} -
- )} -
-
- - ); -} diff --git a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss index 870ae3a1..cbb69193 100644 --- a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss +++ b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/classes.module.scss @@ -1,21 +1,22 @@ @import "@Themes/constants.scss"; .root { + position: absolute; + top: var(--header-height); + left: 0; + + width: 100%; + max-height: calc(100vh - var(--header-height)); + padding: var(--spacing-05, 4px) var(--spacing-2, 16px); + display: flex; flex-direction: column; - background-color: var(--color-generic-white); - box-shadow: $shadow-nav; - padding: 24px; - position: absolute; - top: 83px; - width: 100%; - left: 0; - text-align: center; - max-height: calc(100vh - var(--header-height)); + overflow: auto; - > *:not(:last-child) { - margin-bottom: 24px; - } + + border-radius: var(--menu-radius, 0px); + background: var(--color-generic-white, #FFF); + box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.10); .separator { width: 100%; diff --git a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/index.tsx b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/index.tsx index ede9dd10..983abab0 100644 --- a/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/index.tsx +++ b/src/front/Components/DesignSystem/Header/BurgerMenu/BurgerModal/index.tsx @@ -1,170 +1,196 @@ +import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule"; import LogOutButton from "@Front/Components/DesignSystem/LogOutButton"; +import MenuItem from "@Front/Components/DesignSystem/Menu/MenuItem"; +import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; import Module from "@Front/Config/Module"; import React from "react"; -import NavigationLink from "../../NavigationLink"; import classes from "./classes.module.scss"; -import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule"; -import BurgerModalSubmenu from "./BurgerModalSubmenu"; -import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; type IProps = { isOpen: boolean; closeModal: () => void; }; -type IState = {}; -export default class BurgerModal extends React.Component { - // TODO isEnabled depending on role given by DB - public override render(): JSX.Element | null { - if (!this.props.isOpen) return null; - return ( - <> -
-
- - <> - +
+
+ + <> + - -
- - + ], + link: Module.getInstance().get().modules.pages.Folder.props.path, + }} + /> - - -
- - - - - -
- - ); - } + + + + + + + + + + + + + + + + + +
+ + ); } diff --git a/src/front/Components/DesignSystem/Header/HeaderSubmenu/HeaderSubmenuLink/index.tsx b/src/front/Components/DesignSystem/Header/HeaderSubmenu/HeaderSubmenuLink/index.tsx deleted file mode 100644 index 214feb88..00000000 --- a/src/front/Components/DesignSystem/Header/HeaderSubmenu/HeaderSubmenuLink/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import Link from "next/link"; -import { useRouter } from "next/router"; -import React, { useEffect } from "react"; - -import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import useHoverable from "@Front/Hooks/useHoverable"; - -type IHeaderLinkProps = { - text: string | JSX.Element; - path: string; - routesActive?: string[]; -}; - -export default function HeaderSubmenuLink(props: IHeaderLinkProps) { - const router = useRouter(); - const { pathname } = router; - const [isActive, setIsActive] = React.useState(props.path === pathname); - const { handleMouseLeave, handleMouseEnter, isHovered } = useHoverable(); - - useEffect(() => { - if (props.path === pathname) setIsActive(true); - if (props.routesActive) { - for (const routeActive of props.routesActive) { - if (isActive) break; - if (pathname.includes(routeActive)) setIsActive(true); - } - } - }, [isActive, pathname, props.path, props.routesActive]); - - return ( - - - {props.text} - - - ); -} diff --git a/src/front/Components/DesignSystem/Header/HeaderSubmenu/classes.module.scss b/src/front/Components/DesignSystem/Header/HeaderSubmenu/classes.module.scss deleted file mode 100644 index 0e84d6a6..00000000 --- a/src/front/Components/DesignSystem/Header/HeaderSubmenu/classes.module.scss +++ /dev/null @@ -1,44 +0,0 @@ -@import "@Themes/constants.scss"; - -.root { - display: flex; - position: relative; - width: fit-content; - margin: auto; - height: 83px; - padding: 10px 16px; - .content { - margin: auto; - } - .underline { - width: 100%; - height: 3px; - background-color: var(--color-generic-white); - position: absolute; - bottom: 0; - left: 0; - - &[data-active="true"] { - background-color: var(--color-generic-black); - } - } - - &.desactivated { - cursor: not-allowed; - } - - .sub-menu { - box-shadow: 0px 8px 10px 0px #00000012; - padding: 24px; - text-align: center; - gap: 24px; - left: 0; - transform: translateX(-25%); - width: 300px; - top: 84px; - display: flex; - flex-direction: column; - background: white; - position: absolute; - } -} diff --git a/src/front/Components/DesignSystem/Header/HeaderSubmenu/index.tsx b/src/front/Components/DesignSystem/Header/HeaderSubmenu/index.tsx deleted file mode 100644 index 1f6a939d..00000000 --- a/src/front/Components/DesignSystem/Header/HeaderSubmenu/index.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import classNames from "classnames"; -import { useRouter } from "next/router"; -import React, { useEffect, useState } from "react"; -import { IHeaderLinkProps } from "../ButtonHeader"; - -import Typography, { ETypo, ETypoColor } from "../../Typography"; -import classes from "./classes.module.scss"; -import useHoverable from "@Front/Hooks/useHoverable"; -import HeaderSubmenuLink from "./HeaderSubmenuLink"; -import { IAppRule } from "@Front/Api/Entities/rule"; -import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; - -type IProps = { - text: string | JSX.Element; - links: (IHeaderLinkProps & { - rules?: IAppRule[]; - })[]; -}; - -export default function HeaderSubmenu(props: IProps) { - const router = useRouter(); - const { pathname } = router; - const [isActive, setIsActive] = useState(false); - const { handleMouseLeave, handleMouseEnter, isHovered } = useHoverable(100); - - useEffect(() => { - setIsActive(false); - if (props.links.some((link) => link.path === pathname)) setIsActive(true); - if (props.links.some((link) => link.routesActive?.some((routeActive) => pathname.includes(routeActive)))) setIsActive(true); - }, [isActive, pathname, props.links]); - - return ( - link.rules ?? [])}> -
-
-
- - {props.text} - -
-
- {isHovered && ( -
- {props.links.map((link) => ( - - - - ))} -
- )} -
-
- - ); -} diff --git a/src/front/Components/DesignSystem/Header/Navigation/index.tsx b/src/front/Components/DesignSystem/Header/Navigation/index.tsx index 5e4244d3..eb4e2878 100644 --- a/src/front/Components/DesignSystem/Header/Navigation/index.tsx +++ b/src/front/Components/DesignSystem/Header/Navigation/index.tsx @@ -8,7 +8,8 @@ import { AdjustmentsVerticalIcon, BanknotesIcon, Square3Stack3DIcon, TagIcon, Us import { usePathname } from "next/navigation"; import React, { useCallback, useEffect } from "react"; -import Menu, { IItem } from "../../Menu"; +import Menu from "../../Menu"; +import { IItem } from "../../Menu/MenuItem"; import ButtonHeader from "../ButtonHeader"; import classes from "./classes.module.scss"; diff --git a/src/front/Components/DesignSystem/Header/NavigationLink/classes.module.scss b/src/front/Components/DesignSystem/Header/NavigationLink/classes.module.scss deleted file mode 100644 index 27c75060..00000000 --- a/src/front/Components/DesignSystem/Header/NavigationLink/classes.module.scss +++ /dev/null @@ -1,12 +0,0 @@ -@import "@Themes/constants.scss"; - -.root { - display: flex; - position: relative; - width: fit-content; - margin: auto; - - .content { - align-content: center; - } -} diff --git a/src/front/Components/DesignSystem/Header/NavigationLink/index.tsx b/src/front/Components/DesignSystem/Header/NavigationLink/index.tsx deleted file mode 100644 index 6972f93f..00000000 --- a/src/front/Components/DesignSystem/Header/NavigationLink/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import React from "react"; -import classes from "./classes.module.scss"; -import Link from "next/link"; -import classNames from "classnames"; -import { useRouter } from "next/router"; -import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; - -type IProps = { - text: string | JSX.Element; - path?: string; - onClick?: () => void; - isEnabled?: boolean; - isActive?: boolean; - routesActive?: string[]; - target?: "blank" | "self" | "_blank"; -}; - -type IPropsClass = IProps; -type IStateClass = {}; - -class NavigationLinkClass extends React.Component { - static defaultProps = { isEnabled: true }; - public override render(): JSX.Element | null { - if (!this.props.isEnabled) return null; - return ( - -
- - {this.props.text} - -
- - ); - } -} - -export default function NavigationLink(props: IProps) { - const router = useRouter(); - const { pathname } = router; - let isActive = props.path === pathname; - if (props.routesActive) { - for (const routeActive of props.routesActive) { - if (isActive) break; - isActive = pathname.includes(routeActive); - } - } - return ; -} diff --git a/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss b/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss index d2eabeed..1745bc20 100644 --- a/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss +++ b/src/front/Components/DesignSystem/Header/Profile/ProfileModal/classes.module.scss @@ -1,14 +1,26 @@ @import "@Themes/constants.scss"; .root { - display: flex; - flex-direction: column; - background-color: var(--color-generic-white); - box-shadow: $shadow-nav; - padding: 24px; position: absolute; - top: 107px; - right: 66px; + top: 48px; + + display: inline-flex; + flex-direction: column; + align-items: flex-start; + + padding: var(--spacing-05, 4px) var(--spacing-2, 16px); + + border-radius: var(--menu-radius, 0); + border: 1px solid var(--menu-border, #d7dce0); + background: var(--color-generic-white, #fff); + + text-wrap: nowrap; + + box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.1); + z-index: 3; + top: calc(var(--header-height) + 10px); + right: 32px; + text-align: center; animation: smooth-appear 0.2s ease forwards; @@ -20,15 +32,6 @@ opacity: 1; } } - - > *:not(:last-child) { - margin-bottom: 24px; - } - - .separator { - width: 100%; - border: 1px solid var(--color-neutral-200); - } } .background { diff --git a/src/front/Components/DesignSystem/Header/Profile/ProfileModal/index.tsx b/src/front/Components/DesignSystem/Header/Profile/ProfileModal/index.tsx index 3a815e2e..535151e9 100644 --- a/src/front/Components/DesignSystem/Header/Profile/ProfileModal/index.tsx +++ b/src/front/Components/DesignSystem/Header/Profile/ProfileModal/index.tsx @@ -2,8 +2,8 @@ import LogOutButton from "@Front/Components/DesignSystem/LogOutButton"; import Module from "@Front/Config/Module"; import React from "react"; -import NavigationLink from "../../NavigationLink"; import classes from "./classes.module.scss"; +import MenuItem from "@Front/Components/DesignSystem/Menu/MenuItem"; type IProps = { isOpen: boolean; @@ -19,10 +19,28 @@ export default class ProfileModal extends React.Component { <>
- - - -
+ + + + +
diff --git a/src/front/Components/DesignSystem/LogOutButton/index.tsx b/src/front/Components/DesignSystem/LogOutButton/index.tsx index a4f3bcd1..6e1b1e13 100644 --- a/src/front/Components/DesignSystem/LogOutButton/index.tsx +++ b/src/front/Components/DesignSystem/LogOutButton/index.tsx @@ -1,27 +1,20 @@ -import React from "react"; -import Image from "next/image"; -import DisconnectIcon from "@Assets/Icons/disconnect.svg"; -import classes from "./classes.module.scss"; -import Typography, { ETypo, ETypoColor } from "../Typography"; -import { useRouter } from "next/router"; -import UserStore from "@Front/Stores/UserStore"; import { FrontendVariables } from "@Front/Config/VariablesFront"; +import UserStore from "@Front/Stores/UserStore"; +import { PowerIcon } from "@heroicons/react/24/outline"; +import { useRouter } from "next/router"; +import React, { useCallback } from "react"; + +import MenuItem from "../Menu/MenuItem"; export default function LogOut() { const router = useRouter(); const variables = FrontendVariables.getInstance(); - const disconnect = async () => { - await UserStore.instance.disconnect(); - router.push(`https://qual-connexion.idnot.fr/user/auth/logout?sourceURL=${variables.FRONT_APP_HOST}`); - }; + const disconnect = useCallback(() => { + UserStore.instance + .disconnect() + .then(() => router.push(`https://qual-connexion.idnot.fr/user/auth/logout?sourceURL=${variables.FRONT_APP_HOST}`)); + }, [router, variables.FRONT_APP_HOST]); - return ( -
- - Déconnexion - - disconnect -
- ); + return , onClick: disconnect }} />; } diff --git a/src/front/Components/DesignSystem/Menu/MenuItem/classes.module.scss b/src/front/Components/DesignSystem/Menu/MenuItem/classes.module.scss index 715b9ccf..9e952ad8 100644 --- a/src/front/Components/DesignSystem/Menu/MenuItem/classes.module.scss +++ b/src/front/Components/DesignSystem/Menu/MenuItem/classes.module.scss @@ -1,5 +1,6 @@ .root { width: 100%; + .menu-item { display: flex; padding: var(--spacing-md, 16px); @@ -7,12 +8,16 @@ align-items: center; gap: var(--spacing-lg, 24px); cursor: pointer; + } - > svg { - width: 24px; - height: 24px; - transition: all ease-in-out 0.1s; - } + svg { + width: 24px; + height: 24px; + transition: transform 0.3s ease-in-out; + } + + .chevron.open { + transform: rotate(180deg); } .separator { @@ -20,4 +25,14 @@ height: 1px; background-color: var(--separator-stroke-light, #d7dce0); } + + .dropdown { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease-in-out; + } + + .dropdown.open { + max-height: 500px; + } } diff --git a/src/front/Components/DesignSystem/Menu/MenuItem/index.tsx b/src/front/Components/DesignSystem/Menu/MenuItem/index.tsx index 72e0c830..3ca577ff 100644 --- a/src/front/Components/DesignSystem/Menu/MenuItem/index.tsx +++ b/src/front/Components/DesignSystem/Menu/MenuItem/index.tsx @@ -3,27 +3,71 @@ import classes from "./classes.module.scss"; import { useRouter } from "next/router"; import React, { useCallback, useEffect } from "react"; import useHoverable from "@Front/Hooks/useHoverable"; -import { IItem } from ".."; import classNames from "classnames"; +import { IAppRule } from "@Front/Api/Entities/rule"; +import { ChevronDownIcon } from "@heroicons/react/24/outline"; +import useOpenable from "@Front/Hooks/useOpenable"; type IProps = { item: IItem; - closeMenuCb: () => void; }; + +type IItemBase = { + text: string; + icon?: JSX.Element; + hasSeparator?: boolean; + color?: ETypoColor; + onClose?: () => void; +}; + +type IItemWithLink = IItemBase & { + link: string; + rules?: IAppRule[]; + routesActive?: string[]; + onClick?: never; + dropdown?: never; + target?: "_blank"; +}; + +type IItemWithOnClick = IItemBase & { + onClick: () => void; + link?: never; + rules?: never; + routesActive?: never; + dropdown?: never; + target?: never; +}; + +type IItemWithDropdown = IItemBase & { + dropdown: { + items: IItem[]; + }; + routesActive?: never; + link?: never; + rules?: never; + onClick?: never; + target?: never; +}; + +export type IItem = IItemWithLink | IItemWithOnClick | IItemWithDropdown; + export default function MenuItem(props: IProps) { - const { item, closeMenuCb } = props; + const { item } = props; const router = useRouter(); const { pathname } = router; const [isActive, setIsActive] = React.useState(item.link === pathname); + const { isOpen, toggle, open } = useOpenable(); + const handleClickElement = useCallback( (e: React.MouseEvent) => { - closeMenuCb(); + item.onClose?.(); const link = e.currentTarget.getAttribute("data-link"); + if (item.target === "_blank") window.open(item.link, "_blank"); if (link) router.push(link); if (item.onClick) item.onClick(); }, - [closeMenuCb, item, router], + [item, router], ); const { handleMouseEnter, handleMouseLeave, isHovered } = useHoverable(); @@ -44,7 +88,25 @@ export default function MenuItem(props: IProps) { if (pathname.includes(routeActive)) setIsActive(true); } } - }, [isActive, item.link, item.routesActive, pathname]); + if (item.dropdown) { + for (const subItem of item.dropdown.items) { + if (isActive) break; + if (subItem.link === pathname) { + !isOpen && open(); + setIsActive(true); + } + if (subItem.routesActive) { + for (const routeActive of subItem.routesActive) { + if (isActive) break; + if (pathname.includes(routeActive)) { + !isOpen && open(); + setIsActive(true); + } + } + } + } + } + }, [isActive, isOpen, item.dropdown, item.link, item.routesActive, open, pathname]); return (
-
- {React.cloneElement(item.icon, { color: `var(${getColor()})` })} +
+ {item.icon && React.cloneElement(item.icon, { color: `var(${getColor()})` })} {item.text} + {item.dropdown && + React.cloneElement(, { + color: `var(${getColor()})`, + })}
+ {item.dropdown && ( +
+ {item.dropdown.items.map((subItem, index) => ( + + ))} +
+ )} {item.hasSeparator &&
}
); diff --git a/src/front/Components/DesignSystem/Menu/index.tsx b/src/front/Components/DesignSystem/Menu/index.tsx index f0dca424..891b978c 100644 --- a/src/front/Components/DesignSystem/Menu/index.tsx +++ b/src/front/Components/DesignSystem/Menu/index.tsx @@ -1,35 +1,10 @@ -import { IAppRule } from "@Front/Api/Entities/rule"; -import { ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; import useHoverable from "@Front/Hooks/useHoverable"; import useOpenable from "@Front/Hooks/useOpenable"; import React, { useEffect, useRef } from "react"; import classes from "./classes.module.scss"; -import MenuItem from "./MenuItem"; - -type IItemBase = { - icon: JSX.Element; - text: string; - hasSeparator?: boolean; - color?: ETypoColor; -}; - -type IItemWithLink = IItemBase & { - link: string; - rules?: IAppRule[]; - routesActive?: string[]; - onClick?: never; -}; - -type IItemWithOnClick = IItemBase & { - onClick: () => void; - link?: never; - rules?: never; - routesActive?: never; -}; - -export type IItem = IItemWithLink | IItemWithOnClick; +import MenuItem, { IItem } from "./MenuItem"; type IProps = { children: React.ReactNode; @@ -79,7 +54,7 @@ export default function Menu(props: IProps) { {items.map((item, index) => { return ( - + ); })} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx index ef264e44..c7c6722b 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx @@ -1,6 +1,5 @@ import CircleProgress from "@Front/Components/DesignSystem/CircleProgress"; import IconButton, { EIconButtonVariant } from "@Front/Components/DesignSystem/IconButton"; -import Menu, { IItem } from "@Front/Components/DesignSystem/Menu"; import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Module from "@Front/Config/Module"; @@ -10,6 +9,8 @@ import { useCallback } from "react"; import { AnchorStatus } from ".."; import classes from "./classes.module.scss"; +import { IItem } from "@Front/Components/DesignSystem/Menu/MenuItem"; +import Menu from "@Front/Components/DesignSystem/Menu"; type IProps = { folder: OfficeFolder | null; From f39ab33f82cebcb1d51d5110a5057ac4a32ffce6 Mon Sep 17 00:00:00 2001 From: Maxime Lalo Date: Thu, 25 Jul 2024 13:21:48 +0200 Subject: [PATCH 07/16] :sparkles: Responsive notary dashboard --- .../FolderListContainer/classes.module.scss | 16 -- .../BlockList/classes.module.scss | 35 ----- .../DropdownNavigation/classes.module.scss | 60 ++++++++ .../DropdownNavigation/index.tsx | 82 ++++++++++ .../SearchBlockList/classes.module.scss | 48 ++++++ .../DesignSystem/SearchBlockList/index.tsx | 26 +++- .../classes.module.scss | 123 +-------------- .../DefaultNotaryDashboard/index.tsx | 140 ++++-------------- .../Components/Layouts/DesignSystem/index.tsx | 74 +++++++++ 9 files changed, 323 insertions(+), 281 deletions(-) delete mode 100644 src/front/Components/DesignSystem/SearchBlockList/BlockList/classes.module.scss create mode 100644 src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/classes.module.scss create mode 100644 src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx diff --git a/src/front/Components/DesignSystem/FolderListContainer/classes.module.scss b/src/front/Components/DesignSystem/FolderListContainer/classes.module.scss index deb6e813..560b12a5 100644 --- a/src/front/Components/DesignSystem/FolderListContainer/classes.module.scss +++ b/src/front/Components/DesignSystem/FolderListContainer/classes.module.scss @@ -1,23 +1,7 @@ @import "@Themes/constants.scss"; .root { - width: calc(100vh - 83px); display: flex; flex-direction: column; justify-content: space-between; - - .header { - flex: 1; - } - - .searchbar { - padding: 40px 24px 24px 24px; - } - - .folderlist-container { - max-height: calc(100vh - 290px); - height: calc(100vh - 290px); - overflow: auto; - border-right: 1px solid var(--color-neutral-200); - } } diff --git a/src/front/Components/DesignSystem/SearchBlockList/BlockList/classes.module.scss b/src/front/Components/DesignSystem/SearchBlockList/BlockList/classes.module.scss deleted file mode 100644 index fcf2657b..00000000 --- a/src/front/Components/DesignSystem/SearchBlockList/BlockList/classes.module.scss +++ /dev/null @@ -1,35 +0,0 @@ -@import "@Themes/constants.scss"; - -.root { - display: inline-flex; - justify-content: space-between; - align-items: center; - width: 100%; - padding: 24px; - border: 1px solid var(--color-neutral-200); - cursor: pointer; - - &:hover { - background-color: var(--color-neutral-200); - } - - &[data-selected="true"] { - background-color: var(--color-neutral-200); - } - - .left-side { - display: inline-flex; - justify-content: space-between; - align-items: center; - overflow-wrap: anywhere; - .warning { - margin-left: 32px; - } - } - - .right-side { - display: flex; - align-items: center; - gap: 16px; - } -} diff --git a/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/classes.module.scss b/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/classes.module.scss new file mode 100644 index 00000000..dc058383 --- /dev/null +++ b/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/classes.module.scss @@ -0,0 +1,60 @@ +@import "@Themes/constants.scss"; + +.root { + .dropdown-header { + cursor: pointer; + display: flex; + padding: var(--spacing-2, 16px) var(--spacing-sm, 8px); + align-items: center; + gap: var(--spacing-2, 16px); + + border-radius: var(--input-radius, 0px); + border: 1px solid var(--dropdown-input-border-hovered, #b4bec5); + background: var(--dropdown-input-background, #fff); + + .text-container { + display: flex; + flex-direction: column; + height: var(--spacing-6, 48px); + padding: 0px var(--spacing-2, 16px); + flex: 1; + } + + > svg { + transition: transform 200ms ease-in-out; + } + } + + .dropdown-content { + margin-top: 8px; + display: flex; + padding: var(--spacing-sm, 8px); + flex-direction: column; + align-items: flex-start; + gap: 8px; + align-self: stretch; + + max-height: 200px; + overflow-y: auto; + border-radius: var(--dropdown-radius, 0px); + border: 1px solid var(--dropdown-menu-border-primary, #005bcb); + background: var(--dropdown-menu-background, #fff); + + .dropdown-item { + cursor: pointer; + padding: var(--spacing-1, 8px) var(--spacing-2, 16px); + } + } + + &[data-is-opened="true"] { + .dropdown-header { + border-radius: var(--input-radius, 0px); + border: 1px solid var(--dropdown-input-border-expanded, #005bcb); + background: var(--dropdown-input-background, #fff); + + > svg { + transform: rotate(180deg); + } + } + } +} diff --git a/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx b/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx new file mode 100644 index 00000000..50c7ef77 --- /dev/null +++ b/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx @@ -0,0 +1,82 @@ +import React, { useCallback, useEffect } from "react"; +import { IBlock } from "../BlockList/Block"; +import classes from "./classes.module.scss"; +import Typography, { ETypo, ETypoColor } from "../../Typography"; +import { ChevronDownIcon } from "@heroicons/react/24/outline"; +type IProps = { + blocks: IBlock[]; + onSelectedBlock: (block: IBlock) => void; + defaultSelectedBlock?: IBlock; +}; + +export default function DropdownNavigation({ blocks, onSelectedBlock, defaultSelectedBlock = blocks[0] }: IProps) { + const [selectedBlock, setSelectedBlock] = React.useState(defaultSelectedBlock ?? null); + const [isDropdownOpened, setIsDropdownOpened] = React.useState(false); + const rootRef = React.useRef(null); + + const selectBlock = useCallback( + (id: string) => { + setIsDropdownOpened(false); + setSelectedBlock(blocks.find((folder) => folder.id === id)!); + onSelectedBlock && onSelectedBlock(blocks.find((folder) => folder.id === id)!); + }, + [blocks, onSelectedBlock], + ); + + const handleOnClick = () => setIsDropdownOpened((prev) => !prev); + + useEffect(() => { + // on click outside of root, close dropdown + const handleClickOutside = (event: MouseEvent) => { + if (rootRef.current && !rootRef.current.contains(event.target as Node)) { + setIsDropdownOpened(false); + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + useEffect(() => { + if (defaultSelectedBlock) setSelectedBlock(defaultSelectedBlock); + }, [defaultSelectedBlock]); + return ( +
+ {selectedBlock && ( + <> +
+
+ {selectedBlock.secondaryText && ( + + {selectedBlock.secondaryText} + + )} + + {selectedBlock.primaryText} + +
+ +
+ + {isDropdownOpened && ( +
+ {blocks + .filter((block) => block.id !== selectedBlock.id) + .map((block) => ( +
selectBlock(block.id)}> + {block.secondaryText && ( + + {block.secondaryText} + + )} + + {block.primaryText} + +
+ ))} +
+ )} + + )} +
+ ); +} diff --git a/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss b/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss index e7bcaa27..d7a8ef40 100644 --- a/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss +++ b/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss @@ -1,3 +1,4 @@ +@import "@Themes/constants.scss"; .root { width: 336px; height: 100%; @@ -9,6 +10,11 @@ flex-direction: column; justify-content: flex-start; + @media (max-width: $screen-m) { + gap: 16px; + padding: var(--spacing-lg, 24px); + width: auto; + } .block-list { overflow-y: auto; ::-webkit-scrollbar { @@ -16,13 +22,55 @@ } -ms-overflow-style: none; /* IE and Edge */ scrollbar-width: none; /* Firefox */ + + @media (max-width: $screen-m) { + display: none; + } + } + + .responsive-dropdown { + display: none; + + @media (max-width: $screen-m) { + display: block; + } } .searchbar { padding: var(--spacing-md, 16px); + @media (max-width: $screen-m) { + padding: 0px; + display: flex; + gap: var(--spacing-md, 16px); + } + + > label { + flex: 1; + } + + .responsive-button-container { + display: none; + + @media (max-width: $screen-m) { + display: block; + flex: 1; + } + + @media (max-width: $screen-s) { + display: none; + } + } } .bottom-container { margin-top: auto; + + @media (max-width: $screen-m) { + display: none; + } + + @media (max-width: $screen-s) { + display: block; + } } } diff --git a/src/front/Components/DesignSystem/SearchBlockList/index.tsx b/src/front/Components/DesignSystem/SearchBlockList/index.tsx index 3dd43a52..0ed80f61 100644 --- a/src/front/Components/DesignSystem/SearchBlockList/index.tsx +++ b/src/front/Components/DesignSystem/SearchBlockList/index.tsx @@ -5,6 +5,7 @@ import classes from "./classes.module.scss"; import SearchBar from "../SearchBar"; import Button from "../Button"; import { useRouter } from "next/router"; +import DropdownNavigation from "./DropdownNavigation"; type IProps = { blocks: IBlock[]; @@ -17,6 +18,7 @@ type IProps = { export default function SearchBlockList(props: IProps) { const { blocks, onSelectedBlock, bottomButton } = props; + const [selectedBlock, setSelectedBlock] = useState(null); const router = useRouter(); const [blocksShowing, setBlocksShowing] = useState(blocks); @@ -54,6 +56,14 @@ export default function SearchBlockList(props: IProps) { router.push(bottomButton.link); }, [bottomButton, router]); + const handleSelectedBlock = useCallback( + (block: IBlock) => { + setSelectedBlock(block); + onSelectedBlock(block); + }, + [onSelectedBlock], + ); + useEffect(() => { setBlocksShowing(blocks); }, [blocks]); @@ -62,9 +72,23 @@ export default function SearchBlockList(props: IProps) {
+ {bottomButton && ( +
+ +
+ )}
- + +
+
+
{bottomButton && (
diff --git a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss index 4a8599a1..882a9394 100644 --- a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/classes.module.scss @@ -1,132 +1,23 @@ @import "@Themes/constants.scss"; -@keyframes growWidth { - 0% { - width: 100%; - } - - 100% { - width: 200%; - } -} - .root { position: relative; .content { display: flex; - overflow: hidden; + justify-content: flex-start; height: calc(100vh - var(--header-height)); - .overlay { - position: absolute; - width: 100%; - height: 100%; - background-color: var(--color-generic-white); - opacity: 0.5; - z-index: 2; - transition: all 0.3s $custom-easing; + @media (max-width: $screen-m) { + flex-direction: column; } - - .left-side { - background-color: var(--color-generic-white); - z-index: 3; - display: flex; - width: 336px; - min-width: 336px; - transition: all 0.3s $custom-easing; - overflow: hidden; - - @media (max-width: ($screen-m - 1px)) { - width: 56px; - min-width: 56px; - transform: translateX(-389px); - - &.opened { - transform: translateX(0px); - width: 336px; - min-width: 336px; - } - } - - @media (max-width: $screen-s) { - width: 0px; - min-width: 0px; - - &.opened { - width: 100vw; - min-width: 100vw; - } - } - } - - .closable-left-side { - position: absolute; - background-color: var(--color-generic-white); - z-index: 0; - display: flex; - justify-content: center; - min-width: 56px; - max-width: 56px; - height: calc(100vh - var(--header-height)); - border-right: 1px var(--color-neutral-200) solid; - - @media (min-width: $screen-m) { - display: none; - } - - .chevron-icon { - margin-top: 21px; - transform: rotate(180deg); - cursor: pointer; - } - - @media (max-width: $screen-s) { - display: none; - } - } - .right-side { - min-width: calc(100vw - 389px); - padding: 24px; + min-width: calc(100% - 336px); overflow-y: auto; + padding: var(--spacing-lg, 24px); - @media (max-width: ($screen-m - 1px)) { - min-width: calc(100vw - 56px); + @media (max-width: $screen-m) { + width: 100%; } - - @media (max-width: $screen-s) { - flex: 1; - min-width: unset; - } - - .back-arrow-mobile { - display: none; - @media (max-width: $screen-s) { - display: block; - margin-bottom: 24px; - } - } - - .back-arrow-desktop { - @media (max-width: $screen-s) { - display: none; - } - } - } - } - - .background-image-container { - position: fixed; - top: 0; - right: 0; - @media (max-width: $screen-l) { - display: none; - } - - .background-image { - width: 100%; - height: 100%; - object-fit: cover; } } } diff --git a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx index da2d01dc..5f40199a 100644 --- a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx @@ -1,18 +1,11 @@ -import ChevronIcon from "@Assets/Icons/chevron.svg"; import Folders, { IGetFoldersParams } from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; -import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import FolderArchivedListContainer from "@Front/Components/DesignSystem/FolderArchivedListContainer"; import FolderListContainer from "@Front/Components/DesignSystem/FolderListContainer"; import Header from "@Front/Components/DesignSystem/Header"; import Version from "@Front/Components/DesignSystem/Version"; import BackArrow from "@Front/Components/Elements/BackArrow"; -import WindowStore from "@Front/Stores/WindowStore"; -import { ChevronLeftIcon } from "@heroicons/react/24/outline"; -import classNames from "classnames"; import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; -import Image, { StaticImageData } from "next/image"; -import React, { ReactNode } from "react"; +import React, { ReactNode, useEffect } from "react"; import classes from "./classes.module.scss"; @@ -24,94 +17,16 @@ type IProps = { hasBackArrow: boolean; backArrowUrl?: string; mobileBackText?: string; - image?: StaticImageData; -}; -type IState = { - folders: OfficeFolder[] | null; - isLeftSideOpen: boolean; - leftSideCanBeClosed: boolean; }; -export default class DefaultNotaryDashboard extends React.Component { - private onWindowResize = () => {}; - public static defaultProps: Partial = { - hasBackArrow: false, - isArchived: false, - }; +export default function DefaultNotaryDashboard(props: IProps) { + const { hasBackArrow, onSelectedFolder, backArrowUrl, children, isArchived } = props; - public constructor(props: IProps) { - super(props); - this.state = { - folders: null, - isLeftSideOpen: false, - leftSideCanBeClosed: typeof window !== "undefined" ? window.innerWidth < 1024 : false, - }; - this.onOpenLeftSide = this.onOpenLeftSide.bind(this); - this.onCloseLeftSide = this.onCloseLeftSide.bind(this); - } + const [folders, setFolders] = React.useState([]); - public override render(): JSX.Element { - return ( -
-
-
- {this.state.isLeftSideOpen &&
} -
- {this.props.isArchived && this.state.folders && ( - - )} - {!this.props.isArchived && this.state.folders && ( - - )} -
-
- open side menu -
- -
- {this.props.hasBackArrow && ( -
- -
- )} - {this.props.mobileBackText && ( -
- -
- )} - {this.props.children} -
- {this.props.image && ( -
- {"right -
- )} -
- -
- ); - } - - public override async componentDidMount() { - this.onWindowResize = WindowStore.getInstance().onResize((window) => this.onResize(window)); + useEffect(() => { let targetedStatus: EFolderStatus = EFolderStatus["LIVE" as keyof typeof EFolderStatus]; - if (this.props.isArchived) targetedStatus = EFolderStatus.ARCHIVED; + if (isArchived) targetedStatus = EFolderStatus.ARCHIVED; const query: IGetFoldersParams = { q: { where: { status: targetedStatus }, @@ -143,27 +58,26 @@ export default class DefaultNotaryDashboard extends React.Component setFolders(folders)); + }, [isArchived]); - private onOpenLeftSide() { - this.setState({ isLeftSideOpen: true }); - } - - private onCloseLeftSide() { - if (!this.state.leftSideCanBeClosed) return; - this.setState({ isLeftSideOpen: false }); - } - - private onResize(window: Window) { - if (window.innerWidth > 1023) { - if (!this.state.leftSideCanBeClosed) return; - this.setState({ leftSideCanBeClosed: false }); - } - this.setState({ leftSideCanBeClosed: true }); - } + return ( +
+
+
+ +
+ {hasBackArrow && ( +
+ +
+ )} + {children} +
+
+ +
+ ); } diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 13d4ae9f..276577a6 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -28,6 +28,8 @@ import { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import Menu from "@Front/Components/DesignSystem/Menu"; +import DropdownNavigation from "@Front/Components/DesignSystem/SearchBlockList/DropdownNavigation"; +import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList"; export default function DesignSystem() { const { isOpen, open, close } = useOpenable(); @@ -79,6 +81,78 @@ export default function DesignSystem() {
+ Navigation latérale + {}} + bottomButton={{ + link: "/", + text: "Créer un dossier", + }} + /> + Dropdown navigation + {}} + /> Button icon with menu Date: Thu, 25 Jul 2024 13:28:34 +0200 Subject: [PATCH 08/16] :bug: Fixing build --- .../LayoutTemplates/DefaultNotaryDashboard/index.tsx | 4 ++-- src/front/Components/Layouts/Folder/index.tsx | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx index 5f40199a..2a5e00a7 100644 --- a/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultNotaryDashboard/index.tsx @@ -13,8 +13,8 @@ type IProps = { title: string; children?: ReactNode; isArchived?: boolean; - onSelectedFolder: (folder: OfficeFolder) => void; - hasBackArrow: boolean; + onSelectedFolder?: (folder: OfficeFolder) => void; + hasBackArrow?: boolean; backArrowUrl?: string; mobileBackText?: string; }; diff --git a/src/front/Components/Layouts/Folder/index.tsx b/src/front/Components/Layouts/Folder/index.tsx index d4d5da21..a9aeaa84 100644 --- a/src/front/Components/Layouts/Folder/index.tsx +++ b/src/front/Components/Layouts/Folder/index.tsx @@ -1,4 +1,3 @@ -import backgroundImage from "@Assets/images/background_refonte_reverse.svg"; import LogoIcon from "@Assets/logo_small_blue.svg"; import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; @@ -60,11 +59,7 @@ export default function Folder() { }, [router]); return ( - +
From 3e9c096deb861d07f933857df40876e9d243e93b Mon Sep 17 00:00:00 2001 From: Maxime Lalo Date: Thu, 25 Jul 2024 17:27:49 +0200 Subject: [PATCH 09/16] :sparkles: New favicon --- public/favicon.ico | Bin 9662 -> 0 bytes public/favicon.svg | 5 ++++ public/manifest.json | 26 +++++++++--------- .../Components/DesignSystem/Header/index.tsx | 2 +- .../LayoutTemplates/DefaultLayout.tsx | 2 +- 5 files changed, 20 insertions(+), 15 deletions(-) delete mode 100644 public/favicon.ico create mode 100644 public/favicon.svg diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index 022a2b9345f36eeaff95abeff7bf314c037d2524..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9662 zcmd6tzi(Vc5XaY|NQo<29ui2DF6rP;a8KcDpd~fUT|tdglIkqc&>+*Lyd-T<2$pnd*>t}?CH>|fu}R#quR4$QIwEhSAk@5!gKcq5PZoJZ!*}H8 zP=mVcnus|XjO%6?=dEFspOP`SEg#pWsEDgLIO$$JYCd z=Y~5Gqalj(8j?rDL31(n__dX-J!UaxTZ8?dvl5kF`u^jC>f4VB_0zba``hPtv;G^3 z?ZxU0w3V$rW`@^u@WeH3hq#nn{5oIxc=`dQY7+Ov`?h>F;>08E9wL+I0f+XB-Se z>Q0X^e2uxwDf;>Nu$4nf&&lTC*ScL0r^M878$W+?8fjcD$*UB`+*|YP!M!VGH^a{S z8+Y5eX`zjDL7av8gYypNh(6&?c>Q=zUT2S|Nf+ep^^;0XA=uLeaeCe-Z=})r*QeEs z<^2V_uQ_>uhu)@t{2ubYS@Dd%Lr6lXI7S-GBP@uysGs_xAw( z6!|<;`;ly>bs5Q8OOMkw>0^_7PA*;Kd*tlVw53Xan!na&TTn`r|G-@8n?L_{aNk(_ zdZEXA(?!_XcL~lZCVxip-nwhUPcO$rUr=+?vHptn;x&5Y5|jTdi1*fA8@3dFeEKsV zia&>CoA`bI`1tTg04xqn~**eSY}6Sj;

!|;8ByUpn8`MCFplY1*%J~Q|Izq5x7x98-L!sOrY z+CyN@9Z9LJeLl4nKN2ZU!QIx zCt^kfrXt3hT1&6}i$&z@29`%DtT~zRjc)*BF620evrB$Ua##zy<)s{sG#d9o>s=5r z2mPCiVa;**;WEv40eTsu6fbgk)|JcWSYz8~@xS_|FE`=e-%=h^`Q3QUbNRSDW}2@{ z^yElmXSh@OC_ZNbj$@5ejZ!1-Gh{OjbT)=rUnlmeO5Yn^hVU-@&k$aPFG9EjpXmP& z!2zxx|H8*1NL>aYynw$Rg3M%i#TTsagzyml$`zlm-U}h-h<8a7f+cV~MDFk|SSyb> aKg-+dV0BT6>N>6JwpiBD>S}df*8M-9=#6^- diff --git a/public/favicon.svg b/public/favicon.svg new file mode 100644 index 00000000..74592a78 --- /dev/null +++ b/public/favicon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/public/manifest.json b/public/manifest.json index 3b435604..7b9ece0e 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,15 +1,15 @@ { - "short_name": "lecoffre", - "name": "lecoffre", - "icons": [ - { - "src": "/favicon.ico", - "sizes": "32x32 16x16", - "type": "image/x-icon" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "light", - "background_color": "light" + "short_name": "lecoffre", + "name": "lecoffre", + "icons": [ + { + "src": "/favicon.svg", + "sizes": "32x32 16x16", + "type": "image/x-icon" + } + ], + "start_url": ".", + "display": "standalone", + "theme_color": "light", + "background_color": "light" } diff --git a/src/front/Components/DesignSystem/Header/index.tsx b/src/front/Components/DesignSystem/Header/index.tsx index 4e5c17bc..addada55 100644 --- a/src/front/Components/DesignSystem/Header/index.tsx +++ b/src/front/Components/DesignSystem/Header/index.tsx @@ -54,7 +54,7 @@ export default function Header(props: IProps) { <>

- +
diff --git a/src/front/Components/LayoutTemplates/DefaultLayout.tsx b/src/front/Components/LayoutTemplates/DefaultLayout.tsx index 148fedf7..322f5bd3 100644 --- a/src/front/Components/LayoutTemplates/DefaultLayout.tsx +++ b/src/front/Components/LayoutTemplates/DefaultLayout.tsx @@ -8,7 +8,7 @@ export const DefaultLayout = ({ children }: DefaultLayoutProps) => { <> LEcoffre - {/* */} + {/* */}
{children} From 8738d8faf43423686057e26b6e91b7f4b0eec34f Mon Sep 17 00:00:00 2001 From: Maxime Sallerin <97036207+maxime-sallerin@users.noreply.github.com> Date: Fri, 26 Jul 2024 09:58:54 +0200 Subject: [PATCH 10/16] Feature/dropdown (#179) --- .../DropdownOption/classes.module.scss | 21 +++++++++ .../DropdownMenu/DropdownOption/index.tsx | 34 ++++++++++++++ .../Dropdown/DropdownMenu/classes.module.scss | 35 +++++++++++++++ .../Dropdown/DropdownMenu/index.tsx | 44 ++++++++++++++++++ .../DesignSystem/Dropdown/classes.module.scss | 45 +++++++++++++++++++ .../DesignSystem/Dropdown/index.tsx | 44 ++++++++++++++++++ .../DesignSystem/Typography/index.tsx | 3 ++ .../Layouts/DesignSystem/classes.module.scss | 1 + .../Components/Layouts/DesignSystem/index.tsx | 31 ++++++++++--- 9 files changed, 253 insertions(+), 5 deletions(-) create mode 100644 src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss create mode 100644 src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx create mode 100644 src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss create mode 100644 src/front/Components/DesignSystem/Dropdown/DropdownMenu/index.tsx create mode 100644 src/front/Components/DesignSystem/Dropdown/classes.module.scss create mode 100644 src/front/Components/DesignSystem/Dropdown/index.tsx diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss new file mode 100644 index 00000000..884a962d --- /dev/null +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss @@ -0,0 +1,21 @@ +.root { + display: flex; + padding: var(--spacing-1, 8px) var(--spacing-2, 16px); + align-items: center; + gap: var(--spacing-sm, 8px); + justify-content: space-between; + + border-radius: var(--dropdown-radius, 0px); + border: 1px solid var(--dropdown-border, rgba(0, 0, 0, 0)); + + background: var(--dropdown-option-background-default, #fff); + + &:hover { + background-color: var(--dropdown-option-background-hovered); + } + + &:focus, + &:active { + background-color: var(--dropdown-option-background-pressed); + } +} diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx new file mode 100644 index 00000000..05be3eb9 --- /dev/null +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx @@ -0,0 +1,34 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import { CheckIcon } from "@heroicons/react/24/outline"; +import { useCallback } from "react"; + +import classes from "./classes.module.scss"; +import IconButton from "@Front/Components/DesignSystem/IconButton"; + +export type IOption = { + id: string; + label: string; +}; + +type IProps = { + option: IOption; + isActive: boolean; + onClick?: (option: IOption) => void; +}; + +export default function DropdownOption(props: IProps) { + const { option, onClick, isActive } = props; + + const handleOnClick = useCallback(() => onClick && onClick(option), [onClick, option]); + + return ( +
+ + {option.label} + + {isActive && } />} +
+ ); +} diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss new file mode 100644 index 00000000..19135403 --- /dev/null +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss @@ -0,0 +1,35 @@ +.root { + position: relative; + overflow: hidden; + + .content { + width: 100%; + display: flex; + flex-direction: column; + gap: 8px; + + padding: var(--spacing-sm, 8px); + border-radius: var(--dropdown-radius, 0px); + + background: var(--dropdown-menu-background, #fff); + + border: 1px solid var(--dropdown-menu-border-primary, #005bcb); + + max-height: 0; + opacity: 0; + transition: max-height 0.3s ease-in-out, opacity 0.3s ease-in-out; + + position: absolute; + top: 100%; + left: 0; + transform: translateY(8px); + } + + &.open { + overflow: visible; + .content { + max-height: 500px; + opacity: 1; + } + } +} diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/index.tsx b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/index.tsx new file mode 100644 index 00000000..c19f6982 --- /dev/null +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/index.tsx @@ -0,0 +1,44 @@ +import classNames from "classnames"; +import React, { useCallback } from "react"; + +import classes from "./classes.module.scss"; +import DropdownOption, { IOption } from "./DropdownOption"; + +type IProps = { + options: IOption[]; + selectedOption: IOption | null; + children: React.ReactNode; + openable: { + isOpen: boolean; + open: () => void; + close: () => void; + toggle: () => void; + }; + onSelect?: (option: IOption) => void; +}; +export default function DropdownMenu(props: IProps) { + const { children, options, onSelect, openable, selectedOption } = props; + + const handleSelect = useCallback( + (option: IOption) => { + onSelect?.(option); + openable.close(); + }, + [onSelect, openable], + ); + + return ( +
+ {children} +
+ {options.map((option) => { + return ; + })} +
+
+ ); + + function isActive(option: IOption): boolean { + return selectedOption?.id === option.id; + } +} diff --git a/src/front/Components/DesignSystem/Dropdown/classes.module.scss b/src/front/Components/DesignSystem/Dropdown/classes.module.scss new file mode 100644 index 00000000..8406a67c --- /dev/null +++ b/src/front/Components/DesignSystem/Dropdown/classes.module.scss @@ -0,0 +1,45 @@ +@import "@Themes/constants.scss"; + +.root { + cursor: pointer; + height: 56px; + + display: flex; + align-items: center; + + padding: var(--spacing-2, 16px) var(--spacing-sm, 8px); + gap: var(--spacing-2, 16px); + + border-radius: var(--input-radius, 0px); + border: 1px solid var(--dropdown-input-border-default, #d7dce0); + background: var(--dropdown-input-background, #fff); + + .content { + width: 100%; + display: flex; + padding: 0px var(--spacing-2, 16px); + align-items: center; + flex: 1 0 0; + } + + &:hover { + border-color: var(--dropdown-input-border-hovered); + } + + &.active { + border-color: var(--dropdown-input-border-filled); + } + + &.open { + border-color: var(--dropdown-input-border-expanded); + + svg { + transform: rotate(180deg); + } + } + + &.disabled { + opacity: var(--opacity-disabled, 0.3); + pointer-events: none; + } +} diff --git a/src/front/Components/DesignSystem/Dropdown/index.tsx b/src/front/Components/DesignSystem/Dropdown/index.tsx new file mode 100644 index 00000000..a819e349 --- /dev/null +++ b/src/front/Components/DesignSystem/Dropdown/index.tsx @@ -0,0 +1,44 @@ +import useOpenable from "@Front/Hooks/useOpenable"; +import classNames from "classnames"; +import { useState } from "react"; + +import Typography, { ETypo, ETypoColor } from "../Typography"; +import classes from "./classes.module.scss"; +import DropdownMenu from "./DropdownMenu"; +import { IOption } from "./DropdownMenu/DropdownOption"; +import IconButton from "../IconButton"; +import { ChevronDownIcon } from "@heroicons/react/24/outline"; + +type IProps = { + options: IOption[]; + placeholder: string; + disabled?: boolean; +}; + +export default function Dropdown(props: IProps) { + const { options, placeholder, disabled } = props; + const [selectedOption, setSelectedOption] = useState(null); + const openable = useOpenable({ defaultOpen: false }); + + return ( + +
+
+ + {selectedOption?.label ?? placeholder} + +
+ } /> +
+
+ ); +} diff --git a/src/front/Components/DesignSystem/Typography/index.tsx b/src/front/Components/DesignSystem/Typography/index.tsx index 2aaeec59..9f63599c 100644 --- a/src/front/Components/DesignSystem/Typography/index.tsx +++ b/src/front/Components/DesignSystem/Typography/index.tsx @@ -156,6 +156,9 @@ export enum ETypoColor { CONTRAST_ACTIVED = "--contrast-actived", NAVIGATION_BUTTON_CONTRAST_DEFAULT = "--navigation-button-contrast-default", NAVIGATION_BUTTON_CONTRAST_ACTIVE = "--navigation-button-contrast-active", + + DROPDOWN_CONTRAST_DEFAULT = "--dropdown-contrast-default", + DROPDOWN_CONTRAST_ACTIVE = "--dropdown-contrast-active", } export default function Typography(props: IProps) { diff --git a/src/front/Components/Layouts/DesignSystem/classes.module.scss b/src/front/Components/Layouts/DesignSystem/classes.module.scss index 57f1d643..90be8834 100644 --- a/src/front/Components/Layouts/DesignSystem/classes.module.scss +++ b/src/front/Components/Layouts/DesignSystem/classes.module.scss @@ -3,6 +3,7 @@ flex-direction: column; gap: 32px; .components { + max-width: 600px; .inputs { display: flex; flex-direction: column; diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 276577a6..708e58a8 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -1,12 +1,17 @@ import Alert, { EAlertVariant } from "@Front/Components/DesignSystem/Alert"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import CircleProgress from "@Front/Components/DesignSystem/CircleProgress"; +import Dropdown from "@Front/Components/DesignSystem/Dropdown"; +import Footer from "@Front/Components/DesignSystem/Footer"; import Form from "@Front/Components/DesignSystem/Form"; import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import IconButton, { EIconButtonVariant } from "@Front/Components/DesignSystem/IconButton"; +import Menu from "@Front/Components/DesignSystem/Menu"; import Modal from "@Front/Components/DesignSystem/Modal"; import Newsletter from "@Front/Components/DesignSystem/Newsletter"; +import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList"; +import DropdownNavigation from "@Front/Components/DesignSystem/SearchBlockList/DropdownNavigation"; import Table from "@Front/Components/DesignSystem/Table"; import Tag, { ETagColor, ETagVariant } from "@Front/Components/DesignSystem/Tag"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; @@ -14,7 +19,6 @@ 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, @@ -27,9 +31,6 @@ import { import { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; -import Menu from "@Front/Components/DesignSystem/Menu"; -import DropdownNavigation from "@Front/Components/DesignSystem/SearchBlockList/DropdownNavigation"; -import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList"; export default function DesignSystem() { const { isOpen, open, close } = useOpenable(); @@ -78,8 +79,28 @@ export default function DesignSystem() { return ( DesignSystem - +
+
+ Dropdown + +
Navigation latérale Date: Fri, 26 Jul 2024 10:07:14 +0200 Subject: [PATCH 11/16] fix routing rib office --- src/front/Components/DesignSystem/Header/Navigation/index.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/front/Components/DesignSystem/Header/Navigation/index.tsx b/src/front/Components/DesignSystem/Header/Navigation/index.tsx index eb4e2878..e6812a0f 100644 --- a/src/front/Components/DesignSystem/Header/Navigation/index.tsx +++ b/src/front/Components/DesignSystem/Header/Navigation/index.tsx @@ -176,6 +176,7 @@ const officeItems: IItem[] = [ icon: , text: "RIB Office", link: Module.getInstance().get().modules.pages.OfficesRib.props.path, + routesActive: [Module.getInstance().get().modules.pages.OfficesRib.props.path], rules: [ { action: AppRuleActions.update, From b39662f3955c4c39f11e99e8566c788f87b75d60 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 26 Jul 2024 11:05:13 +0200 Subject: [PATCH 12/16] :sparkles: add option nav --- .../DropdownOption/classes.module.scss | 12 ++++++ .../DropdownMenu/DropdownOption/index.tsx | 38 +++++++++++++++---- .../DesignSystem/Dropdown/index.tsx | 10 ++++- .../Components/Layouts/DesignSystem/index.tsx | 4 ++ 4 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss index 884a962d..e959747b 100644 --- a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss @@ -10,6 +10,18 @@ background: var(--dropdown-option-background-default, #fff); + svg { + width: 24px; + height: 24px; + } + + .content { + display: flex; + flex-direction: column; + align-items: flex-start; + flex: 1 0 0; + } + &:hover { background-color: var(--dropdown-option-background-hovered); } diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx index 05be3eb9..1970ab48 100644 --- a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx @@ -1,13 +1,13 @@ +import IconButton from "@Front/Components/DesignSystem/IconButton"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import { CheckIcon } from "@heroicons/react/24/outline"; import { useCallback } from "react"; import classes from "./classes.module.scss"; -import IconButton from "@Front/Components/DesignSystem/IconButton"; export type IOption = { id: string; - label: string; + label: string | { text: string; subtext: string }; }; type IProps = { @@ -23,12 +23,34 @@ export default function DropdownOption(props: IProps) { return (
- - {option.label} - - {isActive && } />} + {getContent(option.label)} + {isActive && }
); + + function getContent(label: string | { text: string; subtext: string }) { + if (typeof label === "string") { + return ( + + {label} + + ); + } + return ( +
+ + {label.text} + + + {label.subtext} + +
+ ); + } } diff --git a/src/front/Components/DesignSystem/Dropdown/index.tsx b/src/front/Components/DesignSystem/Dropdown/index.tsx index a819e349..8bd40c39 100644 --- a/src/front/Components/DesignSystem/Dropdown/index.tsx +++ b/src/front/Components/DesignSystem/Dropdown/index.tsx @@ -34,11 +34,19 @@ export default function Dropdown(props: IProps) { - {selectedOption?.label ?? placeholder} + {getLabel(selectedOption) ?? placeholder}
} />
); + + function getLabel(option: IOption | null): string | null { + if (!option) return null; + if (typeof option.label === "string") { + return option.label; + } + return `${option.label.text} ${option.label.subtext}`; + } } diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 708e58a8..774e41d5 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -97,6 +97,10 @@ export default function DesignSystem() { id: "3", label: "Option 3", }, + { + id: "4", + label: { text: "Option 4", subtext: "Subtext" }, + }, ]} placeholder="Placeholder" /> From 1ee2b977f6fdee8e464647e77e0bd57677a324b9 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 26 Jul 2024 12:22:33 +0200 Subject: [PATCH 13/16] :sparkles: Autocomplete --- .../Autocomplete/classes.module.scss | 41 ++++++++++++ .../DesignSystem/Autocomplete/index.tsx | 65 +++++++++++++++++++ .../DropdownOption/classes.module.scss | 5 ++ .../DropdownMenu/DropdownOption/index.tsx | 4 +- .../Dropdown/DropdownMenu/classes.module.scss | 1 + .../SearchBar/classes.module.scss | 11 ++++ .../DesignSystem/SearchBar/index.tsx | 16 +++-- .../Components/Layouts/DesignSystem/index.tsx | 26 +++++++- 8 files changed, 161 insertions(+), 8 deletions(-) create mode 100644 src/front/Components/DesignSystem/Autocomplete/classes.module.scss create mode 100644 src/front/Components/DesignSystem/Autocomplete/index.tsx diff --git a/src/front/Components/DesignSystem/Autocomplete/classes.module.scss b/src/front/Components/DesignSystem/Autocomplete/classes.module.scss new file mode 100644 index 00000000..452fdaad --- /dev/null +++ b/src/front/Components/DesignSystem/Autocomplete/classes.module.scss @@ -0,0 +1,41 @@ +@import "@Themes/constants.scss"; + +.root { + cursor: pointer; + height: 56px; + + display: flex; + align-items: center; + + padding: var(--spacing-2, 16px) var(--spacing-sm, 8px); + gap: var(--spacing-2, 16px); + + border-radius: var(--input-radius, 0px); + border: 1px solid var(--dropdown-input-border-default, #d7dce0); + background: var(--dropdown-input-background, #fff); + + .content { + width: 100%; + display: flex; + padding: 0px var(--spacing-2, 16px); + align-items: center; + flex: 1 0 0; + } + + &:hover { + border-color: var(--dropdown-input-border-hovered); + } + + &.active { + border-color: var(--dropdown-input-border-filled); + } + + &.open { + border-color: var(--dropdown-input-border-expanded); + } + + &.disabled { + opacity: var(--opacity-disabled, 0.3); + pointer-events: none; + } +} diff --git a/src/front/Components/DesignSystem/Autocomplete/index.tsx b/src/front/Components/DesignSystem/Autocomplete/index.tsx new file mode 100644 index 00000000..d95a7a47 --- /dev/null +++ b/src/front/Components/DesignSystem/Autocomplete/index.tsx @@ -0,0 +1,65 @@ +import useOpenable from "@Front/Hooks/useOpenable"; +import { useState, useEffect, useCallback } from "react"; +import DropdownMenu from "../Dropdown/DropdownMenu"; +import { IOption } from "../Dropdown/DropdownMenu/DropdownOption"; +import SearchBar from "../SearchBar"; + +type IProps = { + options: IOption[]; + placeholder: string; + disabled?: boolean; +}; + +export default function Autocomplete(props: IProps) { + const { options, placeholder, disabled } = props; + const [selectedOption, setSelectedOption] = useState(null); + const [searchValue, setSearchValue] = useState(""); + const [filteredOptions, setFilteredOptions] = useState(options); + const openable = useOpenable({ defaultOpen: false }); + + useEffect(() => { + if (searchValue) { + const filteredOptions = options.filter((option) => getLabel(option)?.toLowerCase().includes(searchValue.toLowerCase())); + console.log(filteredOptions); + if (filteredOptions.length === 0) + return setFilteredOptions([{ id: "no-results", label: "Aucun résulats", notSelectable: true }]); + return setFilteredOptions(filteredOptions); + } + return setFilteredOptions(options); + }, [searchValue, options]); + + const handleSearchChange = useCallback( + (value: string) => { + setSearchValue(value); + if (value) { + openable.open(); + } else { + openable.close(); + } + }, + [openable], + ); + + const handleSelectOption = useCallback( + (option: IOption) => { + setSelectedOption(option); + setSearchValue(getLabel(option) || ""); + openable.close(); + }, + [openable], + ); + + function getLabel(option: IOption | null): string | null { + if (!option) return null; + if (typeof option.label === "string") { + return option.label; + } + return `${option.label.text} ${option.label.subtext}`; + } + + return ( + + + + ); +} diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss index e959747b..0cd1dc23 100644 --- a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/classes.module.scss @@ -30,4 +30,9 @@ &:active { background-color: var(--dropdown-option-background-pressed); } + + &[data-not-selectable="true"] { + pointer-events: none; + user-select: none; + } } diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx index 1970ab48..dee89d43 100644 --- a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption/index.tsx @@ -1,4 +1,3 @@ -import IconButton from "@Front/Components/DesignSystem/IconButton"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import { CheckIcon } from "@heroicons/react/24/outline"; import { useCallback } from "react"; @@ -8,6 +7,7 @@ import classes from "./classes.module.scss"; export type IOption = { id: string; label: string | { text: string; subtext: string }; + notSelectable?: boolean; }; type IProps = { @@ -22,7 +22,7 @@ export default function DropdownOption(props: IProps) { const handleOnClick = useCallback(() => onClick && onClick(option), [onClick, option]); return ( -
+
{getContent(option.label)} {isActive && }
diff --git a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss index 19135403..d8742a45 100644 --- a/src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss +++ b/src/front/Components/DesignSystem/Dropdown/DropdownMenu/classes.module.scss @@ -7,6 +7,7 @@ display: flex; flex-direction: column; gap: 8px; + z-index: 3; padding: var(--spacing-sm, 8px); border-radius: var(--dropdown-radius, 0px); diff --git a/src/front/Components/DesignSystem/SearchBar/classes.module.scss b/src/front/Components/DesignSystem/SearchBar/classes.module.scss index bfb3e58c..a9a21a68 100644 --- a/src/front/Components/DesignSystem/SearchBar/classes.module.scss +++ b/src/front/Components/DesignSystem/SearchBar/classes.module.scss @@ -1,6 +1,8 @@ @import "@Themes/constants.scss"; .root { + height: 56px; + display: flex; padding: var(--spacing-2, 16px) var(--spacing-sm, 8px); align-items: flex-start; @@ -10,6 +12,10 @@ border: 1px solid var(--input-main-border-default, #d7dce0); background: var(--input-background, #fff); + svg { + stroke: var(--button-icon-button-default-default); + } + &:hover { border-radius: var(--input-radius, 0px); border: 1px solid var(--input-main-border-hovered, #b4bec5); @@ -28,6 +34,11 @@ background: var(--input-background, #fff); } + &[data-is-disabled="true"] { + opacity: var(--opacity-disabled, 0.3); + pointer-events: none; + } + .input-container { display: flex; flex: 1; diff --git a/src/front/Components/DesignSystem/SearchBar/index.tsx b/src/front/Components/DesignSystem/SearchBar/index.tsx index 57a7af19..113305ce 100644 --- a/src/front/Components/DesignSystem/SearchBar/index.tsx +++ b/src/front/Components/DesignSystem/SearchBar/index.tsx @@ -1,16 +1,18 @@ -import React, { useCallback } from "react"; +import React, { useCallback, useEffect } from "react"; import classes from "./classes.module.scss"; import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline"; type IProps = { onChange?: (input: string) => void; + value?: string; placeholder?: string; + disabled?: boolean; }; -export default function SearchBar({ onChange, placeholder = "Rechercher" }: IProps) { +export default function SearchBar({ onChange, value: propValue, placeholder = "Rechercher", disabled = false }: IProps) { const [isFocused, setIsFocused] = React.useState(false); - const [value, setValue] = React.useState(""); + const [value, setValue] = React.useState(propValue || ""); const changeValue = useCallback( (value: string) => { @@ -25,8 +27,14 @@ export default function SearchBar({ onChange, placeholder = "Rechercher" }: IPro const handleBlur = () => setIsFocused(false); const clearValue = () => changeValue(""); + useEffect(() => { + if (propValue !== undefined) { + setValue(propValue); + } + }, [propValue]); + return ( -