From 486eacf686ae7fec1da1e5125a76dab99360936c Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 18 Sep 2024 14:37:31 +0200 Subject: [PATCH] :sparkles: refonte client dashboard + responsive --- .../DesignSystem/Button/classes.module.scss | 1 - .../NotificationBox/classes.module.scss | 29 ++++ .../DesignSystem/NotificationBox/index.tsx | 40 +++++ .../Components/Elements/ContactBox/index.tsx | 3 +- .../ContactBox/classes.module.scss | 37 +++++ .../ClientDashboard/ContactBox/index.tsx | 116 +++++++++++++ .../classes.module.scss | 6 + .../ClientDashboard/classes.module.scss | 54 ++++-- .../Layouts/ClientDashboard/index.tsx | 157 ++++++++---------- 9 files changed, 334 insertions(+), 109 deletions(-) create mode 100644 src/front/Components/DesignSystem/NotificationBox/classes.module.scss create mode 100644 src/front/Components/DesignSystem/NotificationBox/index.tsx create mode 100644 src/front/Components/Layouts/ClientDashboard/ContactBox/classes.module.scss create mode 100644 src/front/Components/Layouts/ClientDashboard/ContactBox/index.tsx diff --git a/src/front/Components/DesignSystem/Button/classes.module.scss b/src/front/Components/DesignSystem/Button/classes.module.scss index 1ef3abbf..b651239d 100644 --- a/src/front/Components/DesignSystem/Button/classes.module.scss +++ b/src/front/Components/DesignSystem/Button/classes.module.scss @@ -700,7 +700,6 @@ */ &[fullwidthattr="true"] { width: 100%; - flex: 1; } &[fullwidthattr="false"] { diff --git a/src/front/Components/DesignSystem/NotificationBox/classes.module.scss b/src/front/Components/DesignSystem/NotificationBox/classes.module.scss new file mode 100644 index 00000000..f562eedb --- /dev/null +++ b/src/front/Components/DesignSystem/NotificationBox/classes.module.scss @@ -0,0 +1,29 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + align-items: center; + gap: var(--spacing-md, 16px); + + width: 355px; + padding: var(--spacing-sm, 8px) var(--spacing-md, 16px); + + border-radius: var(--notification-radius, 8px); + + .content { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + } + + &:hover { + background: var(--neutral-weak-higlight, #f7f8f8); + } + + &.unread { + background: var(--notification-unread-default, #fff3ed); + &:hover { + background: var(--notification-unread-hovered, #ffe4d4); + } + } +} diff --git a/src/front/Components/DesignSystem/NotificationBox/index.tsx b/src/front/Components/DesignSystem/NotificationBox/index.tsx new file mode 100644 index 00000000..7c4299a4 --- /dev/null +++ b/src/front/Components/DesignSystem/NotificationBox/index.tsx @@ -0,0 +1,40 @@ +import classNames from "classnames"; +import React from "react"; + +import Typography, { ETypo, ETypoColor } from "../Typography"; +import classes from "./classes.module.scss"; +import Button, { EButtonSize, EButtonstyletype, EButtonVariant, IButtonProps } from "../Button"; + +type IProps = { + text: string; + read: boolean; + button: IButtonProps; + className?: string; +}; + +export default function NotificationBox(props: IProps) { + const { className, text, button, read } = props; + + return ( +
+
+ + {text} + + +
+ + {!read && ( + + + + )} +
+ ); +} diff --git a/src/front/Components/Elements/ContactBox/index.tsx b/src/front/Components/Elements/ContactBox/index.tsx index a898e169..73dd1842 100644 --- a/src/front/Components/Elements/ContactBox/index.tsx +++ b/src/front/Components/Elements/ContactBox/index.tsx @@ -1,11 +1,10 @@ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import { Contact as ContactCustomer, Note } from "le-coffre-resources/dist/Customer"; -import { Contact as ContactNotary } from "le-coffre-resources/dist/Notary"; import classes from "./classes.module.scss"; type IProps = { - contact: ContactCustomer | ContactNotary; + contact: ContactCustomer; note: Note | null; }; diff --git a/src/front/Components/Layouts/ClientDashboard/ContactBox/classes.module.scss b/src/front/Components/Layouts/ClientDashboard/ContactBox/classes.module.scss new file mode 100644 index 00000000..f6b53440 --- /dev/null +++ b/src/front/Components/Layouts/ClientDashboard/ContactBox/classes.module.scss @@ -0,0 +1,37 @@ +@import "@Themes/constants.scss"; + +.root { + width: 100%; + display: flex; + justify-content: space-between; + + padding: var(--spacing-md, 16px); + gap: var(--spacing-md, 16px); + + background: var(--primary-weak-higlight, #e5eefa); + + .left { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + + .note-and-rib-button { + display: none; + + @media screen and (max-width: $screen-s) { + display: block; + } + } + } + + .right { + margin-right: var(--spacing-xl, 32px); + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + + @media screen and (max-width: $screen-s) { + display: none; + } + } +} diff --git a/src/front/Components/Layouts/ClientDashboard/ContactBox/index.tsx b/src/front/Components/Layouts/ClientDashboard/ContactBox/index.tsx new file mode 100644 index 00000000..03ad6bc8 --- /dev/null +++ b/src/front/Components/Layouts/ClientDashboard/ContactBox/index.tsx @@ -0,0 +1,116 @@ +import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import { ArrowDownTrayIcon } from "@heroicons/react/24/outline"; +import Customer from "le-coffre-resources/dist/Customer"; +import { OfficeFolder as OfficeFolderNotary } from "le-coffre-resources/dist/Notary"; +import { useCallback, useEffect, useMemo, useState } from "react"; + +import classes from "./classes.module.scss"; +import OfficeRib from "@Front/Api/LeCoffreApi/Customer/OfficeRib/OfficeRib"; + +type IProps = { + folder: OfficeFolderNotary; + customer: Customer; +}; + +export default function ContactBox(props: IProps) { + const { folder, customer } = props; + + const [ribUrl, setRibUrl] = useState(null); + + const notaryContact = useMemo( + () => + folder?.stakeholders!.find((stakeholder) => stakeholder.office_role?.name === "Collaborateur")?.contact ?? + folder?.stakeholders![0]!.contact, + [folder], + ); + + const note = useMemo( + () => + folder?.notes?.find((note) => note.customer?.uid === customer?.uid) ?? { + content: "Aucune note", + created_at: new Date(), + updated_at: new Date(), + }, + [customer?.uid, folder?.notes], + ); + + useEffect(() => { + if (!folder?.office?.uid) return; + OfficeRib.getInstance() + .getRibStream(folder.office.uid) + .then((blob) => setRibUrl(URL.createObjectURL(blob))); + }, [folder]); + + const downloadRib = useCallback(async () => { + if (!ribUrl) return; + const a = document.createElement("a"); + a.style.display = "none"; + a.href = ribUrl; + a.download = ""; + document.body.appendChild(a); + a.click(); + }, [ribUrl]); + + return ( +
+
+
+ + Votre notaire + + + {notaryContact?.first_name} {notaryContact?.last_name} + +
+
+ + Numéro de téléphone + + + {notaryContact?.cell_phone_number ?? notaryContact?.phone_number ?? "_"} + +
+
+ + E-mail + + + {notaryContact?.email ?? "_"} + +
+
+ {noteAndRibButton()} +
+
+ +
{noteAndRibButton()}
+
+ ); + + function noteAndRibButton() { + return ( + <> +
+ + Note dossier + + + {note?.content ?? "-"} + +
+ {ribUrl && ( + + )} + + ); + } +} diff --git a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss index cde520cf..c13c6a35 100644 --- a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss +++ b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss @@ -12,4 +12,10 @@ flex-direction: column; gap: var(--spacing-sm, 8px); } + + @media screen and (max-width: $screen-s) { + flex-direction: column; + gap: var(--spacing-md, 16px); + align-items: flex-start; + } } diff --git a/src/front/Components/Layouts/ClientDashboard/classes.module.scss b/src/front/Components/Layouts/ClientDashboard/classes.module.scss index 584a4e5c..3fd3e298 100644 --- a/src/front/Components/Layouts/ClientDashboard/classes.module.scss +++ b/src/front/Components/Layouts/ClientDashboard/classes.module.scss @@ -5,36 +5,54 @@ flex-direction: column; gap: var(--spacing-xl, 32px); - .title-container { - flex-direction: column; + .top { display: flex; - gap: var(--spacing-sm, 8px); + gap: var(--spacing-lg, 24px); - .office-container { + .folder-info-container { + flex-direction: column; display: flex; - align-items: center; - gap: var(--spacing-md, 16px); + width: 100%; + gap: var(--spacing-sm, 8px); + + .office-container { + display: flex; + align-items: center; + gap: var(--spacing-md, 16px); + } + } + + @media screen and (max-width: $screen-s) { + .desktop-separator { + display: none; + } + + flex-direction: column; } } - .content { + .documents { display: flex; - gap: var(--spacing-lg, 24px); - align-items: flex-start; + flex-direction: column; + gap: var(--spacing-xl, 32px); - .notary { - display: flex; - width: 300px; - flex-direction: column; - align-items: flex-start; - gap: var(--spacing-lg, 24px); - } - - .documents { + .content { display: flex; flex-direction: column; gap: var(--spacing-xl, 32px); width: 100%; + + @media screen and (max-width: $screen-s) { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-md, 16px); + } + + @media screen and (max-width: 734px) { + display: grid; + grid-template-columns: 1fr; + gap: var(--spacing-xl, 32px); + } } } } diff --git a/src/front/Components/Layouts/ClientDashboard/index.tsx b/src/front/Components/Layouts/ClientDashboard/index.tsx index da2fb194..3808b83b 100644 --- a/src/front/Components/Layouts/ClientDashboard/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/index.tsx @@ -4,23 +4,24 @@ import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/Customer/ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Customer, { Document } from "le-coffre-resources/dist/Customer"; -import React, { useCallback, useEffect, useMemo, useState } from "react"; -import { type OfficeFolder as OfficeFolderNotary } from "le-coffre-resources/dist/Notary"; +import React, { useCallback, useEffect, useState } from "react"; +import { DocumentNotary, type OfficeFolder as OfficeFolderNotary } from "le-coffre-resources/dist/Notary"; import classes from "./classes.module.scss"; import { useRouter } from "next/router"; import JwtService, { ICustomerJwtPayload } from "@Front/Services/JwtService/JwtService"; import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders"; -import OfficeRib from "@Front/Api/LeCoffreApi/Customer/OfficeRib/OfficeRib"; import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; import DefaultCustomerDashboard from "@Front/Components/LayoutTemplates/DefaultCustomerDashboard"; -import ContactBox from "@Front/Components/Elements/ContactBox"; -import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import { ArrowDownTrayIcon } from "@heroicons/react/24/outline"; + +import { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import DepositDocumentComponent from "./DepositDocumentComponent"; -import Link from "next/link"; import Module from "@Front/Config/Module"; +import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator"; +import NotificationBox from "@Front/Components/DesignSystem/NotificationBox"; +import ContactBox from "./ContactBox"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; type IProps = {}; @@ -31,8 +32,7 @@ export default function ClientDashboard(props: IProps) { const [customer, setCustomer] = useState(null); const [folder, setFolder] = useState(null); - - const [ribUrl, setRibUrl] = useState(null); + const [documentsNotary, setDocumentsNotary] = useState([]); const fetchFolderAndCustomer = useCallback(async () => { let jwt: ICustomerJwtPayload | undefined; @@ -55,6 +55,11 @@ export default function ClientDashboard(props: IProps) { office_role: true, }, }, + deed: { + include: { + deed_type: true, + }, + }, }, }); @@ -99,95 +104,71 @@ export default function ClientDashboard(props: IProps) { fetchFolderAndCustomer().then(({ customer }) => fetchDocuments(customer.uid)); }, [fetchDocuments, fetchFolderAndCustomer]); - const notaryContact = useMemo( - () => - folder?.stakeholders!.find((stakeholder) => stakeholder.office_role?.name === "Collaborateur")?.contact ?? - folder?.stakeholders![0]!.contact, - [folder], - ); - - const note = useMemo( - () => - folder?.notes?.find((note) => note.customer?.uid === customer?.uid) ?? { - content: "Aucune note", - created_at: new Date(), - updated_at: new Date(), - }, - [customer?.uid, folder?.notes], - ); - useEffect(() => { - if (!folder?.office?.uid) return; - OfficeRib.getInstance() - .getRibStream(folder.office.uid) - .then((blob) => setRibUrl(URL.createObjectURL(blob))); - }, [folder]); - - const downloadRib = useCallback(async () => { - if (!ribUrl) return; - const a = document.createElement("a"); - a.style.display = "none"; - a.href = ribUrl; - a.download = ""; - document.body.appendChild(a); - a.click(); - }, [ribUrl]); + const customerUid = JwtService.getInstance().decodeCustomerJwt()?.customerId; + if (!folderUid || !customerUid) return; + DocumentsNotary.getInstance() + .get({ where: { folder: { uid: folderUid }, customer: { uid: customerUid } }, include: { files: true } }) + .then((documentsNotary) => setDocumentsNotary(documentsNotary)); + }, [folderUid]); return (
-
- - Dossier {folder?.folder_number} - {folder?.name} - - - Bonjour {customer?.contact?.first_name.concat(" ", customer?.contact?.last_name)} - - -
+
+
- Office + Dossier {folder?.folder_number} - {folder?.name} + + Bonjour {customer?.contact?.first_name.concat(" ", customer?.contact?.last_name)} + + +
+ + Office + - - {folder?.office?.name} - + + {folder?.office?.name} + +
+ + {(documentsNotary?.length ?? 0) > 0 && ( + + router.push( + Module.getInstance() + .get() + .modules.pages.ClientDashboard.pages.ReceiveDocuments.props.path.replace( + "[folderUid]", + folderUid as string, + ), + ), + }} + read={false} + /> + )}
-
-
- - Votre Notaire - - {notaryContact && } - {ribUrl && ( - - )} - - - -
-
- - Documents à envoyer - + + {customer && folder && } + +
+ + Documents à envoyer + +
{documents?.map((document) => (