From 719832d41e7188c7e52dbe2bfadd99c339054b58 Mon Sep 17 00:00:00 2001 From: Vins Date: Wed, 7 Aug 2024 08:52:02 +0200 Subject: [PATCH 01/63] Fixed auto reload page after client delete --- .../ClientView/DocumentTables/index.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index 8d85e9f2..8714f3dc 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -201,6 +201,14 @@ export default function DocumentTables(props: IProps) { return (validatedDocuments.length / total) * 100; }, [askedDocuments.length, refusedDocuments.length, toValidateDocuments.length, validatedDocuments.length]); + const handleDelete = useCallback( + (documentUid: string) => { + setDocuments(documents.filter((document) => document.uid !== documentUid)); + window.location.reload(); + }, + [documents], + ); + return (
@@ -217,7 +225,7 @@ export default function DocumentTables(props: IProps) { setDocuments(documents.filter((document) => document.uid !== uid))} + onDeleteSuccess={handleDelete} documentUid={documentUid} /> )} From a813a4e57ea4ba6b01b85690a9e7e79c4a5ff057 Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 8 Aug 2024 13:37:24 +0200 Subject: [PATCH 02/63] :sparkles: seprator and wip drag and drop --- .../DragAndDrop/classes.module.scss | 27 +++ .../DesignSystem/DragAndDrop/index.tsx | 35 ++++ .../Separator/classes.module.scss | 24 +++ .../DesignSystem/Separator/index.tsx | 33 ++++ .../DesignSystem/Typography/index.tsx | 2 + .../Layouts/DesignSystem/classes.module.scss | 7 +- .../Components/Layouts/DesignSystem/index.tsx | 157 ++++++++++-------- 7 files changed, 213 insertions(+), 72 deletions(-) create mode 100644 src/front/Components/DesignSystem/DragAndDrop/classes.module.scss create mode 100644 src/front/Components/DesignSystem/DragAndDrop/index.tsx create mode 100644 src/front/Components/DesignSystem/Separator/classes.module.scss create mode 100644 src/front/Components/DesignSystem/Separator/index.tsx diff --git a/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss b/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss new file mode 100644 index 00000000..30993fb9 --- /dev/null +++ b/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss @@ -0,0 +1,27 @@ +@import "@Themes/constants.scss"; + +.root { + display: inline-flex; + padding: var(--spacing-2, 16px) var(--Radius-2xl, 32px) var(--spacing-2, 16px) var(--spacing-xl, 32px); + align-items: center; + gap: var(--spacing-4, 32px); + + .content { + display: flex; + flex-direction: column; + gap: var(--spacing-sm, 8px); + + .deposit-document { + display: flex; + gap: var(--spacing-sm, 8px); + } + } + + svg{ + min-width: var(--spacing-3, 24px); + min-height: var(--spacing-3, 24px); + width: var(--spacing-3, 24px); + height: var(--spacing-3, 24px); + stroke: var(--color-primary-500); + } +} diff --git a/src/front/Components/DesignSystem/DragAndDrop/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/index.tsx new file mode 100644 index 00000000..1fe559a9 --- /dev/null +++ b/src/front/Components/DesignSystem/DragAndDrop/index.tsx @@ -0,0 +1,35 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import React from "react"; +import { DocumentPlusIcon } from "@heroicons/react/24/outline"; + +import classes from "./classes.module.scss"; +import classNames from "classnames"; +import Separator, { ESeperatorColor, ESeperatorDirection } from "../Separator"; +import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "../Button"; + +type IProps = {}; + +export default function DragAndDrop(props: IProps) { + const {} = props; + + return ( +
+ + +
+
+ + Drag and Drop ou + + +
+ + + Description + +
+
+ ); +} diff --git a/src/front/Components/DesignSystem/Separator/classes.module.scss b/src/front/Components/DesignSystem/Separator/classes.module.scss new file mode 100644 index 00000000..51b570fd --- /dev/null +++ b/src/front/Components/DesignSystem/Separator/classes.module.scss @@ -0,0 +1,24 @@ +@import "@Themes/constants.scss"; + +.root { + height: 2px; + width: 100%; + background-color: var(--separator-stroke-default); + + &.vertical { + width: 2px; + height: 100%; + } + + &.light { + background-color: var(--separator-stroke-light); + } + + &.strong { + background-color: var(--separator-stroke-strong); + } + + &.contrast { + background-color: var(--separator-stroke-contrast); + } +} diff --git a/src/front/Components/DesignSystem/Separator/index.tsx b/src/front/Components/DesignSystem/Separator/index.tsx new file mode 100644 index 00000000..21ccbc1e --- /dev/null +++ b/src/front/Components/DesignSystem/Separator/index.tsx @@ -0,0 +1,33 @@ +import React from "react"; + +import classes from "./classes.module.scss"; +import classNames from "classnames"; + +export enum ESeperatorColor { + LIGHT = "light", + DEFAULT = "default", + STRONG = "strong", + CONTRAST = "contrast", +} + +export enum ESeperatorDirection { + HORIZONTAL = "horizontal", + VERTICAL = "vertical", +} + +type IProps = { + color?: ESeperatorColor; + direction?: ESeperatorDirection; + size?: number; +}; + +export default function Separator(props: IProps) { + const { color = ESeperatorColor.DEFAULT, direction = ESeperatorDirection.HORIZONTAL, size } = props; + + return ( +
+ ); +} diff --git a/src/front/Components/DesignSystem/Typography/index.tsx b/src/front/Components/DesignSystem/Typography/index.tsx index 584397a6..248cad65 100644 --- a/src/front/Components/DesignSystem/Typography/index.tsx +++ b/src/front/Components/DesignSystem/Typography/index.tsx @@ -149,6 +149,8 @@ export enum ETypoColor { INPUT_ERROR = "--input-error", TEXT_ACCENT = "--text-accent", + TEXT_PRIMARY = "--text-primary", + TEXT_SECONDARY = "--text-secondary", CONTRAST_DEFAULT = "--contrast-default", CONTRAST_HOVERED = "--contrast-hovered", diff --git a/src/front/Components/Layouts/DesignSystem/classes.module.scss b/src/front/Components/Layouts/DesignSystem/classes.module.scss index c0f72ca1..22111a86 100644 --- a/src/front/Components/Layouts/DesignSystem/classes.module.scss +++ b/src/front/Components/Layouts/DesignSystem/classes.module.scss @@ -3,15 +3,16 @@ flex-direction: column; gap: 32px; .components { + display: flex; + flex-direction: column; + gap: 32px; max-width: 600px; + .inputs { display: flex; flex-direction: column; gap: 24px; } - display: flex; - flex-direction: column; - gap: 24px; .rows { display: flex; diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 0eab5b90..619f47dd 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -36,6 +36,8 @@ import classes from "./classes.module.scss"; import CheckboxesInputElement from "@Front/Components/DesignSystem/CheckBox"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import Toggle, { EToggleSize } from "@Front/Components/DesignSystem/Toggle"; +import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator"; +import DragAndDrop from "@Front/Components/DesignSystem/DragAndDrop"; export default function DesignSystem() { const { isOpen, open, close } = useOpenable(); @@ -83,78 +85,95 @@ export default function DesignSystem() { return ( - DesignSystem
-
-
- - - - -
- -
- - - - -
+ DesignSystem
+ Drag and Drop + + Separators +
+ + + + +
+
+ + + + +
+ + Checkboxes +
+ + + + +
+ Radio boxes +
+ + + + +
+ Toggle
From b6565833b16904ee06891519c4922bf68fd39c5e Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 8 Aug 2024 17:49:01 +0200 Subject: [PATCH 03/63] :sparkles: drag and drop --- .../DocumentElement/classes.module.scss | 39 ++++ .../DragAndDrop/DocumentElement/index.tsx | 37 ++++ .../DragAndDrop/classes.module.scss | 49 ++++- .../DesignSystem/DragAndDrop/index.tsx | 168 +++++++++++++++--- .../Components/Layouts/DesignSystem/index.tsx | 2 +- 5 files changed, 266 insertions(+), 29 deletions(-) create mode 100644 src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss create mode 100644 src/front/Components/DesignSystem/DragAndDrop/DocumentElement/index.tsx diff --git a/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss b/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss new file mode 100644 index 00000000..cdba1ed0 --- /dev/null +++ b/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss @@ -0,0 +1,39 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + max-width: 357px; + width: 100%; + gap: var(--spacing-sm, 8px); + justify-content: space-between; + align-items: center; + + .content { + display: flex; + gap: var(--spacing-sm, 8px); + align-items: center; + + .file-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 277px; + } + } + + svg { + min-width: var(--spacing-3, 24px); + min-height: var(--spacing-3, 24px); + width: var(--spacing-3, 24px); + height: var(--spacing-3, 24px); + stroke: var(--color-primary-500); + } + + .error{ + min-width: var(--spacing-3, 24px); + min-height: var(--spacing-3, 24px); + width: var(--spacing-3, 24px); + height: var(--spacing-3, 24px); + stroke: var(--color-error-500); + } +} \ No newline at end of file diff --git a/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/index.tsx new file mode 100644 index 00000000..efb8aa20 --- /dev/null +++ b/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/index.tsx @@ -0,0 +1,37 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import { CheckCircleIcon, XCircleIcon, XMarkIcon } from "@heroicons/react/24/outline"; +import React from "react"; + +import IconButton, { EIconButtonVariant } from "../../IconButton"; +import Loader from "../../Loader"; +import classes from "./classes.module.scss"; + +type IProps = { + isLoading: boolean; + file: File | null; + onRemove: () => void; + error?: string; +}; + +export default function DocumentElement(props: IProps) { + const { isLoading, onRemove, file, error } = props; + + return ( +
+
+ {isLoading ? : !error ? : } + {error && ( + + {error} + + )} + {file && !error && ( + + {file.name} + + )} +
+ } variant={error ? EIconButtonVariant.ERROR : EIconButtonVariant.NEUTRAL} /> +
+ ); +} diff --git a/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss b/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss index 30993fb9..0c3fae28 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss +++ b/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss @@ -2,22 +2,57 @@ .root { display: inline-flex; + flex-direction: column; + gap: var(--spacing-3, 24px); + + width: fit-content; padding: var(--spacing-2, 16px) var(--Radius-2xl, 32px) var(--spacing-2, 16px) var(--spacing-xl, 32px); - align-items: center; - gap: var(--spacing-4, 32px); + + border-radius: var(--Radius-md, 8px); + border: 1px dashed var(--dropdown-input-border-hovered, #b4bec5); + + &:hover { + border-color: var(--dropdown-input-border-expanded); + background: var(--primary-weak-higlight, #e5eefa); + } .content { - display: flex; - flex-direction: column; - gap: var(--spacing-sm, 8px); + display: inline-flex; + align-items: center; + gap: var(--spacing-4, 32px); - .deposit-document { + .browse-document-container { display: flex; + flex-direction: column; gap: var(--spacing-sm, 8px); + + .browse-document { + display: flex; + gap: var(--spacing-sm, 8px); + + &.desktop { + @media screen and (max-width: $screen-s) { + display: none; + } + } + + &.mobile { + display: none; + @media screen and (max-width: $screen-s) { + display: flex; + } + } + } } } - svg{ + .documents { + display: flex; + flex-direction: column; + gap: var(--spacing-sm, 8px); + } + + svg { min-width: var(--spacing-3, 24px); min-height: var(--spacing-3, 24px); width: var(--spacing-3, 24px); diff --git a/src/front/Components/DesignSystem/DragAndDrop/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/index.tsx index 1fe559a9..16ce9619 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/index.tsx +++ b/src/front/Components/DesignSystem/DragAndDrop/index.tsx @@ -1,35 +1,161 @@ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import React from "react"; import { DocumentPlusIcon } from "@heroicons/react/24/outline"; - -import classes from "./classes.module.scss"; import classNames from "classnames"; -import Separator, { ESeperatorColor, ESeperatorDirection } from "../Separator"; -import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "../Button"; +import React, { useCallback, useRef, useState } from "react"; -type IProps = {}; +import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "../Button"; +import Separator, { ESeperatorColor, ESeperatorDirection } from "../Separator"; +import classes from "./classes.module.scss"; +import DocumentElement from "./DocumentElement"; + +type IProps = { + name?: string; + title: string; + description: string; +}; + +type IMimeTypes = { + extension: string; + size: number; +}; + +const mimeTypesAccepted: { [key: string]: IMimeTypes } = { + "application/pdf": { + extension: "pdf", + size: 41943040, + }, + "image/jpeg": { + extension: "jpeg", + size: 41943040, + }, + "image/png": { + extension: "png", + size: 41943040, + }, + "image/jpg": { + extension: "jpg", + size: 41943040, + }, +}; + +type IDocument = { + id: string; + file: File | null; + isLoading: boolean; + error?: string; +}; export default function DragAndDrop(props: IProps) { - const {} = props; + const { name, title, description } = props; + const fileInputRef = useRef(null); + + const [documents, setDocuments] = useState([]); + + const handleFiles = useCallback((files: File[]) => { + files.forEach((file) => { + setDocuments((prevDocs) => [...prevDocs, { id: file.name, file: file, isLoading: true }]); + setTimeout(() => { + if (mimeTypesAccepted[file.type]) { + const newDoc: IDocument = { id: file.name, file, isLoading: false }; + setDocuments((prevDocs) => prevDocs.map((doc) => (doc.id === newDoc.id ? newDoc : doc))); + } else { + const errorDoc: IDocument = { id: file.name, file: null, isLoading: false, error: "Type de fichier non accepté" }; + setDocuments((prevDocs) => prevDocs.map((doc) => (doc.id === errorDoc.id ? errorDoc : doc))); + } + }, 1000); + }); + }, []); + + const handleDrop = useCallback( + (event: React.DragEvent) => { + event.preventDefault(); + const files = Array.from(event.dataTransfer.files); + handleFiles(files); + }, + [handleFiles], + ); + + const handleRemove = useCallback((id: string) => { + setDocuments((prevDocs) => prevDocs.filter((doc) => doc.id !== id)); + }, []); + + const handleBrowse = useCallback( + (event: React.ChangeEvent) => { + const files = Array.from(event.target.files || []); + handleFiles(files); + }, + [handleFiles], + ); + + const triggerFileInput = () => { + if (fileInputRef.current) { + fileInputRef.current.click(); + } + }; return ( -
- - +
e.preventDefault()}>
-
- - Drag and Drop ou - - -
+ + +
+
+ + {title} + + +
- - Description - +
+ +
+ + + {description} + +
+ {documents.length > 0 && ( +
+ {documents.map((doc) => ( + handleRemove(doc.id)} + error={doc.error} + /> + ))} +
+ )}
); + + function inputFile() { + return ( + + ); + } } diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 619f47dd..187dc05f 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -90,7 +90,7 @@ export default function DesignSystem() { DesignSystem
Drag and Drop - + Separators
From 0d9eb149c23bd2b5fcd45ac9bbf708b4f55f3f01 Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 8 Aug 2024 17:59:58 +0200 Subject: [PATCH 04/63] :sparkles: add neutral tag --- .../Components/DesignSystem/Tag/classes.module.scss | 4 ++++ src/front/Components/DesignSystem/Tag/index.tsx | 10 ++++++---- src/front/Components/DesignSystem/Typography/index.tsx | 6 ++++++ src/front/Components/Layouts/DesignSystem/index.tsx | 2 ++ src/front/Themes/variables.scss | 2 ++ 5 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/front/Components/DesignSystem/Tag/classes.module.scss b/src/front/Components/DesignSystem/Tag/classes.module.scss index 651f6877..f0dd81b3 100644 --- a/src/front/Components/DesignSystem/Tag/classes.module.scss +++ b/src/front/Components/DesignSystem/Tag/classes.module.scss @@ -24,4 +24,8 @@ &.error { background-color: var(--tag-error-background); } + + &.neutral { + background-color: var(--tag-neutral-background); + } } diff --git a/src/front/Components/DesignSystem/Tag/index.tsx b/src/front/Components/DesignSystem/Tag/index.tsx index 090a90fd..1f62074f 100644 --- a/src/front/Components/DesignSystem/Tag/index.tsx +++ b/src/front/Components/DesignSystem/Tag/index.tsx @@ -9,6 +9,7 @@ export enum ETagColor { SUCCESS = "success", ERROR = "error", WARNING = "warning", + NEUTRAL = "neutral", } export enum ETagVariant { @@ -24,10 +25,11 @@ type IProps = { }; const colorMap: Record = { - [ETagColor.INFO]: ETypoColor.COLOR_INFO_900, - [ETagColor.SUCCESS]: ETypoColor.COLOR_SUCCESS_700, - [ETagColor.ERROR]: ETypoColor.COLOR_SECONDARY_700, - [ETagColor.WARNING]: ETypoColor.COLOR_WARNING_700, + [ETagColor.INFO]: ETypoColor.TAG_INFO_CONTRAST, + [ETagColor.SUCCESS]: ETypoColor.TAG_SUCCESS_CONTRAST, + [ETagColor.ERROR]: ETypoColor.TAG_ERROR_CONTRAST, + [ETagColor.WARNING]: ETypoColor.TAG_WARNING_CONTRAST, + [ETagColor.NEUTRAL]: ETypoColor.TAG_NEUTRAL_CONTRAST, }; const typoMap: Record = { diff --git a/src/front/Components/DesignSystem/Typography/index.tsx b/src/front/Components/DesignSystem/Typography/index.tsx index 248cad65..9ceaf113 100644 --- a/src/front/Components/DesignSystem/Typography/index.tsx +++ b/src/front/Components/DesignSystem/Typography/index.tsx @@ -163,6 +163,12 @@ export enum ETypoColor { DROPDOWN_CONTRAST_ACTIVE = "--dropdown-contrast-active", INPUT_CHIP_CONTRAST = "--input-chip-contrast", + + TAG_NEUTRAL_CONTRAST = "--tag-neutral-contrast", + TAG_INFO_CONTRAST = "--tag-info-contrast", + TAG_SUCCESS_CONTRAST = "--tag-success-contrast", + TAG_WARNING_CONTRAST = "--tag-warning-contrast", + TAG_ERROR_CONTRAST = "--tag-error-contrast", } export default function Typography(props: IProps) { diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 187dc05f..c4827956 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -389,6 +389,7 @@ export default function DesignSystem() { +
Table Tags @@ -397,6 +398,7 @@ export default function DesignSystem() { +
Table diff --git a/src/front/Themes/variables.scss b/src/front/Themes/variables.scss index 3bcb8aaa..812dee5c 100644 --- a/src/front/Themes/variables.scss +++ b/src/front/Themes/variables.scss @@ -520,6 +520,8 @@ --tabs-contrast-warning: var(--color-warning-500); --tag-error-background: var(--error-weak-higlight); --tag-error-contrast: var(--error-weak-contrast); + --tag-neutral-background: var(--neutral-weak-higlight); + --tag-neutral-contrast: var(--neutral-weak-contrast); --tag-info-background: var(--info-weak-higlight); --tag-info-contrast: var(--info-strong-higlight); --tag-success-background: var(--success-weak-higlight); From 2953bd37de2d6c6b9e4a20e43f863dce66d97a8d Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 9 Aug 2024 17:42:52 +0200 Subject: [PATCH 05/63] Toaster --- .../Components/DesignSystem/Alert/index.tsx | 11 +- .../BadgeIcon/classes.module.scss | 46 ++++++++ .../DesignSystem/BadgeIcon/index.tsx | 23 ++++ .../Toaster/ToastContent/classes.module.scss | 5 + .../Toaster/ToastContent/index.tsx | 28 +++++ .../DesignSystem/Toaster/classes.module.scss | 23 ++++ .../Components/DesignSystem/Toaster/index.tsx | 111 ++++++++++++++++++ .../DesignSystem/Typography/index.tsx | 3 + .../LayoutTemplates/DefaultLayout.tsx | 7 +- .../Components/Layouts/DesignSystem/index.tsx | 51 +++++++- 10 files changed, 299 insertions(+), 9 deletions(-) create mode 100644 src/front/Components/DesignSystem/BadgeIcon/classes.module.scss create mode 100644 src/front/Components/DesignSystem/BadgeIcon/index.tsx create mode 100644 src/front/Components/DesignSystem/Toaster/ToastContent/classes.module.scss create mode 100644 src/front/Components/DesignSystem/Toaster/ToastContent/index.tsx create mode 100644 src/front/Components/DesignSystem/Toaster/classes.module.scss create mode 100644 src/front/Components/DesignSystem/Toaster/index.tsx diff --git a/src/front/Components/DesignSystem/Alert/index.tsx b/src/front/Components/DesignSystem/Alert/index.tsx index 64d70a5c..ac3c8298 100644 --- a/src/front/Components/DesignSystem/Alert/index.tsx +++ b/src/front/Components/DesignSystem/Alert/index.tsx @@ -7,6 +7,7 @@ import Button, { EButtonSize, EButtonstyletype, EButtonVariant, IButtonProps } f import classNames from "classnames"; import IconButton from "../IconButton"; import useOpenable from "@Front/Hooks/useOpenable"; +import BadgeIcon, { EBadgeColor } from "../BadgeIcon"; type IProps = { variant: EAlertVariant; @@ -35,6 +36,14 @@ const variantButtonMap: Record = { [EAlertVariant.NEUTRAL]: EButtonVariant.NEUTRAL, }; +const variantColorMap: Record = { + [EAlertVariant.INFO]: EBadgeColor.INFO, + [EAlertVariant.SUCCESS]: EBadgeColor.SUCCESS, + [EAlertVariant.WARNING]: EBadgeColor.WARNING, + [EAlertVariant.ERROR]: EBadgeColor.ERROR, + [EAlertVariant.NEUTRAL]: EBadgeColor.NEUTRAL, +}; + export default function Alert(props: IProps) { const { isOpen, close } = useOpenable({ defaultOpen: true }); const { variant = EAlertVariant.INFO, title, description, firstButton, secondButton, closeButton, icon, fullWidth } = props; @@ -43,7 +52,7 @@ export default function Alert(props: IProps) { return (
- {icon ?? } + } color={variantColorMap[variant]} />
diff --git a/src/front/Components/DesignSystem/BadgeIcon/classes.module.scss b/src/front/Components/DesignSystem/BadgeIcon/classes.module.scss new file mode 100644 index 00000000..d5fdf0b8 --- /dev/null +++ b/src/front/Components/DesignSystem/BadgeIcon/classes.module.scss @@ -0,0 +1,46 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + padding: var(--spacing-1, 8px); + align-items: center; + align-self: flex-start; + + border-radius: var(--alerts-badge-radius, 360px); + border: 1px solid var(--alerts-badge-border, rgba(0, 0, 0, 0)); + background: var(--alerts-badge-background, #fff); + box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.1); + + svg { + width: 24px; + height: 24px; + min-width: 24px; + min-height: 24px; + + stroke: var(--alerts-badge-contrast-info); + } + + &.error { + svg { + stroke: var(--alerts-badge-contrast-error); + } + } + + &.warning { + svg { + stroke: var(--alerts-badge-contrast-warning); + } + } + + &.success { + svg { + stroke: var(--alerts-badge-contrast-success); + } + } + + &.neutral { + svg { + stroke: var(--alerts-badge-contrast-neutral); + } + } +} diff --git a/src/front/Components/DesignSystem/BadgeIcon/index.tsx b/src/front/Components/DesignSystem/BadgeIcon/index.tsx new file mode 100644 index 00000000..9b46963a --- /dev/null +++ b/src/front/Components/DesignSystem/BadgeIcon/index.tsx @@ -0,0 +1,23 @@ +import classNames from "classnames"; +import React from "react"; + +import classes from "./classes.module.scss"; + +export enum EBadgeColor { + INFO = "info", + SUCCESS = "success", + WARNING = "warning", + ERROR = "error", + NEUTRAL = "neutral", +} + +type IProps = { + icon: React.ReactNode; + color: EBadgeColor; +}; + +export default function BadgeIcon(props: IProps) { + const { icon, color } = props; + + return
{icon}
; +} diff --git a/src/front/Components/DesignSystem/Toaster/ToastContent/classes.module.scss b/src/front/Components/DesignSystem/Toaster/ToastContent/classes.module.scss new file mode 100644 index 00000000..51761669 --- /dev/null +++ b/src/front/Components/DesignSystem/Toaster/ToastContent/classes.module.scss @@ -0,0 +1,5 @@ +.root { + display: flex; + align-items: center; + gap: var(--spacing-lg, 24px); +} diff --git a/src/front/Components/DesignSystem/Toaster/ToastContent/index.tsx b/src/front/Components/DesignSystem/Toaster/ToastContent/index.tsx new file mode 100644 index 00000000..eec4e7ef --- /dev/null +++ b/src/front/Components/DesignSystem/Toaster/ToastContent/index.tsx @@ -0,0 +1,28 @@ +import React from "react"; + +import Typography, { ETypo, ETypoColor } from "../../Typography"; +import classes from "./classes.module.scss"; + +type IProps = { + title: string; + description?: string; + icon?: React.ReactNode; +}; + +export default function ToastContent(props: IProps) { + const { icon, title, description } = props; + + return ( +
+ {icon} +
+ + {title} + + + {description} + +
+
+ ); +} diff --git a/src/front/Components/DesignSystem/Toaster/classes.module.scss b/src/front/Components/DesignSystem/Toaster/classes.module.scss new file mode 100644 index 00000000..1fcb7ab0 --- /dev/null +++ b/src/front/Components/DesignSystem/Toaster/classes.module.scss @@ -0,0 +1,23 @@ +.root { + width: fit-content !important; + .wrapper { + width: 387px; + + display: flex; + align-items: center; + + padding: var(--spacing-2, 16px); + border-radius: var(--toaster-radius, 0px); + border: 1px solid var(--toaster-border, #e5eefa); + background: var(--toaster-background, #fff); + /* shadow/sm */ + box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.1); + + .body { + } + + .progress { + height: 2px; + } + } +} diff --git a/src/front/Components/DesignSystem/Toaster/index.tsx b/src/front/Components/DesignSystem/Toaster/index.tsx new file mode 100644 index 00000000..b5af618d --- /dev/null +++ b/src/front/Components/DesignSystem/Toaster/index.tsx @@ -0,0 +1,111 @@ +import { ArrowLeftStartOnRectangleIcon, CheckIcon, ExclamationTriangleIcon, InformationCircleIcon, XMarkIcon } from "@heroicons/react/24/outline"; +import React from "react"; +import { toast, ToastContainer } from "react-toastify"; + +import BadgeIcon, { EBadgeColor } from "../BadgeIcon"; +import IconButton from "../IconButton"; +import Loader from "../Loader"; +import classes from "./classes.module.scss"; +import ToastContent from "./ToastContent"; + +import "react-toastify/dist/ReactToastify.css"; + +export default function Toaster() { + return ( + } />} + /> + ); +} + +export class ToasterService { + private static instance: ToasterService; + private constructor() {} + + public static getInstance() { + return (this.instance ??= new this()); + } + + public text({ title, description }: { title: string; description?: string }) { + toast.info(, { + icon: false, + progressStyle: { backgroundColor: "var(--primary-default-base)" }, + }); + } + + public info({ title, description }: { title: string; description?: string }) { + toast.info( + } color={EBadgeColor.INFO} />} + />, + { + icon: false, + progressStyle: { backgroundColor: "var(--info-default-base)" }, + }, + ); + } + + public success({ title, description }: { title: string; description?: string }) { + toast.info( + } color={EBadgeColor.SUCCESS} />} />, + { + icon: false, + progressStyle: { backgroundColor: "var(--success-default-base)" }, + }, + ); + } + + public error({ title, description }: { title: string; description?: string }) { + toast.info( + } color={EBadgeColor.ERROR} />} />, + { + icon: false, + progressStyle: { backgroundColor: "var(--error-default-base)" }, + }, + ); + } + + public warning({ title, description }: { title: string; description?: string }) { + toast.info( + } color={EBadgeColor.WARNING} />} + />, + { + icon: false, + progressStyle: { backgroundColor: "var(--warning-default-base)" }, + }, + ); + } + + public loading({ title, description }: { title: string; description?: string }) { + toast.info( + } color={EBadgeColor.INFO} />} />, + { + icon: false, + autoClose: false, + }, + ); + } + + public loggedOut({ title, description }: { title: string; description?: string }) { + toast.info( + } color={EBadgeColor.NEUTRAL} />} + />, + { + icon: false, + autoClose: false, + }, + ); + } +} diff --git a/src/front/Components/DesignSystem/Typography/index.tsx b/src/front/Components/DesignSystem/Typography/index.tsx index 9ceaf113..2e6167da 100644 --- a/src/front/Components/DesignSystem/Typography/index.tsx +++ b/src/front/Components/DesignSystem/Typography/index.tsx @@ -169,6 +169,9 @@ export enum ETypoColor { TAG_SUCCESS_CONTRAST = "--tag-success-contrast", TAG_WARNING_CONTRAST = "--tag-warning-contrast", TAG_ERROR_CONTRAST = "--tag-error-contrast", + + TOASTER_CONTRAST_TITLE = "--toaster-contrast-title", + TOASTER_CONTRAST_TEXT = "--toaster-contrast-text", } export default function Typography(props: IProps) { diff --git a/src/front/Components/LayoutTemplates/DefaultLayout.tsx b/src/front/Components/LayoutTemplates/DefaultLayout.tsx index 322f5bd3..b5e81b75 100644 --- a/src/front/Components/LayoutTemplates/DefaultLayout.tsx +++ b/src/front/Components/LayoutTemplates/DefaultLayout.tsx @@ -1,8 +1,9 @@ import Head from "next/head"; import { ReactNode } from "react"; +import Toaster from "../DesignSystem/Toaster"; + type DefaultLayoutProps = { children: ReactNode }; -import { ToastContainer } from "react-toastify"; -import "react-toastify/dist/ReactToastify.css"; + export const DefaultLayout = ({ children }: DefaultLayoutProps) => { return ( <> @@ -12,7 +13,7 @@ export const DefaultLayout = ({ children }: DefaultLayoutProps) => {
{children} - +
); diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index c4827956..0cf4f2cd 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -2,7 +2,9 @@ import Alert, { EAlertVariant } from "@Front/Components/DesignSystem/Alert"; import Autocomplete from "@Front/Components/DesignSystem/Autocomplete"; import AutocompleteMultiSelect from "@Front/Components/DesignSystem/AutocompleteMultiSelect"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import CheckboxesInputElement from "@Front/Components/DesignSystem/CheckBox"; import CircleProgress from "@Front/Components/DesignSystem/CircleProgress"; +import DragAndDrop from "@Front/Components/DesignSystem/DragAndDrop"; import Dropdown from "@Front/Components/DesignSystem/Dropdown"; import Footer from "@Front/Components/DesignSystem/Footer"; import Form from "@Front/Components/DesignSystem/Form"; @@ -12,10 +14,13 @@ import IconButton, { EIconButtonVariant } from "@Front/Components/DesignSystem/I import Menu from "@Front/Components/DesignSystem/Menu"; import Modal from "@Front/Components/DesignSystem/Modal"; import Newsletter from "@Front/Components/DesignSystem/Newsletter"; +import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList"; import DropdownNavigation from "@Front/Components/DesignSystem/SearchBlockList/DropdownNavigation"; +import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator"; import Table from "@Front/Components/DesignSystem/Table"; import Tag, { ETagColor, ETagVariant } from "@Front/Components/DesignSystem/Tag"; +import Toggle, { EToggleSize } from "@Front/Components/DesignSystem/Toggle"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import NumberPicker from "@Front/Components/Elements/NumberPicker"; import Tabs from "@Front/Components/Elements/Tabs"; @@ -33,11 +38,7 @@ import { import { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; -import CheckboxesInputElement from "@Front/Components/DesignSystem/CheckBox"; -import RadioBox from "@Front/Components/DesignSystem/RadioBox"; -import Toggle, { EToggleSize } from "@Front/Components/DesignSystem/Toggle"; -import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator"; -import DragAndDrop from "@Front/Components/DesignSystem/DragAndDrop"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; export default function DesignSystem() { const { isOpen, open, close } = useOpenable(); @@ -89,6 +90,46 @@ export default function DesignSystem() {
DesignSystem
+ Toast +
+ + + +
+
+ + + +
+ Drag and Drop Separators From 5a9648d3339a79793adfad22c2eb206819e62dbd Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 12 Aug 2024 12:33:19 +0200 Subject: [PATCH 06/63] =?UTF-8?q?:sparkles:=20Int=C3=A9gration=20Send=20Do?= =?UTF-8?q?cuments=20pages=20+=20add=20send=20documents=20button?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InformationSection/index.tsx | 38 +++--- .../Folder/SendDocuments/classes.module.scss | 36 +++++ .../Layouts/Folder/SendDocuments/index.tsx | 123 ++++++++++++++++++ src/front/Config/Module/development.json | 7 + src/front/Config/Module/preprod.json | 7 + src/front/Config/Module/production.json | 7 + src/front/Config/Module/staging.json | 7 + .../[folderUid]/send-documents/index.tsx | 5 + 8 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 src/front/Components/Layouts/Folder/SendDocuments/classes.module.scss create mode 100644 src/front/Components/Layouts/Folder/SendDocuments/index.tsx create mode 100644 src/pages/folders/[folderUid]/send-documents/index.tsx diff --git a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx index c7c6722b..7e2e3067 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx @@ -1,16 +1,17 @@ import CircleProgress from "@Front/Components/DesignSystem/CircleProgress"; import IconButton, { EIconButtonVariant } from "@Front/Components/DesignSystem/IconButton"; +import Menu from "@Front/Components/DesignSystem/Menu"; +import { IItem } from "@Front/Components/DesignSystem/Menu/MenuItem"; import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Module from "@Front/Config/Module"; -import { ArchiveBoxIcon, EllipsisHorizontalIcon, PencilSquareIcon, UsersIcon } from "@heroicons/react/24/outline"; +import { ArchiveBoxIcon, EllipsisHorizontalIcon, PaperAirplaneIcon, PencilSquareIcon, UsersIcon } from "@heroicons/react/24/outline"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; -import { useCallback } from "react"; +import { useMemo } 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"; +import Link from "next/link"; type IProps = { folder: OfficeFolder | null; @@ -23,7 +24,7 @@ type IProps = { export default function InformationSection(props: IProps) { const { folder, progress, onArchive, anchorStatus, isArchived } = props; - const getSubMenuElement = useCallback(() => { + const menuItems = useMemo(() => { let elements: IItem[] = []; // Creating the three elements and adding them conditionnally @@ -41,31 +42,18 @@ export default function InformationSection(props: IProps) { link: Module.getInstance() .get() .modules.pages.Folder.pages.EditInformations.props.path.replace("[folderUid]", folder?.uid ?? ""), - hasSeparator: true, - }; - - const archiveElement = { - icon: , - text: "Archiver le dossier", - onClick: onArchive, - color: ETypoColor.ERROR_WEAK_CONTRAST, + hasSeparator: false, }; // If the folder is not anchored, we can modify the collaborators and the informations if (anchorStatus === AnchorStatus.NOT_ANCHORED) { elements.push(modifyCollaboratorsElement); - // Remove the separator if it's the last item (if the folder is not archived) - if (isArchived) modifyInformationsElement.hasSeparator = false; elements.push(modifyInformationsElement); } - // If the folder is not archived, we can archive it - if (!isArchived) { - elements.push(archiveElement); - } return elements; - }, [anchorStatus, folder?.uid, isArchived, onArchive]); + }, [anchorStatus, folder?.uid]); return (
@@ -88,9 +76,17 @@ export default function InformationSection(props: IProps) {
- + + } variant={EIconButtonVariant.NEUTRAL} /> + + } variant={EIconButtonVariant.NEUTRAL} /> + {!isArchived && } variant={EIconButtonVariant.ERROR} />}
diff --git a/src/front/Components/Layouts/Folder/SendDocuments/classes.module.scss b/src/front/Components/Layouts/Folder/SendDocuments/classes.module.scss new file mode 100644 index 00000000..613b5a8d --- /dev/null +++ b/src/front/Components/Layouts/Folder/SendDocuments/classes.module.scss @@ -0,0 +1,36 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + margin: 24px auto; + width: 566px; + + @media (max-width: $screen-m) { + width: 474px; + } + + @media (max-width: $screen-s) { + width: 100%; + padding: var(--spacing-md, 16px); + } + + .radioboxes { + display: flex; + flex-direction: column; + gap: var(--Radius-lg, 16px); + } + + .form { + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + .buttons-container { + display: flex; + gap: var(--spacing-md, 16px); + } + } +} diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx new file mode 100644 index 00000000..96f094a7 --- /dev/null +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -0,0 +1,123 @@ +import backgroundImage from "@Assets/images/background_refonte.svg"; +import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; +import AutocompleteMultiSelect from "@Front/Components/DesignSystem/AutocompleteMultiSelect"; +import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import DragAndDrop from "@Front/Components/DesignSystem/DragAndDrop"; +import Form from "@Front/Components/DesignSystem/Form"; +import RadioBox from "@Front/Components/DesignSystem/RadioBox"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import BackArrow from "@Front/Components/Elements/BackArrow"; +import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; +import Module from "@Front/Config/Module"; +import { PaperAirplaneIcon } from "@heroicons/react/24/outline"; +import { OfficeFolder } from "le-coffre-resources/dist/Notary"; +import { useRouter } from "next/router"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; + +import classes from "./classes.module.scss"; + +enum EClientSelection { + ALL_CLIENTS = "all_clients", + SELECTED_CLIENTS = "selected_clients", +} + +export default function SendDocuments() { + const router = useRouter(); + let { folderUid } = router.query; + const [folder, setFolder] = useState(null); + const [clientSelection, setClientSelection] = useState(null); + + const onFormSubmit = useCallback( + async ( + _e: React.FormEvent | null, + _values: { + [key: string]: any; + }, + //TODO: when back is done + ) => {}, + [], + ); + + const fetchFolder = useCallback(async () => { + Folders.getInstance() + .getByUid(folderUid as string, { + q: { + customers: { + include: { + contact: true, + }, + }, + }, + }) + .then((folder) => setFolder(folder)) + .catch((e) => console.warn(e)); + }, [folderUid]); + + const onClientSelectionChange = useCallback((e: React.ChangeEvent) => { + setClientSelection(e.target.value as EClientSelection); + console.log(e.target.value); + }, []); + + useEffect(() => { + fetchFolder(); + }, [fetchFolder]); + + const backUrl = useMemo( + () => + Module.getInstance() + .get() + .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid as string), + [folderUid], + ); + + const clientsOptions = useMemo(() => { + if (!folder?.customers) return []; + return folder.customers.map((customer) => ({ + id: customer.uid ?? "", + label: `${customer.contact?.first_name} ${customer.contact?.last_name}`, + })); + }, [folder]); + + return ( + +
+ + + Envoyer des documents, sélectionnez les destinataires : + +
+ + +
+ +
+ {clientSelection === EClientSelection.SELECTED_CLIENTS && ( + + )} + + +
+ + + + +
+ +
+
+ ); +} diff --git a/src/front/Config/Module/development.json b/src/front/Config/Module/development.json index 253742bf..09587298 100644 --- a/src/front/Config/Module/development.json +++ b/src/front/Config/Module/development.json @@ -59,6 +59,13 @@ "labelKey": "add_client_to_folder" } }, + "SendDocuments": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/send-documents", + "labelKey": "send_documents" + } + }, "AskDocument": { "enabled": true, "props": { diff --git a/src/front/Config/Module/preprod.json b/src/front/Config/Module/preprod.json index 253742bf..09587298 100644 --- a/src/front/Config/Module/preprod.json +++ b/src/front/Config/Module/preprod.json @@ -59,6 +59,13 @@ "labelKey": "add_client_to_folder" } }, + "SendDocuments": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/send-documents", + "labelKey": "send_documents" + } + }, "AskDocument": { "enabled": true, "props": { diff --git a/src/front/Config/Module/production.json b/src/front/Config/Module/production.json index 253742bf..09587298 100644 --- a/src/front/Config/Module/production.json +++ b/src/front/Config/Module/production.json @@ -59,6 +59,13 @@ "labelKey": "add_client_to_folder" } }, + "SendDocuments": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/send-documents", + "labelKey": "send_documents" + } + }, "AskDocument": { "enabled": true, "props": { diff --git a/src/front/Config/Module/staging.json b/src/front/Config/Module/staging.json index 253742bf..09587298 100644 --- a/src/front/Config/Module/staging.json +++ b/src/front/Config/Module/staging.json @@ -59,6 +59,13 @@ "labelKey": "add_client_to_folder" } }, + "SendDocuments": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/send-documents", + "labelKey": "send_documents" + } + }, "AskDocument": { "enabled": true, "props": { diff --git a/src/pages/folders/[folderUid]/send-documents/index.tsx b/src/pages/folders/[folderUid]/send-documents/index.tsx new file mode 100644 index 00000000..06bf18b7 --- /dev/null +++ b/src/pages/folders/[folderUid]/send-documents/index.tsx @@ -0,0 +1,5 @@ +import SendDocuments from "@Front/Components/Layouts/Folder/SendDocuments"; + +export default function Route() { + return ; +} From b3d8dfae5e46e533be9af8963537efc2da64397d Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 12 Aug 2024 19:42:25 +0200 Subject: [PATCH 07/63] :fix: dashed drag and drop --- .../DragAndDrop/classes.module.scss | 27 ++++++++++++++++--- .../DesignSystem/DragAndDrop/index.tsx | 5 +++- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss b/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss index 0c3fae28..7c452659 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss +++ b/src/front/Components/DesignSystem/DragAndDrop/classes.module.scss @@ -1,6 +1,7 @@ @import "@Themes/constants.scss"; .root { + position: relative; display: inline-flex; flex-direction: column; gap: var(--spacing-3, 24px); @@ -8,11 +9,31 @@ width: fit-content; padding: var(--spacing-2, 16px) var(--Radius-2xl, 32px) var(--spacing-2, 16px) var(--spacing-xl, 32px); - border-radius: var(--Radius-md, 8px); - border: 1px dashed var(--dropdown-input-border-hovered, #b4bec5); + clip-path: inset(0 round var(--Radius-md, 8px)); + + &::before { + content: ""; + position: absolute; + left: -15px; + top: -15px; + right: -15px; + bottom: -15px; + border: 16px dashed var(--dropdown-input-border-hovered); + border-radius: calc(2 * var(--Radius-md, 8px)); + box-sizing: border-box; + z-index: -1; + } + + &.filled { + &::before { + border-color: var(--dropdown-input-border-expanded); + } + } &:hover { - border-color: var(--dropdown-input-border-expanded); + &::before { + border-color: var(--dropdown-input-border-expanded); + } background: var(--primary-weak-higlight, #e5eefa); } diff --git a/src/front/Components/DesignSystem/DragAndDrop/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/index.tsx index 16ce9619..a803b05c 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/index.tsx +++ b/src/front/Components/DesignSystem/DragAndDrop/index.tsx @@ -94,7 +94,10 @@ export default function DragAndDrop(props: IProps) { }; return ( -
e.preventDefault()}> +
0 && classes["filled"])} + onDrop={handleDrop} + onDragOver={(e) => e.preventDefault()}>
From bd8c5091511c539f6d42e67518a5afff79aa4f73 Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 13 Aug 2024 10:37:50 +0200 Subject: [PATCH 08/63] add separator thickness --- src/front/Components/DesignSystem/Separator/index.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/front/Components/DesignSystem/Separator/index.tsx b/src/front/Components/DesignSystem/Separator/index.tsx index 21ccbc1e..bb9c4389 100644 --- a/src/front/Components/DesignSystem/Separator/index.tsx +++ b/src/front/Components/DesignSystem/Separator/index.tsx @@ -1,7 +1,7 @@ +import classNames from "classnames"; import React from "react"; import classes from "./classes.module.scss"; -import classNames from "classnames"; export enum ESeperatorColor { LIGHT = "light", @@ -19,15 +19,16 @@ type IProps = { color?: ESeperatorColor; direction?: ESeperatorDirection; size?: number; + thickness?: number; }; export default function Separator(props: IProps) { - const { color = ESeperatorColor.DEFAULT, direction = ESeperatorDirection.HORIZONTAL, size } = props; + const { color = ESeperatorColor.DEFAULT, direction = ESeperatorDirection.HORIZONTAL, size, thickness = 1 } = props; return (
); } From 7938e9790ac074af57f60dbf90ad74d85b724046 Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 13 Aug 2024 11:20:19 +0200 Subject: [PATCH 09/63] =?UTF-8?q?homog=C3=A9n=C3=A9isation=20des=20buttons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DesignSystem/Button/classes.module.scss | 402 ++++++++++-------- 1 file changed, 218 insertions(+), 184 deletions(-) diff --git a/src/front/Components/DesignSystem/Button/classes.module.scss b/src/front/Components/DesignSystem/Button/classes.module.scss index 9beda2dd..1ef3abbf 100644 --- a/src/front/Components/DesignSystem/Button/classes.module.scss +++ b/src/front/Components/DesignSystem/Button/classes.module.scss @@ -26,8 +26,8 @@ */ &[variant="primary"] { - color: var(--button-contained-primary-hovered-contrast); - border: 1px solid var(--button-contained-primary-default-border); + color: var(--button-contained-primary-default-contrast); + border-color: var(--button-contained-primary-default-border); background: var(--button-contained-primary-default-background); svg { @@ -35,7 +35,7 @@ } &:hover { - border: 1px solid var(--button-contained-primary-hovered-border); + border-color: var(--button-contained-primary-hovered-border); background: var(--button-contained-primary-hovered-background); svg { @@ -46,7 +46,7 @@ &:focus, &:active { color: var(--button-contained-primary-default-contrast); - border: 1px solid var(--button-contained-primary-pressed-border); + border-color: var(--button-contained-primary-pressed-border); background: var(--button-contained-primary-pressed-background); svg { @@ -56,7 +56,7 @@ &[styletype="outlined"] { color: var(--button-outlined-primary-default-contrast); - border: 1px solid var(--button-outlined-primary-default-border); + border-color: var(--button-outlined-primary-default-border); background: var(--button-outlined-primary-default-background); svg { @@ -64,7 +64,7 @@ } &:hover { - border: 1px solid var(--button-outlined-primary-hovered-border); + border-color: var(--button-outlined-primary-hovered-border); background: var(--button-outlined-primary-hovered-background); svg { @@ -75,7 +75,7 @@ &:focus, &:active { color: var(--button-outlined-primary-pressed-contrast); - border: 1px solid var(--button-outlined-primary-pressed-border); + border-color: var(--button-outlined-primary-pressed-border); background: var(--button-outlined-primary-pressed-background); svg { @@ -86,16 +86,16 @@ &[styletype="text"] { color: var(--button-text-primary-default-contrast); - border-bottom: 1px solid var(--button-text-primary-default-border); + border-color: var(--button-text-primary-default-border); background: var(--button-text-primary-default-background); svg { stroke: var(--button-text-primary-default-contrast); } - &:hover { - border-bottom: 1px solid var(--button-outlined-primary-hovered-border); - background: var(--button-outlined-primary-default-background); + color: var(--button-text-primary-hovered-contrast); + border-color: var(--button-text-primary-hovered-border); + background: var(--button-text-primary-hovered-background); svg { stroke: var(--button-text-primary-hovered-contrast); @@ -104,9 +104,9 @@ &:focus, &:active { - color: var(--color-primary-800); - background: var(--button-outlined-primary-default-background); - border-bottom: 1px solid var(--color-primary-800); + color: var(--button-text-primary-pressed-contrast); + border-color: var(--button-text-primary-pressed-border); + background: var(--button-text-primary-pressed-background); svg { stroke: var(--button-text-primary-pressed-contrast); @@ -117,17 +117,16 @@ &[variant="secondary"] { color: var(--button-contained-secondary-default-contrast); - background: var(--button-contained-secondary-default-background); border-color: var(--button-contained-secondary-default-border); + background: var(--button-contained-secondary-default-background); svg { stroke: var(--button-contained-secondary-default-contrast); } &:hover { - color: var(--button-contained-secondary-hovered-contrast); - background: var(--button-contained-secondary-hovered-background); border-color: var(--button-contained-secondary-hovered-border); + background: var(--button-contained-secondary-hovered-background); svg { stroke: var(--button-contained-secondary-hovered-contrast); @@ -136,9 +135,9 @@ &:focus, &:active { - color: var(--button-contained-secondary-pressed-contrast); - background: var(--button-contained-secondary-pressed-background); + color: var(--button-contained-secondary-default-contrast); border-color: var(--button-contained-secondary-pressed-border); + background: var(--button-contained-secondary-pressed-background); svg { stroke: var(--button-contained-secondary-pressed-contrast); @@ -147,14 +146,15 @@ &[styletype="outlined"] { color: var(--button-outlined-secondary-default-contrast); - border: 1px solid var(--button-outlined-secondary-default-border); + border-color: var(--button-outlined-secondary-default-border); background: var(--button-outlined-secondary-default-background); svg { stroke: var(--button-outlined-secondary-default-contrast); } + &:hover { - border: 1px solid var(--button-outlined-secondary-hovered-border); + border-color: var(--button-outlined-secondary-hovered-border); background: var(--button-outlined-secondary-hovered-background); svg { @@ -165,7 +165,7 @@ &:focus, &:active { color: var(--button-outlined-secondary-pressed-contrast); - border: 1px solid var(--button-outlined-secondary-pressed-border); + border-color: var(--button-outlined-secondary-pressed-border); background: var(--button-outlined-secondary-pressed-background); svg { @@ -176,15 +176,16 @@ &[styletype="text"] { color: var(--button-text-secondary-default-contrast); - border-bottom: 1px solid var(--button-text-secondary-default-border); + border-color: var(--button-text-secondary-default-border); background: var(--button-text-secondary-default-background); svg { stroke: var(--button-text-secondary-default-contrast); } &:hover { - border-bottom: 1px solid var(--button-outlined-secondary-hovered-border); - background: var(--button-outlined-secondary-default-background); + color: var(--button-text-secondary-hovered-contrast); + border-color: var(--button-text-secondary-hovered-border); + background: var(--button-text-secondary-hovered-background); svg { stroke: var(--button-text-secondary-hovered-contrast); @@ -193,9 +194,9 @@ &:focus, &:active { - color: var(--button-outlined-secondary-pressed-contrast); - border-bottom: 1px solid var(--button-outlined-secondary-pressed-border); - background: var(--button-outlined-secondary-pressed-background); + color: var(--button-text-secondary-pressed-contrast); + border-color: var(--button-text-secondary-pressed-border); + background: var(--button-text-secondary-pressed-background); svg { stroke: var(--button-text-secondary-pressed-contrast); @@ -205,8 +206,8 @@ } &[variant="neutral"] { - color: var(--button-contained-neutral-hovered-contrast); - border: 1px solid var(--button-contained-neutral-default-border); + color: var(--button-contained-neutral-default-contrast); + border-color: var(--button-contained-neutral-default-border); background: var(--button-contained-neutral-default-background); svg { @@ -214,7 +215,7 @@ } &:hover { - border: 1px solid var(--button-contained-neutral-hovered-border); + border-color: var(--button-contained-neutral-hovered-border); background: var(--button-contained-neutral-hovered-background); svg { @@ -225,7 +226,7 @@ &:focus, &:active { color: var(--button-contained-neutral-default-contrast); - border: 1px solid var(--button-contained-neutral-pressed-border); + border-color: var(--button-contained-neutral-pressed-border); background: var(--button-contained-neutral-pressed-background); svg { @@ -235,15 +236,17 @@ &[styletype="outlined"] { color: var(--button-outlined-neutral-default-contrast); - border: 1px solid var(--button-outlined-neutral-default-border); + border-color: var(--button-outlined-neutral-default-border); background: var(--button-outlined-neutral-default-background); svg { stroke: var(--button-outlined-neutral-default-contrast); } + &:hover { - border: 1px solid var(--button-outlined-neutral-hovered-border); + border-color: var(--button-outlined-neutral-hovered-border); background: var(--button-outlined-neutral-hovered-background); + svg { stroke: var(--button-outlined-neutral-hovered-contrast); } @@ -252,7 +255,7 @@ &:focus, &:active { color: var(--button-outlined-neutral-pressed-contrast); - border: 1px solid var(--button-outlined-neutral-pressed-border); + border-color: var(--button-outlined-neutral-pressed-border); background: var(--button-outlined-neutral-pressed-background); svg { @@ -263,15 +266,16 @@ &[styletype="text"] { color: var(--button-text-neutral-default-contrast); - border-bottom: 1px solid var(--button-text-neutral-default-border); + border-color: var(--button-text-neutral-default-border); background: var(--button-text-neutral-default-background); + svg { stroke: var(--button-text-neutral-default-contrast); } - &:hover { - border-bottom: 1px solid var(--button-outlined-neutral-hovered-border); - background: var(--button-outlined-neutral-default-background); + color: var(--button-text-neutral-hovered-contrast); + border-color: var(--button-text-neutral-hovered-border); + background: var(--button-text-neutral-hovered-background); svg { stroke: var(--button-text-neutral-hovered-contrast); @@ -280,9 +284,9 @@ &:focus, &:active { - color: var(--color-primary-800); - background: var(--button-outlined-neutral-default-background); - border-bottom: 1px solid var(--color-primary-800); + color: var(--button-text-neutral-pressed-contrast); + border-color: var(--button-text-neutral-pressed-border); + background: var(--button-text-neutral-pressed-background); svg { stroke: var(--button-text-neutral-pressed-contrast); @@ -292,17 +296,17 @@ } &[variant="error"] { - color: var(--color-error-600); - background: var(--color-error-600); - border-color: var(--color-error-600); + color: var(--button-contained-error-default-contrast); + border-color: var(--button-contained-error-default-border); + background: var(--button-contained-error-default-background); svg { stroke: var(--button-contained-error-default-contrast); } &:hover { - background: var(--color-error-800); - border-color: var(--color-error-800); + border-color: var(--button-contained-error-hovered-border); + background: var(--button-contained-error-hovered-background); svg { stroke: var(--button-contained-error-hovered-contrast); @@ -311,8 +315,9 @@ &:focus, &:active { - background: var(--color-error-900); - border-color: var(--color-error-900); + color: var(--button-contained-error-default-contrast); + border-color: var(--button-contained-error-pressed-border); + background: var(--button-contained-error-pressed-background); svg { stroke: var(--button-contained-error-pressed-contrast); @@ -320,13 +325,17 @@ } &[styletype="outlined"] { + color: var(--button-outlined-error-default-contrast); + border-color: var(--button-outlined-error-default-border); + background: var(--button-outlined-error-default-background); + svg { stroke: var(--button-outlined-error-default-contrast); } &:hover { - background-color: var(--color-error-50); - border-color: var(--color-secondary-700); + border-color: var(--button-outlined-error-hovered-border); + background: var(--button-outlined-error-hovered-background); svg { stroke: var(--button-outlined-error-hovered-contrast); @@ -335,9 +344,9 @@ &:focus, &:active { - background-color: var(--color-error-100); - color: var(--color-secondary-700); - border-color: var(--color-secondary-700); + color: var(--button-outlined-error-pressed-contrast); + border-color: var(--button-outlined-error-pressed-border); + background: var(--button-outlined-error-pressed-background); svg { stroke: var(--button-outlined-error-pressed-contrast); @@ -346,14 +355,17 @@ } &[styletype="text"] { + color: var(--button-text-error-default-contrast); + border-color: var(--button-text-error-default-border); + background: var(--button-text-error-default-background); + svg { stroke: var(--button-text-error-default-contrast); } - &:hover { - background-color: transparent; - color: var(--color-error-800); - border-color: var(--color-error-800); + color: var(--button-text-error-hovered-contrast); + border-color: var(--button-text-error-hovered-border); + background: var(--button-text-error-hovered-background); svg { stroke: var(--button-text-error-hovered-contrast); @@ -362,9 +374,9 @@ &:focus, &:active { - background-color: transparent; - color: var(--color-error-900); - border-color: var(--color-error-900); + color: var(--button-text-error-pressed-contrast); + border-color: var(--button-text-error-pressed-border); + background: var(--button-text-error-pressed-background); svg { stroke: var(--button-text-error-pressed-contrast); @@ -373,101 +385,18 @@ } } - &[variant="warning"] { - color: var(--color-warning-600); - background: var(--color-warning-600); - border-color: var(--color-warning-600); - - svg { - stroke: var(--button-contained-warning-default-contrast); - } - - &:hover { - background: var(--color-warning-800); - border-color: var(--color-warning-800); - - svg { - stroke: var(--button-contained-warning-hovered-contrast); - } - } - - &:focus, - &:active { - background: var(--color-warning-900); - border-color: var(--color-warning-900); - - svg { - stroke: var(--button-contained-warning-pressed-contrast); - } - } - - &[styletype="outlined"] { - svg { - stroke: var(--button-outlined-warning-default-contrast); - } - - &:hover { - background-color: var(--color-warning-50); - border-color: var(--color-warning-700); - color: var(--color-warning-700); - - svg { - stroke: var(--button-outlined-warning-hovered-contrast); - } - } - - &:focus, - &:active { - background-color: var(--color-warning-100); - color: var(--color-warning-700); - border-color: var(--color-warning-700); - - svg { - stroke: var(--button-outlined-warning-pressed-contrast); - } - } - } - - &[styletype="text"] { - svg { - stroke: var(--button-text-warning-default-contrast); - } - - &:hover { - background-color: transparent; - color: var(--color-warning-800); - border-color: var(--color-warning-800); - - svg { - stroke: var(--button-text-warning-hovered-contrast); - } - } - - &:focus, - &:active { - background-color: transparent; - color: var(--color-warning-900); - border-color: var(--color-warning-900); - - svg { - stroke: var(--button-text-warning-pressed-contrast); - } - } - } - } - &[variant="success"] { - color: var(--color-success-600); - background: var(--color-success-600); - border-color: var(--color-success-600); + color: var(--button-contained-success-default-contrast); + border-color: var(--button-contained-success-default-border); + background: var(--button-contained-success-default-background); svg { stroke: var(--button-contained-success-default-contrast); } &:hover { - background: var(--color-success-800); - border-color: var(--color-success-800); + border-color: var(--button-contained-success-hovered-border); + background: var(--button-contained-success-hovered-background); svg { stroke: var(--button-contained-success-hovered-contrast); @@ -476,8 +405,9 @@ &:focus, &:active { - background: var(--color-success-900); - border-color: var(--color-success-900); + color: var(--button-contained-success-default-contrast); + border-color: var(--button-contained-success-pressed-border); + background: var(--button-contained-success-pressed-background); svg { stroke: var(--button-contained-success-pressed-contrast); @@ -485,14 +415,17 @@ } &[styletype="outlined"] { + color: var(--button-outlined-success-default-contrast); + border-color: var(--button-outlined-success-default-border); + background: var(--button-outlined-success-default-background); + svg { stroke: var(--button-outlined-success-default-contrast); } &:hover { - background-color: var(--color-success-50); - border-color: var(--color-success-700); - color: var(--color-success-700); + border-color: var(--button-outlined-success-hovered-border); + background: var(--button-outlined-success-hovered-background); svg { stroke: var(--button-outlined-success-hovered-contrast); @@ -501,9 +434,9 @@ &:focus, &:active { - background-color: var(--color-success-100); - color: var(--color-success-700); - border-color: var(--color-success-700); + color: var(--button-outlined-success-pressed-contrast); + border-color: var(--button-outlined-success-pressed-border); + background: var(--button-outlined-success-pressed-background); svg { stroke: var(--button-outlined-success-pressed-contrast); @@ -512,14 +445,17 @@ } &[styletype="text"] { + color: var(--button-text-success-default-contrast); + border-color: var(--button-text-success-default-border); + background: var(--button-text-success-default-background); + svg { stroke: var(--button-text-success-default-contrast); } - &:hover { - background-color: transparent; - color: var(--color-success-800); - border-color: var(--color-success-800); + color: var(--button-text-success-hovered-contrast); + border-color: var(--button-text-success-hovered-border); + background: var(--button-text-success-hovered-background); svg { stroke: var(--button-text-success-hovered-contrast); @@ -528,9 +464,9 @@ &:focus, &:active { - background-color: transparent; - color: var(--color-success-900); - border-color: var(--color-success-900); + color: var(--button-text-success-pressed-contrast); + border-color: var(--button-text-success-pressed-border); + background: var(--button-text-success-pressed-background); svg { stroke: var(--button-text-success-pressed-contrast); @@ -539,18 +475,108 @@ } } + &[variant="warning"] { + color: var(--button-contained-warning-default-contrast); + border-color: var(--button-contained-warning-default-border); + background: var(--button-contained-warning-default-background); + + svg { + stroke: var(--button-contained-warning-default-contrast); + } + + &:hover { + border-color: var(--button-contained-warning-hovered-border); + background: var(--button-contained-warning-hovered-background); + + svg { + stroke: var(--button-contained-warning-hovered-contrast); + } + } + + &:focus, + &:active { + color: var(--button-contained-warning-default-contrast); + border-color: var(--button-contained-warning-pressed-border); + background: var(--button-contained-warning-pressed-background); + + svg { + stroke: var(--button-contained-warning-pressed-contrast); + } + } + + &[styletype="outlined"] { + color: var(--button-outlined-warning-default-contrast); + border-color: var(--button-outlined-warning-default-border); + background: var(--button-outlined-warning-default-background); + + svg { + stroke: var(--button-outlined-warning-default-contrast); + } + + &:hover { + border-color: var(--button-outlined-warning-hovered-border); + background: var(--button-outlined-warning-hovered-background); + + svg { + stroke: var(--button-outlined-warning-hovered-contrast); + } + } + + &:focus, + &:active { + color: var(--button-outlined-warning-pressed-contrast); + border-color: var(--button-outlined-warning-pressed-border); + background: var(--button-outlined-warning-pressed-background); + + svg { + stroke: var(--button-outlined-warning-pressed-contrast); + } + } + } + + &[styletype="text"] { + color: var(--button-text-warning-default-contrast); + border-color: var(--button-text-warning-default-border); + background: var(--button-text-warning-default-background); + + svg { + stroke: var(--button-text-warning-default-contrast); + } + &:hover { + color: var(--button-text-warning-hovered-contrast); + border-color: var(--button-text-warning-hovered-border); + background: var(--button-text-warning-hovered-background); + + svg { + stroke: var(--button-text-warning-hovered-contrast); + } + } + + &:focus, + &:active { + color: var(--button-text-warning-pressed-contrast); + border-color: var(--button-text-warning-pressed-border); + background: var(--button-text-warning-pressed-background); + + svg { + stroke: var(--button-text-warning-pressed-contrast); + } + } + } + } + &[variant="info"] { - color: var(--color-info-700); - background: var(--color-info-700); - border-color: var(--color-info-700); + color: var(--button-contained-info-default-contrast); + border-color: var(--button-contained-info-default-border); + background: var(--button-contained-info-default-background); svg { stroke: var(--button-contained-info-default-contrast); } &:hover { - background: var(--color-info-900); - border-color: var(--color-info-900); + border-color: var(--button-contained-info-hovered-border); + background: var(--button-contained-info-hovered-background); svg { stroke: var(--button-contained-info-hovered-contrast); @@ -559,8 +585,9 @@ &:focus, &:active { - background: var(--color-info-950); - border-color: var(--color-info-950); + color: var(--button-contained-info-default-contrast); + border-color: var(--button-contained-info-pressed-border); + background: var(--button-contained-info-pressed-background); svg { stroke: var(--button-contained-info-pressed-contrast); @@ -568,13 +595,17 @@ } &[styletype="outlined"] { + color: var(--button-outlined-info-default-contrast); + border-color: var(--button-outlined-info-default-border); + background: var(--button-outlined-info-default-background); + svg { stroke: var(--button-outlined-info-default-contrast); } + &:hover { - background-color: var(--color-info-50); - border-color: var(--color-info-700); - color: var(--color-info-700); + border-color: var(--button-outlined-info-hovered-border); + background: var(--button-outlined-info-hovered-background); svg { stroke: var(--button-outlined-info-hovered-contrast); @@ -583,9 +614,9 @@ &:focus, &:active { - background-color: var(--color-info-100); - color: var(--color-info-700); - border-color: var(--color-info-700); + color: var(--button-outlined-info-pressed-contrast); + border-color: var(--button-outlined-info-pressed-border); + background: var(--button-outlined-info-pressed-background); svg { stroke: var(--button-outlined-info-pressed-contrast); @@ -594,14 +625,17 @@ } &[styletype="text"] { + color: var(--button-text-info-default-contrast); + border-color: var(--button-text-info-default-border); + background: var(--button-text-info-default-background); + svg { stroke: var(--button-text-info-default-contrast); } - &:hover { - background-color: transparent; - color: var(--color-info-900); - border-color: var(--color-info-900); + color: var(--button-text-info-hovered-contrast); + border-color: var(--button-text-info-hovered-border); + background: var(--button-text-info-hovered-background); svg { stroke: var(--button-text-info-hovered-contrast); @@ -610,9 +644,9 @@ &:focus, &:active { - background-color: transparent; - color: var(--color-info-950); - border-color: var(--color-info-950); + color: var(--button-text-info-pressed-contrast); + border-color: var(--button-text-info-pressed-border); + background: var(--button-text-info-pressed-background); svg { stroke: var(--button-text-info-pressed-contrast); From ed75a960c4e1e42063ba54fa1335283e2b2f854d Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 13 Aug 2024 11:28:02 +0200 Subject: [PATCH 10/63] fix drag and drop max width --- .../DocumentElement/classes.module.scss | 51 +++++++++---------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss b/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss index cdba1ed0..2685612f 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss +++ b/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss @@ -1,39 +1,38 @@ @import "@Themes/constants.scss"; .root { - display: flex; - max-width: 357px; - width: 100%; - gap: var(--spacing-sm, 8px); - justify-content: space-between; - align-items: center; + display: flex; + width: 100%; + gap: var(--spacing-sm, 8px); + justify-content: space-between; + align-items: center; - .content { - display: flex; - gap: var(--spacing-sm, 8px); - align-items: center; + .content { + display: flex; + gap: var(--spacing-sm, 8px); + align-items: center; - .file-name { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - max-width: 277px; - } - } + .file-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 277px; + } + } - svg { - min-width: var(--spacing-3, 24px); - min-height: var(--spacing-3, 24px); - width: var(--spacing-3, 24px); - height: var(--spacing-3, 24px); - stroke: var(--color-primary-500); - } + svg { + min-width: var(--spacing-3, 24px); + min-height: var(--spacing-3, 24px); + width: var(--spacing-3, 24px); + height: var(--spacing-3, 24px); + stroke: var(--color-primary-500); + } - .error{ + .error { min-width: var(--spacing-3, 24px); min-height: var(--spacing-3, 24px); width: var(--spacing-3, 24px); height: var(--spacing-3, 24px); stroke: var(--color-error-500); } -} \ No newline at end of file +} From 9fa0ae6039426398a2f4212fd5dab6f9db7894fb Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 13 Aug 2024 11:47:28 +0200 Subject: [PATCH 11/63] sent documents table --- .../DocumentTables/classes.module.scss | 6 ++ .../ClientView/DocumentTables/index.tsx | 80 ++++++++++++------- 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss index 1e85e972..c4b3c70e 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss @@ -11,4 +11,10 @@ justify-content: space-between; align-items: center; } + + .actions { + display: flex; + align-items: center; + gap: var(--spacing-sm, 8px); + } } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index 8714f3dc..5259f4d4 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -21,25 +21,6 @@ type IProps = { folderUid: string; }; -const header: readonly IHead[] = [ - { - key: "document_type", - title: "Type de document", - }, - { - key: "document_status", - title: "Statut", - }, - { - key: "created_at", - title: "Demandé le", - }, - { - key: "actions", - title: "Actions", - }, -]; - const tradDocumentStatus: Record = { [EDocumentStatus.ASKED]: "Demandé", [EDocumentStatus.DEPOSITED]: "À valider", @@ -99,7 +80,7 @@ export default function DocumentTables(props: IProps) { label={tradDocumentStatus[document.document_status].toUpperCase()} /> ), - created_at: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", + date: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", actions: openDeleteAskedDocumentModal(document.uid)} />} />, }; }) @@ -122,7 +103,7 @@ export default function DocumentTables(props: IProps) { label={tradDocumentStatus[document.document_status].toUpperCase()} /> ), - created_at: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", + date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", actions: ( ), - created_at: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", + date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", actions: (
), - created_at: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", + date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", actions: "", }; }) @@ -195,6 +176,29 @@ export default function DocumentTables(props: IProps) { [documents], ); + //TODO: modify accordingly when the back will handle sent documents + const sentDocuments: IRowProps[] = useMemo( + () => + documents + .map((document) => { + if (document.document_status !== "sent") return null; + return { + key: document.uid, + document_type: document.document_type?.name ?? "_", + document_status: , + date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", + actions: ( +
+ onDownload(document)} icon={} /> + openDeleteAskedDocumentModal(document.uid)} />} /> +
+ ), + }; + }) + .filter((document) => document !== null) as IRowProps[], + [documents, onDownload, openDeleteAskedDocumentModal], + ); + const progress = useMemo(() => { const total = askedDocuments.length + toValidateDocuments.length + validatedDocuments.length + refusedDocuments.length; if (total === 0) return 0; @@ -217,10 +221,11 @@ export default function DocumentTables(props: IProps) {
- {askedDocuments.length > 0 && } - {toValidateDocuments.length > 0 &&
} - {validatedDocuments.length > 0 &&
} - {refusedDocuments.length > 0 &&
} + {askedDocuments.length > 0 &&
} + {toValidateDocuments.length > 0 &&
} + {validatedDocuments.length > 0 &&
} + {refusedDocuments.length > 0 &&
} + {sentDocuments.length > 0 &&
} {documentUid && ( ); } + +function getHeader(dateColumnTitle: string): IHead[] { + return [ + { + key: "document_type", + title: "Type de document", + }, + { + key: "document_status", + title: "Statut", + }, + { + key: "date", + title: dateColumnTitle, + }, + { + key: "actions", + title: "Action", + }, + ]; +} From 828058d4308fcb573c98d1894cebc244e89d17f4 Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 13 Aug 2024 11:57:12 +0200 Subject: [PATCH 12/63] :sparkles: handle delete sent document modal --- .../DeleteAskedDocumentModal/index.tsx | 1 - .../DeleteSentDocumentModal/index.tsx | 36 ++++++++++++++++ .../ClientView/DocumentTables/index.tsx | 41 ++++++++++++++----- 3 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx index 731bb4c9..87d2586a 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx @@ -7,7 +7,6 @@ type IProps = { documentUid: string; isOpen: boolean; onClose?: () => void; - onDeleteSuccess: (uid: string) => void; }; diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx new file mode 100644 index 00000000..f10fb594 --- /dev/null +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx @@ -0,0 +1,36 @@ +import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents"; +import Modal from "@Front/Components/DesignSystem/Modal"; +import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; +import React, { useCallback } from "react"; + +type IProps = { + documentUid: string; + isOpen: boolean; + onClose?: () => void; + onDeleteSuccess: (uid: string) => void; +}; + +export default function DeleteSentDocumentModal(props: IProps) { + const { isOpen, onClose, documentUid, onDeleteSuccess } = props; + + const onDelete = useCallback( + () => + Documents.getInstance() + .delete(documentUid) + .then(() => onDeleteSuccess(documentUid)) + .then(onClose) + .catch((error) => console.warn(error)), + [documentUid, onClose, onDeleteSuccess], + ); + + return ( + + Cette action annulera l'envoi du document. + + ); +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index 5259f4d4..de516731 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -15,6 +15,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import DeleteAskedDocumentModal from "./DeleteAskedDocumentModal"; +import DeleteSentDocumentModal from "./DeleteSentDocumentModal"; type IProps = { documents: Document[]; @@ -33,7 +34,8 @@ export default function DocumentTables(props: IProps) { const [documents, setDocuments] = useState(documentsProps); const [documentUid, setDocumentUid] = useState(null); - const deleteAskedOocumentModal = useOpenable(); + const deleteAskedDocumentModal = useOpenable(); + const deleteSentDocumentModal = useOpenable(); useEffect(() => { setDocuments(documentsProps); @@ -43,9 +45,18 @@ export default function DocumentTables(props: IProps) { (uid: string | undefined) => { if (!uid) return; setDocumentUid(uid); - deleteAskedOocumentModal.open(); + deleteAskedDocumentModal.open(); }, - [deleteAskedOocumentModal], + [deleteAskedDocumentModal], + ); + + const openDeleteSentDocumentModal = useCallback( + (uid: string | undefined) => { + if (!uid) return; + setDocumentUid(uid); + deleteSentDocumentModal.open(); + }, + [deleteSentDocumentModal], ); const onDownload = useCallback((doc: Document) => { @@ -190,13 +201,13 @@ export default function DocumentTables(props: IProps) { actions: (
onDownload(document)} icon={} /> - openDeleteAskedDocumentModal(document.uid)} />} /> + openDeleteSentDocumentModal(document.uid)} />} />
), }; }) .filter((document) => document !== null) as IRowProps[], - [documents, onDownload, openDeleteAskedDocumentModal], + [documents, onDownload, openDeleteSentDocumentModal], ); const progress = useMemo(() => { @@ -227,12 +238,20 @@ export default function DocumentTables(props: IProps) { {refusedDocuments.length > 0 &&
} {sentDocuments.length > 0 &&
} {documentUid && ( - + <> + + + )} ); From 065e8ad559ae9e1b2b3066c2eda7fd264321202d Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 13 Aug 2024 12:35:51 +0200 Subject: [PATCH 13/63] :sparkles: refont page select folder client side --- .../SearchBlockList/classes.module.scss | 4 ++ .../DesignSystem/SearchBlockList/index.tsx | 5 +- src/front/Components/Layouts/Folder/index.tsx | 4 +- .../Layouts/SelectFolder/classes.module.scss | 29 ++++---- .../Components/Layouts/SelectFolder/index.tsx | 68 +++++++++++-------- 5 files changed, 64 insertions(+), 46 deletions(-) diff --git a/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss b/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss index cc668f67..68c4106d 100644 --- a/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss +++ b/src/front/Components/DesignSystem/SearchBlockList/classes.module.scss @@ -75,4 +75,8 @@ display: block; } } + + &[data-fullwidth="true"] { + width: 100%; + } } diff --git a/src/front/Components/DesignSystem/SearchBlockList/index.tsx b/src/front/Components/DesignSystem/SearchBlockList/index.tsx index 0ca8fd77..93627bdd 100644 --- a/src/front/Components/DesignSystem/SearchBlockList/index.tsx +++ b/src/front/Components/DesignSystem/SearchBlockList/index.tsx @@ -14,9 +14,10 @@ export type ISearchBlockListProps = { text: string; link: string; }; + fullwidth?: boolean; }; export default function SearchBlockList(props: ISearchBlockListProps) { - const { blocks, onSelectedBlock, bottomButton } = props; + const { blocks, onSelectedBlock, bottomButton, fullwidth = false } = props; const [selectedBlock, setSelectedBlock] = useState(null); const router = useRouter(); @@ -69,7 +70,7 @@ export default function SearchBlockList(props: ISearchBlockListProps) { }, [blocks]); return ( -
+
{bottomButton && ( diff --git a/src/front/Components/Layouts/Folder/index.tsx b/src/front/Components/Layouts/Folder/index.tsx index fdcda8f0..ead04297 100644 --- a/src/front/Components/Layouts/Folder/index.tsx +++ b/src/front/Components/Layouts/Folder/index.tsx @@ -62,13 +62,13 @@ export default function Folder() { {activeUser && activeUser.contact && ( - + Bonjour {activeUser.contact.first_name}, bienvenue sur LeCoffre.io )} {!activeUser || (!activeUser.contact && ( - + Bonjour, bienvenue sur LeCoffre.io ))} diff --git a/src/front/Components/Layouts/SelectFolder/classes.module.scss b/src/front/Components/Layouts/SelectFolder/classes.module.scss index 6334c67f..48d62920 100644 --- a/src/front/Components/Layouts/SelectFolder/classes.module.scss +++ b/src/front/Components/Layouts/SelectFolder/classes.module.scss @@ -1,17 +1,22 @@ -.root { - position: relative; - .select-folder-container { - max-width: 530px; - padding: 80px 72px; +@import "@Themes/constants.scss"; +.root { + margin: 80px auto; + width: 472px; + + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + @media (max-width: $screen-s) { + width: 100%; + margin: 0; + padding: var(--spacing-md, 16px); + } + + .title-container { display: flex; flex-direction: column; - justify-content: center; - gap: 48px; - margin: auto; - background-color: white; - .title { - text-align: center; - } + gap: var(--spacing-sm, 8px); } } diff --git a/src/front/Components/Layouts/SelectFolder/index.tsx b/src/front/Components/Layouts/SelectFolder/index.tsx index 5d84f4bb..74999979 100644 --- a/src/front/Components/Layouts/SelectFolder/index.tsx +++ b/src/front/Components/Layouts/SelectFolder/index.tsx @@ -1,26 +1,28 @@ +import backgroundImage from "@Assets/images/background_refonte.svg"; +import LogoIcon from "@Assets/logo_small_blue.svg"; import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders"; -import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; +import SearchBlockList from "@Front/Components/DesignSystem/SearchBlockList"; +import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import JwtService from "@Front/Services/JwtService/JwtService"; import { OfficeFolder } from "le-coffre-resources/dist/Customer"; +import Image from "next/image"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; -import LandingImage from "../Login/landing-connect.jpeg"; import classes from "./classes.module.scss"; -import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block"; -import BlockList from "@Front/Components/DesignSystem/SearchBlockList/BlockList"; export default function SelectFolder() { const [folders, setFolders] = useState([]); const router = useRouter(); useEffect(() => { - async function getFolders() { - const jwt = JwtService.getInstance().decodeCustomerJwt(); - if (!jwt) return; + const jwt = JwtService.getInstance().decodeCustomerJwt(); + if (!jwt) return; - const folders = await Folders.getInstance().get({ + Folders.getInstance() + .get({ q: { where: { customers: { @@ -40,11 +42,8 @@ export default function SelectFolder() { customers: true, }, }, - }); - setFolders(folders); - } - - getFolders(); + }) + .then((folders) => setFolders(folders)); }, []); const handleSelectBlock = useCallback( @@ -55,26 +54,35 @@ export default function SelectFolder() { ); return ( - +
-
-
- Vos dossiers -
-
- { - return { - id: folder.uid!, - primaryText: folder.name!, - selected: false, - }; - })} - /> -
+
+ + + Vos dossiers en cours + + + + Veuillez sélectionner le dossier pour lequel vous souhaitez déposer ou consulter des documents. +
+ + + Liste des dossiers disponibles : + + +
); } + +function getBlocks(folders: OfficeFolder[]): IBlock[] { + return folders.map((folder) => { + return { + id: folder.uid!, + primaryText: folder.name!, + secondaryText: folder.folder_number!, + }; + }); +} From b6304a2814bbe03d291323b6cf2bdfdf07c93940 Mon Sep 17 00:00:00 2001 From: Maxime Sallerin <97036207+maxime-sallerin@users.noreply.github.com> Date: Mon, 19 Aug 2024 16:33:40 +0200 Subject: [PATCH 14/63] Feature/client dashboard (#183) --- .../DepositDocument/classes.module.scss | 106 ---- .../DesignSystem/DepositDocument/index.tsx | 452 ------------------ .../classes.module.scss | 0 .../index.tsx | 4 +- .../DesignSystem/DragAndDrop/index.tsx | 134 ++++-- .../DesignSystem/Typography/index.tsx | 2 + .../Elements/ContactBox/classes.module.scss | 22 + .../Components/Elements/ContactBox/index.tsx | 48 ++ .../DefaultCustomerDashboard/index.tsx | 68 +++ .../classes.module.scss | 15 + .../DepositDocumentComponent/index.tsx | 64 +++ .../ClientDashboard/classes.module.scss | 129 +---- .../Layouts/ClientDashboard/index.tsx | 292 +++++------ .../Layouts/ClientDashboard/index2.tsx | 140 ------ .../Components/Layouts/DesignSystem/index.tsx | 2 +- src/front/Components/Layouts/Folder/index.tsx | 26 +- .../Components/Layouts/SelectFolder/index.tsx | 9 +- src/front/Config/Module/development.json | 7 + src/front/Config/Module/preprod.json | 7 + src/front/Config/Module/production.json | 7 + src/front/Config/Module/staging.json | 7 + src/front/Hooks/useUser.ts | 26 + 22 files changed, 527 insertions(+), 1040 deletions(-) delete mode 100644 src/front/Components/DesignSystem/DepositDocument/classes.module.scss delete mode 100644 src/front/Components/DesignSystem/DepositDocument/index.tsx rename src/front/Components/DesignSystem/DragAndDrop/{DocumentElement => DocumentFileElement}/classes.module.scss (100%) rename src/front/Components/DesignSystem/DragAndDrop/{DocumentElement => DocumentFileElement}/index.tsx (93%) create mode 100644 src/front/Components/Elements/ContactBox/classes.module.scss create mode 100644 src/front/Components/Elements/ContactBox/index.tsx create mode 100644 src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx create mode 100644 src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss create mode 100644 src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx delete mode 100644 src/front/Components/Layouts/ClientDashboard/index2.tsx create mode 100644 src/front/Hooks/useUser.ts diff --git a/src/front/Components/DesignSystem/DepositDocument/classes.module.scss b/src/front/Components/DesignSystem/DepositDocument/classes.module.scss deleted file mode 100644 index dbbcbd00..00000000 --- a/src/front/Components/DesignSystem/DepositDocument/classes.module.scss +++ /dev/null @@ -1,106 +0,0 @@ -.container { - .root { - padding: 24px; - background-color: var(--color-generic-white); - border: 1px dashed #e7e7e7; - - height: fit-content; - - &[data-drag-over="true"] { - border: 1px dashed var(--color-neutral-500); - } - - &.validated { - border: 1px dashed var(--color-success-600); - } - - .top-container { - display: flex; - align-items: center; - - .left { - margin-right: 28px; - } - - .separator { - background-color: #939393; - width: 1px; - align-self: stretch; - } - - .right { - margin-left: 18px; - - .validated { - color: var(--color-success-600); - } - - .refused-button { - font-size: 14px; - color: var(--color-error-800); - margin-left: 8px; - } - - .title { - display: flex; - align-items: center; - gap: 8px; - } - } - } - - .documents-container { - display: flex; - flex-direction: column; - gap: 16px; - margin-top: 16px; - - .file-container { - display: flex; - align-items: center; - justify-content: space-between; - - .left-part { - display: flex; - align-items: center; - gap: 8px; - .loader { - width: 32px; - height: 32px; - } - } - - .cross { - cursor: pointer; - } - } - } - - .bottom-container { - margin-top: 16px; - - .add-button { - .add-document { - display: flex; - align-items: center; - gap: 14px; - } - } - } - - .text { - margin-bottom: 12px; - } - } - - .modal-content { - display: flex; - flex-direction: column; - gap: 16px; - } - - .error-message { - color: var(--color-error-600); - margin-top: 8px; - } -} diff --git a/src/front/Components/DesignSystem/DepositDocument/index.tsx b/src/front/Components/DesignSystem/DepositDocument/index.tsx deleted file mode 100644 index 79958a8d..00000000 --- a/src/front/Components/DesignSystem/DepositDocument/index.tsx +++ /dev/null @@ -1,452 +0,0 @@ -import DepositDocumentIcon from "@Assets/Icons/deposit-document.svg"; -import PlusIcon from "@Assets/Icons/plus.svg"; -import CrossIcon from "@Assets/Icons/cross.svg"; -import DocumentCheckIcon from "@Assets/Icons/document-check.svg"; -import Image from "next/image"; -import React from "react"; - -import Button, { EButtonstyletype, EButtonVariant } from "../Button"; -import Tooltip from "../ToolTip"; -import Typography, { ETypo, ETypoColor } from "../Typography"; -import classes from "./classes.module.scss"; -import { Document, DocumentHistory, File as FileCustomer } from "le-coffre-resources/dist/Customer"; -import Files from "@Front/Api/LeCoffreApi/Customer/Files/Files"; -import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; -import classNames from "classnames"; -import Confirm from "../OldModal/Confirm"; -import Alert from "../OldModal/Alert"; -import GreenCheckIcon from "@Assets/Icons/green-check.svg"; -import Loader from "../Loader"; -import TextAreaField from "../Form/TextareaField"; -import { toast } from "react-toastify"; - -type IProps = { - defaultFiles?: FileCustomer[]; - onChange?: (files: File[]) => void; - document: Document; -}; - -type IFile = { - index: number; - file: File; - uid: string; - archived: Date | null; - fileName: string; -}; - -type IState = { - files: IFile[]; - isDragOver: boolean; - currentFiles?: FileCustomer[]; - refusedReason?: string; - isShowRefusedReasonModalVisible: boolean; - showFailedUploaded: string | null; - loading: boolean; -}; - -type fileAccepted = { - extension: string; - size: number; -}; - -const filesAccepted: { [key: string]: fileAccepted } = { - "application/pdf": { - extension: "pdf", - size: 41943040, - }, - "image/jpeg": { - extension: "jpeg", - size: 41943040, - }, - "image/png": { - extension: "png", - size: 41943040, - }, - "image/jpg": { - extension: "jpg", - size: 41943040, - }, -}; - -export default class DepositDocument extends React.Component { - private inputRef = React.createRef(); - private index = 0; - - public constructor(props: IProps) { - super(props); - - this.state = { - files: [], - isDragOver: false, - currentFiles: this.props.defaultFiles, - refusedReason: "", - isShowRefusedReasonModalVisible: false, - showFailedUploaded: null, - loading: false, - }; - - this.addDocument = this.addDocument.bind(this); - this.onFileChange = this.onFileChange.bind(this); - this.addFile = this.addFile.bind(this); - this.removeFile = this.removeFile.bind(this); - this.onDragOver = this.onDragOver.bind(this); - this.onDragDrop = this.onDragDrop.bind(this); - this.onDragLeave = this.onDragLeave.bind(this); - this.onCloseModalShowRefusedReason = this.onCloseModalShowRefusedReason.bind(this); - this.onOpenModalShowRefusedReason = this.onOpenModalShowRefusedReason.bind(this); - this.showRefusedReason = this.showRefusedReason.bind(this); - this.onCloseAlertUpload = this.onCloseAlertUpload.bind(this); - } - - public override render(): JSX.Element { - return ( -
-
- -
-
- -
-
-
- -
- {this.props.document.document_type?.name} -
- {this.props.document.document_type?.public_description !== " " && - this.props.document.document_type?.public_description !== "" && - this.props.document.document_status !== EDocumentStatus.VALIDATED && ( - - )} - {this.props.document.document_status === EDocumentStatus.VALIDATED && ( - - )} -
- {this.props.document.document_status !== EDocumentStatus.VALIDATED && ( - - Sélectionnez des documents .jpg, .pdf ou .png - - )} - {this.props.document.document_history?.map((history) => ( -
{this.renderDocumentHistory(history)}
- ))} -
-
-
- {this.state.files.map((file) => { - const fileObj = file.file; - if (file.archived) return; - return ( -
-
- - - {this.shortName(file.fileName || fileObj.name)} - -
- -
- ); - })} - {this.state.loading && ( -
-
-
- -
- - Chargement... - -
-
-
- )} -
- {this.props.document.document_status !== EDocumentStatus.VALIDATED && ( -
- -
- )} - -
- - Votre document a été refusé pour la raison suivante : - - -
-
-
- {this.props.document.document_status === EDocumentStatus.REFUSED && ( - - Ce document n'est pas conforme. Veuillez le déposer à nouveau. - - )} - {this.state.showFailedUploaded && ( - -
- - {this.state.showFailedUploaded} - -
-
- )} -
- ); - } - - public override componentDidMount(): void { - if (this.props.defaultFiles) { - this.setState({ - files: this.props.defaultFiles.map((file) => ({ - index: this.index++, - file: new File([""], file.file_path ?? "", {}), - uid: file.uid!, - fileName: file.file_name, - archived: file.archived_at ? new Date(file.archived_at) : null, - })), - }); - } - } - - private openSuccessToast() { - toast.success("Document envoyé avec succès"); - } - - private onCloseModalShowRefusedReason() { - this.setState({ - isShowRefusedReasonModalVisible: false, - }); - } - - private onOpenModalShowRefusedReason() { - this.setState({ - isShowRefusedReasonModalVisible: true, - }); - } - - private renderDocumentHistory(history: DocumentHistory): JSX.Element | null { - switch (history.document_status) { - case EDocumentStatus.ASKED: - return ( - - Demandé par votre notaire le {this.formatDate(history.created_at!)} - - ); - case EDocumentStatus.VALIDATED: - return ( - - Validé par votre notaire le {this.formatDate(history.created_at!)} - - ); - case EDocumentStatus.DEPOSITED: - return ( - - Déposé le {this.formatDate(history.created_at!)} - - ); - - case EDocumentStatus.REFUSED: - return ( - - Document non conforme - {history.refused_reason && history.refused_reason.length > 0 && ( - - )} - - ); - } - return null; - } - - private shortName(name: string): string { - const maxLength = 20; - if (name.length > maxLength) { - return name.substring(0, maxLength / 2) + "..." + name.substring(name.length - maxLength / 2, name.length); - } - return name; - } - - private onDragOver(event: React.DragEvent) { - if (!this.state.isDragOver) { - this.setState({ - isDragOver: true, - }); - } - event.preventDefault(); - } - - private showRefusedReason(refusedReason: string) { - this.setState({ - refusedReason, - }); - this.onOpenModalShowRefusedReason(); - } - - private onDragLeave(event: React.DragEvent) { - this.setState({ - isDragOver: false, - }); - event.preventDefault(); - } - - private async onDragDrop(event: React.DragEvent) { - event.preventDefault(); - this.setState({ - isDragOver: false, - }); - const file = event.dataTransfer.files[0]; - if (file) this.addFile(file); - } - - private async addFile(file: File) { - const fileAccepted = filesAccepted[file.type]; - if (!fileAccepted) { - alert("Le fichier déposé doit être au format .jpg .pdf .jpeg ou .png"); - return false; - } - if (file.size > fileAccepted.size) { - alert("Le fichier est trop volumineux et ne doit pas dépasser 32mo"); - return false; - } - this.setState({ - loading: true, - }); - - const formData = new FormData(); - formData.append("file", file, file.name); - const query = JSON.stringify({ document: { uid: this.props.document.uid } }); - formData.append("q", query); - - let newFile: FileCustomer; - try { - newFile = await Files.getInstance().post(formData); - } catch (e) { - this.setState({ showFailedUploaded: "Le fichier ne correspond pas aux critères demandés", loading: false }); - return false; - } - const files = this.state.currentFiles ? [...this.state.currentFiles, newFile] : [newFile]; - - const newFileList = [ - ...this.state.files, - { - index: this.index++, - file: file, - uid: newFile.uid!, - archived: null, - fileName: newFile?.file_name ?? "", - }, - ]; - this.openSuccessToast(); - this.setState( - { - currentFiles: files, - loading: false, - files: newFileList, - }, - () => { - if (this.props.onChange) this.props.onChange(newFileList.map((file) => file.file)); - }, - ); - - return true; - } - - private async removeFile(e: any) { - const image = e.target as HTMLElement; - const indexToRemove = image.getAttribute("data-file"); - if (!indexToRemove) return; - const file = this.state.files.find((file) => file.index === parseInt(indexToRemove)); - if (!file) return; - this.setState({ - files: this.state.files.filter((file) => file.index !== parseInt(indexToRemove)), - }); - - if (this.props.onChange) this.props.onChange(this.state.files.map((file) => file.file)); - await Files.getInstance().delete(file.uid); - } - - private async onFileChange() { - if (!this.inputRef.current) return; - const files = this.inputRef.current.files; - if (!files) { - this.setState({ loading: false }); - return; - } - const file = files[0]; - - try { - if (file) { - await this.setState({ loading: true }, () => { - this.addFile(file); - }); - } - } catch (e) { - this.setState({ loading: false }); - } - } - - private onCloseAlertUpload() { - this.setState({ showFailedUploaded: null }); - } - - private addDocument() { - if (!this.inputRef.current) return; - this.inputRef.current.value = ""; - this.inputRef.current.click(); - } - - private formatDate(date: Date) { - const dateToConvert = new Date(date); - return dateToConvert.toLocaleDateString("fr-FR"); - } -} diff --git a/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss b/src/front/Components/DesignSystem/DragAndDrop/DocumentFileElement/classes.module.scss similarity index 100% rename from src/front/Components/DesignSystem/DragAndDrop/DocumentElement/classes.module.scss rename to src/front/Components/DesignSystem/DragAndDrop/DocumentFileElement/classes.module.scss diff --git a/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/DocumentFileElement/index.tsx similarity index 93% rename from src/front/Components/DesignSystem/DragAndDrop/DocumentElement/index.tsx rename to src/front/Components/DesignSystem/DragAndDrop/DocumentFileElement/index.tsx index efb8aa20..f703b9f3 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/DocumentElement/index.tsx +++ b/src/front/Components/DesignSystem/DragAndDrop/DocumentFileElement/index.tsx @@ -7,13 +7,13 @@ import Loader from "../../Loader"; import classes from "./classes.module.scss"; type IProps = { - isLoading: boolean; file: File | null; onRemove: () => void; + isLoading?: boolean; error?: string; }; -export default function DocumentElement(props: IProps) { +export default function DocumentFileElement(props: IProps) { const { isLoading, onRemove, file, error } = props; return ( diff --git a/src/front/Components/DesignSystem/DragAndDrop/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/index.tsx index a803b05c..ef30c062 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/index.tsx +++ b/src/front/Components/DesignSystem/DragAndDrop/index.tsx @@ -1,18 +1,33 @@ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import { DocumentPlusIcon } from "@heroicons/react/24/outline"; import classNames from "classnames"; -import React, { useCallback, useRef, useState } from "react"; +import React, { useCallback, useEffect, useRef, useState } from "react"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "../Button"; import Separator, { ESeperatorColor, ESeperatorDirection } from "../Separator"; import classes from "./classes.module.scss"; -import DocumentElement from "./DocumentElement"; +import DocumentFileElement from "./DocumentFileElement"; +/** + * @description Drag and drop component to upload files + * @param {string} title - Title of the component + * @param {string} description - Description of the component + * @param {IDocumentFileWithUid[]} defaultFiles - Default files to display + * @param {(fileUid: string) => Promise} onDelete - Function to delete a file (must be used with defaultFiles) + * @param {(file: File) => Promise} onAddFile - Function to add a file (must be used with defaultFiles) + */ type IProps = { - name?: string; title: string; - description: string; -}; + description?: string; + defaultFiles?: IDocumentFileWithUid[]; + onDelete?: (fileUid: string) => Promise; + onAddFile?: (file: File) => Promise; +} & ( + | { onDelete: (fileUid: string) => Promise; onAddFile?: never; defaultFiles: IDocumentFileWithUid[] } + | { onDelete?: never; onAddFile: (file: File) => Promise; defaultFiles: IDocumentFileWithUid[] } + | { onDelete?: (fileUid: string) => Promise; onAddFile?: (file: File) => Promise; defaultFiles: IDocumentFileWithUid[] } + | { onDelete?: never; onAddFile?: never; defaultFiles?: never } +); type IMimeTypes = { extension: string; @@ -38,53 +53,87 @@ const mimeTypesAccepted: { [key: string]: IMimeTypes } = { }, }; -type IDocument = { +type IDocumentFileBase = { id: string; file: File | null; - isLoading: boolean; + uid?: string; + isLoading?: boolean; error?: string; }; +export type IDocumentFileWithUid = IDocumentFileBase & { + uid: string; +}; + +type IDocumentFile = IDocumentFileBase | IDocumentFileWithUid; + export default function DragAndDrop(props: IProps) { - const { name, title, description } = props; + const { title, description, defaultFiles, onDelete, onAddFile } = props; const fileInputRef = useRef(null); - const [documents, setDocuments] = useState([]); + const [documentFiles, setDocumentFiles] = useState([]); - const handleFiles = useCallback((files: File[]) => { - files.forEach((file) => { - setDocuments((prevDocs) => [...prevDocs, { id: file.name, file: file, isLoading: true }]); - setTimeout(() => { - if (mimeTypesAccepted[file.type]) { - const newDoc: IDocument = { id: file.name, file, isLoading: false }; - setDocuments((prevDocs) => prevDocs.map((doc) => (doc.id === newDoc.id ? newDoc : doc))); - } else { - const errorDoc: IDocument = { id: file.name, file: null, isLoading: false, error: "Type de fichier non accepté" }; - setDocuments((prevDocs) => prevDocs.map((doc) => (doc.id === errorDoc.id ? errorDoc : doc))); + useEffect(() => { + if (defaultFiles) { + setDocumentFiles(defaultFiles); + } + }, [defaultFiles]); + + const handleAddFiles = useCallback( + (files: File[]) => { + files.forEach((file) => { + setDocumentFiles((prevDocs) => [...prevDocs, { id: file.name, file: file, isLoading: true }]); + try { + if (!mimeTypesAccepted[file.type]) { + throw new Error("Type de fichier non accepté"); + } + const newDoc: IDocumentFile = { id: file.name, file, isLoading: false }; + + if (onAddFile) { + // As onAddFile is used along defaultFiles prop we dont need to update the state here but the parent component should update the defaultFiles prop + return onAddFile(file); + } + + return setTimeout(async () => { + setDocumentFiles((prevDocs) => prevDocs.map((doc) => (doc.id === newDoc.id ? newDoc : doc))); + }, 1000); + } catch (error: any) { + const errorDoc: IDocumentFile = { id: file.name, file: null, isLoading: false, error: error.message }; + return setDocumentFiles((prevDocs) => prevDocs.map((doc) => (doc.id === errorDoc.id ? errorDoc : doc))); } - }, 1000); - }); - }, []); + }); + }, + [onAddFile], + ); const handleDrop = useCallback( (event: React.DragEvent) => { event.preventDefault(); const files = Array.from(event.dataTransfer.files); - handleFiles(files); + handleAddFiles(files); }, - [handleFiles], + [handleAddFiles], ); - const handleRemove = useCallback((id: string) => { - setDocuments((prevDocs) => prevDocs.filter((doc) => doc.id !== id)); - }, []); + const handleRemove = useCallback( + (documentFile: IDocumentFile) => { + const loadingDoc = { ...documentFile, isLoading: true }; + setDocumentFiles((prevDocs) => prevDocs.map((doc) => (doc.id === documentFile.id ? loadingDoc : doc))); + + if (documentFile.uid) { + return onDelete?.(documentFile.uid); + } + return setDocumentFiles((prevDocs) => prevDocs.filter((doc) => doc.id !== documentFile.id)); + }, + [onDelete], + ); const handleBrowse = useCallback( (event: React.ChangeEvent) => { const files = Array.from(event.target.files || []); - handleFiles(files); + handleAddFiles(files); }, - [handleFiles], + [handleAddFiles], ); const triggerFileInput = () => { @@ -95,7 +144,7 @@ export default function DragAndDrop(props: IProps) { return (
0 && classes["filled"])} + className={classNames(classes["root"], documentFiles.length > 0 && classes["filled"])} onDrop={handleDrop} onDragOver={(e) => e.preventDefault()}>
@@ -127,20 +176,22 @@ export default function DragAndDrop(props: IProps) {
- - {description} - + {description && ( + + {description} + + )}
- {documents.length > 0 && ( + {documentFiles.length > 0 && (
- {documents.map((doc) => ( - handleRemove(doc.id)} - error={doc.error} + {documentFiles.map((documentFile) => ( + handleRemove(documentFile)} + error={documentFile.error} /> ))}
@@ -152,7 +203,6 @@ export default function DragAndDrop(props: IProps) { return ( +
+ + {contact?.first_name} {contact?.last_name} + +
+
+ + Numéro de téléphone + + + {contact?.cell_phone_number ?? contact?.phone_number ?? "_"} + +
+
+ + E-mail + + + {contact?.email ?? "_"} + +
+
+ + Note client + + + {note?.content ?? "-"} + +
+
+ ); +} diff --git a/src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx b/src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx new file mode 100644 index 00000000..8dfc3a60 --- /dev/null +++ b/src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx @@ -0,0 +1,68 @@ +import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders"; +import { IBlock } from "@Front/Components/DesignSystem/SearchBlockList/BlockList/Block"; +import Module from "@Front/Config/Module"; +import JwtService from "@Front/Services/JwtService/JwtService"; +import { OfficeFolder } from "le-coffre-resources/dist/Customer"; +import { useRouter } from "next/router"; +import React, { useEffect, useState } from "react"; + +import DefaultDashboardWithList, { IPropsDashboardWithList } from "../DefaultDashboardWithList"; + +type IProps = IPropsDashboardWithList & {}; + +export default function DefaultCustomerDashboard(props: IProps) { + const router = useRouter(); + const { folderUid } = router.query; + const [folders, setFolders] = useState([]); + + useEffect(() => { + const jwt = JwtService.getInstance().decodeCustomerJwt(); + if (!jwt) return; + + Folders.getInstance() + .get({ + q: { + where: { + customers: { + some: { + contact: { + email: jwt.email, + }, + }, + }, + }, + orderBy: [ + { + created_at: "desc", + }, + ], + include: { + customers: true, + }, + }, + }) + .then((folders) => setFolders(folders)); + }, []); + + const onSelectedBlock = (block: IBlock) => { + const folder = folders.find((folder) => folder.uid === block.id); + if (!folder) return; + router.push( + Module.getInstance() + .get() + .modules.pages.ClientDashboard.props.path.replace("[folderUid]", folder.uid ?? ""), + ); + }; + return ; + + function getBlocks(folders: OfficeFolder[]): IBlock[] { + return folders.map((folder) => { + return { + id: folder.uid!, + primaryText: folder.name!, + secondaryText: folder.folder_number!, + isActive: folderUid === folder.uid, + }; + }); + } +} diff --git a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss new file mode 100644 index 00000000..cde520cf --- /dev/null +++ b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/classes.module.scss @@ -0,0 +1,15 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + justify-content: space-between; + align-items: center; + align-self: stretch; + flex-wrap: wrap; + + .title { + display: flex; + flex-direction: column; + gap: var(--spacing-sm, 8px); + } +} diff --git a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx new file mode 100644 index 00000000..943361af --- /dev/null +++ b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx @@ -0,0 +1,64 @@ +import DragAndDrop, { IDocumentFileWithUid } from "@Front/Components/DesignSystem/DragAndDrop"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import { Document } from "le-coffre-resources/dist/Customer"; +import { useCallback, useMemo } from "react"; + +import classes from "./classes.module.scss"; +import Files from "@Front/Api/LeCoffreApi/Customer/Files/Files"; + +type IProps = { + document: Document; + onChange: () => void; +}; + +export default function DepositDocumentComponent(props: IProps) { + const { document, onChange } = props; + + const defaultFiles: IDocumentFileWithUid[] = useMemo(() => { + const filesNotArchived = document.files?.filter((file) => !file.archived_at) ?? []; + return filesNotArchived.map((file) => ({ + id: file.uid!, + file: new File([""], file.file_name!, { type: file.mimetype }), + uid: file.uid!, + })); + }, [document.files]); + + const addFile = useCallback( + (file: File) => { + const formData = new FormData(); + formData.append("file", file, file.name); + const query = JSON.stringify({ document: { uid: document.uid } }); + formData.append("q", query); + return Files.getInstance().post(formData).then(onChange); + }, + [document.uid, onChange], + ); + + const deleteFile = useCallback( + (filedUid: string) => { + return Files.getInstance().delete(filedUid).then(onChange); + }, + [onChange], + ); + + return ( +
+
+ + {document.document_type?.name ?? "_"} + + + Demandé le: {document.created_at ? new Date(document.created_at).toLocaleDateString() : "_"} + +
+ + +
+ ); +} diff --git a/src/front/Components/Layouts/ClientDashboard/classes.module.scss b/src/front/Components/Layouts/ClientDashboard/classes.module.scss index 5fc0ae9c..584a4e5c 100644 --- a/src/front/Components/Layouts/ClientDashboard/classes.module.scss +++ b/src/front/Components/Layouts/ClientDashboard/classes.module.scss @@ -1,120 +1,39 @@ @import "@Themes/constants.scss"; .root { - .header { + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + .title-container { + flex-direction: column; display: flex; - padding: 64px; - justify-content: space-between; + gap: var(--spacing-sm, 8px); - @media (max-width: $screen-m) { - flex-wrap: wrap; - - .text { - margin: 32px 0; - } - } - - @media (max-width: $screen-s) { - flex-wrap: wrap; - - .text { - margin: 32px 0; - } - - .button { - flex: 1; - } - } - - .folder-number { - margin-top: 16px; - } - - .office-name { - margin-top: 8px; - text-transform: uppercase; - } - - .subtitle { - margin: 64px 0 32px 0; - } - - .contact { + .office-container { display: flex; - gap: 20px; - } - - .contact-text { - text-align: right; - line-height: 15px; - } - - .contact-button { - margin-top: 4%; - } - - .separator { - width: 20px; - height: 50px; /* Adjust the height as needed */ - background-color: gray; - margin: 0 20px; /* Adjust the margin as needed */ - } - - .note-box { - border: 1px solid #e0e0e0; /* Light grey border */ - margin-top: 25px; - padding: 10px; - width: 100%; - height: 100px; /* Adjust height as needed */ - box-sizing: border-box; - position: relative; + align-items: center; + gap: var(--spacing-md, 16px); } } - .sub-container { - background-color: var(--color-neutral-50); - padding: 64px; + .content { + display: flex; + gap: var(--spacing-lg, 24px); + align-items: flex-start; - .content { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 32px; - margin-bottom: 64px; - - @media (max-width: $screen-s) { - grid-template-columns: 1fr; - } + .notary { + display: flex; + width: 300px; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-lg, 24px); } - .component-to-replace { - min-width: 124px; - height: 98px; - background-color: white; - } - - .text { - margin: 32px 0; - } - - .button { - width: fit-content; - } - - @media (max-width: $screen-s) { - .button { - width: 100%; - } - } - } - - .modal-content { - .text { - margin: 24px 0; - } - - .component-to-replace { - background-color: var(--color-neutral-50); - height: 98px; + .documents { + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); width: 100%; } } diff --git a/src/front/Components/Layouts/ClientDashboard/index.tsx b/src/front/Components/Layouts/ClientDashboard/index.tsx index d7478605..84e097c5 100644 --- a/src/front/Components/Layouts/ClientDashboard/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/index.tsx @@ -1,19 +1,25 @@ "use client"; import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/Customer/Documents/Documents"; -import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import DepositDocument from "@Front/Components/DesignSystem/DepositDocument"; + import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; -import Customer, { Document, DocumentType, Note, OfficeFolder } from "le-coffre-resources/dist/Customer"; -import React, { useCallback, useEffect, useState } from "react"; + +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 classes from "./classes.module.scss"; import { useRouter } from "next/router"; import JwtService, { ICustomerJwtPayload } from "@Front/Services/JwtService/JwtService"; -import DepositOtherDocument from "@Front/Components/DesignSystem/DepositOtherDocument"; 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 DepositDocumentComponent from "./DepositDocumentComponent"; + type IProps = {}; export default function ClientDashboard(props: IProps) { @@ -22,12 +28,11 @@ export default function ClientDashboard(props: IProps) { const [documents, setDocuments] = useState(null); const [customer, setCustomer] = useState(null); - const [contact, setContact] = useState(null); - const [folder, setFolder] = useState(null); - const [note, setNote] = useState(null); - const [isAddDocumentModalVisible, setIsAddDocumentModalVisible] = useState(false); + const [folder, setFolder] = useState(null); - const getDocuments = useCallback(async () => { + const [ribUrl, setRibUrl] = useState(null); + + const fetchFolderAndCustomer = useCallback(async () => { let jwt: ICustomerJwtPayload | undefined; if (typeof document !== "undefined") { jwt = JwtService.getInstance().decodeCustomerJwt(); @@ -50,66 +55,73 @@ export default function ClientDashboard(props: IProps) { }, }, }); - //Loop through the folder stakeholders, if there is at least one stakeholder that role is "Collaborateur" set contact to this stakeholders.contact, else, take the first stakeholders of the list - const contact = folder.stakeholders!.find((stakeholder) => stakeholder.office_role?.name === "Collaborateur")?.contact; - setContact(contact ?? folder.stakeholders![0]!.contact); - const actualCustomer = folder?.customers?.find((customer) => customer.contact?.email === jwt?.email); - if (!actualCustomer) throw new Error("Customer not found"); + const customer = folder?.customers?.find((customer) => customer.contact?.email === jwt?.email); + if (!customer) throw new Error("Customer not found"); - let note = folder.notes?.find((note) => note.customer?.uid === actualCustomer.uid); - // if (!note) throw new Error("Note not found"); - if (!note) { - note = { - content: "Aucune note", - created_at: new Date(), - updated_at: new Date(), - }; - } + setFolder(folder); + setCustomer(customer); - const query: IGetDocumentsparams = { - where: { depositor: { uid: actualCustomer.uid }, folder_uid: folderUid as string }, - include: { - files: true, - document_history: true, - document_type: true, - depositor: true, - folder: { - include: { - customers: { - include: { - contact: true, + return { folder, customer }; + }, [folderUid]); + + const fetchDocuments = useCallback( + (customerUid: string | undefined) => { + const query: IGetDocumentsparams = { + where: { depositor: { uid: customerUid }, folder_uid: folderUid as string }, + include: { + files: true, + document_history: true, + document_type: true, + depositor: true, + folder: { + include: { + customers: { + include: { + contact: true, + }, }, }, }, }, + }; + + return Documents.getInstance() + .get(query) + .then((documents) => setDocuments(documents)); + }, + [folderUid], + ); + + useEffect(() => { + 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], + ); - const documentList = await Documents.getInstance().get(query); - - //const folder = await Folders.getInstance().getByUid(folderUid as string, { q: { office: true, customers: true } }); - - setFolder(folder); - setDocuments(documentList); - setCustomer(actualCustomer); - setNote(note); - }, [folderUid]); - - const onCloseModalAddDocument = useCallback(() => { - setIsAddDocumentModalVisible(false); - getDocuments(); - }, [getDocuments]); - - const onOpenModalAddDocument = useCallback(() => { - setIsAddDocumentModalVisible(true); - }, []); - - const downloadFile = useCallback(async () => { + useEffect(() => { if (!folder?.office?.uid) return; - const blob = await OfficeRib.getInstance().getRibStream(folder.office.uid); - const ribUrl = URL.createObjectURL(blob); + 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"; @@ -117,122 +129,64 @@ export default function ClientDashboard(props: IProps) { a.download = ""; document.body.appendChild(a); a.click(); - }, [folder]); - - useEffect(() => { - getDocuments(); - }, [folderUid, getDocuments]); - - const renderHeader = useCallback(() => { - return ( -
-
- {/* TODO Get name from userStore */} -
- - Bonjour {customer?.contact?.first_name.concat(" ", customer?.contact?.last_name)} - -
- - - Dossier {folder?.folder_number} - {folder?.name} - - - - {folder?.office?.name} - - - - Documents à envoyer - - - - Votre notaire est dans l'attente de documents pour valider votre dossier. Voici la liste des documents. -
Veuillez glisser / déposer chaque document dans la zone prévue à cet effet ou cliquez sur la zone puis - sélectionnez le document correspondant.
En déposant un document, celui-ci est automatiquement enregistré et - transmis à votre notaire. -
-
- - {note?.content} - -
-
- -
- -

- {contact?.first_name} {contact?.last_name} -

-

{contact?.phone_number ?? contact?.cell_phone_number}

-

{contact?.email}

-
-
- {folder?.office?.rib_name && ( - //Div to avoid the button to be on the same line as the text - - )} -
-
- ); - }, [ - contact?.cell_phone_number, - contact?.email, - contact?.first_name, - contact?.last_name, - contact?.phone_number, - customer?.contact?.first_name, - customer?.contact?.last_name, - downloadFile, - folder?.folder_number, - folder?.name, - folder?.office?.name, - folder?.office?.rib_name, - note?.content, - ]); - - const renderBox = useCallback(() => { - return ( - ({ - document_type: DocumentType.hydrate({ - name: "Autres documents", - }), - })} - /> - ); - }, [customer, folderUid, isAddDocumentModalVisible, onCloseModalAddDocument]); + }, [ribUrl]); return ( - +
- {renderHeader()} -
-
+
+ + Dossier {folder?.folder_number} - {folder?.name} + + + Bonjour {customer?.contact?.first_name.concat(" ", customer?.contact?.last_name)} + + +
+ + Office + + + + {folder?.office?.name} + +
+
+
+
+ + Votre Notaire + + {notaryContact && } + {ribUrl && ( + + )} + +
+
+ + Documents à envoyer + {documents?.map((document) => ( - + fetchDocuments(customer?.uid)} + /> ))}
- Documents supplémentaires (facultatif) - - Vous souhaitez envoyer d'autres documents à votre notaire ? - -
- {isAddDocumentModalVisible && renderBox()} - + ); } diff --git a/src/front/Components/Layouts/ClientDashboard/index2.tsx b/src/front/Components/Layouts/ClientDashboard/index2.tsx deleted file mode 100644 index 89cb3b6d..00000000 --- a/src/front/Components/Layouts/ClientDashboard/index2.tsx +++ /dev/null @@ -1,140 +0,0 @@ -//import Customers from "@Front/Api/LeCoffreApi/Customer/Customers/Customers"; -import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import DepositDocument from "@Front/Components/DesignSystem/DepositDocument"; -import TextField from "@Front/Components/DesignSystem/Form/TextField"; -import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; -import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; -import Base from "@Front/Components/Layouts/Base"; -import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; -import Customer, { Document, DocumentType } from "le-coffre-resources/dist/Customer"; -import React from "react"; - -import classes from "./classes.module.scss"; - -type IProps = {}; -type IState = { - isAddDocumentModalVisible: boolean; - documents: Document[]; - mockedCustomer: Customer | null; -}; - -export default class ClientDashboard extends Base { - public constructor(props: IProps) { - super(props); - this.state = { - isAddDocumentModalVisible: false, - documents: [], - mockedCustomer: null, - }; - this.onCloseModalAddDocument = this.onCloseModalAddDocument.bind(this); - this.onOpenModalAddDocument = this.onOpenModalAddDocument.bind(this); - } - - public override render(): JSX.Element { - return ( - -
- {this.renderHeader()} -
-
- {this.state.documents?.map((document) => ( - - ))} -
- Documents supplémentaires (facultatif) - - Vous souhaitez envoyer d'autres documents à votre notaire ? - - -
- -
- - Vous souhaitez envoyer un autre document à votre notaire ? - - - - Glissez / Déposez votre document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le - document correspondant. - - ({ - document_type: DocumentType.hydrate({ - name: "Autres documents", - }), - })} - /> -
-
-
-
- ); - } - - private renderHeader(): JSX.Element { - return ( -
-
- {/* TODO Get name from userStore */} - - Bonjour {this.state.mockedCustomer?.contact?.first_name.concat(" ", this.state.mockedCustomer?.contact?.last_name)} - - - - Documents à envoyer - - - - Votre notaire est dans l'attente de documents pour valider votre dossier. Voici la liste des documents.Veuillez - glisser / déposez chaque document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le - document correspondant. Si un des documents demandés ne vous concernent pas, veuillez contacter votre notaire à - l'aide du bouton ci-dessus. - -
-
- ); - } - - // public override async componentDidMount() { - // // TODO Get documents of the current customer according to userStore - // // REMOVE this mock - - // const jwt = JwtService.getInstance().decodeJwt(); - // const mockedCustomers = await Customers.getInstance().get({ - // where: { contact: { email: jwt?.email } }, - // }); - // const mockedCustomer: Customer = mockedCustomers[0]!; - - // const query: IGetDocumentsparams = { - // where: { depositor: { uid: mockedCustomer.uid } }, - // include: { - // files: true, - // document_history: true, - // document_type: true, - // }, - // }; - // const documents: Document[] = await Documents.getInstance().get(query); - // this.setState({ documents, mockedCustomer }); - // } - - private onCloseModalAddDocument() { - this.setState({ isAddDocumentModalVisible: false }); - } - - private onOpenModalAddDocument() { - this.setState({ isAddDocumentModalVisible: true }); - } -} diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index 0cf4f2cd..ea214504 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -131,7 +131,7 @@ export default function DesignSystem() { Logged Out Drag and Drop - + Separators
diff --git a/src/front/Components/Layouts/Folder/index.tsx b/src/front/Components/Layouts/Folder/index.tsx index ead04297..099f05db 100644 --- a/src/front/Components/Layouts/Folder/index.tsx +++ b/src/front/Components/Layouts/Folder/index.tsx @@ -1,40 +1,24 @@ import LogoIcon from "@Assets/logo_small_blue.svg"; -import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users"; +import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import Module from "@Front/Config/Module"; -import JwtService from "@Front/Services/JwtService/JwtService"; import { DocumentIcon } from "@heroicons/react/24/outline"; -import User from "le-coffre-resources/dist/Notary"; +import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus"; import Image from "next/image"; import Link from "next/link"; +import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import classes from "./classes.module.scss"; -import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; -import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus"; -import { useRouter } from "next/router"; +import useUser from "@Front/Hooks/useUser"; export default function Folder() { const [_isArchivedModalOpen, _setIsArchivedModalOpen] = useState(true); const router = useRouter(); - const [activeUser, setActiveUser] = useState(); - - useEffect(() => { - const decodedJwt = JwtService.getInstance().decodeJwt(); - if (!decodedJwt) return; - Users.getInstance() - .getByUid(decodedJwt.userId, { - q: { - contact: true, - }, - }) - .then((user) => { - setActiveUser(user); - }); - }, []); + const { user: activeUser } = useUser(); useEffect(() => { Folders.getInstance() diff --git a/src/front/Components/Layouts/SelectFolder/index.tsx b/src/front/Components/Layouts/SelectFolder/index.tsx index 74999979..29692b50 100644 --- a/src/front/Components/Layouts/SelectFolder/index.tsx +++ b/src/front/Components/Layouts/SelectFolder/index.tsx @@ -12,10 +12,11 @@ import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; +import Module from "@Front/Config/Module"; export default function SelectFolder() { - const [folders, setFolders] = useState([]); const router = useRouter(); + const [folders, setFolders] = useState([]); useEffect(() => { const jwt = JwtService.getInstance().decodeCustomerJwt(); @@ -48,7 +49,11 @@ export default function SelectFolder() { const handleSelectBlock = useCallback( (folder: IBlock) => { - router.push("/client-dashboard/" + folder.id); + router.push( + Module.getInstance() + .get() + .modules.pages.ClientDashboard.props.path.replace("[folderUid]", folder.id ?? ""), + ); }, [router], ); diff --git a/src/front/Config/Module/development.json b/src/front/Config/Module/development.json index 09587298..b3d4b6d1 100644 --- a/src/front/Config/Module/development.json +++ b/src/front/Config/Module/development.json @@ -31,6 +31,13 @@ "labelKey": "customer_login" } }, + "ClientDashboard": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]", + "labelKey": "client-dashboard" + } + }, "Folder": { "enabled": true, "props": { diff --git a/src/front/Config/Module/preprod.json b/src/front/Config/Module/preprod.json index 09587298..b3d4b6d1 100644 --- a/src/front/Config/Module/preprod.json +++ b/src/front/Config/Module/preprod.json @@ -31,6 +31,13 @@ "labelKey": "customer_login" } }, + "ClientDashboard": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]", + "labelKey": "client-dashboard" + } + }, "Folder": { "enabled": true, "props": { diff --git a/src/front/Config/Module/production.json b/src/front/Config/Module/production.json index 09587298..b3d4b6d1 100644 --- a/src/front/Config/Module/production.json +++ b/src/front/Config/Module/production.json @@ -31,6 +31,13 @@ "labelKey": "customer_login" } }, + "ClientDashboard": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]", + "labelKey": "client-dashboard" + } + }, "Folder": { "enabled": true, "props": { diff --git a/src/front/Config/Module/staging.json b/src/front/Config/Module/staging.json index 09587298..b3d4b6d1 100644 --- a/src/front/Config/Module/staging.json +++ b/src/front/Config/Module/staging.json @@ -31,6 +31,13 @@ "labelKey": "customer_login" } }, + "ClientDashboard": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]", + "labelKey": "client-dashboard" + } + }, "Folder": { "enabled": true, "props": { diff --git a/src/front/Hooks/useUser.ts b/src/front/Hooks/useUser.ts new file mode 100644 index 00000000..86a583a1 --- /dev/null +++ b/src/front/Hooks/useUser.ts @@ -0,0 +1,26 @@ +import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users"; +import JwtService from "@Front/Services/JwtService/JwtService"; +import User from "le-coffre-resources/dist/Notary"; +import { useEffect, useState } from "react"; + +export default function useUser() { + const [user, setUser] = useState(); + + useEffect(() => { + const decodedJwt = JwtService.getInstance().decodeJwt(); + if (!decodedJwt) return; + Users.getInstance() + .getByUid(decodedJwt.userId, { + q: { + contact: true, + }, + }) + .then((user) => { + setUser(user); + }); + }, []); + + return { + user, + }; +} From 8243e8727154855b8f320e08e07bfd03248baaf1 Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 20 Aug 2024 15:35:35 +0200 Subject: [PATCH 15/63] :sparkles integration page received documents --- .../Components/Elements/BackArrow/index.tsx | 3 +- .../ReceivedDocuments/classes.module.scss | 23 ++++++++ .../ReceivedDocuments/index.tsx | 59 +++++++++++++++++++ .../Layouts/ClientDashboard/index.tsx | 16 ++++- src/front/Config/Module/development.json | 9 +++ src/front/Config/Module/preprod.json | 9 +++ src/front/Config/Module/production.json | 9 +++ src/front/Config/Module/staging.json | 9 +++ .../[folderUid]/received-documents/index.tsx | 5 ++ 9 files changed, 138 insertions(+), 4 deletions(-) create mode 100644 src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/classes.module.scss create mode 100644 src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx create mode 100644 src/pages/client-dashboard/[folderUid]/received-documents/index.tsx diff --git a/src/front/Components/Elements/BackArrow/index.tsx b/src/front/Components/Elements/BackArrow/index.tsx index 8421b1b5..b4714259 100644 --- a/src/front/Components/Elements/BackArrow/index.tsx +++ b/src/front/Components/Elements/BackArrow/index.tsx @@ -5,6 +5,7 @@ import React from "react"; type IProps = { url?: string; + text?: string; }; type IPropsClass = IProps & { @@ -26,7 +27,7 @@ class BackArrowClass extends React.Component { styletype={EButtonstyletype.TEXT} size={EButtonSize.SM} onClick={this.handleClick}> - Retour + {this.props.text ?? "Retour"} ); } diff --git a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/classes.module.scss b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/classes.module.scss new file mode 100644 index 00000000..62f8849f --- /dev/null +++ b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/classes.module.scss @@ -0,0 +1,23 @@ +@import "@Themes/constants.scss"; + +.root { + padding: var(--spacing-3) var(--spacing-15); + max-width: 1156px; + + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-xl, 32px); + + .table{ + width: 100%; + } + + @media screen and (max-width: $screen-m) { + padding: var(--spacing-3); + } + + @media screen and (max-width: $screen-s) { + padding: var(--spacing-2); + } +} diff --git a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx new file mode 100644 index 00000000..bbd62240 --- /dev/null +++ b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx @@ -0,0 +1,59 @@ +import React from "react"; + +import classes from "./classes.module.scss"; +import { useRouter } from "next/router"; + +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; +import Module from "@Front/Config/Module"; +import BackArrow from "@Front/Components/Elements/BackArrow"; +import { ArrowDownTrayIcon } from "@heroicons/react/24/outline"; +import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import { IHead } from "@Front/Components/DesignSystem/Table/MuiTable"; +import Table from "@Front/Components/DesignSystem/Table"; + +type IProps = {}; + +const header: readonly IHead[] = [ + { + key: "name", + title: "Nom", + }, + { + key: "sentAt", + title: "Envoyé le", + }, + { + key: "actions", + title: "Action", + }, +]; + +export default function ReceivedDocuments(props: IProps) { + const router = useRouter(); + let { folderUid } = router.query; + + return ( + +
+ + + Un document vous a été envoyé + +
+ + + + ); +} diff --git a/src/front/Components/Layouts/ClientDashboard/index.tsx b/src/front/Components/Layouts/ClientDashboard/index.tsx index 84e097c5..d1fe593d 100644 --- a/src/front/Components/Layouts/ClientDashboard/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/index.tsx @@ -19,6 +19,8 @@ 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 DepositDocumentComponent from "./DepositDocumentComponent"; +import Link from "next/link"; +import Module from "@Front/Config/Module"; type IProps = {}; @@ -169,9 +171,17 @@ export default function ClientDashboard(props: IProps) { Télécharger le RIB )} - + + +
diff --git a/src/front/Config/Module/development.json b/src/front/Config/Module/development.json index b3d4b6d1..89703255 100644 --- a/src/front/Config/Module/development.json +++ b/src/front/Config/Module/development.json @@ -36,6 +36,15 @@ "props": { "path": "/client-dashboard/[folderUid]", "labelKey": "client-dashboard" + }, + "pages": { + "ReceiveDocuments": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]/received-documents", + "labelKey": "received_documents" + } + } } }, "Folder": { diff --git a/src/front/Config/Module/preprod.json b/src/front/Config/Module/preprod.json index b3d4b6d1..89703255 100644 --- a/src/front/Config/Module/preprod.json +++ b/src/front/Config/Module/preprod.json @@ -36,6 +36,15 @@ "props": { "path": "/client-dashboard/[folderUid]", "labelKey": "client-dashboard" + }, + "pages": { + "ReceiveDocuments": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]/received-documents", + "labelKey": "received_documents" + } + } } }, "Folder": { diff --git a/src/front/Config/Module/production.json b/src/front/Config/Module/production.json index b3d4b6d1..89703255 100644 --- a/src/front/Config/Module/production.json +++ b/src/front/Config/Module/production.json @@ -36,6 +36,15 @@ "props": { "path": "/client-dashboard/[folderUid]", "labelKey": "client-dashboard" + }, + "pages": { + "ReceiveDocuments": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]/received-documents", + "labelKey": "received_documents" + } + } } }, "Folder": { diff --git a/src/front/Config/Module/staging.json b/src/front/Config/Module/staging.json index b3d4b6d1..89703255 100644 --- a/src/front/Config/Module/staging.json +++ b/src/front/Config/Module/staging.json @@ -36,6 +36,15 @@ "props": { "path": "/client-dashboard/[folderUid]", "labelKey": "client-dashboard" + }, + "pages": { + "ReceiveDocuments": { + "enabled": true, + "props": { + "path": "/client-dashboard/[folderUid]/received-documents", + "labelKey": "received_documents" + } + } } }, "Folder": { diff --git a/src/pages/client-dashboard/[folderUid]/received-documents/index.tsx b/src/pages/client-dashboard/[folderUid]/received-documents/index.tsx new file mode 100644 index 00000000..d4856fbc --- /dev/null +++ b/src/pages/client-dashboard/[folderUid]/received-documents/index.tsx @@ -0,0 +1,5 @@ +import ReceivedDocuments from "@Front/Components/Layouts/ClientDashboard/ReceivedDocuments"; + +export default function Route() { + return ; +} From c66108164cc4d575303aa51020e95faf276b1126 Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 20 Aug 2024 15:56:06 +0200 Subject: [PATCH 16/63] :sparkles: Email Reminder Button --- .../EmailReminder/classes.module.scss | 19 +++++++++++++ .../ClientView/EmailReminder/index.tsx | 27 +++++++++++++++++++ .../FolderInformation/ClientView/index.tsx | 4 ++- 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/classes.module.scss create mode 100644 src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/classes.module.scss new file mode 100644 index 00000000..d427c5b7 --- /dev/null +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/classes.module.scss @@ -0,0 +1,19 @@ +@import "@Themes/constants.scss"; + +.root { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 32px); + + .reminder-info { + display: flex; + gap: 8px; + align-items: center; + + .info { + display: flex; + flex-direction: column; + gap: 4px; + } + } +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx new file mode 100644 index 00000000..1d0c1808 --- /dev/null +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -0,0 +1,27 @@ +import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import IconButton, { EIconButtonVariant } from "@Front/Components/DesignSystem/IconButton"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import { ClockIcon, EnvelopeIcon } from "@heroicons/react/24/outline"; + +import classes from "./classes.module.scss"; + +export default function EmailReminder() { + return ( +
+ +
+ } variant={EIconButtonVariant.NEUTRAL} /> +
+ + Dernière relance: todo + + + Nombre de relance: todo + +
+
+
+ ); +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index 3a02bd33..e1c92d9f 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -8,13 +8,14 @@ import { AnchorStatus } from ".."; import classes from "./classes.module.scss"; import ClientBox from "./ClientBox"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import { DocumentIcon, UserPlusIcon } from "@heroicons/react/24/outline"; +import { DocumentIcon, EnvelopeIcon, UserPlusIcon } from "@heroicons/react/24/outline"; import Module from "@Front/Config/Module"; import Link from "next/link"; import NoDocument from "./NoDocument"; import DocumentTables from "./DocumentTables"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; +import EmailReminder from "./EmailReminder"; type IProps = { folder: OfficeFolder; @@ -114,6 +115,7 @@ export default function ClientView(props: IProps) { )} +
{doesCustomerHaveDocument ? ( From d40c075289e271e36e2939eeec3618c9a88ba464 Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 21 Aug 2024 12:03:41 +0200 Subject: [PATCH 17/63] :sparkles: reminder modal + historique des relances des documents --- .../classes.module.scss | 23 ++++++++ .../Folder/DocumentsReminderHistory/index.tsx | 53 +++++++++++++++++++ .../ClientView/ClientBox/index.tsx | 5 +- .../ReminderModal/classes.module.scss | 5 ++ .../EmailReminder/ReminderModal/index.tsx | 37 +++++++++++++ .../ClientView/EmailReminder/index.tsx | 34 ++++++++++-- .../FolderInformation/ClientView/index.tsx | 4 +- src/front/Config/Module/development.json | 7 +++ src/front/Config/Module/preprod.json | 7 +++ src/front/Config/Module/production.json | 7 +++ src/front/Config/Module/staging.json | 7 +++ .../documents-reminder-history/index.tsx | 5 ++ 12 files changed, 186 insertions(+), 8 deletions(-) create mode 100644 src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss create mode 100644 src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx create mode 100644 src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss create mode 100644 src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx create mode 100644 src/pages/folders/[folderUid]/documents-reminder-history/index.tsx diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss new file mode 100644 index 00000000..62f8849f --- /dev/null +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss @@ -0,0 +1,23 @@ +@import "@Themes/constants.scss"; + +.root { + padding: var(--spacing-3) var(--spacing-15); + max-width: 1156px; + + display: flex; + flex-direction: column; + align-items: flex-start; + gap: var(--spacing-xl, 32px); + + .table{ + width: 100%; + } + + @media screen and (max-width: $screen-m) { + padding: var(--spacing-3); + } + + @media screen and (max-width: $screen-s) { + padding: var(--spacing-2); + } +} diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx new file mode 100644 index 00000000..f946f00c --- /dev/null +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx @@ -0,0 +1,53 @@ +import Table from "@Front/Components/DesignSystem/Table"; +import { IHead } from "@Front/Components/DesignSystem/Table/MuiTable"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import BackArrow from "@Front/Components/Elements/BackArrow"; +import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; +import Module from "@Front/Config/Module"; +import { useRouter } from "next/router"; +import React from "react"; + +import classes from "./classes.module.scss"; + +type IProps = {}; + +const header: readonly IHead[] = [ + { + key: "remindedAt", + title: "Date de relance", + }, + { + key: "customer", + title: "Client", + }, + { + key: "document_type", + title: "Type de document", + }, + { + key: "statut", + title: "Satut", + }, +]; + +export default function DocumentsReminderHistory(props: IProps) { + const router = useRouter(); + let { folderUid } = router.query; + + return ( + +
+ + + Historique des relances de documents + +
+ + + ); +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/index.tsx index 882aaaaf..44c86b1c 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/index.tsx @@ -6,16 +6,15 @@ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Ty import Module from "@Front/Config/Module"; import useOpenable from "@Front/Hooks/useOpenable"; import { PencilSquareIcon, TrashIcon, UsersIcon } from "@heroicons/react/24/outline"; -import { Note } from "le-coffre-resources/dist/Customer"; +import Customer, { Note } from "le-coffre-resources/dist/Customer"; import { useCallback } from "react"; -import { ICustomer } from ".."; import { AnchorStatus } from "../.."; import classes from "./classes.module.scss"; import DeleteCustomerModal from "./DeleteCustomerModal"; type IProps = { - customer: ICustomer; + customer: Customer; anchorStatus: AnchorStatus; folderUid: string | undefined; customerNote: Note | null; diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss new file mode 100644 index 00000000..97b000ca --- /dev/null +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss @@ -0,0 +1,5 @@ +@import "@Themes/constants.scss"; + +.root { + +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx new file mode 100644 index 00000000..a932de41 --- /dev/null +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx @@ -0,0 +1,37 @@ +import Modal from "@Front/Components/DesignSystem/Modal"; +import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; +import Customer from "le-coffre-resources/dist/Customer"; +import React, { useCallback } from "react"; + +import classes from "./classes.module.scss"; + +type IProps = { + isOpen: boolean; + onClose?: () => void; + onRemindSuccess: () => void; + customer: Customer; +}; + +export default function ReminderModal(props: IProps) { + const { isOpen, onClose, onRemindSuccess, customer } = props; + + const onRemind = useCallback(() => { + onRemindSuccess(); + onClose?.(); + }, [onClose, onRemindSuccess]); + + return ( + +
+ + Sélectionnez le(s) document(s) pour lequel vous souhaitez relancer le client. + +
+
+ ); +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index 1d0c1808..f3812518 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -1,18 +1,45 @@ import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import IconButton, { EIconButtonVariant } from "@Front/Components/DesignSystem/IconButton"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import useOpenable from "@Front/Hooks/useOpenable"; import { ClockIcon, EnvelopeIcon } from "@heroicons/react/24/outline"; +import Customer from "le-coffre-resources/dist/Customer"; import classes from "./classes.module.scss"; +import ReminderModal from "./ReminderModal"; +import { useRouter } from "next/router"; +import Module from "@Front/Config/Module"; +import Link from "next/link"; + +type IProps = { + customer: Customer; +}; + +export default function EmailReminder(props: IProps) { + const { customer } = props; + const { isOpen, open, close } = useOpenable(); + const router = useRouter(); + + let { folderUid } = router.query; -export default function EmailReminder() { return (
-
- } variant={EIconButtonVariant.NEUTRAL} /> + + } variant={EIconButtonVariant.NEUTRAL} /> +
Dernière relance: todo @@ -22,6 +49,7 @@ export default function EmailReminder() {
+ {}} onClose={close} customer={customer} />
); } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index e1c92d9f..444d2e83 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -8,7 +8,7 @@ import { AnchorStatus } from ".."; import classes from "./classes.module.scss"; import ClientBox from "./ClientBox"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import { DocumentIcon, EnvelopeIcon, UserPlusIcon } from "@heroicons/react/24/outline"; +import { DocumentIcon, UserPlusIcon } from "@heroicons/react/24/outline"; import Module from "@Front/Config/Module"; import Link from "next/link"; import NoDocument from "./NoDocument"; @@ -115,7 +115,7 @@ export default function ClientView(props: IProps) { )} - + {doesCustomerHaveDocument ? ( diff --git a/src/front/Config/Module/development.json b/src/front/Config/Module/development.json index 89703255..e6628aad 100644 --- a/src/front/Config/Module/development.json +++ b/src/front/Config/Module/development.json @@ -61,6 +61,13 @@ "labelKey": "folder_information" } }, + "DocumentsReminderHistory": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/documents-reminder-history", + "labelKey": "documents_reminder_history" + } + }, "CreateFolder": { "enabled": true, "props": { diff --git a/src/front/Config/Module/preprod.json b/src/front/Config/Module/preprod.json index 89703255..e6628aad 100644 --- a/src/front/Config/Module/preprod.json +++ b/src/front/Config/Module/preprod.json @@ -61,6 +61,13 @@ "labelKey": "folder_information" } }, + "DocumentsReminderHistory": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/documents-reminder-history", + "labelKey": "documents_reminder_history" + } + }, "CreateFolder": { "enabled": true, "props": { diff --git a/src/front/Config/Module/production.json b/src/front/Config/Module/production.json index 89703255..e6628aad 100644 --- a/src/front/Config/Module/production.json +++ b/src/front/Config/Module/production.json @@ -61,6 +61,13 @@ "labelKey": "folder_information" } }, + "DocumentsReminderHistory": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/documents-reminder-history", + "labelKey": "documents_reminder_history" + } + }, "CreateFolder": { "enabled": true, "props": { diff --git a/src/front/Config/Module/staging.json b/src/front/Config/Module/staging.json index 89703255..e6628aad 100644 --- a/src/front/Config/Module/staging.json +++ b/src/front/Config/Module/staging.json @@ -61,6 +61,13 @@ "labelKey": "folder_information" } }, + "DocumentsReminderHistory": { + "enabled": true, + "props": { + "path": "/folders/[folderUid]/documents-reminder-history", + "labelKey": "documents_reminder_history" + } + }, "CreateFolder": { "enabled": true, "props": { diff --git a/src/pages/folders/[folderUid]/documents-reminder-history/index.tsx b/src/pages/folders/[folderUid]/documents-reminder-history/index.tsx new file mode 100644 index 00000000..5672d61d --- /dev/null +++ b/src/pages/folders/[folderUid]/documents-reminder-history/index.tsx @@ -0,0 +1,5 @@ +import DocumentsReminderHistory from "@Front/Components/Layouts/Folder/DocumentsReminderHistory"; + +export default function Route() { + return ; +} From 84e820b90aede172a7dd34c6d911e028d5b0f52a Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 22 Aug 2024 15:33:38 +0200 Subject: [PATCH 18/63] :sparkles: responsive no folder page --- .../DesignSystem/Separator/index.tsx | 5 ++-- .../classes.module.scss | 4 +++ .../Layouts/Folder/classes.module.scss | 26 ++++++++++++++----- src/front/Components/Layouts/Folder/index.tsx | 11 ++++++-- 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/src/front/Components/DesignSystem/Separator/index.tsx b/src/front/Components/DesignSystem/Separator/index.tsx index bb9c4389..c3d2b26b 100644 --- a/src/front/Components/DesignSystem/Separator/index.tsx +++ b/src/front/Components/DesignSystem/Separator/index.tsx @@ -20,14 +20,15 @@ type IProps = { direction?: ESeperatorDirection; size?: number; thickness?: number; + className?: string; }; export default function Separator(props: IProps) { - const { color = ESeperatorColor.DEFAULT, direction = ESeperatorDirection.HORIZONTAL, size, thickness = 1 } = props; + const { color = ESeperatorColor.DEFAULT, direction = ESeperatorDirection.HORIZONTAL, size, thickness = 1, className } = props; return (
); diff --git a/src/front/Components/LayoutTemplates/DefaultDashboardWithList/classes.module.scss b/src/front/Components/LayoutTemplates/DefaultDashboardWithList/classes.module.scss index da2293c5..0d189a58 100644 --- a/src/front/Components/LayoutTemplates/DefaultDashboardWithList/classes.module.scss +++ b/src/front/Components/LayoutTemplates/DefaultDashboardWithList/classes.module.scss @@ -32,6 +32,10 @@ .right-side { min-width: 100%; + + .right-side-content { + overflow-y: hidden; + } } } } diff --git a/src/front/Components/Layouts/Folder/classes.module.scss b/src/front/Components/Layouts/Folder/classes.module.scss index 850483a8..c716d594 100644 --- a/src/front/Components/Layouts/Folder/classes.module.scss +++ b/src/front/Components/Layouts/Folder/classes.module.scss @@ -3,7 +3,7 @@ .root { .content { display: flex; - width: 648px; + max-width: 648px; flex-direction: column; justify-content: center; gap: var(--spacing-2xl, 40px); @@ -14,8 +14,8 @@ gap: var(--spacing-md, 16px); align-self: stretch; - .logo{ - fill: "red" + .logo { + fill: "red"; } } @@ -45,11 +45,23 @@ gap: var(--spacing-sm, 8px); } - .separator { - background-color: var(--separator-stroke-light); - width: 1px; - align-self: stretch; + @media screen and (max-width: 600px) { + flex-direction: column; } } } + + .mobile { + display: none; + @media screen and (max-width: 600px) { + display: flex; + } + } + + .desktop { + display: flex; + @media screen and (max-width: 600px) { + display: none; + } + } } diff --git a/src/front/Components/Layouts/Folder/index.tsx b/src/front/Components/Layouts/Folder/index.tsx index 099f05db..b5cf37a3 100644 --- a/src/front/Components/Layouts/Folder/index.tsx +++ b/src/front/Components/Layouts/Folder/index.tsx @@ -13,6 +13,7 @@ import { useEffect, useState } from "react"; import classes from "./classes.module.scss"; import useUser from "@Front/Hooks/useUser"; +import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator"; export default function Folder() { const [_isArchivedModalOpen, _setIsArchivedModalOpen] = useState(true); @@ -37,7 +38,6 @@ export default function Folder() { ); }); }, [router]); - return (
@@ -87,7 +87,14 @@ export default function Folder() { Accéder aux guides
-
+ + +
Vous avez des questions ? From 79f965e5021bc32aea968b61cf3691530cbe9287 Mon Sep 17 00:00:00 2001 From: Max S Date: Sun, 25 Aug 2024 16:14:33 +0200 Subject: [PATCH 19/63] :sparkles: responsive information folder section --- .../DesignSystem/CircleProgress/index.tsx | 8 +- .../InformationSection/classes.module.scss | 98 +++++++++++++++++-- .../InformationSection/index.tsx | 79 +++++++++++++-- 3 files changed, 166 insertions(+), 19 deletions(-) diff --git a/src/front/Components/DesignSystem/CircleProgress/index.tsx b/src/front/Components/DesignSystem/CircleProgress/index.tsx index 4b66e985..ee6f9208 100644 --- a/src/front/Components/DesignSystem/CircleProgress/index.tsx +++ b/src/front/Components/DesignSystem/CircleProgress/index.tsx @@ -1,13 +1,15 @@ import React, { useCallback, useEffect, useRef, useState } from "react"; import Typography, { ETypo, ETypoColor } from "../Typography"; import classes from "./classes.module.scss"; +import classNames from "classnames"; type IProps = { percentage: number; + className?: string; }; export default function CircleProgress(props: IProps) { - const { percentage } = props; + const { percentage, className } = props; const [animatedProgress, setAnimatedProgress] = useState(0); const requestRef = useRef(); @@ -41,7 +43,7 @@ export default function CircleProgress(props: IProps) { const offset = circumference - (animatedProgress / 100) * circumference; return ( -
+
); -} \ No newline at end of file +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/classes.module.scss index dd4839c0..bf486242 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/classes.module.scss @@ -1,18 +1,41 @@ @import "@Themes/constants.scss"; +$mobile-breakpoint: 600px; + .root { display: flex; - gap: var(--spacing-lg, 40px); + gap: var(--spacing-lg, 24px); + + @media screen and (max-width: $mobile-breakpoint) { + flex-direction: column; + } + .info-box1 { display: flex; width: 100%; flex-direction: column; gap: var(--spacing-sm, 8px); + .folder-number-container { + display: flex; + justify-content: space-between; + align-items: center; + gap: var(--spacing-lg, 24px); + + } + .open-date { display: flex; gap: var(--spacing-sm, 8px); } + + @media screen and (max-width: $screen-s) { + width: 54vw; + } + + @media screen and (max-width: $mobile-breakpoint) { + width: 100%; + } } .info-box2 { @@ -22,22 +45,74 @@ width: 100%; max-width: 400px; + @media screen and (max-width: $mobile-breakpoint) { + max-width: 100%; + } + .progress-container { - width: 100%; display: flex; justify-content: space-between; align-items: center; - .icon-container { - display: flex; - gap: var(--spacing-md, 8px); + @media screen and (max-width: $screen-s) { + flex-direction: column-reverse; + gap: var(--spacing-lg, 24px); + } + + @media screen and (max-width: $mobile-breakpoint) { + align-items: flex-start; + } + } + } + + .icon-container { + display: flex; + gap: var(--spacing-md, 8px); + + &.desktop { + display: flex; + @media screen and (max-width: $mobile-breakpoint) { + display: none; } } - .description-container { - .text { - max-height: 60px; - overflow-y: auto; + &.mobile { + display: none; + @media screen and (max-width: $mobile-breakpoint) { + display: flex; + } + } + } + + .description-container { + .text { + max-height: 60px; + overflow-y: auto; + white-space: normal; + word-wrap: break-word; + } + + &.desktop { + @media screen and (max-width: $screen-s) { + display: none; + } + } + + &.ipad { + display: none; + @media screen and (max-width: $screen-s) { + display: block; + } + + @media screen and (max-width: $mobile-breakpoint) { + display: none; + } + } + + &.mobile { + display: none; + @media screen and (max-width: $mobile-breakpoint) { + display: block; } } } @@ -46,5 +121,10 @@ background-color: var(--separator-stroke-light); width: 1px; align-self: stretch; + + @media screen and (max-width: $mobile-breakpoint) { + height: 1px; + width: 100%; + } } } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx index 7e2e3067..eef289b6 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/InformationSection/index.tsx @@ -6,12 +6,13 @@ import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Module from "@Front/Config/Module"; import { ArchiveBoxIcon, EllipsisHorizontalIcon, PaperAirplaneIcon, PencilSquareIcon, UsersIcon } from "@heroicons/react/24/outline"; +import classNames from "classnames"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; +import Link from "next/link"; import { useMemo } from "react"; import { AnchorStatus } from ".."; import classes from "./classes.module.scss"; -import Link from "next/link"; type IProps = { folder: OfficeFolder | null; @@ -24,7 +25,7 @@ type IProps = { export default function InformationSection(props: IProps) { const { folder, progress, onArchive, anchorStatus, isArchived } = props; - const menuItems = useMemo(() => { + const menuItemsDekstop = useMemo(() => { let elements: IItem[] = []; // Creating the three elements and adding them conditionnally @@ -48,17 +49,71 @@ export default function InformationSection(props: IProps) { // If the folder is not anchored, we can modify the collaborators and the informations if (anchorStatus === AnchorStatus.NOT_ANCHORED) { elements.push(modifyCollaboratorsElement); - elements.push(modifyInformationsElement); } return elements; }, [anchorStatus, folder?.uid]); + + const menuItemsMobile = useMemo(() => { + let elements: IItem[] = []; + + // Creating the three elements and adding them conditionnally + const modifyCollaboratorsElement = { + icon: , + text: "Modifier les collaborateurs", + link: Module.getInstance() + .get() + .modules.pages.Folder.pages.EditCollaborators.props.path.replace("[folderUid]", folder?.uid ?? ""), + hasSeparator: true, + }; + const modifyInformationsElement = { + icon: , + text: "Modifier les informations du dossier", + link: Module.getInstance() + .get() + .modules.pages.Folder.pages.EditInformations.props.path.replace("[folderUid]", folder?.uid ?? ""), + hasSeparator: true, + }; + + // If the folder is not anchored, we can modify the collaborators and the informations + if (anchorStatus === AnchorStatus.NOT_ANCHORED) { + elements.push(modifyCollaboratorsElement); + elements.push(modifyInformationsElement); + } + + elements.push({ + icon: , + text: "Envoyer des documents", + link: Module.getInstance() + .get() + .modules.pages.Folder.pages.SendDocuments.props.path.replace("[folderUid]", folder?.uid ?? ""), + hasSeparator: !isArchived, + }); + + if (!isArchived) { + elements.push({ + icon: , + text: "Archiver le dossier", + onClick: onArchive, + hasSeparator: false, + }); + } + + return elements; + }, [anchorStatus, folder?.uid, isArchived, onArchive]); return (
- {folder?.folder_number} +
+ {folder?.folder_number} +
+ + } variant={EIconButtonVariant.NEUTRAL} /> + +
+
{folder?.name}
@@ -69,13 +124,22 @@ export default function InformationSection(props: IProps) { {folder?.created_at ? new Date(folder.created_at).toLocaleDateString() : ""}
+ +
+ + Note du dossier + + + {folder?.description} + +
-
+
} variant={EIconButtonVariant.NEUTRAL} /> - + + } variant={EIconButtonVariant.NEUTRAL} /> {!isArchived && } variant={EIconButtonVariant.ERROR} />}
-
+
Note du dossier From 334313e71dd50b561037267471accfe3b628b51e Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 26 Aug 2024 11:45:01 +0200 Subject: [PATCH 20/63] :sparkles: responsive folder client view --- .../ClientView/DocumentTables/index.tsx | 31 ++++++++++--- .../ClientView/classes.module.scss | 23 +++++++++- .../FolderInformation/ClientView/index.tsx | 44 ++++++++++--------- 3 files changed, 70 insertions(+), 28 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index de516731..103c3270 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -16,6 +16,7 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import DeleteAskedDocumentModal from "./DeleteAskedDocumentModal"; import DeleteSentDocumentModal from "./DeleteSentDocumentModal"; +import { useMediaQuery } from "@mui/material"; type IProps = { documents: Document[]; @@ -34,6 +35,8 @@ export default function DocumentTables(props: IProps) { const [documents, setDocuments] = useState(documentsProps); const [documentUid, setDocumentUid] = useState(null); + const isMobile = useMediaQuery("(max-width:524px)"); + const deleteAskedDocumentModal = useOpenable(); const deleteSentDocumentModal = useOpenable(); @@ -232,11 +235,11 @@ export default function DocumentTables(props: IProps) {
- {askedDocuments.length > 0 &&
} - {toValidateDocuments.length > 0 &&
} - {validatedDocuments.length > 0 &&
} - {refusedDocuments.length > 0 &&
} - {sentDocuments.length > 0 &&
} + {askedDocuments.length > 0 &&
} + {toValidateDocuments.length > 0 &&
} + {validatedDocuments.length > 0 &&
} + {refusedDocuments.length > 0 &&
} + {sentDocuments.length > 0 &&
} {documentUid && ( <>
-
+
value.customer?.uid === customer.uid) ?? null} /> - {anchorStatus === AnchorStatus.NOT_ANCHORED && ( - - - - )} - +
+ {anchorStatus === AnchorStatus.NOT_ANCHORED && ( + + + + )} + +
+ {doesCustomerHaveDocument ? ( ) : ( From a36864b80bf48f9b15cac5c715655af1ae67a144 Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 26 Aug 2024 12:11:07 +0200 Subject: [PATCH 21/63] :sparkles: responsive alert --- .../DesignSystem/Alert/classes.module.scss | 72 +++++++++---------- .../Components/DesignSystem/Alert/index.tsx | 10 ++- 2 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/front/Components/DesignSystem/Alert/classes.module.scss b/src/front/Components/DesignSystem/Alert/classes.module.scss index e800be15..77dd499e 100644 --- a/src/front/Components/DesignSystem/Alert/classes.module.scss +++ b/src/front/Components/DesignSystem/Alert/classes.module.scss @@ -11,6 +11,36 @@ border: 1px solid var(--alerts-info-border); background: var(--alerts-info-background); + @media screen and (max-width: 680px) { + flex-direction: column; + } + + .top { + align-self: stretch; + display: flex; + justify-content: space-between; + align-items: center; + } + + .close-button { + display: block; + &.desktop { + display: block; + + @media screen and (max-width: 680px) { + display: none; + } + } + + &.mobile { + display: none; + + @media screen and (max-width: 680px) { + display: block; + } + } + } + .content { display: flex; flex-direction: column; @@ -25,64 +55,34 @@ .button-container { display: flex; gap: var(--spacing-md, 16px); - } - } - .icon { - display: flex; - padding: var(--spacing-1, 8px); - align-items: center; - align-self: flex-start; - - border-radius: var(--alerts-badge-radius, 360px); - border: 1px solid var(--alerts-badge-border, rgba(0, 0, 0, 0)); - background: var(--alerts-badge-background, #fff); - box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.1); - - svg { - width: 24px; - height: 24px; - min-width: 24px; - min-height: 24px; - - stroke: var(--alerts-badge-contrast-info); + @media screen and (max-width: 680px) { + flex-direction: column; + button { + width: 100%; + } + } } } &.error { border-color: var(--alerts-error-border); background: var(--alerts-error-background); - - .icon svg { - stroke: var(--alerts-badge-contrast-error); - } } &.warning { border-color: var(--alerts-warning-border); background: var(--alerts-warning-background); - - .icon svg { - stroke: var(--alerts-badge-contrast-warning); - } } &.success { border-color: var(--alerts-success-border); background: var(--alerts-success-background); - - .icon svg { - stroke: var(--alerts-badge-contrast-success); - } } &.neutral { border-color: var(--alerts-neutral-border); background: var(--alerts-neutral-background); - - .icon svg { - stroke: var(--alerts-badge-contrast-neutral); - } } &.fullwidth { diff --git a/src/front/Components/DesignSystem/Alert/index.tsx b/src/front/Components/DesignSystem/Alert/index.tsx index ac3c8298..c3568abb 100644 --- a/src/front/Components/DesignSystem/Alert/index.tsx +++ b/src/front/Components/DesignSystem/Alert/index.tsx @@ -52,7 +52,13 @@ export default function Alert(props: IProps) { return (
- } color={variantColorMap[variant]} /> +
+ } color={variantColorMap[variant]} /> + {closeButton && ( + } /> + )} +
+
@@ -84,7 +90,7 @@ export default function Alert(props: IProps) { )}
- {closeButton && } />} + {closeButton && } />}
); } From 06e99a53fa90cdef6ffbcb64d8f7fb7fab934f95 Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 26 Aug 2024 15:45:27 +0200 Subject: [PATCH 22/63] :sparkles page 404 --- .../Elements/HelpBox/classes.module.scss | 5 +++ .../Components/Elements/HelpBox/index.tsx | 39 ++++++++++++++++++ .../Layouts/Folder/classes.module.scss | 6 --- src/front/Components/Layouts/Folder/index.tsx | 31 +++++++------- .../Layouts/PageNotFound/classes.module.scss | 39 ++++++++++++------ .../Components/Layouts/PageNotFound/index.tsx | 40 +++++++++++++++---- 6 files changed, 116 insertions(+), 44 deletions(-) create mode 100644 src/front/Components/Elements/HelpBox/classes.module.scss create mode 100644 src/front/Components/Elements/HelpBox/index.tsx diff --git a/src/front/Components/Elements/HelpBox/classes.module.scss b/src/front/Components/Elements/HelpBox/classes.module.scss new file mode 100644 index 00000000..0c94c931 --- /dev/null +++ b/src/front/Components/Elements/HelpBox/classes.module.scss @@ -0,0 +1,5 @@ +.root { + display: flex; + flex-direction: column; + gap: var(--spacing-sm, 8px); +} diff --git a/src/front/Components/Elements/HelpBox/index.tsx b/src/front/Components/Elements/HelpBox/index.tsx new file mode 100644 index 00000000..9770f464 --- /dev/null +++ b/src/front/Components/Elements/HelpBox/index.tsx @@ -0,0 +1,39 @@ +import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import classes from "./classes.module.scss"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import Link from "next/link"; + +export type IProps = { + title: string; + description: string; + button: { text: string; link?: string; onClick?: () => void }; +}; + +export default function HelpBox(props: IProps) { + const { title, description, button } = props; + return ( +
+ + {title} + + + {description} + + {button.link ? ( + + + + ) : ( + + )} +
+ ); +} diff --git a/src/front/Components/Layouts/Folder/classes.module.scss b/src/front/Components/Layouts/Folder/classes.module.scss index c716d594..9fd3d27a 100644 --- a/src/front/Components/Layouts/Folder/classes.module.scss +++ b/src/front/Components/Layouts/Folder/classes.module.scss @@ -39,12 +39,6 @@ display: flex; gap: var(--spacing-lg, 24px); - .box { - display: flex; - flex-direction: column; - gap: var(--spacing-sm, 8px); - } - @media screen and (max-width: 600px) { flex-direction: column; } diff --git a/src/front/Components/Layouts/Folder/index.tsx b/src/front/Components/Layouts/Folder/index.tsx index b5cf37a3..5bab6189 100644 --- a/src/front/Components/Layouts/Folder/index.tsx +++ b/src/front/Components/Layouts/Folder/index.tsx @@ -1,9 +1,12 @@ import LogoIcon from "@Assets/logo_small_blue.svg"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; -import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import HelpBox from "@Front/Components/Elements/HelpBox"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import Module from "@Front/Config/Module"; +import useUser from "@Front/Hooks/useUser"; import { DocumentIcon } from "@heroicons/react/24/outline"; import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus"; import Image from "next/image"; @@ -12,8 +15,6 @@ import { useRouter } from "next/router"; import { useEffect, useState } from "react"; import classes from "./classes.module.scss"; -import useUser from "@Front/Hooks/useUser"; -import Separator, { ESeperatorColor, ESeperatorDirection } from "@Front/Components/DesignSystem/Separator"; export default function Folder() { const [_isArchivedModalOpen, _setIsArchivedModalOpen] = useState(true); @@ -80,13 +81,11 @@ export default function Folder() {
-
- Besoin d'aide ? - Consultez nos guides pour bien démarrer. - -
+ -
- Vous avez des questions ? - Notre équipe de support est là pour vous aider. - -
+
diff --git a/src/front/Components/Layouts/PageNotFound/classes.module.scss b/src/front/Components/Layouts/PageNotFound/classes.module.scss index 0921d66e..6e8af869 100644 --- a/src/front/Components/Layouts/PageNotFound/classes.module.scss +++ b/src/front/Components/Layouts/PageNotFound/classes.module.scss @@ -1,21 +1,34 @@ -@import "@Themes/constants.scss"; @import "@Themes/animation.scss"; +@import "@Themes/constants.scss"; .root { - height: 100%; - width: 100%; + margin: 80px auto; + width: 474px; + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); - .content { + @media (max-width: $screen-s) { + width: 100%; margin: auto; - - .text { - margin: 32px 0; - } - - @media(max-width: $screen-s) { - text-align: center; - } + padding: var(--spacing-md, 16px); } -} \ No newline at end of file + .content { + display: flex; + padding: var(--spacing-xl, 32px) var(--spacing-lg, 24px); + flex-direction: column; + gap: var(--spacing-lg, 24px); + + border-radius: var(--radius-rounded, 16px); + background: var(--background-primary, #fff); + box-shadow: 0px 4px 16px 0px rgba(0, 0, 0, 0.1); + + .text { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); + } + } +} diff --git a/src/front/Components/Layouts/PageNotFound/index.tsx b/src/front/Components/Layouts/PageNotFound/index.tsx index d1d53861..ba8a15a2 100644 --- a/src/front/Components/Layouts/PageNotFound/index.tsx +++ b/src/front/Components/Layouts/PageNotFound/index.tsx @@ -1,27 +1,51 @@ +import backgroundImage from "@Assets/images/background_refonte.svg"; +import LogoIcon from "@Assets/logo_small_blue.svg"; import Button from "@Front/Components/DesignSystem/Button"; -import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import HelpBox from "@Front/Components/Elements/HelpBox"; +import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import Module from "@Front/Config/Module"; +import Image from "next/image"; import Link from "next/link"; + import BasePage from "../Base"; import classes from "./classes.module.scss"; -import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; - -import backgroundImage from "@Assets/images/404-background-image.jpeg"; export default class PageNotFound extends BasePage { public override render(): JSX.Element { return (
-
- Erreur 404 - - La page que vous recherchez semble introuvable. +
+ + + Oups ! Page introuvable + + Il semble que la page que vous recherchez n'existe pas ou a été déplacée. + +
+
+
+ + Pas de panique ! Voici ce que vous pouvez faire : + + + • Retourner à la page d'accueil en cliquant sur le bouton ci-dessous. + + + • Contactez-nous si vous avez besoin d'aide. + +
+
); From 7832cb2f5c1864e42c966ad7a06bab66a493f909 Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 26 Aug 2024 17:00:25 +0200 Subject: [PATCH 23/63] :sparkles: tooltip --- .../DesignSystem/TooltipElement/index.tsx | 27 +++++++++++++++++++ .../Components/Layouts/DesignSystem/index.tsx | 13 +++++++++ 2 files changed, 40 insertions(+) create mode 100644 src/front/Components/DesignSystem/TooltipElement/index.tsx diff --git a/src/front/Components/DesignSystem/TooltipElement/index.tsx b/src/front/Components/DesignSystem/TooltipElement/index.tsx new file mode 100644 index 00000000..a7f31d77 --- /dev/null +++ b/src/front/Components/DesignSystem/TooltipElement/index.tsx @@ -0,0 +1,27 @@ +import { styled, Tooltip, tooltipClasses, TooltipProps } from "@mui/material"; + +import Typography, { ETypo, ETypoColor } from "../Typography"; + +type IProps = TooltipProps; + +export default function TooltipElement(props: IProps) { + const CustomTooltip = styled(({ className, ...props }: TooltipProps) => ( + + {props.title} + + } + classes={{ popper: className }} + /> + ))(({ theme }) => ({ + [`& .${tooltipClasses.tooltip}`]: { + backgroundColor: "var(--tooltip-background, #FFF)", + boxShadow: theme.shadows[1], + borderRadius: "var(--tooltip-radius, 4px)", + }, + })); + + return ; +} diff --git a/src/front/Components/Layouts/DesignSystem/index.tsx b/src/front/Components/Layouts/DesignSystem/index.tsx index ea214504..cfc0629a 100644 --- a/src/front/Components/Layouts/DesignSystem/index.tsx +++ b/src/front/Components/Layouts/DesignSystem/index.tsx @@ -32,6 +32,7 @@ import { ArrowLongRightIcon, EllipsisHorizontalIcon, PencilSquareIcon, + QuestionMarkCircleIcon, UsersIcon, XMarkIcon, } from "@heroicons/react/24/outline"; @@ -39,6 +40,7 @@ import { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; +import TooltipElement from "@Front/Components/DesignSystem/TooltipElement"; export default function DesignSystem() { const { isOpen, open, close } = useOpenable(); @@ -90,6 +92,17 @@ export default function DesignSystem() {
DesignSystem
+ Tooltip +
+ + + + + + Work for any children + + +
Toast
- - -
+
+ + + + +
+ + )}
From 62b51b4047acc2527d3d188e53b208be4abdde13 Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 27 Aug 2024 12:15:41 +0200 Subject: [PATCH 25/63] :hammer: email reminder --- .../DesignSystem/CheckBox/index.tsx | 4 +- .../Form/SelectFieldOld/index.tsx | 12 ++-- .../Layouts/Folder/AskDocuments/index.tsx | 8 +-- .../ReminderModal/classes.module.scss | 4 +- .../EmailReminder/ReminderModal/index.tsx | 63 ++++++++++++++++++- .../ClientView/EmailReminder/index.tsx | 29 +++++---- .../ClientView/classes.module.scss | 2 +- .../FolderInformation/ClientView/index.tsx | 6 +- .../Folder/UpdateFolderMetadata/index.tsx | 4 +- .../UpdateFolderMetadata/index.tsx | 6 +- 10 files changed, 105 insertions(+), 33 deletions(-) diff --git a/src/front/Components/DesignSystem/CheckBox/index.tsx b/src/front/Components/DesignSystem/CheckBox/index.tsx index 4ee3c5ba..baab77db 100644 --- a/src/front/Components/DesignSystem/CheckBox/index.tsx +++ b/src/front/Components/DesignSystem/CheckBox/index.tsx @@ -4,11 +4,11 @@ import Tooltip from "../ToolTip"; import Typography, { ETypo, ETypoColor } from "../Typography"; import classes from "./classes.module.scss"; import classNames from "classnames"; -import { IOptionOld } from "../Form/SelectFieldOld"; +import { IOption } from "../Form/SelectFieldOld"; type IProps = { name?: string; - option: IOptionOld; + option: IOption; toolTip?: string; onChange?: (e: React.ChangeEvent) => void; checked: boolean; diff --git a/src/front/Components/DesignSystem/Form/SelectFieldOld/index.tsx b/src/front/Components/DesignSystem/Form/SelectFieldOld/index.tsx index ba077302..55418357 100644 --- a/src/front/Components/DesignSystem/Form/SelectFieldOld/index.tsx +++ b/src/front/Components/DesignSystem/Form/SelectFieldOld/index.tsx @@ -10,9 +10,9 @@ import classes from "./classes.module.scss"; import { NextRouter, useRouter } from "next/router"; type IProps = { - selectedOption?: IOptionOld; - onChange?: (selectedOption: IOptionOld) => void; - options: IOptionOld[]; + selectedOption?: IOption; + onChange?: (selectedOption: IOption) => void; + options: IOption[]; hasBorderRightCollapsed?: boolean; placeholder?: string; className?: string; @@ -21,7 +21,7 @@ type IProps = { errors?: ValidationError; }; -export type IOptionOld = { +export type IOption = { value: unknown; label: string; icon?: ReactNode; @@ -32,7 +32,7 @@ type IState = { isOpen: boolean; listWidth: number; listHeight: number; - selectedOption: IOptionOld | null; + selectedOption: IOption | null; errors: ValidationError | null; }; @@ -187,7 +187,7 @@ class SelectFieldClass extends React.Component { }); } - private onSelect(option: IOptionOld, e: React.MouseEvent) { + private onSelect(option: IOption, e: React.MouseEvent) { if (this.props.disabled) return; this.props.onChange && this.props.onChange(option); this.setState({ diff --git a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx index 2951fde8..8a5f1dde 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx @@ -13,14 +13,14 @@ import React, { useCallback, useEffect, useState } from "react"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import classes from "./classes.module.scss"; import ParameterDocuments from "./ParameterDocuments"; -import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; +import { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import backgroundImage from "@Assets/images/background_refonte.svg"; export default function AskDocuments() { const router = useRouter(); let { folderUid, customerUid } = router.query; const [isCreateDocumentModalVisible, setIsCreateDocumentModalVisible] = useState(false); - const [documentTypes, setDocumentTypes] = useState([]); + const [documentTypes, setDocumentTypes] = useState([]); const [folder, setFolder] = useState(null); const closeModal = () => setIsCreateDocumentModalVisible(false); @@ -62,7 +62,7 @@ export default function AskDocuments() { ); const getAvailableDocuments = useCallback( - async (folder: OfficeFolder): Promise => { + async (folder: OfficeFolder): Promise => { // Getting already asked documents UIDs in an array const userDocumentTypesUids = folder .documents!.filter((document) => document.depositor!.uid! === customerUid!) @@ -81,7 +81,7 @@ export default function AskDocuments() { if (!documentTypes) return []; // Else, return an array document types formatted as IOPtions - const documentTypesOptions: IOptionOld[] = documentTypes.map((documentType) => { + const documentTypesOptions: IOption[] = documentTypes.map((documentType) => { return { label: documentType!.name!, value: documentType!.uid!, diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss index 97b000ca..44bdf503 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/classes.module.scss @@ -1,5 +1,7 @@ @import "@Themes/constants.scss"; .root { - + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx index a932de41..5eaa0ab1 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx @@ -1,7 +1,10 @@ +import CheckBox from "@Front/Components/DesignSystem/CheckBox"; +import { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import Modal from "@Front/Components/DesignSystem/Modal"; +import Separator, { ESeperatorColor } from "@Front/Components/DesignSystem/Separator"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Customer from "le-coffre-resources/dist/Customer"; -import React, { useCallback } from "react"; +import React, { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; @@ -14,11 +17,52 @@ type IProps = { export default function ReminderModal(props: IProps) { const { isOpen, onClose, onRemindSuccess, customer } = props; + const [selectedOptions, setSelectedOptions] = useState([]); + const [isAllSelected, setIsAllSelected] = useState(false); const onRemind = useCallback(() => { + console.log("selectedOptions", selectedOptions); onRemindSuccess(); onClose?.(); - }, [onClose, onRemindSuccess]); + }, [onClose, onRemindSuccess, selectedOptions]); + + const documentsOptions: IOption[] = useMemo( + () => + customer.documents?.map((document) => { + return { + label: document.document_type?.name ?? "", + value: document.document_type?.uid ?? "", + }; + }) ?? [], + [customer], + ); + + const handleOnChange = useCallback( + (e: React.ChangeEvent) => { + const { value, checked } = e.target; + const optionSelected = documentsOptions.find((option) => option.value === value); + if (checked && optionSelected) { + setSelectedOptions((prev) => [...prev, optionSelected]); + } else { + setSelectedOptions((prev) => prev.filter((option) => option.value !== value)); + } + }, + [documentsOptions], + ); + + const handleSelectAll = useCallback( + (e: React.ChangeEvent) => { + const { checked } = e.target; + if (checked) { + setSelectedOptions(documentsOptions); + setIsAllSelected(true); + } else { + setSelectedOptions([]); + setIsAllSelected(false); + } + }, + [documentsOptions], + ); return ( Sélectionnez le(s) document(s) pour lequel vous souhaitez relancer le client. + + + {documentsOptions.map((option) => ( + + ))}
); diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index f3812518..ed20215c 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -13,10 +13,12 @@ import Link from "next/link"; type IProps = { customer: Customer; + doesCustomerHaveDocument: boolean; + isAnchored: boolean; }; export default function EmailReminder(props: IProps) { - const { customer } = props; + const { customer, doesCustomerHaveDocument, isAnchored } = props; const { isOpen, open, close } = useOpenable(); const router = useRouter(); @@ -24,14 +26,17 @@ export default function EmailReminder(props: IProps) { return (
- + {!isAnchored && ( + + )}
} variant={EIconButtonVariant.NEUTRAL} />
+ {/* TODO: mettre la date de la dernière relance */} - Dernière relance: todo + Dernière relance: - + {/* TODO: mettre le nombre de relance */} - Nombre de relance: todo + Nombre de relance: -
diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss index e3002c6c..531ab7bc 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss @@ -35,7 +35,7 @@ $mobile-breakpoint: 664px; .button-container { display: flex; flex-direction: column; - gap: var(--spacing-lg, 24px); + gap: var(--spacing-md, 16px); } @media screen and (max-width: $screen-s) { diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index dc4a9361..389bc528 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -115,7 +115,11 @@ export default function ClientView(props: IProps) { )} - +
diff --git a/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx b/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx index 38299062..8a23300d 100644 --- a/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx @@ -1,7 +1,7 @@ import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Form from "@Front/Components/DesignSystem/Form"; -import Select, { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; +import Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; @@ -81,7 +81,7 @@ export default function UpdateFolderMetadata() { const deedOption = { label: selectedFolder?.deed?.deed_type?.name, value: selectedFolder?.deed?.deed_type?.uid, - } as IOptionOld; + } as IOption; const openingDate = new Date(selectedFolder?.created_at ?? ""); if (!selectedFolder?.created_at) return <>; const defaultValue = openingDate.toISOString().split("T")[0]; diff --git a/src/front/Components/Layouts/FolderArchived/UpdateFolderMetadata/index.tsx b/src/front/Components/Layouts/FolderArchived/UpdateFolderMetadata/index.tsx index fc3708bb..8a0fd2e6 100644 --- a/src/front/Components/Layouts/FolderArchived/UpdateFolderMetadata/index.tsx +++ b/src/front/Components/Layouts/FolderArchived/UpdateFolderMetadata/index.tsx @@ -1,6 +1,6 @@ import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Form from "@Front/Components/DesignSystem/Form"; -import Select, { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; +import Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; @@ -18,7 +18,7 @@ type IProps = { }; type IState = { selectedFolder: OfficeFolder | null; - selectedOption?: IOptionOld; + selectedOption?: IOption; }; class UpdateFolderMetadataClass extends BasePage { constructor(props: IProps) { @@ -74,7 +74,7 @@ class UpdateFolderMetadataClass extends BasePage { ); } - private onSelectedOption(option: IOptionOld) { + private onSelectedOption(option: IOption) { this.setState({ selectedOption: option, }); From 5f7a4c2e63b04bdbab256cdfa2c29552a33f32a8 Mon Sep 17 00:00:00 2001 From: Vins Date: Mon, 9 Sep 2024 05:45:00 +0200 Subject: [PATCH 26/63] Doing --- package-lock.json | 759 ++++++++---------- package.json | 2 +- .../LeCoffreApi/Notary/Customers/Customers.ts | 10 + .../DocumentReminders/DocumentReminders.ts | 41 + .../Notary/DocumentsNotary/DocumentsNotary.ts | 53 ++ .../DesignSystem/DragAndDrop/index.tsx | 10 +- .../EmailReminder/ReminderModal/index.tsx | 4 +- .../ClientView/EmailReminder/index.tsx | 55 +- .../Layouts/Folder/SendDocuments/index.tsx | 108 ++- tsconfig.json | 3 +- 10 files changed, 613 insertions(+), 432 deletions(-) create mode 100644 src/front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders.ts create mode 100644 src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts diff --git a/package-lock.json b/package-lock.json index cbaf67ac..090ff495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "form-data": "^4.0.0", "heroicons": "^2.1.5", "jwt-decode": "^3.1.2", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.151", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.160", "next": "^14.2.3", "prettier": "^2.8.7", "react": "18.2.0", @@ -57,11 +57,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.9.tgz", - "integrity": "sha512-G8v3jRg+z8IwY1jHFxvCNhOPYPterE4XljNgdGTYfSTtzzwjIswIzIaSPSLs3R7yFuqnqNeay5rjICfqVr+/6A==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", "dependencies": { - "@babel/types": "^7.24.9", + "@babel/types": "^7.25.6", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -70,40 +70,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", @@ -116,17 +82,6 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { "version": "7.24.8", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", @@ -158,9 +113,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz", - "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "dependencies": { + "@babel/types": "^7.25.6" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -169,9 +127,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz", - "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.6.tgz", + "integrity": "sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -180,31 +138,28 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz", - "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.8", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.8", - "@babel/types": "^7.24.8", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -213,9 +168,9 @@ } }, "node_modules/@babel/types": { - "version": "7.24.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.9.tgz", - "integrity": "sha512-xm8XrMKz0IlUdocVbYJe0Z9xEgidU7msskG8BbhnTPK/HZ2z/7FP7ykqPgrUH+C+r414mNfNWam1f2vqOjqjYQ==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", "dependencies": { "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", @@ -226,15 +181,15 @@ } }, "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", "babel-plugin-macros": "^3.1.0", "convert-source-map": "^1.5.0", "escape-string-regexp": "^4.0.0", @@ -244,47 +199,47 @@ } }, "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "stylis": "4.2.0" } }, "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" }, "node_modules/@emotion/is-prop-valid": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", - "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", "dependencies": { - "@emotion/memoize": "^0.8.1" + "@emotion/memoize": "^0.9.0" } }, "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" }, "node_modules/@emotion/react": { - "version": "11.11.4", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.4.tgz", - "integrity": "sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==", + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.3", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", "hoist-non-react-statics": "^3.3.1" }, "peerDependencies": { @@ -297,33 +252,33 @@ } }, "node_modules/@emotion/serialize": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.4.tgz", - "integrity": "sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", + "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.0", "csstype": "^3.0.2" } }, "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" }, "node_modules/@emotion/styled": { - "version": "11.11.5", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.5.tgz", - "integrity": "sha512-/ZjjnaNKvuMPxcIiUkf/9SHoG4Q196DRl1w82hQ3WCsjo1IUR8uaGWrC6a87CrYAW0Kb/pK7hk8BnLgLRi9KoQ==", + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", "dependencies": { "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/is-prop-valid": "^1.2.2", - "@emotion/serialize": "^1.1.4", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1" + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" }, "peerDependencies": { "@emotion/react": "^11.0.0-rc.0", @@ -336,27 +291,27 @@ } }, "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" }, "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", "peerDependencies": { "react": ">=16.8.0" } }, "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" }, "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", @@ -436,38 +391,26 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.4.tgz", - "integrity": "sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", + "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", "dependencies": { - "@floating-ui/utils": "^0.2.4" + "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.7.tgz", - "integrity": "sha512-wmVfPG5o2xnKDU4jx/m4w5qva9FWHcnZ8BvzEe90D/RpwsJaTAVYPEPdQ8sbr/N8zZTAHlZUTQdqg8ZUbzHmng==", + "version": "1.6.10", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", + "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.4" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz", - "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==", - "dependencies": { - "@floating-ui/dom": "^1.0.0" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "@floating-ui/utils": "^0.2.7" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.4.tgz", - "integrity": "sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA==" + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", + "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" }, "node_modules/@heroicons/react": { "version": "2.1.5", @@ -552,57 +495,26 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@mui/base": { - "version": "5.0.0-beta.40", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.40.tgz", - "integrity": "sha512-I/lGHztkCzvwlXpjD2+SNmvNQvB4227xBXhISPjEaJUXGImOQ9f3D2Yj/T3KasSI/h0MLWy74X0J6clhPmsRbQ==", - "dependencies": { - "@babel/runtime": "^7.23.9", - "@floating-ui/react-dom": "^2.0.8", - "@mui/types": "^7.2.14", - "@mui/utils": "^5.15.14", - "@popperjs/core": "^2.11.8", - "clsx": "^2.1.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui-org" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@mui/core-downloads-tracker": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.1.tgz", - "integrity": "sha512-62Jq7ACYi/55Kjkh/nVfEL3F3ytTYTsdB8MGJ9iI+eRQv+Aoem5CPUAzQihUo25qqh1VkVu9/jQn3dFbyrXHgw==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.16.7.tgz", + "integrity": "sha512-RtsCt4Geed2/v74sbihWzzRs+HsIQCfclHeORh5Ynu2fS4icIKozcSubwuG7vtzq2uW3fOR1zITSP84TNt2GoQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/mui-org" } }, "node_modules/@mui/material": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.1.tgz", - "integrity": "sha512-BGTgJRb0d/hX9tus5CEb6N/Fo8pE4tYA+s9r4/S0PCrtZ3urCLXlTH4qrAvggQbiF1cYRAbHCkVHoQ+4Pdxl+w==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.16.7.tgz", + "integrity": "sha512-cwwVQxBhK60OIOqZOVLFt55t01zmarKJiJUWbk0+8s/Ix5IaUzAShqlJchxsIQ4mSrWqgcKCCXKtIlG5H+/Jmg==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/base": "5.0.0-beta.40", - "@mui/core-downloads-tracker": "^5.16.1", - "@mui/system": "^5.16.1", + "@mui/core-downloads-tracker": "^5.16.7", + "@mui/system": "^5.16.7", "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.1", + "@mui/utils": "^5.16.6", + "@popperjs/core": "^2.11.8", "@types/react-transition-group": "^4.4.10", "clsx": "^2.1.0", "csstype": "^3.1.3", @@ -637,12 +549,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.1.tgz", - "integrity": "sha512-2EGCKnAlq9vRIFj61jNWNXlKAxXp56577OVvsts7fAqRx+G1y6F+N7Q198SBaz8jYQeGKSz8ZMXK/M3FqjdEyw==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.16.6.tgz", + "integrity": "sha512-rAk+Rh8Clg7Cd7shZhyt2HGTTE5wYKNSJ5sspf28Fqm/PZ69Er9o6KX25g03/FG2dfpg5GCwZh/xOojiTfm3hw==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/utils": "^5.16.1", + "@mui/utils": "^5.16.6", "prop-types": "^15.8.1" }, "engines": { @@ -663,9 +575,9 @@ } }, "node_modules/@mui/styled-engine": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.1.tgz", - "integrity": "sha512-JwWUBaYR8HHCFefSeos0z6JoTbu0MnjAuNHu4QoDgPxl2EE70XH38CsKay66Iy0QkNWmGTRXVU2sVFgUOPL/Dw==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.16.6.tgz", + "integrity": "sha512-zaThmS67ZmtHSWToTiHslbI8jwrmITcN93LQaR2lKArbvS7Z3iLkwRoiikNWutx9MBs8Q6okKvbZq1RQYB3v7g==", "dependencies": { "@babel/runtime": "^7.23.9", "@emotion/cache": "^11.11.0", @@ -694,15 +606,15 @@ } }, "node_modules/@mui/system": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.1.tgz", - "integrity": "sha512-VaFcClC+uhvIEzhzcNmh9FRBvrG9IPjsOokhj6U1HPZsFnLzHV7AD7dJcT6LxWoiIZj9Ej0GK+MGh/b8+BtSlQ==", + "version": "5.16.7", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.16.7.tgz", + "integrity": "sha512-Jncvs/r/d/itkxh7O7opOunTqbbSSzMTHzZkNLM+FjAOg+cYAZHrPDlYe1ZGKUYORwwb2XexlWnpZp0kZ4AHuA==", "dependencies": { "@babel/runtime": "^7.23.9", - "@mui/private-theming": "^5.16.1", - "@mui/styled-engine": "^5.16.1", + "@mui/private-theming": "^5.16.6", + "@mui/styled-engine": "^5.16.6", "@mui/types": "^7.2.15", - "@mui/utils": "^5.16.1", + "@mui/utils": "^5.16.6", "clsx": "^2.1.0", "csstype": "^3.1.3", "prop-types": "^15.8.1" @@ -733,11 +645,11 @@ } }, "node_modules/@mui/types": { - "version": "7.2.15", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.15.tgz", - "integrity": "sha512-nbo7yPhtKJkdf9kcVOF8JZHPZTmqXjJ/tI0bdWgHg5tp9AnIN4Y7f7wm9T+0SyGYJk76+GYZ8Q5XaTYAsUHN0Q==", + "version": "7.2.16", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.16.tgz", + "integrity": "sha512-qI8TV3M7ShITEEc8Ih15A2vLzZGLhD+/UPNwck/hcls2gwg7dyRjNGXcQYHKLB5Q7PuTRfrTkAoPa2VV1s67Ag==", "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { "@types/react": { @@ -746,12 +658,14 @@ } }, "node_modules/@mui/utils": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.1.tgz", - "integrity": "sha512-4UQzK46tAEYs2xZv79hRiIc3GxZScd00kGPDadNrGztAEZlmSaUY8cb9ITd2xCiTfzsx5AN6DH8aaQ8QEKJQeQ==", + "version": "5.16.6", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.16.6.tgz", + "integrity": "sha512-tWiQqlhxAt3KENNiSRL+DIn9H5xNVK6Jjf70x3PnfQPz1MPBdh7yyIcAyVBT9xiw7hP3SomRhPR7hzBMBCjqEA==", "dependencies": { "@babel/runtime": "^7.23.9", + "@mui/types": "^7.2.15", "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", "prop-types": "^15.8.1", "react-is": "^18.3.1" }, @@ -773,9 +687,9 @@ } }, "node_modules/@next/env": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", - "integrity": "sha512-/zZGkrTOsraVfYjGP8uM0p6r0BDT6xWpkjdVbcz66PJVSpwXX3yNiRycxAuDfBKGWBrZBXRuK/YVlkNgxHGwmA==" + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.8.tgz", + "integrity": "sha512-L44a+ynqkolyNBnYfF8VoCiSrjSZWgEHYKkKLGcs/a80qh7AkfVUD/MduVPgdsWZ31tgROR+yJRA0PZjSVBXWQ==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.2.4", @@ -786,9 +700,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.5.tgz", - "integrity": "sha512-/9zVxJ+K9lrzSGli1///ujyRfon/ZneeZ+v4ptpiPoOU+GKZnm8Wj8ELWU1Pm7GHltYRBklmXMTUqM/DqQ99FQ==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.8.tgz", + "integrity": "sha512-1VrQlG8OzdyvvGZhGJFnaNE2P10Jjy/2FopnqbY0nSa/gr8If3iINxvOEW3cmVeoAYkmW0RsBazQecA2dBFOSw==", "cpu": [ "arm64" ], @@ -801,9 +715,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.5.tgz", - "integrity": "sha512-vXHOPCwfDe9qLDuq7U1OYM2wUY+KQ4Ex6ozwsKxp26BlJ6XXbHleOUldenM67JRyBfVjv371oneEvYd3H2gNSA==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.8.tgz", + "integrity": "sha512-87t3I86rNRSOJB1gXIUzaQWWSWrkWPDyZGsR0Z7JAPtLeX3uUOW2fHxl7dNWD2BZvbvftctTQjgtfpp7nMtmWg==", "cpu": [ "x64" ], @@ -816,9 +730,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.5.tgz", - "integrity": "sha512-vlhB8wI+lj8q1ExFW8lbWutA4M2ZazQNvMWuEDqZcuJJc78iUnLdPPunBPX8rC4IgT6lIx/adB+Cwrl99MzNaA==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.8.tgz", + "integrity": "sha512-ta2sfVzbOpTbgBrF9HM5m+U58dv6QPuwU4n5EX4LLyCJGKc433Z0D9h9gay/HSOjLEXJ2fJYrMP5JYYbHdxhtw==", "cpu": [ "arm64" ], @@ -831,9 +745,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.5.tgz", - "integrity": "sha512-NpDB9NUR2t0hXzJJwQSGu1IAOYybsfeB+LxpGsXrRIb7QOrYmidJz3shzY8cM6+rO4Aojuef0N/PEaX18pi9OA==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.8.tgz", + "integrity": "sha512-+IoLTPK6Z5uIgDhgeWnQF5/o5GBN7+zyUNrs4Bes1W3g9++YELb8y0unFybS8s87ntAKMDl6jeQ+mD7oNwp/Ng==", "cpu": [ "arm64" ], @@ -846,9 +760,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.5.tgz", - "integrity": "sha512-8XFikMSxWleYNryWIjiCX+gU201YS+erTUidKdyOVYi5qUQo/gRxv/3N1oZFCgqpesN6FPeqGM72Zve+nReVXQ==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.8.tgz", + "integrity": "sha512-pO+hVXC+mvzUOQJJRG4RX4wJsRJ5BkURSf6dD6EjUXAX4Ml9es1WsEfkaZ4lcpmFzFvY47IkDaffks/GdCn9ag==", "cpu": [ "x64" ], @@ -861,9 +775,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.5.tgz", - "integrity": "sha512-6QLwi7RaYiQDcRDSU/os40r5o06b5ue7Jsk5JgdRBGGp8l37RZEh9JsLSM8QF0YDsgcosSeHjglgqi25+m04IQ==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.8.tgz", + "integrity": "sha512-bCat9izctychCtf3uL1nqHq31N5e1VxvdyNcBQflkudPMLbxVnlrw45Vi87K+lt1CwrtVayHqzo4ie0Szcpwzg==", "cpu": [ "x64" ], @@ -876,9 +790,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.5.tgz", - "integrity": "sha512-1GpG2VhbspO+aYoMOQPQiqc/tG3LzmsdBH0LhnDS3JrtDx2QmzXe0B6mSZZiN3Bq7IOMXxv1nlsjzoS1+9mzZw==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.8.tgz", + "integrity": "sha512-gbxfUaSPV7EyUobpavida2Hwi62GhSJaSg7iBjmBWoxkxlmETOD7U4tWt763cGIsyE6jM7IoNavq0BXqwdW2QA==", "cpu": [ "arm64" ], @@ -891,9 +805,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.5.tgz", - "integrity": "sha512-Igh9ZlxwvCDsu6438FXlQTHlRno4gFpJzqPjSIBZooD22tKeI4fE/YMRoHVJHmrQ2P5YL1DoZ0qaOKkbeFWeMg==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.8.tgz", + "integrity": "sha512-PUXzEzjTTlUh3b5VAn1nlpwvujTnuCMMwbiCnaTazoVlN1nA3kWjlmp42IfURA2N/nyrlVEw7pURa/o4Qxj1cw==", "cpu": [ "ia32" ], @@ -906,9 +820,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.5.tgz", - "integrity": "sha512-tEQ7oinq1/CjSG9uSTerca3v4AZ+dFa+4Yu6ihaG8Ud8ddqLQgFGcnwYls13H5X5CPDPZJdYxyeMui6muOLd4g==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.8.tgz", + "integrity": "sha512-EnPKv0ttq02E9/1KZ/8Dn7kuutv6hy1CKc0HlNcvzOQcm4/SQtvfws5gY0zrG9tuupd3HfC2L/zcTrnBhpjTuQ==", "cpu": [ "x64" ], @@ -921,9 +835,9 @@ } }, "node_modules/@next/third-parties": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@next/third-parties/-/third-parties-14.2.5.tgz", - "integrity": "sha512-PDRJm8RZ3rnGNporHKjcdCeZqoW8iJ5uP0clo1Z08TqJiQzuntJ66zrGYCJyqTakx62UJNOp73YsQCFo6kbYYg==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/@next/third-parties/-/third-parties-14.2.8.tgz", + "integrity": "sha512-Vus4MYsb+7B2X4Mks9aCztZwgnzTxU9sHEm1Y35z7Vw1seh43ummniD9CBk7A8dVJZf8NGpx8re6YSZLkaSQiQ==", "dependencies": { "third-party-capital": "1.0.20" }, @@ -964,6 +878,14 @@ "node": ">= 8" } }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "engines": { + "node": ">=12.4.0" + } + }, "node_modules/@popperjs/core": { "version": "2.11.8", "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", @@ -973,10 +895,15 @@ "url": "https://opencollective.com/popperjs" } }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==" + }, "node_modules/@rushstack/eslint-patch": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.3.tgz", - "integrity": "sha512-qC/xYId4NMebE6w/V33Fh9gWxLgURiNYgVNObbJl2LZv0GUUItCcCqC5axQSwRaAgaxl2mELq1rMzlswaQ0Zxg==" + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.4.tgz", + "integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==" }, "node_modules/@swc/counter": { "version": "0.1.3", @@ -1037,9 +964,9 @@ "dev": true }, "node_modules/@types/react-transition-group": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.10.tgz", - "integrity": "sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "dependencies": { "@types/react": "*" } @@ -1055,9 +982,9 @@ "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, "node_modules/@types/validator": { - "version": "13.12.0", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.0.tgz", - "integrity": "sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==" + "version": "13.12.1", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.1.tgz", + "integrity": "sha512-w0URwf7BQb0rD/EuiG12KP0bailHKHP5YVviJG9zw3ykAokL0TuxU2TUqMB7EwZ59bDHYdeTIvjI5m0S7qHfOA==" }, "node_modules/@typescript-eslint/parser": { "version": "5.62.0", @@ -1359,17 +1286,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/array.prototype.toreversed": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", - "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - } - }, "node_modules/array.prototype.tosorted": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", @@ -1431,19 +1347,19 @@ } }, "node_modules/axe-core": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.9.1.tgz", - "integrity": "sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", + "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", "engines": { "node": ">=4" } }, "node_modules/axobject-query": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz", - "integrity": "sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==", - "dependencies": { - "deep-equal": "^2.0.5" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "engines": { + "node": ">= 0.4" } }, "node_modules/b4a": { @@ -1477,9 +1393,9 @@ "optional": true }, "node_modules/bare-fs": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", - "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.3.tgz", + "integrity": "sha512-7RYKL+vZVCyAsMLi5SPu7QGauGGT8avnP/HO571ndEuV4MYdGXvLhtW67FuLPeEI8EiIY7zbbRR9x7x7HU0kgw==", "optional": true, "dependencies": { "bare-events": "^2.0.0", @@ -1488,9 +1404,9 @@ } }, "node_modules/bare-os": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.0.tgz", - "integrity": "sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.2.tgz", + "integrity": "sha512-HZoJwzC+rZ9lqEemTMiO0luOePoGYNBgsLLgegKR/cljiJvcDNhDZQkzC+NC5Oh0aHbdBNSOHpghwMuB5tqhjg==", "optional": true }, "node_modules/bare-path": { @@ -1503,11 +1419,12 @@ } }, "node_modules/bare-stream": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.1.3.tgz", - "integrity": "sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.2.1.tgz", + "integrity": "sha512-YTB47kHwBW9zSG8LD77MIBAAQXjU2WjAkMHeeb7hUplVs6+IoM5I7uEVQNPMB7lj9r8I76UMdoMkGnCodHOLqg==", "optional": true, "dependencies": { + "b4a": "^1.6.6", "streamx": "^2.18.0" } }, @@ -1632,9 +1549,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "version": "1.0.30001659", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001659.tgz", + "integrity": "sha512-Qxxyfv3RdHAfJcXelgf0hU4DFUVXBGTjqrBUZLUh8AtlGnsDo+CnncYtTd95+ZKfnANUOzxyIQCuU/UeBZBYoA==", "funding": [ { "type": "opencollective", @@ -1915,11 +1832,11 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -2092,9 +2009,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.17.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz", - "integrity": "sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -2372,6 +2289,40 @@ } } }, + "node_modules/eslint-config-next/node_modules/eslint-import-resolver-typescript": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.3.tgz", + "integrity": "sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.3.5", + "enhanced-resolve": "^5.15.0", + "eslint-module-utils": "^2.8.1", + "fast-glob": "^3.3.2", + "get-tsconfig": "^4.7.5", + "is-bun-module": "^1.0.2", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", @@ -2390,34 +2341,10 @@ "ms": "^2.1.1" } }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", - "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.11.0.tgz", + "integrity": "sha512-gbBE5Hitek/oG6MUVj6sFuzEjA/ClzNflVrLovHi/JgLdC7fiN5gLAY1WIPW1a0V5I999MnsrvVrCOGmmVqDBQ==", "dependencies": { "debug": "^3.2.7" }, @@ -2439,25 +2366,26 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.29.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", - "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "version": "2.30.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.30.0.tgz", + "integrity": "sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==", "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.8", + "array.prototype.findlastindex": "^1.2.5", "array.prototype.flat": "^1.3.2", "array.prototype.flatmap": "^1.3.2", "debug": "^3.2.7", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", + "eslint-module-utils": "^2.9.0", + "hasown": "^2.0.2", + "is-core-module": "^2.15.1", "is-glob": "^4.0.3", "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.0", "semver": "^6.3.1", "tsconfig-paths": "^3.15.0" }, @@ -2496,16 +2424,16 @@ } }, "node_modules/eslint-plugin-jsx-a11y": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.9.0.tgz", - "integrity": "sha512-nOFOCaJG2pYqORjK19lqPqxMO/JpvdCZdPtNdxY3kvom3jTvkAbOvQvD8wuD0G8BYR0IGAGYDlzqWJOh/ybn2g==", + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz", + "integrity": "sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==", "dependencies": { "aria-query": "~5.1.3", "array-includes": "^3.1.8", "array.prototype.flatmap": "^1.3.2", "ast-types-flow": "^0.0.8", - "axe-core": "^4.9.1", - "axobject-query": "~3.1.1", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", "damerau-levenshtein": "^1.0.8", "emoji-regex": "^9.2.2", "es-iterator-helpers": "^1.0.19", @@ -2521,18 +2449,17 @@ "node": ">=4.0" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" } }, "node_modules/eslint-plugin-react": { - "version": "7.34.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.4.tgz", - "integrity": "sha512-Np+jo9bUwJNxCsT12pXtrGhJgT3T44T1sHhn1Ssr42XFn8TES0267wPGo5nNrMHi8qkyimDAX2BUmkf9pSaVzA==", + "version": "7.35.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.2.tgz", + "integrity": "sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", "array.prototype.flatmap": "^1.3.2", - "array.prototype.toreversed": "^1.1.2", "array.prototype.tosorted": "^1.1.4", "doctrine": "^2.1.0", "es-iterator-helpers": "^1.0.19", @@ -2553,7 +2480,7 @@ "node": ">=4" }, "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, "node_modules/eslint-plugin-react-hooks": { @@ -3005,9 +2932,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.0.tgz", + "integrity": "sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -3226,17 +3153,17 @@ ] }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "engines": { "node": ">= 4" } }, "node_modules/immutable": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", - "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==" + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", + "integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -3380,6 +3307,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-bun-module": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.2.1.tgz", + "integrity": "sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==", + "dependencies": { + "semver": "^7.6.3" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -3392,9 +3327,9 @@ } }, "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dependencies": { "hasown": "^2.0.2" }, @@ -3781,7 +3716,7 @@ } }, "node_modules/le-coffre-resources": { - "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#67348c776c8319ed8707ade406a2ce454e7adc2e", + "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#6c3cb06f1dc5307bf491e5f17289379c8e0b8ffc", "license": "MIT", "dependencies": { "class-transformer": "^0.5.1", @@ -3802,9 +3737,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.11.4", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.4.tgz", - "integrity": "sha512-F/R50HQuWWYcmU/esP5jrH5LiWYaN7DpN0a/99U8+mnGGtnx8kmRE+649dQh3v+CowXXZc8vpkf5AmYkO0AQ7Q==" + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.7.tgz", + "integrity": "sha512-x2xON4/Qg2bRIS11KIN9yCNYUjhtiEjNyptjX0mX+pyKHecxuJVLIpfX1lq9ZD6CrC/rB+y4GBi18c6CEcUR+A==" }, "node_modules/lines-and-columns": { "version": "1.2.4", @@ -3855,9 +3790,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -3921,9 +3856,9 @@ "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/nanoid": { "version": "3.3.7", @@ -3953,11 +3888,11 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/next": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.5.tgz", - "integrity": "sha512-0f8aRfBVL+mpzfBjYfQuLWh2WyAwtJXCRfkPF4UJ5qd2YwrHczsrSzXU4tRMV0OAxR8ZJZWPFn6uhSC56UTsLA==", + "version": "14.2.8", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.8.tgz", + "integrity": "sha512-EyEyJZ89r8C5FPlS/401AiF3O8jeMtHIE+bLom9MwcdWJJFBgRl+MR/2VgO0v5bI6tQORNY0a0DR5sjpFNrjbg==", "dependencies": { - "@next/env": "14.2.5", + "@next/env": "14.2.8", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -3972,15 +3907,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.5", - "@next/swc-darwin-x64": "14.2.5", - "@next/swc-linux-arm64-gnu": "14.2.5", - "@next/swc-linux-arm64-musl": "14.2.5", - "@next/swc-linux-x64-gnu": "14.2.5", - "@next/swc-linux-x64-musl": "14.2.5", - "@next/swc-win32-arm64-msvc": "14.2.5", - "@next/swc-win32-ia32-msvc": "14.2.5", - "@next/swc-win32-x64-msvc": "14.2.5" + "@next/swc-darwin-arm64": "14.2.8", + "@next/swc-darwin-x64": "14.2.8", + "@next/swc-linux-arm64-gnu": "14.2.8", + "@next/swc-linux-arm64-musl": "14.2.8", + "@next/swc-linux-x64-gnu": "14.2.8", + "@next/swc-linux-x64-musl": "14.2.8", + "@next/swc-win32-arm64-msvc": "14.2.8", + "@next/swc-win32-ia32-msvc": "14.2.8", + "@next/swc-win32-x64-msvc": "14.2.8" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -4002,9 +3937,9 @@ } }, "node_modules/node-abi": { - "version": "3.65.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", - "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", + "version": "3.67.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz", + "integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==", "dependencies": { "semver": "^7.3.5" }, @@ -4261,9 +4196,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -4757,9 +4692,9 @@ } }, "node_modules/sass": { - "version": "1.77.8", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.8.tgz", - "integrity": "sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==", + "version": "1.78.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.78.0.tgz", + "integrity": "sha512-AaIqGSrjo5lA2Yg7RvFZrlXDBCp3nV4XP73GrLGvdRWWwk+8H3l0SDvq/5bA4eF+0RFPLuWUk3E+P1U/YqnpsQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -4781,9 +4716,9 @@ } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -4952,9 +4887,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } @@ -4979,9 +4914,9 @@ } }, "node_modules/streamx": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", - "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.0.tgz", + "integrity": "sha512-ZGd1LhDeGFucr1CUCTBOS58ZhEendd0ttpGT3usTvosS4ntIwKN9LJFp+OeCSprsCPL14BXVRZlHGRY1V9PVzQ==", "dependencies": { "fast-fifo": "^1.3.2", "queue-tick": "^1.0.1", @@ -5247,9 +5182,9 @@ } }, "node_modules/tslib": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", - "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" }, "node_modules/tsutils": { "version": "3.21.0", @@ -5479,12 +5414,12 @@ } }, "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.4.tgz", + "integrity": "sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==", "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", "is-async-function": "^2.0.0", "is-date-object": "^1.0.5", "is-finalizationregistry": "^1.0.2", @@ -5493,8 +5428,8 @@ "is-weakref": "^1.0.2", "isarray": "^2.0.5", "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.15" }, "engines": { "node": ">= 0.4" diff --git a/package.json b/package.json index 76f7e6ba..29cd50e8 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "form-data": "^4.0.0", "heroicons": "^2.1.5", "jwt-decode": "^3.1.2", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.151", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.160", "next": "^14.2.3", "prettier": "^2.8.7", "react": "18.2.0", diff --git a/src/front/Api/LeCoffreApi/Notary/Customers/Customers.ts b/src/front/Api/LeCoffreApi/Notary/Customers/Customers.ts index c6c3918e..f9378372 100644 --- a/src/front/Api/LeCoffreApi/Notary/Customers/Customers.ts +++ b/src/front/Api/LeCoffreApi/Notary/Customers/Customers.ts @@ -87,4 +87,14 @@ export default class Customers extends BaseNotary { return Promise.reject(err); } } + + public async sendReminder(uid: string, documentsUid: string[]): Promise { + const url = new URL(this.baseURl.concat(`/${uid}/send_reminder`)); + try { + await this.postRequest(url, { documentsUid }); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } } diff --git a/src/front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders.ts b/src/front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders.ts new file mode 100644 index 00000000..36b55ee2 --- /dev/null +++ b/src/front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders.ts @@ -0,0 +1,41 @@ +import { DocumentReminder } from "le-coffre-resources/dist/Notary"; + +import BaseNotary from "../BaseNotary"; + +// TODO Type get query params -> Where + inclue + orderby +export interface IGetDocumentRemindersparams { + where?: {}; + include?: {}; + orderBy?: {}; +} + +// TODO Type getbyuid query params + +export default class DocumentReminders extends BaseNotary { + private static instance: DocumentReminders; + private readonly baseURl = this.namespaceUrl.concat("/document_reminders"); + + private constructor() { + super(); + } + + public static getInstance() { + if (!this.instance) { + return new this(); + } else { + return this.instance; + } + } + + public async get(q: IGetDocumentRemindersparams): Promise { + const url = new URL(this.baseURl); + const query = { q }; + Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts b/src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts new file mode 100644 index 00000000..db56b405 --- /dev/null +++ b/src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts @@ -0,0 +1,53 @@ +import { DocumentNotary } from "le-coffre-resources/dist/Notary"; +import BaseNotary from "../BaseNotary"; + +// TODO Type get query params -> Where + inclue + orderby +export interface IGetDocumentNotaryparams { + where?: {}; + include?: {}; + orderBy?: {}; +} + +// TODO Type getbyuid query params + +export default class DocumentsNotary extends BaseNotary { + private static instance: DocumentsNotary; + private readonly baseURl = this.namespaceUrl.concat("/documents_notary"); + + private constructor() { + super(); + } + + public static getInstance() { + if (!this.instance) { + return new this(); + } else { + return this.instance; + } + } + + // public async get(q: IGetDocumentNotaryparams): Promise { + // const url = new URL(this.baseURl); + // const query = { q }; + // Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + // try { + // return await this.getRequest(url); + // } catch (err) { + // this.onError(err); + // return Promise.reject(err); + // } + // } + + /** + * @description : Create a Document Notary + */ + public async post(body: any): Promise { + const url = new URL(this.baseURl); + try { + return await this.postRequestFormData(url, body); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Components/DesignSystem/DragAndDrop/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/index.tsx index ef30c062..5f7bc70e 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/index.tsx +++ b/src/front/Components/DesignSystem/DragAndDrop/index.tsx @@ -22,6 +22,8 @@ type IProps = { defaultFiles?: IDocumentFileWithUid[]; onDelete?: (fileUid: string) => Promise; onAddFile?: (file: File) => Promise; + onAddToList?: (file: IDocumentFile) => void; + onRemoveFromList?: (file: IDocumentFile) => void; } & ( | { onDelete: (fileUid: string) => Promise; onAddFile?: never; defaultFiles: IDocumentFileWithUid[] } | { onDelete?: never; onAddFile: (file: File) => Promise; defaultFiles: IDocumentFileWithUid[] } @@ -68,7 +70,7 @@ export type IDocumentFileWithUid = IDocumentFileBase & { type IDocumentFile = IDocumentFileBase | IDocumentFileWithUid; export default function DragAndDrop(props: IProps) { - const { title, description, defaultFiles, onDelete, onAddFile } = props; + const { title, description, defaultFiles, onDelete, onAddFile, onAddToList, onRemoveFromList } = props; const fileInputRef = useRef(null); const [documentFiles, setDocumentFiles] = useState([]); @@ -95,6 +97,9 @@ export default function DragAndDrop(props: IProps) { } return setTimeout(async () => { + if (onAddToList) { + onAddToList(newDoc); + } setDocumentFiles((prevDocs) => prevDocs.map((doc) => (doc.id === newDoc.id ? newDoc : doc))); }, 1000); } catch (error: any) { @@ -117,6 +122,9 @@ export default function DragAndDrop(props: IProps) { const handleRemove = useCallback( (documentFile: IDocumentFile) => { + if (onRemoveFromList) { + onRemoveFromList(documentFile); + } const loadingDoc = { ...documentFile, isLoading: true }; setDocumentFiles((prevDocs) => prevDocs.map((doc) => (doc.id === documentFile.id ? loadingDoc : doc))); diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx index 5eaa0ab1..343dd6c6 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx @@ -7,6 +7,7 @@ import Customer from "le-coffre-resources/dist/Customer"; import React, { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; +import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; type IProps = { isOpen: boolean; @@ -22,6 +23,7 @@ export default function ReminderModal(props: IProps) { const onRemind = useCallback(() => { console.log("selectedOptions", selectedOptions); + Customers.getInstance().sendReminder(customer.uid!, selectedOptions.map((option) => option.value) as string[]); onRemindSuccess(); onClose?.(); }, [onClose, onRemindSuccess, selectedOptions]); @@ -31,7 +33,7 @@ export default function ReminderModal(props: IProps) { customer.documents?.map((document) => { return { label: document.document_type?.name ?? "", - value: document.document_type?.uid ?? "", + value: document.uid ?? "", }; }) ?? [], [customer], diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index ed20215c..c3ee930d 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -10,6 +10,9 @@ import ReminderModal from "./ReminderModal"; import { useRouter } from "next/router"; import Module from "@Front/Config/Module"; import Link from "next/link"; +import { useCallback, useEffect, useState } from "react"; +import DocumentReminders from "@Front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders"; +import { DocumentReminder } from "le-coffre-resources/dist/Notary"; type IProps = { customer: Customer; @@ -19,9 +22,25 @@ type IProps = { export default function EmailReminder(props: IProps) { const { customer, doesCustomerHaveDocument, isAnchored } = props; + const [reminders, setReminders] = useState(null); const { isOpen, open, close } = useOpenable(); const router = useRouter(); + const fetchReminders = useCallback(async () => { + DocumentReminders.getInstance() + .get({ + where: { document: { depositor: { uid: customer.uid } } }, + include: { document: "true" }, + orderBy: { reminder_date: "desc" }, + }) + .then((reminders) => setReminders(reminders)) + .catch((e) => console.warn(e)); + }, [customer.uid]); + + useEffect(() => { + fetchReminders(); + }, []); + let { folderUid } = router.query; return ( @@ -47,16 +66,38 @@ export default function EmailReminder(props: IProps) {
{/* TODO: mettre la date de la dernière relance */} - - Dernière relance: - - + {!reminders && ( + + Dernière relance: - + + )} + + {reminders && reminders.length > 0 && ( + + Dernière relance: {new Date(reminders[0]!.reminder_date!).toLocaleDateString()} + + )} {/* TODO: mettre le nombre de relance */} - - Nombre de relance: - - + {!reminders && ( + + Nombre de relance: - + + )} + {reminders && reminders.length > 0 && ( + + Nombre de relance: {reminders.length} + + )}
- {}} onClose={close} customer={customer} /> + { + window.location.reload(); + }} + onClose={close} + customer={customer} + /> ); } diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx index 5b038dbd..33528ba8 100644 --- a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -15,17 +15,34 @@ import { useRouter } from "next/router"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; enum EClientSelection { ALL_CLIENTS = "all_clients", SELECTED_CLIENTS = "selected_clients", } +type IDocumentFileBase = { + id: string; + file: File | null; + uid?: string; + isLoading?: boolean; + error?: string; +}; + +export type IDocumentFileWithUid = IDocumentFileBase & { + uid: string; +}; + +type IDocumentFile = IDocumentFileBase | IDocumentFileWithUid; + export default function SendDocuments() { const router = useRouter(); let { folderUid } = router.query; const [folder, setFolder] = useState(null); - const [clientSelection, setClientSelection] = useState(null); + const [clientSelection, setClientSelection] = useState(EClientSelection.SELECTED_CLIENTS); + const [files, setFiles] = useState([]); + const [selectedClients, setSelectedClients] = useState([]); const onFormSubmit = useCallback( async ( @@ -34,10 +51,53 @@ export default function SendDocuments() { [key: string]: any; }, //TODO: when back is done - ) => {}, - [], + ) => { + if (folder?.customers && clientSelection === EClientSelection.ALL_CLIENTS) { + const allClientIds = folder.customers.map((customer) => customer.uid ?? ""); + setSelectedClients(allClientIds); + } + const formData = new FormData(); + + selectedClients.forEach(async (customer) => { + console.log(files[0]?.file); + + if (!files[0]?.file) return; + formData.append("customerUid", customer as string); + formData.append("folderUid", folderUid as string); + formData.append("file", files[0].file as File); + const documentNotary = await DocumentsNotary.getInstance().post(formData); + console.log(documentNotary); + }); + // const formData = new FormData(); + // files.forEach((file) => { + // if (file.file) { + // formData.append("file", file.file); + // } + // }); + // selectedClients.forEach((client) => { + // formData.append("customers", client); + // }); + // formData.append("folder", folderUid as string); + // const documentNotary = await DocumentsNotary.getInstance().post(formData); + // console.log(documentNotary); + }, + [files, clientSelection, selectedClients], ); + const onAddToList = useCallback((documentFile: IDocumentFile) => { + const test = files; + test.push(documentFile); + setFiles(test); + }, []); + + const onRemoveFromList = useCallback((documentFile: IDocumentFile) => { + const test = files; + const index = test.findIndex((doc) => doc.id === documentFile.id); + if (index === -1) return; + test.splice(index, 1); + setFiles(test); + }, []); + const fetchFolder = useCallback(async () => { Folders.getInstance() .getByUid(folderUid as string, { @@ -53,14 +113,34 @@ export default function SendDocuments() { .catch((e) => console.warn(e)); }, [folderUid]); - const onClientSelectionChange = useCallback((e: React.ChangeEvent) => { - setClientSelection(e.target.value as EClientSelection); - console.log(e.target.value); + const onClientSelectionChange = useCallback( + (e: React.ChangeEvent) => { + const selection = e.target.value as EClientSelection; + setClientSelection(selection); + + if (selection === EClientSelection.ALL_CLIENTS && folder?.customers) { + // Automatically select all customers + const allClientIds = folder.customers.map((customer) => customer.uid ?? ""); + setSelectedClients(allClientIds); + } else { + // Clear selected clients when selecting "Sélectionner certains clients" + setSelectedClients([]); + } + }, + [folder], + ); + + const handleClientSelectionChange = useCallback((selectedOptions: any) => { + setSelectedClients(selectedOptions.map((option: any) => option.id)); }, []); useEffect(() => { fetchFolder(); - }, [fetchFolder]); + if (folder?.customers && clientSelection === EClientSelection.ALL_CLIENTS) { + const allClientIds = folder.customers.map((customer) => customer.uid ?? ""); + setSelectedClients(allClientIds); + } + }, []); const backUrl = useMemo( () => @@ -100,16 +180,26 @@ export default function SendDocuments() { value={EClientSelection.SELECTED_CLIENTS} label="Sélectionner certains clients" onChange={onClientSelectionChange} + defaultChecked />
{clientSelection === EClientSelection.SELECTED_CLIENTS && ( - + )} {clientSelection && ( <> - +
diff --git a/tsconfig.json b/tsconfig.json index 3766e1e0..06d018fa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -80,7 +80,8 @@ "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "allowJs": true, - "isolatedModules": true + "isolatedModules": true, + "downlevelIteration": true }, "include": [ "next-env.d.ts", From a2068bb0fa0d6bf69e83c44c625517daebfcd0b8 Mon Sep 17 00:00:00 2001 From: Vins Date: Mon, 9 Sep 2024 11:15:41 +0200 Subject: [PATCH 27/63] Fixed Notary documents --- .../DesignSystem/DragAndDrop/index.tsx | 15 ++-- .../Layouts/Folder/SendDocuments/index.tsx | 75 +++++++++++-------- 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/src/front/Components/DesignSystem/DragAndDrop/index.tsx b/src/front/Components/DesignSystem/DragAndDrop/index.tsx index 5f7bc70e..cf40d7e1 100644 --- a/src/front/Components/DesignSystem/DragAndDrop/index.tsx +++ b/src/front/Components/DesignSystem/DragAndDrop/index.tsx @@ -22,8 +22,8 @@ type IProps = { defaultFiles?: IDocumentFileWithUid[]; onDelete?: (fileUid: string) => Promise; onAddFile?: (file: File) => Promise; - onAddToList?: (file: IDocumentFile) => void; - onRemoveFromList?: (file: IDocumentFile) => void; + name?: string; + onChange?: (files: File[]) => void; } & ( | { onDelete: (fileUid: string) => Promise; onAddFile?: never; defaultFiles: IDocumentFileWithUid[] } | { onDelete?: never; onAddFile: (file: File) => Promise; defaultFiles: IDocumentFileWithUid[] } @@ -70,7 +70,7 @@ export type IDocumentFileWithUid = IDocumentFileBase & { type IDocumentFile = IDocumentFileBase | IDocumentFileWithUid; export default function DragAndDrop(props: IProps) { - const { title, description, defaultFiles, onDelete, onAddFile, onAddToList, onRemoveFromList } = props; + const { title, description, defaultFiles, onDelete, onAddFile, name, onChange } = props; const fileInputRef = useRef(null); const [documentFiles, setDocumentFiles] = useState([]); @@ -81,6 +81,8 @@ export default function DragAndDrop(props: IProps) { } }, [defaultFiles]); + useEffect(() => onChange?.(documentFiles.map((doc) => doc.file).filter((file) => file !== null) as File[]), [documentFiles, onChange]); + const handleAddFiles = useCallback( (files: File[]) => { files.forEach((file) => { @@ -97,9 +99,6 @@ export default function DragAndDrop(props: IProps) { } return setTimeout(async () => { - if (onAddToList) { - onAddToList(newDoc); - } setDocumentFiles((prevDocs) => prevDocs.map((doc) => (doc.id === newDoc.id ? newDoc : doc))); }, 1000); } catch (error: any) { @@ -122,9 +121,6 @@ export default function DragAndDrop(props: IProps) { const handleRemove = useCallback( (documentFile: IDocumentFile) => { - if (onRemoveFromList) { - onRemoveFromList(documentFile); - } const loadingDoc = { ...documentFile, isLoading: true }; setDocumentFiles((prevDocs) => prevDocs.map((doc) => (doc.id === documentFile.id ? loadingDoc : doc))); @@ -210,6 +206,7 @@ export default function DragAndDrop(props: IProps) { function inputFile() { return ( (null); const [clientSelection, setClientSelection] = useState(EClientSelection.SELECTED_CLIENTS); - const [files, setFiles] = useState([]); const [selectedClients, setSelectedClients] = useState([]); + const [files, setFiles] = useState([]); const onFormSubmit = useCallback( async ( _e: React.FormEvent | null, - _values: { + values: { [key: string]: any; }, //TODO: when back is done @@ -57,14 +57,21 @@ export default function SendDocuments() { setSelectedClients(allClientIds); } const formData = new FormData(); + console.log("files", files); + + // get the files from the input which name is "files" + // console.log({ values }); + // const files: File[] = values["files"]; + // console.log({ files }); selectedClients.forEach(async (customer) => { - console.log(files[0]?.file); - - if (!files[0]?.file) return; formData.append("customerUid", customer as string); formData.append("folderUid", folderUid as string); - formData.append("file", files[0].file as File); + if (!files[0]) { + console.error("No files to send"); + return; + } + formData.append("file", files[0]); const documentNotary = await DocumentsNotary.getInstance().post(formData); console.log(documentNotary); }); @@ -81,22 +88,22 @@ export default function SendDocuments() { // const documentNotary = await DocumentsNotary.getInstance().post(formData); // console.log(documentNotary); }, - [files, clientSelection, selectedClients], + [clientSelection, selectedClients, files], ); - const onAddToList = useCallback((documentFile: IDocumentFile) => { - const test = files; - test.push(documentFile); - setFiles(test); - }, []); + // const onAddToList = useCallback((documentFile: IDocumentFile) => { + // const test = files; + // test.push(documentFile); + // setFiles(test); + // }, []); - const onRemoveFromList = useCallback((documentFile: IDocumentFile) => { - const test = files; - const index = test.findIndex((doc) => doc.id === documentFile.id); - if (index === -1) return; - test.splice(index, 1); - setFiles(test); - }, []); + // const onRemoveFromList = useCallback((documentFile: IDocumentFile) => { + // const test = files; + // const index = test.findIndex((doc) => doc.id === documentFile.id); + // if (index === -1) return; + // test.splice(index, 1); + // setFiles(test); + // }, []); const fetchFolder = useCallback(async () => { Folders.getInstance() @@ -150,6 +157,10 @@ export default function SendDocuments() { [folderUid], ); + const handleFileChange = useCallback((files: File[]) => { + setFiles(files); + }, []); + const clientsOptions = useMemo(() => { if (!folder?.customers) return []; return folder.customers.map((customer) => ({ @@ -195,10 +206,10 @@ export default function SendDocuments() { {clientSelection && ( <>
From a7021e6acb0206b0591653f4a1b85155f562cac5 Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 9 Sep 2024 16:04:34 +0200 Subject: [PATCH 28/63] :sparkles: connect historique des relances --- .../Folder/DocumentsReminderHistory/index.tsx | 62 ++++++++++++++++++- .../ClientView/EmailReminder/index.tsx | 47 +++++--------- 2 files changed, 75 insertions(+), 34 deletions(-) diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx index f946f00c..f9a4130f 100644 --- a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx @@ -1,13 +1,17 @@ +import DocumentReminders from "@Front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders"; import Table from "@Front/Components/DesignSystem/Table"; -import { IHead } from "@Front/Components/DesignSystem/Table/MuiTable"; +import { IHead, IRowProps } from "@Front/Components/DesignSystem/Table/MuiTable"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; import Module from "@Front/Config/Module"; +import { DocumentReminder } from "le-coffre-resources/dist/Notary"; import { useRouter } from "next/router"; -import React from "react"; +import React, { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; +import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; +import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; type IProps = {}; @@ -31,9 +35,35 @@ const header: readonly IHead[] = [ ]; export default function DocumentsReminderHistory(props: IProps) { + const [reminders, setReminders] = useState(null); const router = useRouter(); let { folderUid } = router.query; + const fetchReminders = useCallback(async () => { + DocumentReminders.getInstance() + .get({ + include: { + document: { + include: { + depositor: { + include: { + contact: true, + }, + }, + document_type: true, + }, + }, + }, + orderBy: { reminder_date: "desc" }, + }) + .then((reminders) => setReminders(reminders)) + .catch((e) => console.warn(e)); + }, []); + + useEffect(() => { + fetchReminders(); + }, [fetchReminders]); + return (
@@ -46,8 +76,34 @@ export default function DocumentsReminderHistory(props: IProps) { Historique des relances de documents -
+
); } + +function buildRows(reminders: DocumentReminder[] | null): IRowProps[] { + if (!reminders) return []; + return reminders.map((reminder) => ({ + key: reminder.uid ?? "", + remindedAt: new Date(reminder.reminder_date!).toLocaleDateString(), + customer: `${reminder.document?.depositor?.contact?.first_name} ${reminder.document?.depositor?.contact?.last_name}`, + document_type: reminder.document?.document_type?.name, + statut: getTag(reminder.document?.document_status as EDocumentStatus), + })); +} + +function getTag(status: EDocumentStatus) { + switch (status) { + case EDocumentStatus.ASKED: + return ; + case EDocumentStatus.DEPOSITED: + return ; + case EDocumentStatus.VALIDATED: + return ; + case EDocumentStatus.REFUSED: + return ; + default: + return ; + } +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index c3ee930d..ca9155d2 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -1,18 +1,18 @@ +import DocumentReminders from "@Front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import IconButton, { EIconButtonVariant } from "@Front/Components/DesignSystem/IconButton"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import Module from "@Front/Config/Module"; import useOpenable from "@Front/Hooks/useOpenable"; import { ClockIcon, EnvelopeIcon } from "@heroicons/react/24/outline"; import Customer from "le-coffre-resources/dist/Customer"; +import { DocumentReminder } from "le-coffre-resources/dist/Notary"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; import ReminderModal from "./ReminderModal"; -import { useRouter } from "next/router"; -import Module from "@Front/Config/Module"; -import Link from "next/link"; -import { useCallback, useEffect, useState } from "react"; -import DocumentReminders from "@Front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders"; -import { DocumentReminder } from "le-coffre-resources/dist/Notary"; type IProps = { customer: Customer; @@ -39,7 +39,7 @@ export default function EmailReminder(props: IProps) { useEffect(() => { fetchReminders(); - }, []); + }, [fetchReminders]); let { folderUid } = router.query; @@ -61,33 +61,18 @@ export default function EmailReminder(props: IProps) { title={"Voir l'historique des relances"} href={Module.getInstance() .get() - .modules.pages.Folder.pages.DocumentsReminderHistory.props.path.replace("[folderUid]", folderUid as string)}> + .modules.pages.Folder.pages.DocumentsReminderHistory.props.path.replace("[folderUid]", folderUid as string) + .replace("[customerUid]", customer.uid ?? "")}> } variant={EIconButtonVariant.NEUTRAL} />
- {/* TODO: mettre la date de la dernière relance */} - {!reminders && ( - - Dernière relance: - - - )} - - {reminders && reminders.length > 0 && ( - - Dernière relance: {new Date(reminders[0]!.reminder_date!).toLocaleDateString()} - - )} - {/* TODO: mettre le nombre de relance */} - {!reminders && ( - - Nombre de relance: - - - )} - {reminders && reminders.length > 0 && ( - - Nombre de relance: {reminders.length} - - )} + + Dernière relance:{" "} + {reminders && reminders.length > 0 ? new Date(reminders[0]!.reminder_date!).toLocaleDateString() : "-"} + + + Nombre de relance: {reminders && reminders.length > 0 ? reminders.length : "0"} +
Date: Mon, 9 Sep 2024 16:45:02 +0200 Subject: [PATCH 29/63] :sparkles: filtrer par customer dans l'historique des relances --- .../DesignSystem/Dropdown/index.tsx | 5 +- .../classes.module.scss | 4 ++ .../Folder/DocumentsReminderHistory/index.tsx | 63 +++++++++++++++++-- 3 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/front/Components/DesignSystem/Dropdown/index.tsx b/src/front/Components/DesignSystem/Dropdown/index.tsx index b88dae07..b45d2070 100644 --- a/src/front/Components/DesignSystem/Dropdown/index.tsx +++ b/src/front/Components/DesignSystem/Dropdown/index.tsx @@ -15,10 +15,11 @@ type IProps = { disabled?: boolean; onSelectionChange?: (option: IOption) => void; selectedOption?: IOption | null; + className?: string; }; export default function Dropdown(props: IProps) { - const { options, placeholder, disabled, onSelectionChange, selectedOption: selectedOptionProps, label } = props; + const { options, placeholder, disabled, onSelectionChange, selectedOption: selectedOptionProps, label, className } = props; const [selectedOption, setSelectedOption] = useState(selectedOptionProps ?? null); const openable = useOpenable({ defaultOpen: false }); @@ -40,7 +41,7 @@ export default function Dropdown(props: IProps) { openable={openable} onSelect={handleOnSelect} selectedOptions={selectedOption ? [selectedOption] : []}> -
+
{label && ( {label} diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss index 62f8849f..9b949a1f 100644 --- a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss @@ -13,6 +13,10 @@ width: 100%; } + .customer-filter{ + width: 472px; + } + @media screen and (max-width: $screen-m) { padding: var(--spacing-3); } diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx index f9a4130f..cc642b1d 100644 --- a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx @@ -1,17 +1,21 @@ +import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; import DocumentReminders from "@Front/Api/LeCoffreApi/Notary/DocumentReminders/DocumentReminders"; +import Dropdown from "@Front/Components/DesignSystem/Dropdown"; +import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption"; import Table from "@Front/Components/DesignSystem/Table"; import { IHead, IRowProps } from "@Front/Components/DesignSystem/Table/MuiTable"; +import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; import Module from "@Front/Config/Module"; +import Customer from "le-coffre-resources/dist/Customer"; +import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import { DocumentReminder } from "le-coffre-resources/dist/Notary"; import { useRouter } from "next/router"; -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; -import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; -import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; type IProps = {}; @@ -36,12 +40,15 @@ const header: readonly IHead[] = [ export default function DocumentsReminderHistory(props: IProps) { const [reminders, setReminders] = useState(null); + const [customers, setCustomers] = useState(null); + const [customerOption, setCustomerOption] = useState(null); const router = useRouter(); let { folderUid } = router.query; - const fetchReminders = useCallback(async () => { + const fetchReminders = useCallback(() => { DocumentReminders.getInstance() .get({ + ...(customerOption && customerOption.id !== "tous" && { where: { document: { depositor: { uid: customerOption.id } } } }), include: { document: { include: { @@ -58,11 +65,49 @@ export default function DocumentsReminderHistory(props: IProps) { }) .then((reminders) => setReminders(reminders)) .catch((e) => console.warn(e)); - }, []); + }, [customerOption]); + + const fetchCustomers = useCallback(async () => { + if (!folderUid) return; + Customers.getInstance() + .get({ + where: { + office_folders: { + some: { + uid: folderUid as string, + }, + }, + }, + }) + .then(setCustomers) + .catch(console.warn); + }, [folderUid]); + + const customersOptions: IOption[] = useMemo(() => { + let options = [ + { + id: "tous", + label: "Tous", + }, + ]; + + customers?.forEach((customer) => { + options.push({ + id: customer.uid ?? "", + label: `${customer.contact?.first_name} ${customer.contact?.last_name}`, + }); + }); + return options; + }, [customers]); useEffect(() => { fetchReminders(); - }, [fetchReminders]); + fetchCustomers(); + }, [customerOption, customersOptions, fetchCustomers, fetchReminders]); + + const onSelectionChange = useCallback((option: IOption | null) => { + setCustomerOption(option ?? null); + }, []); return ( @@ -76,6 +121,12 @@ export default function DocumentsReminderHistory(props: IProps) { Historique des relances de documents +
From eee11aa4bbd9e429fcb09fa772fc6308617a691c Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 10 Sep 2024 19:26:54 +0200 Subject: [PATCH 30/63] :sparkles: connect files notary + handle download --- .../Notary/DocumentsNotary/DocumentsNotary.ts | 40 ++++--- .../LeCoffreApi/Notary/FilesNotary/Files.ts | 71 ++++++++++++ .../DesignSystem/Autocomplete/index.tsx | 1 - .../ToastsContainer/ToastElement/index.tsx | 1 - src/front/Components/Elements/Tabs/index.tsx | 1 - .../ReceivedDocuments/index.tsx | 91 ++++++++++++--- .../DeleteSentDocumentModal/index.tsx | 4 +- .../ClientView/DocumentTables/index.tsx | 46 +++++--- .../EmailReminder/ReminderModal/index.tsx | 3 +- .../FolderInformation/ClientView/index.tsx | 15 ++- .../Layouts/Folder/SendDocuments/index.tsx | 107 ++++++------------ src/front/Components/Layouts/Folder/index.tsx | 1 - 12 files changed, 254 insertions(+), 127 deletions(-) create mode 100644 src/front/Api/LeCoffreApi/Notary/FilesNotary/Files.ts diff --git a/src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts b/src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts index db56b405..518e7ead 100644 --- a/src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts +++ b/src/front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary.ts @@ -1,15 +1,13 @@ import { DocumentNotary } from "le-coffre-resources/dist/Notary"; + import BaseNotary from "../BaseNotary"; -// TODO Type get query params -> Where + inclue + orderby export interface IGetDocumentNotaryparams { where?: {}; include?: {}; orderBy?: {}; } -// TODO Type getbyuid query params - export default class DocumentsNotary extends BaseNotary { private static instance: DocumentsNotary; private readonly baseURl = this.namespaceUrl.concat("/documents_notary"); @@ -26,17 +24,17 @@ export default class DocumentsNotary extends BaseNotary { } } - // public async get(q: IGetDocumentNotaryparams): Promise { - // const url = new URL(this.baseURl); - // const query = { q }; - // Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); - // try { - // return await this.getRequest(url); - // } catch (err) { - // this.onError(err); - // return Promise.reject(err); - // } - // } + public async get(q: IGetDocumentNotaryparams): Promise { + const url = new URL(this.baseURl); + const query = { q }; + Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } /** * @description : Create a Document Notary @@ -50,4 +48,18 @@ export default class DocumentsNotary extends BaseNotary { return Promise.reject(err); } } + + /** + * @description : Delete a Document Notary + */ + public async delete(uid: string): Promise { + const url = new URL(this.baseURl); + url.pathname = url.pathname.concat(`/${uid}`); + try { + await this.deleteRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } } diff --git a/src/front/Api/LeCoffreApi/Notary/FilesNotary/Files.ts b/src/front/Api/LeCoffreApi/Notary/FilesNotary/Files.ts new file mode 100644 index 00000000..c3b9b8ba --- /dev/null +++ b/src/front/Api/LeCoffreApi/Notary/FilesNotary/Files.ts @@ -0,0 +1,71 @@ +import { File } from "le-coffre-resources/dist/SuperAdmin"; + +import BaseNotary from "../BaseNotary"; + +export interface IGetFilesparams { + where?: {}; + include?: {}; +} + +export type IPutFilesParams = {}; + +export interface IPostFilesParams {} + +export default class FilesNotary extends BaseNotary { + private static instance: FilesNotary; + private readonly baseURl = this.namespaceUrl.concat("/files-notary"); + + private constructor() { + super(); + } + + public static getInstance() { + return (this.instance ??= new this()); + } + + public async get(q: IGetFilesparams): Promise { + const url = new URL(this.baseURl); + const query = { q }; + if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + const files = await this.getRequest(url); + return files; + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async getByUid(uid: string, q?: any): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + const query = { q }; + if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + const file = await this.getRequest(url); + return file; + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async delete(uid: string): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + try { + return await this.deleteRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async download(uid: string): Promise { + const url = new URL(this.baseURl.concat(`/download/${uid}`)); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Components/DesignSystem/Autocomplete/index.tsx b/src/front/Components/DesignSystem/Autocomplete/index.tsx index a5169574..eb442067 100644 --- a/src/front/Components/DesignSystem/Autocomplete/index.tsx +++ b/src/front/Components/DesignSystem/Autocomplete/index.tsx @@ -27,7 +27,6 @@ export default function Autocomplete(props: IProps) { 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); diff --git a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx index 896f0894..a94e09aa 100644 --- a/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx +++ b/src/front/Components/DesignSystem/Toasts/ToastsContainer/ToastElement/index.tsx @@ -39,7 +39,6 @@ class ToastElementClass extends React.Component { public override render(): JSX.Element { const toast = this.props.toast; - console.log(toast); const style = { "--data-duration": `${toast.time}ms`, diff --git a/src/front/Components/Elements/Tabs/index.tsx b/src/front/Components/Elements/Tabs/index.tsx index c90dbc36..cdfcdff8 100644 --- a/src/front/Components/Elements/Tabs/index.tsx +++ b/src/front/Components/Elements/Tabs/index.tsx @@ -80,7 +80,6 @@ export default function Tabs({ onSelect, tabs: propsTabs }: IProps) { newTabs.splice(index, 1); newTabs.unshift(tabs.current[index]!); tabs.current = newTabs; - console.log("Updated values ; ", tabs.current); handleSelect(value); }, [handleSelect], diff --git a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx index bbd62240..25af1c60 100644 --- a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx @@ -1,18 +1,22 @@ -import React from "react"; - -import classes from "./classes.module.scss"; -import { useRouter } from "next/router"; - +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; +import FilesNotary from "@Front/Api/LeCoffreApi/Notary/FilesNotary/Files"; +import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import IconButton from "@Front/Components/DesignSystem/IconButton"; +import Table from "@Front/Components/DesignSystem/Table"; +import { IHead, IRowProps } from "@Front/Components/DesignSystem/Table/MuiTable"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; import Module from "@Front/Config/Module"; -import BackArrow from "@Front/Components/Elements/BackArrow"; +import JwtService from "@Front/Services/JwtService/JwtService"; import { ArrowDownTrayIcon } from "@heroicons/react/24/outline"; -import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import { IHead } from "@Front/Components/DesignSystem/Table/MuiTable"; -import Table from "@Front/Components/DesignSystem/Table"; +import { saveAs } from "file-saver"; +import JSZip from "jszip"; +import { DocumentNotary } from "le-coffre-resources/dist/Notary"; +import { useRouter } from "next/router"; +import React, { useCallback, useEffect, useState } from "react"; -type IProps = {}; +import classes from "./classes.module.scss"; const header: readonly IHead[] = [ { @@ -29,9 +33,60 @@ const header: readonly IHead[] = [ }, ]; -export default function ReceivedDocuments(props: IProps) { +export default function ReceivedDocuments() { const router = useRouter(); let { folderUid } = router.query; + const [documentsNotary, setDocumentsNotary] = useState([]); + + useEffect(() => { + 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]); + + const onDownload = useCallback((doc: DocumentNotary) => { + const file = doc.files?.[0]; + if (!file || !file?.uid) return; + + return FilesNotary.getInstance() + .download(file.uid) + .then((blob) => { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = file.file_name ?? "file"; + a.click(); + URL.revokeObjectURL(url); + }) + .catch((e) => console.warn(e)); + }, []); + + const onDownloadAll = useCallback(async () => { + if (documentsNotary.length === 0) return; + + const zip = new JSZip(); + const folder = zip.folder("documents") || zip; + + const downloadPromises = documentsNotary.map(async (doc) => { + const file = doc.files?.[0]; + if (file && file.uid) { + const blob = await FilesNotary.getInstance().download(file.uid); + folder.file(file.file_name ?? "file", blob); + } + }); + + await Promise.all(downloadPromises); + + zip.generateAsync({ type: "blob" }) + .then((blob: any) => { + saveAs(blob, "documents.zip"); + }) + .catch((error: any) => { + console.error("Error generating ZIP file: ", error); + }); + }, [documentsNotary]); return ( @@ -45,15 +100,25 @@ export default function ReceivedDocuments(props: IProps) { Un document vous a été envoyé -
+
); } + +function buildRows(documentsNotary: DocumentNotary[], onDownloadFileNotary: (doc: DocumentNotary) => void): IRowProps[] { + return documentsNotary.map((documentNotary) => ({ + key: documentNotary.uid ?? "", + name: documentNotary.files?.[0]?.file_name?.split(".")?.[0] ?? "_", + sentAt: new Date(documentNotary.created_at!).toLocaleDateString(), + actions: onDownloadFileNotary(documentNotary)} icon={} />, + })); +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx index f10fb594..72fed16e 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx @@ -1,4 +1,4 @@ -import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; import Modal from "@Front/Components/DesignSystem/Modal"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import React, { useCallback } from "react"; @@ -15,7 +15,7 @@ export default function DeleteSentDocumentModal(props: IProps) { const onDelete = useCallback( () => - Documents.getInstance() + DocumentsNotary.getInstance() .delete(documentUid) .then(() => onDeleteSuccess(documentUid)) .then(onClose) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index 103c3270..a9b191d4 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -8,18 +8,21 @@ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Ty import Module from "@Front/Config/Module"; import useOpenable from "@Front/Hooks/useOpenable"; import { ArrowDownTrayIcon, EyeIcon, TrashIcon } from "@heroicons/react/24/outline"; +import { useMediaQuery } from "@mui/material"; import { Document } from "le-coffre-resources/dist/Customer"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; +import { DocumentNotary } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; import { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import DeleteAskedDocumentModal from "./DeleteAskedDocumentModal"; import DeleteSentDocumentModal from "./DeleteSentDocumentModal"; -import { useMediaQuery } from "@mui/material"; +import FilesNotary from "@Front/Api/LeCoffreApi/Notary/FilesNotary/Files"; type IProps = { documents: Document[]; + documentsNotary: DocumentNotary[]; folderUid: string; }; @@ -31,7 +34,7 @@ const tradDocumentStatus: Record = { }; export default function DocumentTables(props: IProps) { - const { documents: documentsProps, folderUid } = props; + const { documents: documentsProps, folderUid, documentsNotary } = props; const [documents, setDocuments] = useState(documentsProps); const [documentUid, setDocumentUid] = useState(null); @@ -79,6 +82,23 @@ export default function DocumentTables(props: IProps) { .catch((e) => console.warn(e)); }, []); + const onDownloadFileNotary = useCallback((doc: DocumentNotary) => { + const file = doc.files?.[0]; + if (!file || !file?.uid) return; + + return FilesNotary.getInstance() + .download(file.uid) + .then((blob) => { + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = file.file_name ?? "file"; + a.click(); + URL.revokeObjectURL(url); + }) + .catch((e) => console.warn(e)); + }, []); + const askedDocuments: IRowProps[] = useMemo( () => documents @@ -190,27 +210,25 @@ export default function DocumentTables(props: IProps) { [documents], ); - //TODO: modify accordingly when the back will handle sent documents const sentDocuments: IRowProps[] = useMemo( () => - documents + documentsNotary .map((document) => { - if (document.document_status !== "sent") return null; return { key: document.uid, - document_type: document.document_type?.name ?? "_", - document_status: , + document_type: document.files?.[0]?.file_name?.split(".")?.[0] ?? "_", + document_status: , date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", actions: (
- onDownload(document)} icon={} /> + onDownloadFileNotary(document)} icon={} /> openDeleteSentDocumentModal(document.uid)} />} />
), }; }) .filter((document) => document !== null) as IRowProps[], - [documents, onDownload, openDeleteSentDocumentModal], + [documentsNotary, onDownloadFileNotary, openDeleteSentDocumentModal], ); const progress = useMemo(() => { @@ -219,13 +237,9 @@ export default function DocumentTables(props: IProps) { return (validatedDocuments.length / total) * 100; }, [askedDocuments.length, refusedDocuments.length, toValidateDocuments.length, validatedDocuments.length]); - const handleDelete = useCallback( - (documentUid: string) => { - setDocuments(documents.filter((document) => document.uid !== documentUid)); - window.location.reload(); - }, - [documents], - ); + const handleDelete = useCallback((_documentUid: string) => { + window.location.reload(); + }, []); return (
diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx index 343dd6c6..5c540d68 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx @@ -22,11 +22,10 @@ export default function ReminderModal(props: IProps) { const [isAllSelected, setIsAllSelected] = useState(false); const onRemind = useCallback(() => { - console.log("selectedOptions", selectedOptions); Customers.getInstance().sendReminder(customer.uid!, selectedOptions.map((option) => option.value) as string[]); onRemindSuccess(); onClose?.(); - }, [onClose, onRemindSuccess, selectedOptions]); + }, [customer.uid, onClose, onRemindSuccess, selectedOptions]); const documentsOptions: IOption[] = useMemo( () => diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index 389bc528..17b5cc49 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -1,3 +1,4 @@ +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Tabs from "@Front/Components/Elements/Tabs"; @@ -6,8 +7,9 @@ import { DocumentIcon, UserPlusIcon } from "@heroicons/react/24/outline"; import Customer from "le-coffre-resources/dist/Customer"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; +import { DocumentNotary } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; -import { useCallback, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { AnchorStatus } from ".."; import classes from "./classes.module.scss"; @@ -25,6 +27,7 @@ export type ICustomer = Customer & { id: string }; export default function ClientView(props: IProps) { const { folder, anchorStatus } = props; + const [documentsNotary, setDocumentsNotary] = useState([]); const customers: ICustomer[] = useMemo( () => @@ -74,6 +77,12 @@ export default function ClientView(props: IProps) { [folder], ); + useEffect(() => { + DocumentsNotary.getInstance() + .get({ where: { folder: { uid: folder.uid }, customer: { uid: customer.uid } }, include: { files: true } }) + .then((documentsNotary) => setDocumentsNotary(documentsNotary)); + }, [customer.uid, folder]); + return (
@@ -123,8 +132,8 @@ export default function ClientView(props: IProps) {
- {doesCustomerHaveDocument ? ( - + {doesCustomerHaveDocument || documentsNotary.length > 0 ? ( + ) : ( )} diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx index 769c0f80..2ad4c75d 100644 --- a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -1,4 +1,5 @@ import backgroundImage from "@Assets/images/background_refonte.svg"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import AutocompleteMultiSelect from "@Front/Components/DesignSystem/AutocompleteMultiSelect"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; @@ -15,96 +16,63 @@ import { useRouter } from "next/router"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; -import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; enum EClientSelection { ALL_CLIENTS = "all_clients", SELECTED_CLIENTS = "selected_clients", } -// type IDocumentFileBase = { -// id: string; -// file: File | null; -// uid?: string; -// isLoading?: boolean; -// error?: string; -// }; - -// export type IDocumentFileWithUid = IDocumentFileBase & { -// uid: string; -// }; - -// type IDocumentFile = IDocumentFileBase | IDocumentFileWithUid; - export default function SendDocuments() { const router = useRouter(); let { folderUid } = router.query; const [folder, setFolder] = useState(null); - const [clientSelection, setClientSelection] = useState(EClientSelection.SELECTED_CLIENTS); + const [clientSelection, setClientSelection] = useState(null); const [selectedClients, setSelectedClients] = useState([]); const [files, setFiles] = useState([]); const onFormSubmit = useCallback( async ( _e: React.FormEvent | null, - values: { + _values: { [key: string]: any; }, - //TODO: when back is done ) => { - if (folder?.customers && clientSelection === EClientSelection.ALL_CLIENTS) { - const allClientIds = folder.customers.map((customer) => customer.uid ?? ""); - setSelectedClients(allClientIds); + if (!files.length) { + console.error("No files to send"); + return; } - const formData = new FormData(); - console.log("files", files); - // get the files from the input which name is "files" - // console.log({ values }); - // const files: File[] = values["files"]; - // console.log({ files }); + try { + await Promise.all( + selectedClients.map(async (customer) => { + const promises = files.map(async (file) => { + const formData = new FormData(); + formData.append("customerUid", customer as string); + formData.append("folderUid", folderUid as string); + formData.append("name", file.name); + formData.append("file", file); - selectedClients.forEach(async (customer) => { - formData.append("customerUid", customer as string); - formData.append("folderUid", folderUid as string); - if (!files[0]) { - console.error("No files to send"); - return; - } - formData.append("file", files[0]); - const documentNotary = await DocumentsNotary.getInstance().post(formData); - console.log(documentNotary); - }); - // const formData = new FormData(); - // files.forEach((file) => { - // if (file.file) { - // formData.append("file", file.file); - // } - // }); - // selectedClients.forEach((client) => { - // formData.append("customers", client); - // }); - // formData.append("folder", folderUid as string); - // const documentNotary = await DocumentsNotary.getInstance().post(formData); - // console.log(documentNotary); + // Envoi de chaque fichier pour chaque client + return DocumentsNotary.getInstance().post(formData); + }); + + // Attendre que tous les fichiers pour un client soient envoyés + await Promise.all(promises); + }), + ); + router.push( + Module.getInstance() + .get() + .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid as string), + ); + console.log("All files have been successfully sent."); + } catch (error) { + console.error("Error while sending files: ", error); + } }, - [clientSelection, selectedClients, files], + [files, folderUid, router, selectedClients], ); - // const onAddToList = useCallback((documentFile: IDocumentFile) => { - // const test = files; - // test.push(documentFile); - // setFiles(test); - // }, []); - - // const onRemoveFromList = useCallback((documentFile: IDocumentFile) => { - // const test = files; - // const index = test.findIndex((doc) => doc.id === documentFile.id); - // if (index === -1) return; - // test.splice(index, 1); - // setFiles(test); - // }, []); - const fetchFolder = useCallback(async () => { Folders.getInstance() .getByUid(folderUid as string, { @@ -126,11 +94,9 @@ export default function SendDocuments() { setClientSelection(selection); if (selection === EClientSelection.ALL_CLIENTS && folder?.customers) { - // Automatically select all customers const allClientIds = folder.customers.map((customer) => customer.uid ?? ""); setSelectedClients(allClientIds); } else { - // Clear selected clients when selecting "Sélectionner certains clients" setSelectedClients([]); } }, @@ -143,11 +109,7 @@ export default function SendDocuments() { useEffect(() => { fetchFolder(); - if (folder?.customers && clientSelection === EClientSelection.ALL_CLIENTS) { - const allClientIds = folder.customers.map((customer) => customer.uid ?? ""); - setSelectedClients(allClientIds); - } - }, []); + }, [fetchFolder]); const backUrl = useMemo( () => @@ -191,7 +153,6 @@ export default function SendDocuments() { value={EClientSelection.SELECTED_CLIENTS} label="Sélectionner certains clients" onChange={onClientSelectionChange} - defaultChecked /> diff --git a/src/front/Components/Layouts/Folder/index.tsx b/src/front/Components/Layouts/Folder/index.tsx index 5bab6189..c7e2dd5e 100644 --- a/src/front/Components/Layouts/Folder/index.tsx +++ b/src/front/Components/Layouts/Folder/index.tsx @@ -30,7 +30,6 @@ export default function Folder() { }, }) .then((folders) => { - console.log(folders); if (folders.length > 0) router.push( Module.getInstance() From 5cfc754260e761e5c86f3b9ebf95a6b9a43d9a98 Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 11 Sep 2024 13:01:30 +0200 Subject: [PATCH 31/63] add missing dependencies --- package-lock.json | 83 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 ++ 2 files changed, 85 insertions(+) diff --git a/package-lock.json b/package-lock.json index 090ff495..ca3b61c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,8 +23,10 @@ "dotenv": "^16.0.3", "eslint": "8.36.0", "eslint-config-next": "13.2.4", + "file-saver": "^2.0.5", "form-data": "^4.0.0", "heroicons": "^2.1.5", + "jszip": "^3.10.1", "jwt-decode": "^3.1.2", "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.160", "next": "^14.2.3", @@ -1731,6 +1733,11 @@ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, "node_modules/cosmiconfig": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", @@ -2771,6 +2778,11 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/file-saver": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==" + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3160,6 +3172,11 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" + }, "node_modules/immutable": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", @@ -3686,6 +3703,49 @@ "node": ">=4.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/jwt-decode": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", @@ -3741,6 +3801,14 @@ "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.7.tgz", "integrity": "sha512-x2xON4/Qg2bRIS11KIN9yCNYUjhtiEjNyptjX0mX+pyKHecxuJVLIpfX1lq9ZD6CrC/rB+y4GBi18c6CEcUR+A==" }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -4130,6 +4198,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4319,6 +4392,11 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -4756,6 +4834,11 @@ "node": ">= 0.4" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, "node_modules/sharp": { "version": "0.32.6", "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.32.6.tgz", diff --git a/package.json b/package.json index 29cd50e8..91b23203 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,10 @@ "dotenv": "^16.0.3", "eslint": "8.36.0", "eslint-config-next": "13.2.4", + "file-saver": "^2.0.5", "form-data": "^4.0.0", "heroicons": "^2.1.5", + "jszip": "^3.10.1", "jwt-decode": "^3.1.2", "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.160", "next": "^14.2.3", From 9451a8e760b761b481df975f4e9365669fa30233 Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 11 Sep 2024 13:01:51 +0200 Subject: [PATCH 32/63] add missing packages --- package-lock.json | 7 +++++++ package.json | 1 + 2 files changed, 8 insertions(+) diff --git a/package-lock.json b/package-lock.json index ca3b61c8..7f22076c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "uuidv4": "^6.2.13" }, "devDependencies": { + "@types/file-saver": "^2.0.7", "@types/react-gtm-module": "^2.0.3" } }, @@ -921,6 +922,12 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/file-saver": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz", + "integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", diff --git a/package.json b/package.json index 91b23203..50e41004 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "uuidv4": "^6.2.13" }, "devDependencies": { + "@types/file-saver": "^2.0.7", "@types/react-gtm-module": "^2.0.3" } } From 15618040759883b67a84cd97f228c56329e1caa8 Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 11 Sep 2024 14:42:55 +0200 Subject: [PATCH 33/63] =?UTF-8?q?:sparkles:=20full=20width=20voir=20les=20?= =?UTF-8?q?documents=20re=C3=A7u=20button?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/front/Components/Layouts/ClientDashboard/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/front/Components/Layouts/ClientDashboard/index.tsx b/src/front/Components/Layouts/ClientDashboard/index.tsx index d1fe593d..da2fb194 100644 --- a/src/front/Components/Layouts/ClientDashboard/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/index.tsx @@ -177,7 +177,8 @@ export default function ClientDashboard(props: IProps) { .modules.pages.ClientDashboard.pages.ReceiveDocuments.props.path.replace( "[folderUid]", folderUid as string, - )}> + )} + style={{ width: "100%" }}> From 8358dbab9cc673f9c9539393e09b154a30b48d30 Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 11 Sep 2024 15:10:45 +0200 Subject: [PATCH 34/63] :sparkles: refont page callback --- .../Components/DesignSystem/Loader/index.tsx | 4 ++- .../Components/Elements/HelpBox/index.tsx | 4 +-- .../Layouts/LoginCallback/classes.module.scss | 31 +++++++--------- .../Layouts/LoginCallback/index.tsx | 35 +++++++++---------- 4 files changed, 34 insertions(+), 40 deletions(-) diff --git a/src/front/Components/DesignSystem/Loader/index.tsx b/src/front/Components/DesignSystem/Loader/index.tsx index c2152759..27f911a0 100644 --- a/src/front/Components/DesignSystem/Loader/index.tsx +++ b/src/front/Components/DesignSystem/Loader/index.tsx @@ -5,9 +5,11 @@ import classes from "./classes.module.scss"; interface IProps { className?: string; + width?: string | number; + color?: string; } export default class Loader extends React.Component { public override render(): JSX.Element { - return ; + return ; } } diff --git a/src/front/Components/Elements/HelpBox/index.tsx b/src/front/Components/Elements/HelpBox/index.tsx index 9770f464..1b6903f9 100644 --- a/src/front/Components/Elements/HelpBox/index.tsx +++ b/src/front/Components/Elements/HelpBox/index.tsx @@ -26,12 +26,12 @@ export default function HelpBox(props: IProps) { styletype={EButtonstyletype.TEXT} size={EButtonSize.MD} onClick={button.onClick}> - Contactez le support + {button.text} ) : ( )} diff --git a/src/front/Components/Layouts/LoginCallback/classes.module.scss b/src/front/Components/Layouts/LoginCallback/classes.module.scss index 72ae8ab8..4ef895b8 100644 --- a/src/front/Components/Layouts/LoginCallback/classes.module.scss +++ b/src/front/Components/Layouts/LoginCallback/classes.module.scss @@ -1,29 +1,22 @@ @import "@Themes/constants.scss"; .root { + margin: 80px auto; + width: 474px; + display: flex; - align-items: center; - justify-content: center; flex-direction: column; - height: 100%; - max-width: 530px; - margin: auto; + gap: var(--spacing-xl, 32px); - .title { - margin: 32px 0; - text-align: center; - @media (max-width: $screen-s) { - font-family: 48px; - } + .title-container { + display: flex; + flex-direction: column; + gap: var(--spacing-sm); } - .loader { - width: 32px; - height: 32px; - } - - .forget-password { - margin-top: 32px; - margin-bottom: 8px; + @media (max-width: $screen-s) { + width: 100%; + margin: auto; + padding: var(--spacing-md, 16px); } } diff --git a/src/front/Components/Layouts/LoginCallback/index.tsx b/src/front/Components/Layouts/LoginCallback/index.tsx index 8011f092..702dc9c5 100644 --- a/src/front/Components/Layouts/LoginCallback/index.tsx +++ b/src/front/Components/Layouts/LoginCallback/index.tsx @@ -7,13 +7,13 @@ import classes from "./classes.module.scss"; import Module from "@Front/Config/Module"; import Auth from "@Front/Api/Auth/IdNot"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; -import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; -import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Loader from "@Front/Components/DesignSystem/Loader"; import UserStore from "@Front/Stores/UserStore"; -import Link from "next/link"; import JwtService from "@Front/Services/JwtService/JwtService"; import CookieService from "@Front/Services/CookieService/CookieService"; +import backgroundImage from "@Assets/images/background_refonte.svg"; +import HelpBox from "@Front/Components/Elements/HelpBox"; export default function LoginCallBack() { const router = useRouter(); @@ -60,23 +60,22 @@ export default function LoginCallBack() { [router]; return ( - +
- - -
Connexion espace professionnel
-
-
- +
+ + + Connexion à votre espace professionnel +
- -
Vous n'arrivez pas à vous connecter ?
-
- - - + + +
+
); From c6ed4e53986a029b257e9f5d8a911638aa064861 Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 11 Sep 2024 15:44:37 +0200 Subject: [PATCH 35/63] :sparkles: refont MyAccount --- .../Form/TextField/classes.module.scss | 3 + .../DesignSystem/Form/TextField/index.tsx | 5 + .../Layouts/LoginCallback/index.tsx | 24 +- .../Layouts/MyAccount/classes.module.scss | 41 ++-- .../Components/Layouts/MyAccount/index.tsx | 214 +++++++----------- 5 files changed, 127 insertions(+), 160 deletions(-) diff --git a/src/front/Components/DesignSystem/Form/TextField/classes.module.scss b/src/front/Components/DesignSystem/Form/TextField/classes.module.scss index 8b25310c..bb0578ca 100644 --- a/src/front/Components/DesignSystem/Form/TextField/classes.module.scss +++ b/src/front/Components/DesignSystem/Form/TextField/classes.module.scss @@ -3,6 +3,7 @@ .root { position: relative; + &[data-is-disabled="true"] { opacity: var(--opacity-disabled, 0.3); .input-container { @@ -27,6 +28,8 @@ } .input-container { + height: 56px; + display: flex; padding: var(--spacing-2, 16px) var(--spacing-sm, 8px); align-items: center; diff --git a/src/front/Components/DesignSystem/Form/TextField/index.tsx b/src/front/Components/DesignSystem/Form/TextField/index.tsx index 915cc7c0..713874cf 100644 --- a/src/front/Components/DesignSystem/Form/TextField/index.tsx +++ b/src/front/Components/DesignSystem/Form/TextField/index.tsx @@ -5,6 +5,9 @@ import BaseField, { IProps as IBaseFieldProps } from "../BaseField"; import classes from "./classes.module.scss"; import classnames from "classnames"; import { XMarkIcon, Square2StackIcon } from "@heroicons/react/24/outline"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; + + export type IProps = IBaseFieldProps & { canCopy?: boolean; password?: boolean; @@ -36,6 +39,7 @@ export default class TextField extends BaseField { onBlur={this.onBlur} name={this.props.name} disabled={this.props.disabled} + readOnly={this.props.readonly} type={this.props.password ? "password" : "text"} /> {this.props.canCopy && !this.hasError() && ( @@ -58,6 +62,7 @@ export default class TextField extends BaseField { private onCopyClick = (): void => { if (this.props.canCopy) { navigator.clipboard.writeText(this.state.value ?? ""); + ToasterService.getInstance().success({ title: "Copié avec succès !", description: this.state.value }); } }; } diff --git a/src/front/Components/Layouts/LoginCallback/index.tsx b/src/front/Components/Layouts/LoginCallback/index.tsx index 702dc9c5..9c8ff248 100644 --- a/src/front/Components/Layouts/LoginCallback/index.tsx +++ b/src/front/Components/Layouts/LoginCallback/index.tsx @@ -1,19 +1,19 @@ -import LandingImage from "../Login/landing-connect.jpeg"; -import Image from "next/image"; +import backgroundImage from "@Assets/images/background_refonte.svg"; import CoffreIcon from "@Assets/logo_small_blue.svg"; +import Auth from "@Front/Api/Auth/IdNot"; +import Loader from "@Front/Components/DesignSystem/Loader"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import HelpBox from "@Front/Components/Elements/HelpBox"; +import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; +import Module from "@Front/Config/Module"; +import CookieService from "@Front/Services/CookieService/CookieService"; +import JwtService from "@Front/Services/JwtService/JwtService"; +import UserStore from "@Front/Stores/UserStore"; +import Image from "next/image"; import { useRouter } from "next/router"; import React, { useEffect } from "react"; + import classes from "./classes.module.scss"; -import Module from "@Front/Config/Module"; -import Auth from "@Front/Api/Auth/IdNot"; -import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; -import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import Loader from "@Front/Components/DesignSystem/Loader"; -import UserStore from "@Front/Stores/UserStore"; -import JwtService from "@Front/Services/JwtService/JwtService"; -import CookieService from "@Front/Services/CookieService/CookieService"; -import backgroundImage from "@Assets/images/background_refonte.svg"; -import HelpBox from "@Front/Components/Elements/HelpBox"; export default function LoginCallBack() { const router = useRouter(); diff --git a/src/front/Components/Layouts/MyAccount/classes.module.scss b/src/front/Components/Layouts/MyAccount/classes.module.scss index 7e5b5fbd..b868e543 100644 --- a/src/front/Components/Layouts/MyAccount/classes.module.scss +++ b/src/front/Components/Layouts/MyAccount/classes.module.scss @@ -1,27 +1,32 @@ @import "@Themes/constants.scss"; .root { - .title { - margin-top: 24px; + margin: 24px auto; + width: 566px; + + @media (max-width: $screen-m) { + width: 474px; } - .parts-container { + @media (max-width: $screen-s) { + width: 100%; + padding: var(--spacing-md, 16px); + } + + + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + .title-container { display: flex; - gap: 64px; - margin-top: 32px; + flex-direction: column; + gap: var(--spacing-sm, 8px); + } - @media (max-width: $screen-m) { - flex-direction: column; - } - .part { - flex: 1; - - .form-container { - display: flex; - flex-direction: column; - gap: 24px; - margin-top: 32px; - } - } + .form { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); } } diff --git a/src/front/Components/Layouts/MyAccount/index.tsx b/src/front/Components/Layouts/MyAccount/index.tsx index 0c9169f1..e4b02143 100644 --- a/src/front/Components/Layouts/MyAccount/index.tsx +++ b/src/front/Components/Layouts/MyAccount/index.tsx @@ -1,142 +1,96 @@ +import backgroundImage from "@Assets/images/background_refonte.svg"; +import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users"; import Form from "@Front/Components/DesignSystem/Form"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import Base from "@Front/Components/Layouts/Base"; -import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; -import React from "react"; +import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; +import JwtService from "@Front/Services/JwtService/JwtService"; +import User from "le-coffre-resources/dist/Notary"; +import React, { useEffect } from "react"; import classes from "./classes.module.scss"; -import User from "le-coffre-resources/dist/Notary"; -import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users"; -import JwtService from "@Front/Services/JwtService/JwtService"; -type IProps = {}; -type IState = { - user: User | null; -}; +export default function MyAccount() { + const [user, setUser] = React.useState(null); -export default class MyAccount extends Base { - constructor(props: IProps) { - super(props); - this.state = { - user: null, - }; - } - - public override render(): JSX.Element { - return ( - -
- - Mon compte - -
-
- - Mes informations - - -
- - - - -
- -
-
- - Mon office - -
-
- - - - -
- -
-
-
-
- ); - } - - public override async componentDidMount() { + useEffect(() => { const jwtDecoded = JwtService.getInstance().decodeJwt(); if (!jwtDecoded) return; - const user = await Users.getInstance().getByUid(jwtDecoded.userId, { - q: { - office_membership: { - include: { - address: true, + Users.getInstance() + .getByUid(jwtDecoded.userId, { + q: { + office_membership: { + include: { + address: true, + }, }, + contact: true, }, - contact: true, - }, - }); - if (!user) return; - this.setState({ - user, - }); - } - private onFormSubmit( - e: React.FormEvent | null, - values: { - [key: string]: string; - }, - ) {} + }) + .then((user) => { + if (!user) return; + setUser(user); + }); + }, []); + + return ( + +
+
+ + Mon compte + + + Mes informations + +
+ +
+ + + + + + + + Mon office + + +
+ + + + + +
+
+ ); } From 58500e52661d880a5901f2200895a4620a8cae64 Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 11 Sep 2024 15:45:24 +0200 Subject: [PATCH 36/63] :hammer: add missing label --- src/front/Components/Layouts/MyAccount/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/front/Components/Layouts/MyAccount/index.tsx b/src/front/Components/Layouts/MyAccount/index.tsx index e4b02143..13ef4111 100644 --- a/src/front/Components/Layouts/MyAccount/index.tsx +++ b/src/front/Components/Layouts/MyAccount/index.tsx @@ -72,7 +72,7 @@ export default function MyAccount() { readonly canCopy /> - + Date: Thu, 12 Sep 2024 12:14:33 +0200 Subject: [PATCH 37/63] :sparkles: add loader when sending documents --- src/front/Components/Layouts/Folder/SendDocuments/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx index 2ad4c75d..0449d17e 100644 --- a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -29,6 +29,7 @@ export default function SendDocuments() { const [clientSelection, setClientSelection] = useState(null); const [selectedClients, setSelectedClients] = useState([]); const [files, setFiles] = useState([]); + const [isSending, setIsSending] = useState(false); const onFormSubmit = useCallback( async ( @@ -43,6 +44,7 @@ export default function SendDocuments() { } try { + setIsSending(true); await Promise.all( selectedClients.map(async (customer) => { const promises = files.map(async (file) => { @@ -65,8 +67,10 @@ export default function SendDocuments() { .get() .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid as string), ); + setIsSending(false); console.log("All files have been successfully sent."); } catch (error) { + setIsSending(false); console.error("Error while sending files: ", error); } }, @@ -179,7 +183,7 @@ export default function SendDocuments() { Annuler
-
From 0da227c333333c98dbcfee2c282f4c1a7e3a86f6 Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 12 Sep 2024 16:14:18 +0200 Subject: [PATCH 38/63] :sparkles: privacy policy --- src/front/Components/Elements/Dot/index.tsx | 10 + .../PrivacyPolicy/classes.module.scss | 14 + .../LegalInformations/PrivacyPolicy/index.tsx | 390 ++++++++++++++++++ .../Layouts/Legal/LegalInformations/index.tsx | 55 +-- 4 files changed, 443 insertions(+), 26 deletions(-) create mode 100644 src/front/Components/Elements/Dot/index.tsx create mode 100644 src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/classes.module.scss create mode 100644 src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx diff --git a/src/front/Components/Elements/Dot/index.tsx b/src/front/Components/Elements/Dot/index.tsx new file mode 100644 index 00000000..0dbbe8d1 --- /dev/null +++ b/src/front/Components/Elements/Dot/index.tsx @@ -0,0 +1,10 @@ +import React from "react"; + +export default function Dot({ children }: { children: React.ReactNode }) { + return ( + <> +     ●  {children} +
+ + ); +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/classes.module.scss b/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/classes.module.scss new file mode 100644 index 00000000..1a8d89ee --- /dev/null +++ b/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/classes.module.scss @@ -0,0 +1,14 @@ +.root { + width: 1056px; + padding: 24px; + + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + section { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + } +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx new file mode 100644 index 00000000..27d4295e --- /dev/null +++ b/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx @@ -0,0 +1,390 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import Dot from "@Front/Components/Elements/Dot"; +import React from "react"; + +import classes from "./classes.module.scss"; +import Module from "@Front/Config/Module"; +import { ELegalOptions } from "@Front/Components/LayoutTemplates/DefaultLegalDashboard"; + +export default function PrivacyPolicy() { + return ( +
+
+ + Politique de confidentialité + + + Version en vigueur à compter du 24 avril 2024 + + + Les informations suivantes vous sont communiquées afin que vous puissiez prendre connaissance des engagements en matière + de protection des données à caractère personnel de LEcoffre.io, qui agit en tant que responsable du traitement pour les + traitements de données à caractère personnel évoqués dans le présent document. + +
+ +
+ + 1. Les données à caractère personnel que nous traitons + + + Dans le cadre des traitements de données à caractère personnel, LEcoffre.io collecte et traite les données suivantes en + qualité de responsable du traitement : + + + Données d'identité (nom, prénom), d'identification (courriel et numéro de téléphone); + Données de paiement; + Données de connexion et de navigation. + + + + Il peut également arriver que des Internautes communiquent d’autres données en contactant LEcoffre.io à l’aide de son + formulaire de contact. + +
+ +
+ + 2. Les finalités de nos traitements + + + Les traitements que nous mettons en œuvre le sont pour assurer les finalités suivantes : + + + répondre à vos demandes de contacts; + la gestion des demandes de droit d'accès, de suppression, de rectification et d'opposition; + vous permettre d’accéder au Site et à la plateforme LECoffre.io; + vous envoyer par courriel nos offres relatives aux Services, des actualités et bonnes pratiques. + +
+ +
+ + 3. Les fondements juridiques de nos traitements + + + Nous ne mettons en œuvre des traitements de données que si au moins l’une des conditions suivantes est remplie : + + + votre consentement aux opérations de traitement a été recueilli; + + l’existence de notre intérêt légitime, ou de celui d’un tiers, qui justifie que nous mettions en œuvre le traitement + de données à caractère personnel concerné; + + + l’exécution d’un contrat qui nous lie à vous nécessite que nous mettions en œuvre le traitement de données à + caractère personnel concerné. + + + Les intérêts légitimes qui sont poursuivis par LEcoffre.io peuvent notamment consister dans le management de son + activité, le suivi de ses contrats et la réalisation de ses prestations. + + +
+ +
+ + 4. Les destinataires de vos données + + + Les données à caractère personnel que nous collectons, de même que celles qui sont recueillies ultérieurement, nous sont + destinées en notre qualité de responsable du traitement. + + + Nous veillons à ce que seules les personnes habilitées puissent avoir accès à ces données. Nos prestataires de services + peuvent être destinataires de ces données pour réaliser les prestations que nous leur confions. Certaines données + personnelles peuvent être adressées à des tiers ou à des autorités légalement habilitées et ce pour satisfaire nos + obligations légales, réglementaires ou conventionnelles. + +
+ +
+ + 5. La durée de conservation de vos données + + + Les durées de conservation que nous appliquons à vos données à caractère personnel sont proportionnées aux finalités + pour lesquelles elles ont été collectées. En conséquence, nous organisons notre politique de conservation des données de + la manière suivante : + + + Durée de conservation des données techniques + + + Les données techniques sont conservées pour la durée strictement nécessaire à la réalisation des finalités visées dans + la présente politique de confidentialité. + + + Conservation des données pendant la durée de la relation contractuelle + + + Les données à caractère personnel faisant l'objet d'un traitement ne sont pas conservées au-delà du temps nécessaire à + l'exécution des obligations définies lors de la conclusion du contrat ou de la durée prédéfinie de la relation + contractuelle. + +
+ +
+ + 6. La sécurité de vos données + + + LEcoffre.io a mis en œuvre des mesures pour protéger la confidentialité, la sécurité et l’intégrité de vos données à + caractère personnel. L’accès aux données à caractère personnel est restreint aux employés et fournisseurs de service qui + ont besoin de connaître ces informations et qui ont été formés pour se conformer aux règles en matière de + confidentialité. + + + LEcoffre.io s’engage à ce que vos données à caractère personnel ne soient pas altérées ou endommagées et que des tiers + non autorisés n’y aient pas accès. + + + Nous disposons des mesures de protection physiques, techniques, électroniques, procédurales et organisationnelles + appropriées pour protéger les informations personnelles recueillies contre tout traitement non autorisé. + + + Toutefois, LEcoffre.io ne saurait vous garantir contre toute perte, destruction ou dommages de vos données à caractère + personnel. + +
+ +
+ + 7. Les droits qui vous sont reconnus + + + Modalités d’exercice de vos droits + + + Vous pouvez exercer vos droits par voie électronique à l’adresse suivante (contact@lecoffre.io) ou par courrier postal à + l’adresse LEcoffre.io - 2, Mail Anne-Catherine – 35000 Rennes, en justifiant de votre identité. + + + Pour ce faire, vous devez indiquer clairement vos nom(s) et prénom(s), l’adresse à laquelle vous souhaitez que la + réponse vous soit envoyée et y joindre la photocopie d’un titre d’identité portant votre signature. + + + Par principe, vous pouvez exercer sans frais l’ensemble de vos droits. Cependant en matière de droit d’accès, il pourra + vous être demandé le paiement de frais raisonnables basés sur les coûts administratifs pour toute copie des données que + vous demanderez. + + + Concernant le droit d’information, LEcoffre.io n’aura pas l’obligation d’y donner suite lorsque vous disposez déjà des + informations dont vous sollicitez la communication. + + + LEcoffre.io vous informera si elle ne peut donner suite à vos demandes. + + + LEcoffre.io tient à vous informer que le non-renseignement ou la modification de vos données sont susceptibles d’avoir + des conséquences dans le traitement de certaines demandes dans le cadre de l’exécution des relations contractuelles et + que votre demande au titre de l’exercice de vos droits sera conservée à des fins de suivi. + + + L’ensemble des droits dont vous bénéficiez est détaillé ci-dessous : + +
+ +
+ + Droit à l’information + + + Vous pouvez exercer vos droits par voie électronique à l’adresse suivante (contact@lecoffre.io) ou par courrier postal à + l’adresse LEcoffre.io - 2, Mail Anne-Catherine – 35000 Rennes, en justifiant de votre identité. + + + Si nous décidons de traiter des données pour des finalités autres que celles indiquées, toutes les informations + relatives à ces nouvelles finalités vous seront communiquées. + + + + Droit d’accès et à la rectification de vos données + + + Vous disposez du droit d’accéder et de faire rectifier vos données personnelles, que vous pouvez exercer auprès de + LEcoffre.io par voie électronique à l’adresse + + + {" "} + contact@lecoffre.io{" "} + + + ou par courrier postal à l’adresse LEcoffre.io – 2, Mail Anne-Catherine – 35000 Rennes. + + + A ce titre, vous avez la confirmation que vos données personnelles sont ou ne sont pas traitées et lorsqu’elles le sont, + et disposez de l’accès à vos données ainsi qu’aux informations concernant : + + + + les finalités du traitement ; + les catégories de données personnelles concernées ; + + les destinataires ou catégories de destinataires ainsi que les organisations internationales auxquels les données + personnelles ont été ou seront communiquées, en particulier les destinataires qui sont établis dans des pays tiers ; + + + lorsque cela est possible, la durée de conservation des données personnelles envisagée ou, lorsque ce n’est pas + possible, les critères utilisés pour déterminer cette durée ; + + + l’existence du droit de demander au responsable du traitement la rectification ou l’effacement de vos données + personnelles, du droit de demander une limitation du traitement de vos données personnelles, du droit de vous + opposer à ce traitement ; + + le droit d’introduire une réclamation auprès d’une autorité de contrôle ; + + des informations relatives à la source des données quand elles ne sont pas collectées directement auprès des + personnes concernées ; + + + l’existence d’une prise de décision automatisée, y compris de profilage, et dans ce dernier cas, des informations + utiles concernant la logique sous-jacente, ainsi que l’importance et les conséquences prévues de ce traitement pour + les personnes concernées. + + + + + Vous pouvez nous demander que vos données personnelles soient, selon les cas, rectifiées, complétées si elles sont + inexactes, incomplètes, équivoques, périmées. + +
+ +
+ + Droit à l’effacement de vos données + + + Vous pouvez nous demander l’effacement de vos données personnelles lorsque l’un des motifs suivants s’applique : + + + + les données personnelles ne sont plus nécessaires au regard des finalités pour lesquelles elles ont été collectées + ou traitées d’une autre manière ; + + vous retirez le consentement préalablement donné ; + + vous vous opposez au traitement de vos données personnelles lorsqu’il n’existe pas de motif légal audit traitement ; + + + le traitement de données personnelles n’est pas conforme aux dispositions de la législation et de la réglementation + applicable ; + + + vos données personnelles ont été collectées dans le cadre de l’offre de services de la société de l’information aux + enfants âgés de moins de 16 ans. + + + + Néanmoins, l’exercice de ce droit ne sera pas possible lorsque la conservation de vos données personnelles est + nécessaire au regard de la législation ou de la réglementation et notamment par exemple pour la constatation, l’exercice + ou la défense de droits en justice. + +
+ +
+ + Droit à la limitation des traitements de données + + + Vous pouvez demander la limitation du traitement de vos données personnelles dans les cas prévus par la législation et + la réglementation. + +
+ +
+ + Droit de vous opposer aux traitements de données + + + Vous avez le droit de vous opposer à un traitement de données personnelles vous concernant lorsque le traitement est + fondé sur l’intérêt légitime du responsable du traitement. + +
+ +
+ + Droit à la portabilité de vos données + + + Vous disposez du droit à la portabilité de vos données personnelles, lorsque : + + + + le traitement est fondé sur le consentement en application de l’article 6, paragraphe 1, point a), ou de l’article + 9, paragraphe 2, point a), ou sur un contrat en application de l’article 6, paragraphe 1, point b) du RGPD ; + + le traitement est effectué à l'aide de procédés automatisés. + +
+ +
+ + Droit de retirer votre consentement + + + Lorsque les traitements de données que nous mettons en œuvre sont fondés sur votre consentement, vous pouvez le retirer + à n’importe quel moment. Nous cessons alors de traiter vos données à caractère personnel sans que les opérations + antérieures pour lesquelles vous aviez consenti ne soient remises en cause. + +
+ +
+ + Droit d’introduire un recours + + + Si vous considérez que LEcoffre.io ne respecte pas ses obligations au regard de vos données à caractère personnel, vous + pouvez adresser une plainte ou une demande auprès de l’autorité compétente. En France, l’autorité compétente est la Cnil + à laquelle vous pouvez adresser une demande par voie électronique en cliquant sur le lien suivant + + + {" "} + https://www.cnil.fr/fr/plaintes/internet.{" "} + + + +
+ +
+ + Droit de définir des directives post-mortem + + + Vous avez la possibilité de définir des directives relatives à la conservation, à l’effacement et à la communication de + vos données personnelles après votre décès et ce auprès d’un tiers de confiance, certifié et chargé de faire respecter + la volonté du défunt, conformément aux exigences du cadre juridique applicable. + +
+ +
+ + 8. Cookies + + + En naviguant sur notre site, des cookies sont déposés sur votre terminal, soit directement, soit après avoir recueilli + votre consentement lorsque la réglementation en matière de cookies le requiert. + + + Vous êtes invité à vous référer aux + + + {" "} + Politiques cookies{" "} + + + concernant l’utilisation par LECoffre.io des cookies. + +
+
+ ); +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/index.tsx index b7a6d200..78dbb8ff 100644 --- a/src/front/Components/Layouts/Legal/LegalInformations/index.tsx +++ b/src/front/Components/Layouts/Legal/LegalInformations/index.tsx @@ -1,34 +1,37 @@ +import DefaultLegalDashboard, { ELegalOptions } from "@Front/Components/LayoutTemplates/DefaultLegalDashboard"; import { useRouter } from "next/router"; import React from "react"; -import classes from "./classes.module.scss"; -import DefaultLegalDashboard, { ELegalOptions } from "@Front/Components/LayoutTemplates/DefaultLegalDashboard"; -import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import Link from "next/link"; -const pdfLinks: Record = { - "mentions-legales": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/mentions_legales.pdf", - "politique-de-confidentialite": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_confidentialite.pdf", - "politique-de-gestion-des-cookies": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_cookies.pdf", - cgs: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgs.pdf", - cgu: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgu.pdf", -}; +import PrivacyPolicy from "./PrivacyPolicy"; + +// const pdfLinks: Record = { +// "mentions-legales": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/mentions_legales.pdf", +// "politique-de-confidentialite": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_confidentialite.pdf", +// "politique-de-gestion-des-cookies": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_cookies.pdf", +// cgs: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgs.pdf", +// cgu: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgu.pdf", +// }; export default function LegalInformations() { const router = useRouter(); let { legalUid } = router.query; - const legalUidTyped = legalUid as ELegalOptions; - return ( - - - - Votre navigateur ne prend pas en charge l'affichage des pdf  - - - cliquez ici pour télécharger le pdf. - - - - - - ); + const legalType = legalUid as ELegalOptions; + return {getLegalInformationContent(legalType)}; +} + +function getLegalInformationContent(legalType: ELegalOptions) { + switch (legalType) { + case ELegalOptions.LEGAL_MENTIONS: + return "Mentions légales"; + case ELegalOptions.CGU: + return "CGU"; + case ELegalOptions.CGS: + return "CGS"; + case ELegalOptions.POLITIQUE_DE_CONFIDENTIALITE: + return ; + case ELegalOptions.POLITIQUE_DE_GESTION_DES_COOKIES: + return "Politique de gestion des cookies"; + default: + return null; + } } From aad5aebdef34241a596b07c9df2815ff4b884844 Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 12 Sep 2024 17:35:00 +0200 Subject: [PATCH 39/63] :sparkles: CGU --- .../Typography/classes.module.scss | 4 + .../DesignSystem/Typography/index.tsx | 14 +- .../LegalInformations/CGU/classes.module.scss | 14 + .../Legal/LegalInformations/CGU/index.tsx | 597 ++++++++++++++++++ .../LegalNotice/classes.module.scss | 14 + .../LegalInformations/LegalNotice/index.tsx | 48 ++ .../LegalInformations/PrivacyPolicy/index.tsx | 32 +- .../LegalInformations/elements}/Dot/index.tsx | 0 .../elements/LinkInline/index.tsx | 13 + .../Layouts/Legal/LegalInformations/index.tsx | 6 +- 10 files changed, 714 insertions(+), 28 deletions(-) create mode 100644 src/front/Components/Layouts/Legal/LegalInformations/CGU/classes.module.scss create mode 100644 src/front/Components/Layouts/Legal/LegalInformations/CGU/index.tsx create mode 100644 src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/classes.module.scss create mode 100644 src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/index.tsx rename src/front/Components/{Elements => Layouts/Legal/LegalInformations/elements}/Dot/index.tsx (100%) create mode 100644 src/front/Components/Layouts/Legal/LegalInformations/elements/LinkInline/index.tsx diff --git a/src/front/Components/DesignSystem/Typography/classes.module.scss b/src/front/Components/DesignSystem/Typography/classes.module.scss index f1085b81..cfa427e1 100644 --- a/src/front/Components/DesignSystem/Typography/classes.module.scss +++ b/src/front/Components/DesignSystem/Typography/classes.module.scss @@ -278,4 +278,8 @@ line-height: 15px; letter-spacing: -0.8px; } + + &.italic { + font-style: italic; + } } diff --git a/src/front/Components/DesignSystem/Typography/index.tsx b/src/front/Components/DesignSystem/Typography/index.tsx index dcdcfdd2..7d9a30e0 100644 --- a/src/front/Components/DesignSystem/Typography/index.tsx +++ b/src/front/Components/DesignSystem/Typography/index.tsx @@ -10,6 +10,7 @@ type IProps = { title?: string; type?: "div" | "span"; onClick?: () => void; + italic?: boolean; }; export enum ETypo { @@ -177,20 +178,27 @@ export enum ETypoColor { } export default function Typography(props: IProps) { - const { typo, color, className, title, children, type = "div", onClick } = props; + const { typo, color, className, title, children, type = "div", onClick, italic } = props; const style = color ? ({ "--data-color": `var(${color})` } as React.CSSProperties) : undefined; if (type === "span") { return ( - + {children} ); } return ( -
+
{children}
); diff --git a/src/front/Components/Layouts/Legal/LegalInformations/CGU/classes.module.scss b/src/front/Components/Layouts/Legal/LegalInformations/CGU/classes.module.scss new file mode 100644 index 00000000..1a8d89ee --- /dev/null +++ b/src/front/Components/Layouts/Legal/LegalInformations/CGU/classes.module.scss @@ -0,0 +1,14 @@ +.root { + width: 1056px; + padding: 24px; + + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + section { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + } +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/CGU/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/CGU/index.tsx new file mode 100644 index 00000000..e153301c --- /dev/null +++ b/src/front/Components/Layouts/Legal/LegalInformations/CGU/index.tsx @@ -0,0 +1,597 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import Dot from "@Front/Components/Layouts/Legal/LegalInformations/elements/Dot"; +import React from "react"; + +import classes from "./classes.module.scss"; +import Module from "@Front/Config/Module"; +import { ELegalOptions } from "@Front/Components/LayoutTemplates/DefaultLegalDashboard"; +import LinkInline from "../elements/LinkInline"; + +export default function CGU() { + return ( +
+
+ + Conditions Générales d'Utilisation + + + Version en vigueur à compter du 24 avril 2024 + + + Les présentes Conditions Générales d’Utilisation sont conclues entre LEcoffre.io, 2 Mail Anne-Catherine – 35000 Rennes, + Numéro Siret 92747436100015, TVA intracommunautaire FR17927474361, et l’Internaute. + + + Tout Internaute qui souhaite utiliser le Site + + (ci-après, le « Site ») dans sa version ordinateur ou mobile est réputé avoir pris connaissance des présentes conditions + générales d’utilisation (ci-après, les « CGU »). + + + Toute utilisation du Site nécessite la consultation et l’acceptation des présentes conditions générales. L’Internaute + reconnaît que l’utilisation du Site nécessite le respect de l’ensemble des prescriptions définies au sein des présentes. + + + Il est tenu à chaque visite de prendre connaissance d’éventuelles évolutions de ces dernières, LEcoffre.io se réservant + le droit de les modifier à tout moment. + + + Ces conditions générales d’utilisation ne sont pas des conditions générales de vente ou des conditions générales de + prestations de services. + + + Elles ont vocation à constituer la règle que doit respecter tout Internaute se rendant sur le Site LEcoffre.io + + + Dernière mise à jour le 24 avril 2024. + +
+ +
+ + 1. Définitions + + + Les termes ci-dessous définis auront entre les Parties la signification suivante : + + + « Internaute » : toute personne accédant et mettant en œuvre les fonctionnalités du Site ; + + « Parties » : désigne au singulier indistinctement Lecoffre.io ou l’Internaute, et au pluriel le LEcoffre.io et + l’Internaute ensemble ; + + + « Règlementation relative à la protection des données à caractère personnel » : ° la loi relative à l’informatique, + aux fichiers et aux libertés n° 78-17 du 6 janvier 1978 modifiée et ses mises à jour ou modification ; et + + + le Règlement (UE) 2016/679 du Parlement européen et du Conseil du 27 avril 2016 (règlement général sur la protection + des données) ; + + + « Site » : site Internet édité par LEcoffre.io accessible à + + + +
+ +
+ + 2. Description des services + + + Le Site permet un accès au service LECoffre.io qui est une plateforme en ligne, par abonnement, permettant le transfert + sécurisé de données et documents à destination des notaires et de leurs offices. + + + Le fait de déposer un document sur la plateforme entraîne donc la conservation temporaire des documents transmis. + + + Une fois le dossier complété et l'ensemble des documents nécessaires à la préparation d'un acte notarié réalisé, le + notaire peut obtenir l'ensemble des documents après que la plateforme lecoffre.io ait certifié l'origine du document via + l'identification de son émetteur et verrouillé l'état des documents par l'établissement d'un jeton unique + + + La technologie utilisée repose sur l'utilisation d’une technologie blockchain. + + + L’Internaute est invité à se référer aux + + concernant l’utilisation de la plateforme. + +
+ +
+ + 3. Entrée en vigueur – Durée + + + Les présentes conditions générales d’utilisation entrent en vigueur à la date de leur mise en ligne et seront opposables + à la date de la première utilisation du Site par l’Internaute. + + + Les présentes conditions d’utilisation sont opposables pendant toute la durée d’utilisation du Site et jusqu’à ce que de + nouvelles conditions générales d’utilisation remplacent les présentes. + + + L’Internaute peut à tout moment renoncer à utiliser le Site mais reste responsable de toute utilisation antérieure. + +
+ +
+ + 4. Objet des CGU + + + Les présentes CGU ont pour objet de présenter et de fixer les conditions d’utilisation du Site, et l’ensemble des pages + du Site. + + + L’Internaute déclare avoir pris connaissance et accepté les présentes conditions générales d’utilisation + +
+ +
+ + 5. Conditions d'accès + + + L’accès au Site est libre et gratuit pour tout Internaute disposant d'un accès à internet ou à un réseau mobile. Tous + les coûts afférents à l'accès, que ce soit les frais matériels, logiciels ou d'accès à internet sont exclusivement à la + charge de l'Utilisateur. Il est seul responsable du bon fonctionnement de son équipement mobile ainsi que de son accès à + internet. + + + LEcoffre.io s’efforce de fournir un accès de qualité et de permettre aux Internautes d'utiliser les moyens de + communication mis à leur disposition dans les meilleures conditions possibles. + + + En raison de la nature et de la complexité du réseau de l’Internet, et en particulier, de ses performances techniques et + des temps de réponse pour consulter, interroger ou transférer les données d’informations, LEcoffre.io fait ses meilleurs + efforts, conformément aux règles de l’art, pour permettre l’accès et l’utilisation du Site. LEcoffre.io ne saurait en + effet assurer une accessibilité ou une disponibilité absolue du Site. + + + Toutefois, LEcoffre.io se réserve le droit, sans préavis, ni indemnité, de fermer temporairement ou définitivement tout + ou partie du service notamment pour effectuer une mise à jour, des opérations de maintenance, des modifications ou + changements sur les méthodes opérationnelles et les serveurs, sans que cette liste ne soit limitative. + + + LEcoffre.io n'est pas responsable des dommages de toute nature qui peuvent résulter de ces changements ou d'une + indisponibilité temporaire ou encore de la fermeture définitive de tout ou partie du Site ou des services qui y sont + associés. + + + LEcoffre.io se réserve le droit de compléter ou de modifier, à tout moment, le Site et les services qui y sont + disponibles en fonction de l’évolution des technologies.{" "} + + + Il appartient à l’Internaute de veiller aux possibilités d’évolution des moyens informatiques et de transmission à sa + disposition pour que ces moyens puissent s’adapter aux évolutions du service. + +
+ +
+ + 6. Liens hypertextes + + + LEcoffre.io se réserve la possibilité de mettre en place des hyperliens sur son Site, donnant accès à des pages web + autres que celles de son Site sur lesquels LEcoffre.io n’exerce aucun contrôle. + + + LEcoffre.io décline toute responsabilité quant aux conditions d’accès à ces pages web, à leur fonctionnement, à leur + utilisation des données à caractère personnel des Internautes et quant au contenu des informations fournies sur ces + pages web au titre de l’activation des hyperliens. + + + L'Internaute qui dispose d’un site internet à titre personnel et désire placer, à des fins personnelles, sur son site un + lien simple renvoyant directement sur la page d’accueil du Site du LEcoffre.io, doit obtenir l’autorisation expresse de + LEcoffre.io pour établir ce lien. + + + En aucun cas, cette autorisation ne pourra être qualifiée de convention implicite d’affiliation. + + + En toute hypothèse, les liens hypertextes renvoyant au Site sans l’autorisation de LEcoffre.io devront être retirés à + première demande de LEcoffre.io. + +
+ +
+ + 7. Sécurité + + + LEcoffre.io fait ses meilleurs efforts, conformément aux règles de l’art, pour sécuriser le Site au regard du risque + encouru et de la nature des données traitées. Toutefois, LEcoffre.io ne saurait être responsable, s’agissant de ce + point, qu’en cas de faute prouvée imputable à cette dernière. Il ne saurait assurer une sécurité absolue. + + + Il est interdit à l’Internaute d'accéder ou de se maintenir, frauduleusement, dans tout ou partie du Site. Il s'interdit + d’utiliser une méthode d’accès autre que l’interface mise à disposition par LEcoffre.io. En cas de découverte d'une + telle méthode ou si l’Internaute entre dans un espace réservé, sans droit, par inadvertance, celui-ci s'engage à en + informer sans délai LEcoffre.io par courrier électronique à l’adresse (contact@lecoffre.io ) afin qu’il puisse prendre + les mesures nécessaires. + + + Il est interdit à l’Internaute de supprimer ou modifier des données contenues sur le Site qui n’auraient pas été + publiées par lui-même, ou d’y introduire frauduleusement des données ou même d’opérer une altération du fonctionnement + du Site. Il veille notamment à ne pas introduire de virus, code malveillant ou toute autre technologie nuisible au Site + + + Tout accès à un espace interdit sera considéré comme un accès frauduleux au sens des dispositions du Code pénal. + + + L’Internaute s’engage à considérer que toutes les données dont il aura eu connaissance à l’occasion d’un tel accès à un + espace non autorisé sont des données confidentielles et s’engage, en conséquence, à ne pas les divulguer. + + + L’Internaute s’interdit notamment de réaliser toute opération visant à saturer une page, les opérations de rebond ou + toute opération ayant pour conséquence d'entraver ou de fausser le fonctionnement du Site + + + L’Internaute s’engage à ne pas utiliser de dispositifs ou de logiciels de toutes sortes qui auraient pour conséquence de + perturber le bon fonctionnement du Site. + + + L’Internaute s’engage à ne pas engager d'action qui imposerait une charge disproportionnée sur les infrastructures du + Site. + + + L’Internaute accepte les caractéristiques et limites de l’internet. Il a conscience que les données circulant sur + l’internet ne sont pas nécessairement protégées, notamment contre les détournements éventuels. + + + L’Internaute prend les mesures appropriées pour assurer la sécurité de ses propres données et / ou logiciels de la + contamination par des éventuels virus sur le réseau internet. + +
+ +
+ + 8. Données à caractère personnel + + + LEcoffre.io déclare qu’il traite les données à caractère personnel conformément aux dispositions de la loi n°78-17 du 6 + janvier 1978 modifiée et du Règlement (UE) 2016/679 du 27 avril 2016 (RGPD). + + + L’Internaute est invité à se référer aux + + concernant l’utilisation par LECoffre.io des données à caractère personnel. + + + L’Internaute est invité à se référer aux + + concernant l’utilisation par LECoffre.io des cookies. + +
+ +
+ + 9. Responsabilité de LEcoffre.io + +
+ +
+ + 9.1. Responsabilité générale + + + La responsabilité de LECoffre.io ne pourra pas être retenue en cas de non-compatibilité du système d’information de + l’Office avec les Services proposés. + + + Pour des raisons de maintenance, ou du fait de tiers, l’accès et le fonctionnement, partiel ou total des Services + LECoffre.io, pourront être suspendus, sans que cette interruption puisse ouvrir droit à une quelconque indemnité au + bénéfice de l’Office ou de tout tiers ou constituer une cause de résiliation. + + + En cas d’interruption des Services LECoffre.io, l’éditeur mettra tous les moyens nécessaires en œuvre pour rétablir le + plus rapidement possible l’accès aux services, sauf si l’interruption résulte d’un défaut qui ne lui est pas imputable. + + + La responsabilité de LECoffre.io ne pourra être engagée sur le fondement d’une garantie de délai de traitement des + échanges dématérialisés. + + + LECoffre.io est un prestataire technique mettant en œuvre un processus d’échanges et d’archivage dématérialisés de + documents et de données. + + + Dans le cas de traitement d’anomalies techniques, LECoffre.io peut être amenée à analyser les aspects techniques + contenus dans les flux à l’exception de tout autre aspect tenant notamment à la validité de l’opération réalisée, aux + effets juridiques liés à l’opération, etc. + + + Dans l’hypothèse où la responsabilité de LECoffre.io se trouverait engagée, pour quelque cause que ce soit, au titre des + présentes conditions, la responsabilité de LECoffre.io est expressément limitée la sécurisation des données qui lui ont + été transmises par les utilisateurs, professionnels ou non, à l’exclusion de tous dommages indirects (notamment dommages + commerciaux et moraux, perte de chiffre d’affaires, perte de clientèle) qui seront exclus de la réparation due par + LECoffre.io. + +
+ +
+ + 9.2. Responsabilité à l’égard des informations présentes sur le Site + + + LEcoffre.io fait ses meilleurs efforts pour proposer sur son Site des informations à jour. + + + Toutes les informations portées à la connaissance des personnes accédant au Site ont été sélectionnées à une date + déterminée. Compte tenu de la nature et de la complexité des technologies qui sont mises en œuvre, chaque Partie + reconnaît que le Site ne peut être exempte d’Anomalies, de défaillances, d’interruptions et d’indisponibilités. + + + En cas de dysfonctionnement ou d’incident de quelque nature que ce soit lors de l’utilisation du Site, l’Internaute doit + en informer immédiatement LEcoffre.io. + + + LEcoffre.io ne saurait être tenue responsable de toute erreur ou omission. + + + Toute mise à jour, nouvelle prestation ou nouvelle caractéristique qui améliore ou augmente un ou plusieurs contenus + d’informations existants sera soumis aux présentes conditions. + + + Les équipements (notamment ordinateur, téléphone, logiciels, moyens de communication électronique) permettant l’accès et + l’utilisation au Site sont à la charge exclusive des Internautes, de même que les frais de communications électroniques + (notamment coûts téléphoniques, coûts d’accès à Internet) résultant de leur utilisation. + +
+ +
+ + 10. Responsabilités de l’Internaute + + + Dans le cadre des présentes CGU, l‘Internaute a été informé qu’il devait s’assurer : + + + du respect des préconisations techniques requises ; + + qu’il dispose de la compétence nécessaire et des informations suffisantes pour une utilisation optimale du Site. + + + + L’Internaute demeure intégralement et exclusivement responsable de l’exploitation des informations obtenues sur le Site.{" "} + + + De manière générale, chaque Internaute s’engage à utiliser le Site :{" "} + + + dans le respect des lois, réglementation et droits des tiers ; + + de manière loyale et conformément à sa destination, dans le respect des présentes CGU et de la Réglementation. + + +
+ +
+ + 11. Obligations de l’Internaute + + + L’Internaute s’engage à n’utiliser le Site ainsi que l’ensemble des informations auxquelles il pourra avoir accès que + pour obtenir des informations et dans un but conforme à l’ordre public, aux bonnes mœurs et aux droits des tiers.{" "} + + + Ainsi, il lui est interdit de publier ou de transmettre via le Site tout élément illicite, préjudiciable, diffamatoire, + pornographique, haineux, raciste ou autrement attentatoire à la dignité humaine notamment. Au cas où LEcoffre.io serait + informé de la présence de contenus illicites sur le Site, LEcoffre.io serait en droit d'en supprimer immédiatement le + contenu et empêcher l’accès au Site à l’Internaute. + + + L’Internaute s’engage, par ailleurs, à ne pas perturber l’usage que pourraient faire les autres Internautes du Site de + ne pas accéder à des Parties du Site dont l’accès est réservé. + +
+ +
+ + 12. Propriété intellectuelle + +
+ +
+ + 12.1 Propriété intellectuelle de LEcoffre.io + + + Le contenu du Site, la structure générale ainsi que les logiciels, textes, images animées ou non, photographies, son + savoir-faire et tous les autres éléments composant le Site sont la propriété exclusive de LEcoffre.io ou des tiers qui + lui ont concédé une licence. + + + L’ensemble des éléments du le Site, sont protégés par le droit d’auteur, le droit des marques, des dessins et modèles + et/ou tous autres droits de propriété intellectuelle. + + + Aucun titre ni droit quelconque sur aucun élément ou logiciel ne sera obtenu par téléchargement ou copie d’éléments de + ce Site. Il est formellement interdit à l’Internaute de reproduire (à part pour son utilisation personnelle et non + commerciale), publier, 7 éditer, transmettre, distribuer, montrer, enlever, supprimer, ajouter à ce Site et aux éléments + et logiciels qu’ils contiennent, pas plus que les modifier ou effectuer un quelconque travail en les prenant pour base, + ni vendre ou participer à aucune vente en rapport avec ce Site, les éléments de ce Site ni aucun logiciel y afférant. + + + L'Internaute s'interdit notamment de modifier, copier, reproduire, télécharger, diffuser, transmettre, exploiter + commercialement et/ou distribuer de quelque façon que ce soit les pages du Site, ou les codes informatiques des éléments + composant le Site. + + + Les présentes conditions générales d’utilisation n’emportent aucune cession d’aucune sorte de droit de propriété + intellectuelle sur les éléments appartenant à LEcoffre.io ou ayants droit tels que les sons, photographies, images, + textes littéraires, travaux artistiques, logiciels, marques, chartes graphiques, logos au bénéfice du consommateur. + + + LEcoffre.io concède à l’Internaute une licence non exclusive pour utiliser le Site. Cette licence est strictement + personnelle et ne peut en aucun cas être cédée ou transférée à quel que tiers que ce soit. La licence est concédée pour + la durée d’utilisation du Site. + + + Toute reproduction et/ou représentation, totale ou partielle d’un de ces droits, sans l’autorisation expresse de + LEcoffre.io, est interdite et constituerait une contrefaçon susceptible d'engager la responsabilité civile et pénale du + contrefacteur. + + + En conséquence, l'Internaute s'interdit tout agissement et tout acte susceptible de porter atteinte directement ou non + aux droits de propriété intellectuelle de LEcoffre.io. + + + Il en est de même des bases de données figurant, le cas échéant, sur le Site qui sont protégées par les articles du Code + de la propriété intellectuelle. Toute extraction ou réutilisation, totale ou partielle desdites bases et de leur contenu + est ainsi interdite sans l’autorisation préalable expresse de LEcoffre.io. + + + Seule une utilisation conforme à la destination de ce Site est autorisée. + + + Toute autre utilisation, non expressément autorisée par écrit et au préalable par LEcoffre.io, est prohibée et + constitutive de contrefaçon. + +
+ +
+ + 12.2 Propriété intellectuelle des tiers + + + Les éléments appartenant à des tiers, tels qu’extrait de films, marques, logo, images, textes, sons, sans que cette + liste ne soit exhaustive, sont la propriété exclusive de leur auteur et sont protégés à ce titre par le droit d’auteur, + le droit des marques ou tout autre droit reconnu par les lois en vigueur. + + + L'Utilisateur s'interdit de porter atteinte, directement ou indirectement, au droit de propriété de tiers, dont les + contenus sont présents sur le Site et s'interdit d'exploiter ces éléments de quelque manière que ce soit. + + + L'Utilisateur s'engage à respecter l'intégralité des droits de tiers, dont les contenus sont présents sur le Site. + +
+ +
+ + 13. Tolérance + + + L’Utilisateur convient que le fait pour LEcoffre.io de tolérer une situation n’a pas pour effet d’accorder à + l’utilisateur des droits acquis. + + + De plus, une telle tolérance ne peut être interprétée comme une renonciation à faire valoir les droits en cause. + +
+ +
+ + 14. Titres + + + En cas de difficultés d’interprétation résultant d’une contradiction entre l’un quelconque des titres figurant en tête + des clauses et l’une quelconque des clauses, les titres seront déclarés inexistants. + +
+ +
+ + 15. Nullité + + + Si une ou plusieurs stipulations des présentes conditions générales d’utilisation sont tenues pour non valides ou + déclarées comme telles en application d’une loi, d’un règlement ou à la suite d’une décision passée en force de chose + jugée d’une juridiction compétente, les autres stipulations garderont toute leur force et leur portée. + +
+ +
+ + 16. Domiciliation + + + Pour l’exécution de la présente convention et sauf dispositions particulières, l’Internaute convient d’adresser toute + correspondance à l’adresse postale de LEcoffre.io : 2, Mail Anne Catherine, 35000 Rennes + +
+ +
+ + 17. Langues et compétences + + + Les présentes Conditions générales d’utilisation ont été initialement rédigées en français. + + + La version française prévaudra sur toute autre traduction en cas de contestation, litige, difficulté d'interprétation ou + d'exécution des présentes Conditions. + +
+ +
+ + 18. Litige + + + Compte tenu de la dimension mondiale du réseau Internet, nous vous informons qu'il faut vous conformer à toutes les + règles applicables dans le pays dans lequel vous résidez. + + + Les présentes conditions générales d’utilisation du Site sont régies par la loi française. + + + En cas de litige lié à l’interprétation, la validité et les conséquences des présentes CGU et, à défaut de solution + amiable préalable, les tribunaux de Rennes seront seuls compétents. + + + Il en est ainsi pour les règles de fond et les règles de forme et ce, nonobstant les lieux d’exécution des obligations + substantielles ou accessoires. + +
+ +
+ + QUESTIONS ? PROBLÈMES ? SUGGESTIONS ? + + + + Nous vous prions de nous contacter à : (contact@lecoffre.io) ou par courrier à LEcoffre.io, 2, Mail Anne-Catherine – + 35000 Rennes, France, afin de signaler toute violation des conditions générales d’utilisation ou pour poser toute + question concernant les CGU, + + et/ou le Site. + +
+
+ ); +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/classes.module.scss b/src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/classes.module.scss new file mode 100644 index 00000000..1a8d89ee --- /dev/null +++ b/src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/classes.module.scss @@ -0,0 +1,14 @@ +.root { + width: 1056px; + padding: 24px; + + display: flex; + flex-direction: column; + gap: var(--spacing-xl, 32px); + + section { + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + } +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/index.tsx new file mode 100644 index 00000000..9e271e65 --- /dev/null +++ b/src/front/Components/Layouts/Legal/LegalInformations/LegalNotice/index.tsx @@ -0,0 +1,48 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import React from "react"; + +import classes from "./classes.module.scss"; + +export default function LegalNotice() { + return ( +
+
+ + Mentions Légales + + + Version en vigueur à compter du 10 avril 2024 + + + + L’éditeur du Site est SMARTCHAIN, dont le siège social est situé au 23 RUE TAITBOUT, 75009 PARIS 9 avec un capital + social de 10 000,00 Euros. +
+ N° RCS : 851 103 267 R.C.S. Paris +
+ Tel : 06 63 84 83 45 +
+ N° individuel / d’identification de TVA : FR56851103267 +
+ + + Directeur de la publication : Konstantin Grouzdev + + + + Hébergement du Site : SMARTCHAIN +
+ Adresse : 23 RUE TAITBOUT, 75009 PARIS 9 +
+ Représentée par Konstantin Grouzdev - Téléphone 06 63 84 83 45 - Site Internet +
+ + + https://www.lecoffre.io/ + + +
+
+
+ ); +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx index 27d4295e..f4be0452 100644 --- a/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx +++ b/src/front/Components/Layouts/Legal/LegalInformations/PrivacyPolicy/index.tsx @@ -1,10 +1,11 @@ import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; -import Dot from "@Front/Components/Elements/Dot"; +import Dot from "@Front/Components/Layouts/Legal/LegalInformations/elements/Dot"; import React from "react"; import classes from "./classes.module.scss"; import Module from "@Front/Config/Module"; import { ELegalOptions } from "@Front/Components/LayoutTemplates/DefaultLegalDashboard"; +import LinkInline from "../elements/LinkInline"; export default function PrivacyPolicy() { return ( @@ -13,7 +14,7 @@ export default function PrivacyPolicy() { Politique de confidentialité - + Version en vigueur à compter du 24 avril 2024 @@ -204,12 +205,7 @@ export default function PrivacyPolicy() { Vous disposez du droit d’accéder et de faire rectifier vos données personnelles, que vous pouvez exercer auprès de LEcoffre.io par voie électronique à l’adresse - - - {" "} - contact@lecoffre.io{" "} - - + ou par courrier postal à l’adresse LEcoffre.io – 2, Mail Anne-Catherine – 35000 Rennes. @@ -337,13 +333,8 @@ export default function PrivacyPolicy() { Si vous considérez que LEcoffre.io ne respecte pas ses obligations au regard de vos données à caractère personnel, vous pouvez adresser une plainte ou une demande auprès de l’autorité compétente. En France, l’autorité compétente est la Cnil - à laquelle vous pouvez adresser une demande par voie électronique en cliquant sur le lien suivant - - - {" "} - https://www.cnil.fr/fr/plaintes/internet.{" "} - - + à laquelle vous pouvez adresser une demande par voie électronique en cliquant sur le lien suivant{" "} + @@ -368,20 +359,15 @@ export default function PrivacyPolicy() { Vous êtes invité à vous référer aux - - - {" "} - Politiques cookies{" "} - - + /> concernant l’utilisation par LECoffre.io des cookies. diff --git a/src/front/Components/Elements/Dot/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/elements/Dot/index.tsx similarity index 100% rename from src/front/Components/Elements/Dot/index.tsx rename to src/front/Components/Layouts/Legal/LegalInformations/elements/Dot/index.tsx diff --git a/src/front/Components/Layouts/Legal/LegalInformations/elements/LinkInline/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/elements/LinkInline/index.tsx new file mode 100644 index 00000000..34d012ac --- /dev/null +++ b/src/front/Components/Layouts/Legal/LegalInformations/elements/LinkInline/index.tsx @@ -0,0 +1,13 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import React from "react"; + +export default function LinkInline({ text, href }: { text: string; href: string }) { + return ( + + + {" "} + {text}{" "} + + + ); +} diff --git a/src/front/Components/Layouts/Legal/LegalInformations/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/index.tsx index 78dbb8ff..d7201c9c 100644 --- a/src/front/Components/Layouts/Legal/LegalInformations/index.tsx +++ b/src/front/Components/Layouts/Legal/LegalInformations/index.tsx @@ -3,6 +3,8 @@ import { useRouter } from "next/router"; import React from "react"; import PrivacyPolicy from "./PrivacyPolicy"; +import LegalNotice from "./LegalNotice"; +import CGU from "./CGU"; // const pdfLinks: Record = { // "mentions-legales": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/mentions_legales.pdf", @@ -22,9 +24,9 @@ export default function LegalInformations() { function getLegalInformationContent(legalType: ELegalOptions) { switch (legalType) { case ELegalOptions.LEGAL_MENTIONS: - return "Mentions légales"; + return ; case ELegalOptions.CGU: - return "CGU"; + return ; case ELegalOptions.CGS: return "CGS"; case ELegalOptions.POLITIQUE_DE_CONFIDENTIALITE: From b6875ff609998dd23b3f02390c7f832baf437a9c Mon Sep 17 00:00:00 2001 From: Max S Date: Thu, 12 Sep 2024 17:37:35 +0200 Subject: [PATCH 40/63] :hammer: restore pdf for cgs et cookie policy for now --- .../Layouts/Legal/LegalInformations/index.tsx | 47 ++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/front/Components/Layouts/Legal/LegalInformations/index.tsx b/src/front/Components/Layouts/Legal/LegalInformations/index.tsx index d7201c9c..1eced150 100644 --- a/src/front/Components/Layouts/Legal/LegalInformations/index.tsx +++ b/src/front/Components/Layouts/Legal/LegalInformations/index.tsx @@ -1,18 +1,21 @@ +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import DefaultLegalDashboard, { ELegalOptions } from "@Front/Components/LayoutTemplates/DefaultLegalDashboard"; +import Link from "next/link"; import { useRouter } from "next/router"; import React from "react"; -import PrivacyPolicy from "./PrivacyPolicy"; -import LegalNotice from "./LegalNotice"; import CGU from "./CGU"; +import classes from "./classes.module.scss"; +import LegalNotice from "./LegalNotice"; +import PrivacyPolicy from "./PrivacyPolicy"; -// const pdfLinks: Record = { -// "mentions-legales": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/mentions_legales.pdf", -// "politique-de-confidentialite": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_confidentialite.pdf", -// "politique-de-gestion-des-cookies": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_cookies.pdf", -// cgs: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgs.pdf", -// cgu: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgu.pdf", -// }; +const pdfLinks: Record = { + "mentions-legales": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/mentions_legales.pdf", + "politique-de-confidentialite": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_confidentialite.pdf", + "politique-de-gestion-des-cookies": "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/politique_cookies.pdf", + cgs: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgs.pdf", + cgu: "https://s3.fr-par.scw.cloud/lecoffre.io-bucket/footer/cgu.pdf", +}; export default function LegalInformations() { const router = useRouter(); @@ -28,11 +31,33 @@ function getLegalInformationContent(legalType: ELegalOptions) { case ELegalOptions.CGU: return ; case ELegalOptions.CGS: - return "CGS"; + return ( + + + Votre navigateur ne prend pas en charge l'affichage des pdf  + + + cliquez ici pour télécharger le pdf. + + + + + ); case ELegalOptions.POLITIQUE_DE_CONFIDENTIALITE: return ; case ELegalOptions.POLITIQUE_DE_GESTION_DES_COOKIES: - return "Politique de gestion des cookies"; + return ( + + + Votre navigateur ne prend pas en charge l'affichage des pdf  + + + cliquez ici pour télécharger le pdf. + + + + + ); default: return null; } From d6456199cf7b96add3a025d540959cfab335d0f2 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 12:19:18 +0200 Subject: [PATCH 41/63] :sparkles: add toaster and fix count email reminder --- .../Api/LeCoffreApi/Notary/Folders/Folders.ts | 1 + .../DeleteAskedDocumentModal/index.tsx | 2 ++ .../DeleteSentDocumentModal/index.tsx | 2 ++ .../EmailReminder/ReminderModal/index.tsx | 9 ++++-- .../ClientView/EmailReminder/index.tsx | 32 +++++++++++-------- .../Layouts/Folder/SendDocuments/index.tsx | 3 +- src/front/Components/Layouts/Folder/index.tsx | 1 + 7 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts b/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts index b7aa1342..ef7ad713 100644 --- a/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts +++ b/src/front/Api/LeCoffreApi/Notary/Folders/Folders.ts @@ -8,6 +8,7 @@ export interface IGetFoldersParams { select?: {}; where?: {}; include?: {}; + orderBy?: {}; }; } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx index 87d2586a..e43a3e1d 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteAskedDocumentModal/index.tsx @@ -1,5 +1,6 @@ import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents"; import Modal from "@Front/Components/DesignSystem/Modal"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import React, { useCallback } from "react"; @@ -18,6 +19,7 @@ export default function DeleteAskedDocumentModal(props: IProps) { Documents.getInstance() .delete(documentUid) .then(() => onDeleteSuccess(documentUid)) + .then(() => ToasterService.getInstance().success({ title: "Succès !", description: "Le document a été supprimé avec succès." })) .then(onClose) .catch((error) => console.warn(error)), [documentUid, onClose, onDeleteSuccess], diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx index 72fed16e..e3d6296e 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/DeleteSentDocumentModal/index.tsx @@ -1,5 +1,6 @@ import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; import Modal from "@Front/Components/DesignSystem/Modal"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import React, { useCallback } from "react"; @@ -18,6 +19,7 @@ export default function DeleteSentDocumentModal(props: IProps) { DocumentsNotary.getInstance() .delete(documentUid) .then(() => onDeleteSuccess(documentUid)) + .then(() => ToasterService.getInstance().success({ title: "Succès !", description: "Le document a été supprimé avec succès." })) .then(onClose) .catch((error) => console.warn(error)), [documentUid, onClose, onDeleteSuccess], diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx index 5c540d68..13629989 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx @@ -8,6 +8,7 @@ import React, { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; type IProps = { isOpen: boolean; @@ -22,9 +23,11 @@ export default function ReminderModal(props: IProps) { const [isAllSelected, setIsAllSelected] = useState(false); const onRemind = useCallback(() => { - Customers.getInstance().sendReminder(customer.uid!, selectedOptions.map((option) => option.value) as string[]); - onRemindSuccess(); - onClose?.(); + Customers.getInstance() + .sendReminder(customer.uid!, selectedOptions.map((option) => option.value) as string[]) + .then(onRemindSuccess) + .then(() => ToasterService.getInstance().success({ title: "Succès !", description: "La relance a été envoyée avec succès." })) + .then(onClose); }, [customer.uid, onClose, onRemindSuccess, selectedOptions]); const documentsOptions: IOption[] = useMemo( diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index ca9155d2..54a5069b 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -9,7 +9,7 @@ import Customer from "le-coffre-resources/dist/Customer"; import { DocumentReminder } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; import { useRouter } from "next/router"; -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import ReminderModal from "./ReminderModal"; @@ -26,22 +26,33 @@ export default function EmailReminder(props: IProps) { const { isOpen, open, close } = useOpenable(); const router = useRouter(); + let { folderUid } = router.query; + const fetchReminders = useCallback(async () => { + if (!customer.uid || !folderUid) return; DocumentReminders.getInstance() .get({ - where: { document: { depositor: { uid: customer.uid } } }, + where: { document: { depositor: { uid: customer.uid }, folder: { uid: folderUid } } }, include: { document: "true" }, orderBy: { reminder_date: "desc" }, }) .then((reminders) => setReminders(reminders)) .catch((e) => console.warn(e)); - }, [customer.uid]); + }, [customer.uid, folderUid]); useEffect(() => { fetchReminders(); }, [fetchReminders]); - let { folderUid } = router.query; + // count the number of reminders group by reminder_date rounded at seconde + const remindersLength = useMemo(() => { + const remindersGroupByDate = reminders?.reduce((acc, reminder) => { + const reminderDate = new Date(reminder.reminder_date!).setSeconds(0, 0); + acc[reminderDate] = acc[reminderDate] ? acc[reminderDate] + 1 : 1; + return acc; + }, {} as Record); + return Object.keys(remindersGroupByDate ?? {}).length; + }, [reminders]); return (
@@ -68,21 +79,14 @@ export default function EmailReminder(props: IProps) {
Dernière relance:{" "} - {reminders && reminders.length > 0 ? new Date(reminders[0]!.reminder_date!).toLocaleDateString() : "-"} + {reminders && remindersLength > 0 ? new Date(reminders[0]!.reminder_date!).toLocaleDateString() : "-"} - Nombre de relance: {reminders && reminders.length > 0 ? reminders.length : "0"} + Nombre de relance: {remindersLength}
- { - window.location.reload(); - }} - onClose={close} - customer={customer} - /> +
); } diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx index 0449d17e..d9691b84 100644 --- a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -16,6 +16,7 @@ import { useRouter } from "next/router"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; enum EClientSelection { ALL_CLIENTS = "all_clients", @@ -68,7 +69,7 @@ export default function SendDocuments() { .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid as string), ); setIsSending(false); - console.log("All files have been successfully sent."); + ToasterService.getInstance().success({ title: "Succès !", description: "Votre document a été envoyée avec succès." }); } catch (error) { setIsSending(false); console.error("Error while sending files: ", error); diff --git a/src/front/Components/Layouts/Folder/index.tsx b/src/front/Components/Layouts/Folder/index.tsx index c7e2dd5e..a3f4ca4b 100644 --- a/src/front/Components/Layouts/Folder/index.tsx +++ b/src/front/Components/Layouts/Folder/index.tsx @@ -27,6 +27,7 @@ export default function Folder() { .get({ q: { where: { status: EFolderStatus.LIVE }, + orderBy: { created_at: "desc" }, }, }) .then((folders) => { From 3044bc16085672ef377c169a5d2c91effed2ba64 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 13:09:51 +0200 Subject: [PATCH 42/63] :hammer: handle better fetching documents in documents tables --- .../ClientView/DocumentTables/index.tsx | 60 +++++++++++++------ .../FolderInformation/ClientView/index.tsx | 18 +----- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index a9b191d4..959a3c93 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -19,10 +19,13 @@ import classes from "./classes.module.scss"; import DeleteAskedDocumentModal from "./DeleteAskedDocumentModal"; import DeleteSentDocumentModal from "./DeleteSentDocumentModal"; import FilesNotary from "@Front/Api/LeCoffreApi/Notary/FilesNotary/Files"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; + +import NoDocument from "../NoDocument"; +import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents"; type IProps = { - documents: Document[]; - documentsNotary: DocumentNotary[]; + customerUid: string; folderUid: string; }; @@ -34,23 +37,46 @@ const tradDocumentStatus: Record = { }; export default function DocumentTables(props: IProps) { - const { documents: documentsProps, folderUid, documentsNotary } = props; - const [documents, setDocuments] = useState(documentsProps); - const [documentUid, setDocumentUid] = useState(null); + const { folderUid, customerUid } = props; + const [documents, setDocuments] = useState([]); + const [documentsNotary, setDocumentsNotary] = useState([]); + const [focusedDocumentUid, setFocusedDocumentUid] = useState(null); const isMobile = useMediaQuery("(max-width:524px)"); const deleteAskedDocumentModal = useOpenable(); const deleteSentDocumentModal = useOpenable(); + const fetchDocuments = useCallback( + () => + Documents.getInstance() + .get({ + where: { folder: { uid: folderUid }, depositor: { uid: customerUid } }, + include: { files: true, document_type: true }, + }) + .then(setDocuments) + .catch(console.warn), + [customerUid, folderUid], + ); + + const fetchDocumentsNotary = useCallback( + () => + DocumentsNotary.getInstance() + .get({ where: { folder: { uid: folderUid }, customer: { uid: customerUid } }, include: { files: true } }) + .then(setDocumentsNotary) + .catch(console.warn), + [customerUid, folderUid], + ); + useEffect(() => { - setDocuments(documentsProps); - }, [documentsProps]); + fetchDocuments(); + fetchDocumentsNotary(); + }, [fetchDocuments, fetchDocumentsNotary]); const openDeleteAskedDocumentModal = useCallback( (uid: string | undefined) => { if (!uid) return; - setDocumentUid(uid); + setFocusedDocumentUid(uid); deleteAskedDocumentModal.open(); }, [deleteAskedDocumentModal], @@ -59,7 +85,7 @@ export default function DocumentTables(props: IProps) { const openDeleteSentDocumentModal = useCallback( (uid: string | undefined) => { if (!uid) return; - setDocumentUid(uid); + setFocusedDocumentUid(uid); deleteSentDocumentModal.open(); }, [deleteSentDocumentModal], @@ -237,9 +263,9 @@ export default function DocumentTables(props: IProps) { return (validatedDocuments.length / total) * 100; }, [askedDocuments.length, refusedDocuments.length, toValidateDocuments.length, validatedDocuments.length]); - const handleDelete = useCallback((_documentUid: string) => { - window.location.reload(); - }, []); + console.log({ documents }); + + if (documents.length === 0 && documentsNotary.length === 0) return ; return (
@@ -254,19 +280,19 @@ export default function DocumentTables(props: IProps) { {validatedDocuments.length > 0 &&
} {refusedDocuments.length > 0 &&
} {sentDocuments.length > 0 &&
} - {documentUid && ( + {focusedDocumentUid && ( <> )} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index 17b5cc49..2608b960 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -1,4 +1,3 @@ -import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Tabs from "@Front/Components/Elements/Tabs"; @@ -7,16 +6,14 @@ import { DocumentIcon, UserPlusIcon } from "@heroicons/react/24/outline"; import Customer from "le-coffre-resources/dist/Customer"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; -import { DocumentNotary } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; -import { useCallback, useEffect, useMemo, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { AnchorStatus } from ".."; import classes from "./classes.module.scss"; import ClientBox from "./ClientBox"; import DocumentTables from "./DocumentTables"; import EmailReminder from "./EmailReminder"; -import NoDocument from "./NoDocument"; type IProps = { folder: OfficeFolder; @@ -27,7 +24,6 @@ export type ICustomer = Customer & { id: string }; export default function ClientView(props: IProps) { const { folder, anchorStatus } = props; - const [documentsNotary, setDocumentsNotary] = useState([]); const customers: ICustomer[] = useMemo( () => @@ -77,12 +73,6 @@ export default function ClientView(props: IProps) { [folder], ); - useEffect(() => { - DocumentsNotary.getInstance() - .get({ where: { folder: { uid: folder.uid }, customer: { uid: customer.uid } }, include: { files: true } }) - .then((documentsNotary) => setDocumentsNotary(documentsNotary)); - }, [customer.uid, folder]); - return (
@@ -132,11 +122,7 @@ export default function ClientView(props: IProps) {
- {doesCustomerHaveDocument || documentsNotary.length > 0 ? ( - - ) : ( - - )} + {customer.uid && folder.uid && }
); From 1790cd51d6ea106af364216304f55b81a73c22d0 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 13:10:14 +0200 Subject: [PATCH 43/63] remove console.log() --- .../ClientView/DocumentTables/index.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index 959a3c93..e38aacf4 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -1,4 +1,7 @@ +import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; import Files from "@Front/Api/LeCoffreApi/Notary/Files/Files"; +import FilesNotary from "@Front/Api/LeCoffreApi/Notary/FilesNotary/Files"; import CircleProgress from "@Front/Components/DesignSystem/CircleProgress"; import IconButton from "@Front/Components/DesignSystem/IconButton"; import Table from "@Front/Components/DesignSystem/Table"; @@ -15,14 +18,10 @@ import { DocumentNotary } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; import { useCallback, useEffect, useMemo, useState } from "react"; +import NoDocument from "../NoDocument"; import classes from "./classes.module.scss"; import DeleteAskedDocumentModal from "./DeleteAskedDocumentModal"; import DeleteSentDocumentModal from "./DeleteSentDocumentModal"; -import FilesNotary from "@Front/Api/LeCoffreApi/Notary/FilesNotary/Files"; -import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; - -import NoDocument from "../NoDocument"; -import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents"; type IProps = { customerUid: string; @@ -263,8 +262,6 @@ export default function DocumentTables(props: IProps) { return (validatedDocuments.length / total) * 100; }, [askedDocuments.length, refusedDocuments.length, toValidateDocuments.length, validatedDocuments.length]); - console.log({ documents }); - if (documents.length === 0 && documentsNotary.length === 0) return ; return ( From 68468f7793f805d635218d3357523ca166757075 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 13:26:15 +0200 Subject: [PATCH 44/63] :hammer: disabled email reminder button when validated documents --- .../EmailReminder/ReminderModal/index.tsx | 19 +++++++++++-------- .../ClientView/EmailReminder/index.tsx | 11 ++++++++--- .../FolderInformation/ClientView/index.tsx | 3 --- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx index 13629989..4da1f326 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx @@ -1,14 +1,15 @@ +import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; import CheckBox from "@Front/Components/DesignSystem/CheckBox"; import { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import Modal from "@Front/Components/DesignSystem/Modal"; import Separator, { ESeperatorColor } from "@Front/Components/DesignSystem/Separator"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Customer from "le-coffre-resources/dist/Customer"; +import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import React, { useCallback, useMemo, useState } from "react"; import classes from "./classes.module.scss"; -import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; -import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; type IProps = { isOpen: boolean; @@ -32,12 +33,14 @@ export default function ReminderModal(props: IProps) { const documentsOptions: IOption[] = useMemo( () => - customer.documents?.map((document) => { - return { - label: document.document_type?.name ?? "", - value: document.uid ?? "", - }; - }) ?? [], + customer.documents + ?.filter((document) => document.document_status !== EDocumentStatus.VALIDATED) + .map((document) => { + return { + label: document.document_type?.name ?? "", + value: document.uid ?? "", + }; + }) ?? [], [customer], ); diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index 54a5069b..bedb14b4 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -13,15 +13,15 @@ import { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import ReminderModal from "./ReminderModal"; +import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; type IProps = { customer: Customer; - doesCustomerHaveDocument: boolean; isAnchored: boolean; }; export default function EmailReminder(props: IProps) { - const { customer, doesCustomerHaveDocument, isAnchored } = props; + const { customer, isAnchored } = props; const [reminders, setReminders] = useState(null); const { isOpen, open, close } = useOpenable(); const router = useRouter(); @@ -54,6 +54,11 @@ export default function EmailReminder(props: IProps) { return Object.keys(remindersGroupByDate ?? {}).length; }, [reminders]); + const doesCustomerHaveNotValidatedDocuments = useMemo( + () => customer.documents && customer.documents.some((document) => document.document_status !== EDocumentStatus.VALIDATED), + [customer.documents], + ); + return (
{!isAnchored && ( @@ -63,7 +68,7 @@ export default function EmailReminder(props: IProps) { variant={EButtonVariant.PRIMARY} styletype={EButtonstyletype.OUTLINED} fullwidth - disabled={doesCustomerHaveDocument}> + disabled={!doesCustomerHaveNotValidatedDocuments}> Relancer par mail )} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index 2608b960..22b7effa 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -56,8 +56,6 @@ export default function ClientView(props: IProps) { [customers], ); - const doesCustomerHaveDocument = useMemo(() => customer.documents && customer.documents.length > 0, [customer]); - const handleClientDelete = useCallback( (customerUid: string) => { if (!folder.uid) return; @@ -116,7 +114,6 @@ export default function ClientView(props: IProps) { )}
From a9ce560a1b550df88d6fd64d176bf6cc59383e6c Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 15:58:36 +0200 Subject: [PATCH 45/63] :sparkles: add error message when no client selected --- .../Form/AutocompleteField/index.tsx | 2 ++ .../AutocompleteMultiSelectField/index.tsx | 2 ++ .../DesignSystem/Form/SelectField/index.tsx | 3 +++ .../Layouts/Folder/SendDocuments/index.tsx | 21 +++++++++++++++++-- 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx b/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx index d774c9ac..28109308 100644 --- a/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx +++ b/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx @@ -34,6 +34,8 @@ export default class AutocompleteField extends BaseField { }; public override componentDidUpdate(prevProps: IProps): void { + super.componentDidUpdate(prevProps); + if (prevProps.selectedOption !== this.props.selectedOption) { this.setState({ selectedOption: this.props.selectedOption ?? null }); } diff --git a/src/front/Components/DesignSystem/Form/AutocompleteMultiSelectField/index.tsx b/src/front/Components/DesignSystem/Form/AutocompleteMultiSelectField/index.tsx index be59f164..95b468a6 100644 --- a/src/front/Components/DesignSystem/Form/AutocompleteMultiSelectField/index.tsx +++ b/src/front/Components/DesignSystem/Form/AutocompleteMultiSelectField/index.tsx @@ -34,6 +34,8 @@ export default class AutocompleteMultiSelectField extends BaseField { }; public override componentDidUpdate(prevProps: IProps): void { + super.componentDidUpdate(prevProps); + + if (prevProps.selectedOption !== this.props.selectedOption) { this.setState({ selectedOption: this.props.selectedOption ?? null }); } diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx index d9691b84..4bbed888 100644 --- a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -17,6 +17,9 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; +import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; +import { ValidationError } from "class-validator"; +import TextField from "@Front/Components/DesignSystem/Form/TextField"; enum EClientSelection { ALL_CLIENTS = "all_clients", @@ -31,6 +34,7 @@ export default function SendDocuments() { const [selectedClients, setSelectedClients] = useState([]); const [files, setFiles] = useState([]); const [isSending, setIsSending] = useState(false); + const [validationError, setValidationError] = useState(null); const onFormSubmit = useCallback( async ( @@ -46,6 +50,17 @@ export default function SendDocuments() { try { setIsSending(true); + + if (selectedClients.length === 0) { + setValidationError({ + property: "clients", + constraints: { + isEmpty: "Veuillez sélectionner au moins un client", + }, + }); + throw new Error("No clients selected"); + } + await Promise.all( selectedClients.map(async (customer) => { const promises = files.map(async (file) => { @@ -72,7 +87,7 @@ export default function SendDocuments() { ToasterService.getInstance().success({ title: "Succès !", description: "Votre document a été envoyée avec succès." }); } catch (error) { setIsSending(false); - console.error("Error while sending files: ", error); + console.warn("Error while sending files: ", error); } }, [files, folderUid, router, selectedClients], @@ -163,10 +178,12 @@ export default function SendDocuments() {
{clientSelection === EClientSelection.SELECTED_CLIENTS && ( - )} {clientSelection && ( From 9dd57124c64d3e064146a41ade6e398a7007881c Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 16:12:36 +0200 Subject: [PATCH 46/63] :sparkles: add toaster when client upload file --- .../DepositDocumentComponent/index.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx index 943361af..37448dbd 100644 --- a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx @@ -5,6 +5,7 @@ import { useCallback, useMemo } from "react"; import classes from "./classes.module.scss"; import Files from "@Front/Api/LeCoffreApi/Customer/Files/Files"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; type IProps = { document: Document; @@ -29,14 +30,22 @@ export default function DepositDocumentComponent(props: IProps) { formData.append("file", file, file.name); const query = JSON.stringify({ document: { uid: document.uid } }); formData.append("q", query); - return Files.getInstance().post(formData).then(onChange); + return Files.getInstance() + .post(formData) + .then(onChange) + .then(() => ToasterService.getInstance().success({ title: "Succès !", description: "Fichier uploadé avec succès!" })) + .catch((error) => ToasterService.getInstance().error({ title: "Erreur !", description: error.message })); }, [document.uid, onChange], ); const deleteFile = useCallback( (filedUid: string) => { - return Files.getInstance().delete(filedUid).then(onChange); + return Files.getInstance() + .delete(filedUid) + .then(onChange) + .then(() => ToasterService.getInstance().success({ title: "Succès !", description: "Fichier supprimé avec succès!" })) + .catch((error) => ToasterService.getInstance().error({ title: "Erreur !", description: error.message })); }, [onChange], ); From 4243262b6b9604c51255030f5c8a700730d89402 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 17:29:34 +0200 Subject: [PATCH 47/63] chore: Refactor email reminder count logic and handle empty reminders list --- .../ClientView/EmailReminder/index.tsx | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index bedb14b4..9992aa4e 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -44,14 +44,26 @@ export default function EmailReminder(props: IProps) { fetchReminders(); }, [fetchReminders]); - // count the number of reminders group by reminder_date rounded at seconde const remindersLength = useMemo(() => { - const remindersGroupByDate = reminders?.reduce((acc, reminder) => { - const reminderDate = new Date(reminder.reminder_date!).setSeconds(0, 0); - acc[reminderDate] = acc[reminderDate] ? acc[reminderDate] + 1 : 1; + // Vérifie que la liste `reminders` n'est pas vide ou null + if (!reminders || reminders.length === 0) { + return 0; + } + + const remindersGroupByDate = reminders.reduce((acc, reminder) => { + // Vérifie si `reminder_date` est bien défini + if (!reminder.reminder_date) return acc; + + // Normalise la date à la seconde près + const reminderDate = new Date(reminder.reminder_date).setMilliseconds(0); + + // Initialise ou incrémente le compteur + acc[reminderDate] = (acc[reminderDate] || 0) + 1; return acc; }, {} as Record); - return Object.keys(remindersGroupByDate ?? {}).length; + + // Retourne la longueur des clés, représentant le nombre de dates uniques + return Object.keys(remindersGroupByDate).length; }, [reminders]); const doesCustomerHaveNotValidatedDocuments = useMemo( From 7774488be73bcf7769e7aaaed8b2aadd64843515 Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 13 Sep 2024 17:30:44 +0200 Subject: [PATCH 48/63] remove unused import --- .../Components/Layouts/Folder/SendDocuments/index.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx index 4bbed888..0f743d79 100644 --- a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -1,25 +1,23 @@ import backgroundImage from "@Assets/images/background_refonte.svg"; import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; -import AutocompleteMultiSelect from "@Front/Components/DesignSystem/AutocompleteMultiSelect"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import DragAndDrop from "@Front/Components/DesignSystem/DragAndDrop"; import Form from "@Front/Components/DesignSystem/Form"; +import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import Module from "@Front/Config/Module"; import { PaperAirplaneIcon } from "@heroicons/react/24/outline"; +import { ValidationError } from "class-validator"; import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { useRouter } from "next/router"; import React, { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; -import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; -import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; -import { ValidationError } from "class-validator"; -import TextField from "@Front/Components/DesignSystem/Form/TextField"; enum EClientSelection { ALL_CLIENTS = "all_clients", From 7d8653ae982c349eb3b9ceb39e746c20cf0e076d Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 16 Sep 2024 11:40:32 +0200 Subject: [PATCH 49/63] :hammer: design review --- .../classes.module.scss | 3 +-- .../Folder/DocumentsReminderHistory/index.tsx | 20 +++++++++++++------ .../EmailReminder/ReminderModal/index.tsx | 4 ++-- .../ClientView/classes.module.scss | 1 + .../FolderInformation/ClientView/index.tsx | 5 +---- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss index 9b949a1f..38c6566e 100644 --- a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/classes.module.scss @@ -1,8 +1,7 @@ @import "@Themes/constants.scss"; .root { - padding: var(--spacing-3) var(--spacing-15); - max-width: 1156px; + padding: var(--spacing-4) 142px; display: flex; flex-direction: column; diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx index cc642b1d..47d7177d 100644 --- a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx @@ -4,7 +4,7 @@ import Dropdown from "@Front/Components/DesignSystem/Dropdown"; import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption"; import Table from "@Front/Components/DesignSystem/Table"; import { IHead, IRowProps } from "@Front/Components/DesignSystem/Table/MuiTable"; -import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; +import Tag, { ETagColor, ETagVariant } from "@Front/Components/DesignSystem/Tag"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; @@ -19,6 +19,13 @@ import classes from "./classes.module.scss"; type IProps = {}; +const tradDocumentStatus: Record = { + [EDocumentStatus.ASKED]: "DEMANDÉ", + [EDocumentStatus.DEPOSITED]: "À VALIDER", + [EDocumentStatus.VALIDATED]: "VALIDÉ", + [EDocumentStatus.REFUSED]: "REFUSÉ", +}; + const header: readonly IHead[] = [ { key: "remindedAt", @@ -126,6 +133,7 @@ export default function DocumentsReminderHistory(props: IProps) { options={customersOptions} onSelectionChange={onSelectionChange} selectedOption={customerOption ?? customersOptions?.[0]} + label="Client" />
@@ -147,14 +155,14 @@ function buildRows(reminders: DocumentReminder[] | null): IRowProps[] { function getTag(status: EDocumentStatus) { switch (status) { case EDocumentStatus.ASKED: - return ; + return ; case EDocumentStatus.DEPOSITED: - return ; + return ; case EDocumentStatus.VALIDATED: - return ; + return ; case EDocumentStatus.REFUSED: - return ; + return ; default: - return ; + return ; } } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx index 4da1f326..58ed5d47 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/ReminderModal/index.tsx @@ -4,7 +4,7 @@ import { IOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import Modal from "@Front/Components/DesignSystem/Modal"; import Separator, { ESeperatorColor } from "@Front/Components/DesignSystem/Separator"; import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; -import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; +import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Customer from "le-coffre-resources/dist/Customer"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import React, { useCallback, useMemo, useState } from "react"; @@ -79,7 +79,7 @@ export default function ReminderModal(props: IProps) { firstButton={{ children: "Annuler", onClick: onClose }} secondButton={{ children: "Relancer", onClick: onRemind }}>
- + Sélectionnez le(s) document(s) pour lequel vous souhaitez relancer le client. )} - +
From 749b05dc84254d06826ee98392d79dbd820273f3 Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 16 Sep 2024 15:16:00 +0200 Subject: [PATCH 50/63] :sparkles: review design --- .../DesignSystem/Table/MuiTable/index.tsx | 18 +- .../DesignSystem/Tag/classes.module.scss | 2 + .../ClientView/ClientBox/classes.module.scss | 3 +- .../DocumentTables/classes.module.scss | 1 + .../ClientView/DocumentTables/index.tsx | 189 +++++++++++------- .../ClientView/classes.module.scss | 1 - 6 files changed, 140 insertions(+), 74 deletions(-) diff --git a/src/front/Components/DesignSystem/Table/MuiTable/index.tsx b/src/front/Components/DesignSystem/Table/MuiTable/index.tsx index 83e05a7f..c7fb8e0e 100644 --- a/src/front/Components/DesignSystem/Table/MuiTable/index.tsx +++ b/src/front/Components/DesignSystem/Table/MuiTable/index.tsx @@ -8,8 +8,9 @@ import TableRow from "@mui/material/TableRow"; import Typography, { ETypo, ETypoColor } from "../../Typography"; import classes from "./classes.module.scss"; +import { SxProps, Theme } from "@mui/material"; -export type IRowProps = { key: string } & Record; +export type IRowProps = { key: string } & Record; content: React.ReactNode }>; type IRow = { key?: string; @@ -29,7 +30,7 @@ export type IHead = { type CellContent = { key: string; - value: React.ReactNode; + value: React.ReactNode | { sx: SxProps; content: React.ReactNode }; }; export default function MuiTable(props: IProps) { @@ -82,12 +83,14 @@ export default function MuiTable(props: IProps) { className={classes["cell"]} key={cell.key} align="left" - sx={{ border: 0, padding: "4px 8px", height: "53px" }}> + sx={{ ...getCellValueStyle(cell.value), border: 0, padding: "4px 8px", height: "53px" }}> - {cell.value} + {cell.value && typeof cell.value === "object" && "content" in cell.value + ? cell.value.content + : cell.value} ))} @@ -99,4 +102,11 @@ export default function MuiTable(props: IProps) { ); + + function getCellValueStyle(value: React.ReactNode | { sx: SxProps; content: React.ReactNode }) { + if (typeof value === "object" && value !== null && "sx" in value) { + return value.sx; + } + return {}; + } } diff --git a/src/front/Components/DesignSystem/Tag/classes.module.scss b/src/front/Components/DesignSystem/Tag/classes.module.scss index f0dd81b3..b8096a8e 100644 --- a/src/front/Components/DesignSystem/Tag/classes.module.scss +++ b/src/front/Components/DesignSystem/Tag/classes.module.scss @@ -9,6 +9,8 @@ align-items: center; justify-content: center; + white-space: nowrap; + &.info { background-color: var(--tag-info-background); } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/classes.module.scss index 5e75f6fa..17c7b641 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/classes.module.scss @@ -2,12 +2,11 @@ .root { display: flex; - width: fit-content; padding: var(--spacing-md, 16px); flex-direction: column; gap: var(--spacing-md, 16px); background: var(--primary-weak-higlight, #e5eefa); - min-width: 300px; + width: 300px; .header { display: flex; diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss index c4b3c70e..2409c790 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/classes.module.scss @@ -16,5 +16,6 @@ display: flex; align-items: center; gap: var(--spacing-sm, 8px); + justify-content: center; } } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index e38aacf4..e464a324 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -131,16 +131,29 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.ASKED) return null; return { key: document.uid, - document_type: document.document_type?.name ?? "_", - document_status: ( - - ), - date: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", - actions: openDeleteAskedDocumentModal(document.uid)} />} />, + document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_status: { + sx: { width: 107 }, + content: ( + + ), + }, + date: { + sx: { width: 107 }, + content: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", + }, + actions: { + sx: { width: 76 }, + content: ( +
+ openDeleteAskedDocumentModal(document.uid)} />} /> +
+ ), + }, }; }) .filter((document) => document !== null) as IRowProps[], @@ -154,24 +167,35 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.DEPOSITED) return null; return { key: document.uid, - document_type: document.document_type?.name ?? "_", - document_status: ( - - ), - date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", - actions: ( - - } /> - - ), + document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_status: { + sx: { width: 107 }, + content: ( + + ), + }, + date: { + sx: { width: 107 }, + content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", + }, + actions: { + sx: { width: 76 }, + content: ( +
+ + } /> + +
+ ), + }, }; }) .filter((document) => document !== null) as IRowProps[], @@ -185,27 +209,36 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.VALIDATED) return null; return { key: document.uid, - document_type: document.document_type?.name ?? "_", - document_status: ( - - ), - date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", - actions: ( -
- - } /> - - onDownload(document)} icon={} /> -
- ), + document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_status: { + sx: { width: 107 }, + content: ( + + ), + }, + date: { + sx: { width: 107 }, + content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", + }, + actions: { + sx: { width: 76 }, + content: ( +
+ + } /> + + onDownload(document)} icon={} /> +
+ ), + }, }; }) .filter((document) => document !== null) as IRowProps[], @@ -219,15 +252,21 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.REFUSED) return null; return { key: document.uid, - document_type: document.document_type?.name ?? "_", - document_status: ( - - ), - date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", + document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_status: { + sx: { width: 107 }, + content: ( + + ), + }, + date: { + sx: { width: 107 }, + content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", + }, actions: "", }; }) @@ -241,15 +280,27 @@ export default function DocumentTables(props: IProps) { .map((document) => { return { key: document.uid, - document_type: document.files?.[0]?.file_name?.split(".")?.[0] ?? "_", - document_status: , - date: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", - actions: ( -
- onDownloadFileNotary(document)} icon={} /> - openDeleteSentDocumentModal(document.uid)} />} /> -
- ), + document_type: { + sx: { width: 400 }, + content: formatName(document.files?.[0]?.file_name?.split(".")?.[0] ?? "") || "_", + }, + document_status: { + sx: { width: 107 }, + content: , + }, + date: { + sx: { width: 107 }, + content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", + }, + actions: { + sx: { width: 76 }, + content: ( +
+ onDownloadFileNotary(document)} icon={} /> + openDeleteSentDocumentModal(document.uid)} />} /> +
+ ), + }, }; }) .filter((document) => document !== null) as IRowProps[], @@ -333,3 +384,7 @@ function getHeader(dateColumnTitle: string, isMobile: boolean): IHead[] { }, ]; } + +function formatName(text: string): string { + return text.replace(/[^a-zA-Z0-9 ]/g, ""); +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss index c8c51b44..531ab7bc 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss @@ -16,7 +16,6 @@ $mobile-breakpoint: 664px; .tabs { width: calc(100% - 210px); } - border-bottom: 1px solid var(--color-neutral-500); } .content { From 6accc0adcdb383680cd1ff5ceee32d08fde9938a Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 16 Sep 2024 17:38:19 +0200 Subject: [PATCH 51/63] :hammer: update modals --- .../DesignSystem/Modal/classes.module.scss | 5 ++- .../AddClientToFolder/classes.module.scss | 2 +- .../ParameterDocuments/classes.module.scss | 11 ++--- .../AskDocuments/ParameterDocuments/index.tsx | 45 ++++++++++--------- .../Folder/AskDocuments/classes.module.scss | 2 +- .../Layouts/Folder/AskDocuments/index.tsx | 4 +- .../ClientView/classes.module.scss | 10 +++++ 7 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/front/Components/DesignSystem/Modal/classes.module.scss b/src/front/Components/DesignSystem/Modal/classes.module.scss index 4d58af84..66c25655 100644 --- a/src/front/Components/DesignSystem/Modal/classes.module.scss +++ b/src/front/Components/DesignSystem/Modal/classes.module.scss @@ -7,7 +7,7 @@ left: 0; width: 100%; height: 100%; - z-index: 3; + z-index: 5; .content { position: fixed; @@ -54,7 +54,8 @@ left: 0; width: 100%; height: 100%; - background-color: rgba(0, 0, 0, 0.5); + opacity: 0.3; + background: var(--primary-default-deep, #013391); overflow: hidden; } } diff --git a/src/front/Components/Layouts/Folder/AddClientToFolder/classes.module.scss b/src/front/Components/Layouts/Folder/AddClientToFolder/classes.module.scss index d51866e2..d8680d4f 100644 --- a/src/front/Components/Layouts/Folder/AddClientToFolder/classes.module.scss +++ b/src/front/Components/Layouts/Folder/AddClientToFolder/classes.module.scss @@ -40,7 +40,7 @@ .cancel-button { display: flex; - margin-right: 32px; + margin-right: var(--spacing-md, 16px); } @media (max-width: $screen-m) { diff --git a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/classes.module.scss b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/classes.module.scss index 4ed9ba68..e484df2b 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/classes.module.scss +++ b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/classes.module.scss @@ -1,11 +1,12 @@ -.add-document-form-container { +.root { display: flex; flex-direction: column; - gap: 24px; + gap: var(--spacing-md, 16px); + width: 566px; .radiobox-container { - > :not(:last-child) { - margin-bottom: 16px; - } + display: flex; + flex-direction: column; + gap: var(--spacing-xs, 8px); } } diff --git a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx index b78b5d0b..36ad03be 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx @@ -4,6 +4,7 @@ import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/Dr import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; +import Modal from "@Front/Components/DesignSystem/Modal"; import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import { DocumentType, OfficeFolder } from "le-coffre-resources/dist/Notary"; @@ -117,32 +118,32 @@ export default function ParameterDocuments(props: IProps) { }, [getAvailableDocuments, props.folder]); return ( - -
+ firstButton={{ children: "Annuler", onClick: handleClose }} + secondButton={{ children: "Ajouter", onClick: addDocument }} + title={"Ajouter un document"}> +
- + - +
+ + {addOrEditDocument === "add" && ( <> @@ -162,6 +163,6 @@ export default function ParameterDocuments(props: IProps) { /> )}
- + ); } diff --git a/src/front/Components/Layouts/Folder/AskDocuments/classes.module.scss b/src/front/Components/Layouts/Folder/AskDocuments/classes.module.scss index cc4cfae8..dcdf2dd8 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/classes.module.scss +++ b/src/front/Components/Layouts/Folder/AskDocuments/classes.module.scss @@ -33,7 +33,7 @@ .buttons-container { display: flex; - gap: 32px; + gap: var(--spacing-md, 16px); margin-top: 32px; @media (max-width: $screen-s) { diff --git a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx index 8a5f1dde..30f2d87f 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx @@ -155,7 +155,7 @@ export default function AskDocuments() {
- +
diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss index 531ab7bc..43df7a3a 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/classes.module.scss @@ -16,6 +16,16 @@ $mobile-breakpoint: 664px; .tabs { width: calc(100% - 210px); } + + border-bottom: 1px solid var(--tabs-stroke); + + > :first-child { + margin-bottom: -1px; + } + + > :last-child { + margin-bottom: -1px; + } } .content { From 109a0f98ddc9ee66edf867b110b35ab7dc5cea3b Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 16 Sep 2024 17:43:43 +0200 Subject: [PATCH 52/63] remove unused import --- .../AskDocuments/ParameterDocuments/index.tsx | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx index 36ad03be..7b457cfa 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx @@ -5,7 +5,6 @@ import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/Au import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import Modal from "@Front/Components/DesignSystem/Modal"; -import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import { DocumentType, OfficeFolder } from "le-coffre-resources/dist/Notary"; import { ChangeEvent, useCallback, useEffect, useState } from "react"; @@ -126,24 +125,23 @@ export default function ParameterDocuments(props: IProps) { title={"Ajouter un document"}>
- + - +
- {addOrEditDocument === "add" && ( <> From e9b67d48c159c14890500a1ebf831b83b7884e58 Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 16 Sep 2024 18:05:58 +0200 Subject: [PATCH 53/63] :sparkles: add hours reminder document history --- .../DesignSystem/Table/MuiTable/index.tsx | 8 +++++++- .../Folder/DocumentsReminderHistory/index.tsx | 20 ++++++++++++++++--- .../ClientView/EmailReminder/index.tsx | 12 +++++++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/front/Components/DesignSystem/Table/MuiTable/index.tsx b/src/front/Components/DesignSystem/Table/MuiTable/index.tsx index c7fb8e0e..6e5a360b 100644 --- a/src/front/Components/DesignSystem/Table/MuiTable/index.tsx +++ b/src/front/Components/DesignSystem/Table/MuiTable/index.tsx @@ -55,7 +55,13 @@ export default function MuiTable(props: IProps) { className={classes["root"]} sx={{ maxHeight: "80vh", overflowY: "auto", overflowX: "hidden", backgroundColor: "var(--table-background-default)" }}>
- + {props.header.map((column) => ( diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx index 47d7177d..3331e2ff 100644 --- a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx @@ -145,10 +145,13 @@ function buildRows(reminders: DocumentReminder[] | null): IRowProps[] { if (!reminders) return []; return reminders.map((reminder) => ({ key: reminder.uid ?? "", - remindedAt: new Date(reminder.reminder_date!).toLocaleDateString(), - customer: `${reminder.document?.depositor?.contact?.first_name} ${reminder.document?.depositor?.contact?.last_name}`, + remindedAt: { sx: { width: 220 }, content: formatDateWithHours(reminder.reminder_date) }, + customer: { + sx: { width: 220 }, + content: `${reminder.document?.depositor?.contact?.first_name} ${reminder.document?.depositor?.contact?.last_name}`, + }, document_type: reminder.document?.document_type?.name, - statut: getTag(reminder.document?.document_status as EDocumentStatus), + statut: { sx: { width: 220 }, content: getTag(reminder.document?.document_status as EDocumentStatus) }, })); } @@ -166,3 +169,14 @@ function getTag(status: EDocumentStatus) { return ; } } + +function formatDateWithHours(date: Date | null) { + if (!date) return "-"; + return new Date(date).toLocaleDateString("fr-FR", { + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }); +} diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx index 9992aa4e..5412078f 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/EmailReminder/index.tsx @@ -95,8 +95,7 @@ export default function EmailReminder(props: IProps) {
- Dernière relance:{" "} - {reminders && remindersLength > 0 ? new Date(reminders[0]!.reminder_date!).toLocaleDateString() : "-"} + Dernière relance: {reminders && remindersLength > 0 ? formatDateWithHours(reminders[0]!.reminder_date) : "-"} Nombre de relance: {remindersLength} @@ -107,3 +106,12 @@ export default function EmailReminder(props: IProps) {
); } + +function formatDateWithHours(date: Date | null) { + if (!date) return "-"; + return new Date(date).toLocaleDateString("fr-FR", { + year: "numeric", + month: "2-digit", + day: "2-digit", + }); +} From 3f3d681543436d4f6e19cc73eb441c79019c661d Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 17 Sep 2024 11:28:19 +0200 Subject: [PATCH 54/63] :sparkles: UpdateClient refacto --- .../Folder/UpdateClient/classes.module.scss | 70 +-- .../Layouts/Folder/UpdateClient/index.tsx | 429 +++++++----------- 2 files changed, 188 insertions(+), 311 deletions(-) diff --git a/src/front/Components/Layouts/Folder/UpdateClient/classes.module.scss b/src/front/Components/Layouts/Folder/UpdateClient/classes.module.scss index cea59680..efd93bb8 100644 --- a/src/front/Components/Layouts/Folder/UpdateClient/classes.module.scss +++ b/src/front/Components/Layouts/Folder/UpdateClient/classes.module.scss @@ -1,57 +1,37 @@ @import "@Themes/constants.scss"; .root { + margin: 24px auto; + width: 566px; + + @media (max-width: $screen-m) { + width: 474px; + } + + @media (max-width: $screen-s) { + width: 100%; + padding: var(--spacing-md, 16px); + } + display: flex; flex-direction: column; - min-height: 100%; - align-items: flex-start; - width: fit-content; - - .back-arrow { - margin-bottom: 24px; - } + gap: var(--spacing-xl, 32px); .form { - width: 100%; + display: flex; + flex-direction: column; + gap: var(--spacing-md, 16px); + } - .content { - margin-top: 32px; + .button-container { + display: flex; + gap: var(--spacing-md, 16px); - - >:not(:last-child) { - margin-bottom: 24px; - } - - } - - .button-container { - width: 100%; - display: flex; - text-align: center; - margin-top: 24px; - - .cancel-button { - display: flex; - margin-right: 32px; - } - - @media (max-width: $screen-m) { - display: flex; - flex-direction: column-reverse; - - .cancel-button { - margin-left: 0; - margin-top: 12px; - - >* { - flex: 1; - } - } - - >* { - width: 100%; - } + @media (max-width: $screen-xs) { + button { + width: 100%; } + flex-direction: column-reverse; } } -} \ No newline at end of file +} diff --git a/src/front/Components/Layouts/Folder/UpdateClient/index.tsx b/src/front/Components/Layouts/Folder/UpdateClient/index.tsx index 92095538..413a6823 100644 --- a/src/front/Components/Layouts/Folder/UpdateClient/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateClient/index.tsx @@ -1,282 +1,179 @@ +import backgroundImage from "@Assets/images/background_refonte.svg"; import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; -import Form from "@Front/Components/DesignSystem/Form"; +import Form, { IBaseField } from "@Front/Components/DesignSystem/Form"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; -import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; +import Modal from "@Front/Components/DesignSystem/Modal"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; -import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; +import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import Module from "@Front/Config/Module"; -import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; -import Link from "next/link"; -import { NextRouter, useRouter } from "next/router"; -import { ChangeEvent } from "react"; - -import BasePage from "../../Base"; -import classes from "./classes.module.scss"; -import { Address } from "le-coffre-resources/dist/Customer"; +import useOpenable from "@Front/Hooks/useOpenable"; import { ValidationError } from "class-validator"; +import { Address } from "le-coffre-resources/dist/Customer"; +import { Contact, Customer } from "le-coffre-resources/dist/Notary"; +import Link from "next/link"; +import { useRouter } from "next/router"; +import { useCallback, useEffect, useState } from "react"; -type IProps = {}; +import classes from "./classes.module.scss"; -type IPropsClass = IProps & { - selectedFolderUid: string; - router: NextRouter; - customerUid: string; -}; -type IState = { - selectedFolder: OfficeFolder | null; - inputNameValue: string; - inputFirstNameValue: string; - inputEmailValue: string; - inputPhoneNumberValue: string; - isOpenLeavingModal: boolean; - doesInputHaveValues: boolean; - inputBirthdate: Date | null; - inputAddress: string; - folder: OfficeFolder | null; - customer: Customer | null; - validationError: ValidationError[]; -}; -class UpdateClientClass extends BasePage { - constructor(props: IPropsClass) { - super(props); - this.state = { - selectedFolder: null, - inputNameValue: "", - inputFirstNameValue: "", - inputEmailValue: "", - inputPhoneNumberValue: "", - isOpenLeavingModal: false, - doesInputHaveValues: false, - inputBirthdate: null, - inputAddress: "", - folder: null, - customer: null, - validationError: [], - }; - this.onSelectedFolder = this.onSelectedFolder.bind(this); - this.onChangeNameInput = this.onChangeNameInput.bind(this); - this.onChangeFirstNameInput = this.onChangeFirstNameInput.bind(this); - this.onChangeEmailInput = this.onChangeEmailInput.bind(this); - this.onChangePhoneNumberInput = this.onChangePhoneNumberInput.bind(this); - this.openLeavingModal = this.openLeavingModal.bind(this); - this.closeLeavingModal = this.closeLeavingModal.bind(this); - this.leavePage = this.leavePage.bind(this); - this.onChangeBirthDateInput = this.onChangeBirthDateInput.bind(this); - this.onChangeAddressInput = this.onChangeAddressInput.bind(this); - this.onFormSubmit = this.onFormSubmit.bind(this); - } +export default function UpdateClient() { + const router = useRouter(); + const { folderUid, customerUid } = router.query; - private backwardPath = Module.getInstance() + const [doesInputHasChanged, setDoesInputHasChanged] = useState(false); + const [customer, setCustomer] = useState(null); + const [validationError, setValidationError] = useState([]); + + const { isOpen, open, close } = useOpenable(); + + const backwardPath = Module.getInstance() .get() - .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid); + .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid as string); - public override render(): JSX.Element { - return ( - -
-
- -
- Modifier les informations du client -
-
- error.property === "first_name")} - /> - error.property === "last_name")} - /> - error.property === "email")} - /> - error.property === "cell_phone_number")} - /> - error.property === "birthdate")} - /> - -
+ useEffect(() => { + const fetchCustomer = async () => { + try { + const customerData = await Customers.getInstance().getByUid(customerUid as string, { + contact: { + include: { + address: true, + }, + }, + }); + if (customerData) { + setCustomer(customerData); + } + } catch (error) { + console.error("Failed to fetch customer", error); + } + }; + fetchCustomer(); + }, [customerUid]); -
- {!this.doesInputsHaveValues() ? ( - - - - ) : ( - - )} - -
- - - Si vous quittez, toutes les modifications que vous avez effectuées ne seront pas enregistrées.{" "} - -
-
- ); - } - - public override async componentDidMount() { - const customer = await Customers.getInstance().getByUid(this.props.customerUid, { - contact: { - include: { - address: true, - }, - }, - }); - if (customer) { - this.setState({ - customer, - }); - } - } - - private async onFormSubmit( - e: React.FormEvent | null, - values: { - [key: string]: string; - }, - ) { - if (!values["cell_phone_number"]) return; - // remove every space from the phone number - values["cell_phone_number"] = values["cell_phone_number"].replace(/\s/g, ""); - values["cell_phone_number"] = values["cell_phone_number"].replace(/\./g, ""); - if (values["cell_phone_number"] && values["cell_phone_number"].length === 10) { - // get the first digit of the phone number - const firstDigit = values["cell_phone_number"].charAt(0); - // if the first digit is a 0 replace it by +33 - if (firstDigit === "0") { - values["cell_phone_number"] = "+33" + values["cell_phone_number"].substring(1); - } - } - const contact = Contact.hydrate({ - first_name: values["first_name"], - last_name: values["last_name"], - email: values["email"], - cell_phone_number: values["cell_phone_number"], - birthdate: values["birthdate"] === "" ? null : new Date(values["birthdate"]!), - civility: "-", - address: values["address"] ? Address.hydrate
({ address: values["address"], city: "-", zip_code: 0 }) : undefined, - }); - - try { - await contact.validateOrReject?.({ groups: ["createCustomer"], forbidUnknownValues: false }); - } catch (validationErrors) { - this.setState({ - validationError: validationErrors as ValidationError[], - }); - return; - } - - try { - await Customers.getInstance().put(this.props.customerUid, { contact }); - this.props.router.push(this.backwardPath); - } catch (backError) { - if (!Array.isArray(backError)) return; - this.setState({ - validationError: backError as ValidationError[], - }); - return; - } - } - - private leavePage() { - this.props.router.push(this.backwardPath); - } - - private openLeavingModal(): void { - this.setState({ isOpenLeavingModal: true }); - } - - private closeLeavingModal(): void { - this.setState({ isOpenLeavingModal: false }); - } - - private onChangeBirthDateInput(event: ChangeEvent) { - this.setState({ inputBirthdate: new Date(event.target.value) }); - } - - private onChangeAddressInput(event: ChangeEvent) { - this.setState({ inputAddress: event.target.value }); - } - - private onChangeNameInput(event: ChangeEvent) { - this.setState({ inputNameValue: event.target.value }); - } - - private onChangeFirstNameInput(event: ChangeEvent) { - this.setState({ inputFirstNameValue: event.target.value }); - } - private onChangeEmailInput(event: ChangeEvent) { - this.setState({ inputEmailValue: event.target.value }); - } - private onChangePhoneNumberInput(event: ChangeEvent) { - this.setState({ inputPhoneNumberValue: event.target.value }); - } - - private onSelectedFolder(folder: OfficeFolder): void { - this.setState({ selectedFolder: folder }); - } - - private doesInputsHaveValues(): boolean { - const doesInputsHaveValues: boolean = - this.state.inputNameValue !== "" || - this.state.inputFirstNameValue !== "" || - this.state.inputEmailValue !== "" || - this.state.inputPhoneNumberValue !== ""; - return doesInputsHaveValues; - } -} - -export default function UpdateClient(props: IProps) { - const router = useRouter(); - let { folderUid, customerUid } = router.query; - folderUid = folderUid as string; - customerUid = customerUid as string; - return ; + + ) : ( + + )} + + + + + Si vous quittez, toutes les modifications que vous avez effectuées ne seront pas enregistrées. + + + + ); } From aedf2e0f5af1fb86609c4a985078dbf4775aedbf Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 17 Sep 2024 15:16:39 +0200 Subject: [PATCH 55/63] Refactor useEffect dependencies in DocumentsReminderHistory component --- .../Layouts/Folder/DocumentsReminderHistory/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx index 3331e2ff..8d637bc4 100644 --- a/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx +++ b/src/front/Components/Layouts/Folder/DocumentsReminderHistory/index.tsx @@ -110,7 +110,7 @@ export default function DocumentsReminderHistory(props: IProps) { useEffect(() => { fetchReminders(); fetchCustomers(); - }, [customerOption, customersOptions, fetchCustomers, fetchReminders]); + }, [fetchCustomers, fetchReminders]); const onSelectionChange = useCallback((option: IOption | null) => { setCustomerOption(option ?? null); From ec8d07772b03d994fc257a4f109db95958740ecf Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 17 Sep 2024 18:25:38 +0200 Subject: [PATCH 56/63] :hammer: fix refused document table --- .../FolderInformation/ClientView/DocumentTables/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index e464a324..e52b7adf 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -267,7 +267,7 @@ export default function DocumentTables(props: IProps) { sx: { width: 107 }, content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", }, - actions: "", + actions: { sx: { width: 76 }, content: "" }, }; }) .filter((document) => document !== null) as IRowProps[], From f6c977b2888746f77d3cc57a4f46d85f0d078b69 Mon Sep 17 00:00:00 2001 From: Max S Date: Tue, 17 Sep 2024 18:32:07 +0200 Subject: [PATCH 57/63] :hammer: remove max-width for cell content table --- .../Components/DesignSystem/Table/MuiTable/classes.module.scss | 1 - src/front/Components/DesignSystem/Table/MuiTable/index.tsx | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/front/Components/DesignSystem/Table/MuiTable/classes.module.scss b/src/front/Components/DesignSystem/Table/MuiTable/classes.module.scss index 1348e460..73041751 100644 --- a/src/front/Components/DesignSystem/Table/MuiTable/classes.module.scss +++ b/src/front/Components/DesignSystem/Table/MuiTable/classes.module.scss @@ -24,7 +24,6 @@ word-wrap: break-word; .content { - max-width: 270px; width: 100%; word-break: break-word; } diff --git a/src/front/Components/DesignSystem/Table/MuiTable/index.tsx b/src/front/Components/DesignSystem/Table/MuiTable/index.tsx index 6e5a360b..d02667a8 100644 --- a/src/front/Components/DesignSystem/Table/MuiTable/index.tsx +++ b/src/front/Components/DesignSystem/Table/MuiTable/index.tsx @@ -93,7 +93,8 @@ export default function MuiTable(props: IProps) { + color={ETypoColor.COLOR_NEUTRAL_900} + > {cell.value && typeof cell.value === "object" && "content" in cell.value ? cell.value.content : cell.value} From 486eacf686ae7fec1da1e5125a76dab99360936c Mon Sep 17 00:00:00 2001 From: Max S Date: Wed, 18 Sep 2024 14:37:31 +0200 Subject: [PATCH 58/63] :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) => ( Date: Fri, 20 Sep 2024 13:12:28 +0200 Subject: [PATCH 59/63] =?UTF-8?q?:sparkles=20add=20status=20t=C3=A9l=C3=A9?= =?UTF-8?q?charg=C3=A9=20in=20documents=20notary=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 434 +++++++----------- package.json | 2 +- .../DocumentsNotary/DocumentsNotary.ts | 38 ++ .../LeCoffreApi/Customer/FilesNotary/Files.ts | 33 ++ .../ReceivedDocuments/index.tsx | 20 +- .../Layouts/ClientDashboard/index.tsx | 34 +- .../ClientView/DocumentTables/index.tsx | 15 +- 7 files changed, 300 insertions(+), 276 deletions(-) create mode 100644 src/front/Api/LeCoffreApi/Customer/DocumentsNotary/DocumentsNotary.ts create mode 100644 src/front/Api/LeCoffreApi/Customer/FilesNotary/Files.ts diff --git a/package-lock.json b/package-lock.json index 7f22076c..6aa1a024 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "heroicons": "^2.1.5", "jszip": "^3.10.1", "jwt-decode": "^3.1.2", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.160", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.167", "next": "^14.2.3", "prettier": "^2.8.7", "react": "18.2.0", @@ -331,9 +331,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.11.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", - "integrity": "sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", + "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -394,26 +394,26 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.6.7", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz", - "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==", + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", "dependencies": { - "@floating-ui/utils": "^0.2.7" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/dom": { - "version": "1.6.10", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz", - "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==", + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", "dependencies": { "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.7" + "@floating-ui/utils": "^0.2.8" } }, "node_modules/@floating-ui/utils": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz", - "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==" + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" }, "node_modules/@heroicons/react": { "version": "2.1.5", @@ -648,9 +648,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.16", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.16.tgz", - "integrity": "sha512-qI8TV3M7ShITEEc8Ih15A2vLzZGLhD+/UPNwck/hcls2gwg7dyRjNGXcQYHKLB5Q7PuTRfrTkAoPa2VV1s67Ag==", + "version": "7.2.17", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.17.tgz", + "integrity": "sha512-oyumoJgB6jDV8JFzRqjBo2daUuHpzDjoO/e3IrRhhHo/FxJlaVhET6mcNrKHUq2E+R+q3ql0qAtvQ4rfWHhAeQ==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -690,9 +690,9 @@ } }, "node_modules/@next/env": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.8.tgz", - "integrity": "sha512-L44a+ynqkolyNBnYfF8VoCiSrjSZWgEHYKkKLGcs/a80qh7AkfVUD/MduVPgdsWZ31tgROR+yJRA0PZjSVBXWQ==" + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.13.tgz", + "integrity": "sha512-s3lh6K8cbW1h5Nga7NNeXrbe0+2jIIYK9YaA9T7IufDWnZpozdFUp6Hf0d5rNWUKu4fEuSX2rCKlGjCrtylfDw==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.2.4", @@ -703,9 +703,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.8.tgz", - "integrity": "sha512-1VrQlG8OzdyvvGZhGJFnaNE2P10Jjy/2FopnqbY0nSa/gr8If3iINxvOEW3cmVeoAYkmW0RsBazQecA2dBFOSw==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.13.tgz", + "integrity": "sha512-IkAmQEa2Htq+wHACBxOsslt+jMoV3msvxCn0WFSfJSkv/scy+i/EukBKNad36grRxywaXUYJc9mxEGkeIs8Bzg==", "cpu": [ "arm64" ], @@ -718,9 +718,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.8.tgz", - "integrity": "sha512-87t3I86rNRSOJB1gXIUzaQWWSWrkWPDyZGsR0Z7JAPtLeX3uUOW2fHxl7dNWD2BZvbvftctTQjgtfpp7nMtmWg==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.13.tgz", + "integrity": "sha512-Dv1RBGs2TTjkwEnFMVL5XIfJEavnLqqwYSD6LXgTPdEy/u6FlSrLBSSfe1pcfqhFEXRAgVL3Wpjibe5wXJzWog==", "cpu": [ "x64" ], @@ -733,9 +733,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.8.tgz", - "integrity": "sha512-ta2sfVzbOpTbgBrF9HM5m+U58dv6QPuwU4n5EX4LLyCJGKc433Z0D9h9gay/HSOjLEXJ2fJYrMP5JYYbHdxhtw==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.13.tgz", + "integrity": "sha512-yB1tYEFFqo4ZNWkwrJultbsw7NPAAxlPXURXioRl9SdW6aIefOLS+0TEsKrWBtbJ9moTDgU3HRILL6QBQnMevg==", "cpu": [ "arm64" ], @@ -748,9 +748,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.8.tgz", - "integrity": "sha512-+IoLTPK6Z5uIgDhgeWnQF5/o5GBN7+zyUNrs4Bes1W3g9++YELb8y0unFybS8s87ntAKMDl6jeQ+mD7oNwp/Ng==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.13.tgz", + "integrity": "sha512-v5jZ/FV/eHGoWhMKYrsAweQ7CWb8xsWGM/8m1mwwZQ/sutJjoFaXchwK4pX8NqwImILEvQmZWyb8pPTcP7htWg==", "cpu": [ "arm64" ], @@ -763,9 +763,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.8.tgz", - "integrity": "sha512-pO+hVXC+mvzUOQJJRG4RX4wJsRJ5BkURSf6dD6EjUXAX4Ml9es1WsEfkaZ4lcpmFzFvY47IkDaffks/GdCn9ag==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.13.tgz", + "integrity": "sha512-aVc7m4YL7ViiRv7SOXK3RplXzOEe/qQzRA5R2vpXboHABs3w8vtFslGTz+5tKiQzWUmTmBNVW0UQdhkKRORmGA==", "cpu": [ "x64" ], @@ -778,9 +778,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.8.tgz", - "integrity": "sha512-bCat9izctychCtf3uL1nqHq31N5e1VxvdyNcBQflkudPMLbxVnlrw45Vi87K+lt1CwrtVayHqzo4ie0Szcpwzg==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.13.tgz", + "integrity": "sha512-4wWY7/OsSaJOOKvMsu1Teylku7vKyTuocvDLTZQq0TYv9OjiYYWt63PiE1nTuZnqQ4RPvME7Xai+9enoiN0Wrg==", "cpu": [ "x64" ], @@ -793,9 +793,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.8.tgz", - "integrity": "sha512-gbxfUaSPV7EyUobpavida2Hwi62GhSJaSg7iBjmBWoxkxlmETOD7U4tWt763cGIsyE6jM7IoNavq0BXqwdW2QA==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.13.tgz", + "integrity": "sha512-uP1XkqCqV2NVH9+g2sC7qIw+w2tRbcMiXFEbMihkQ8B1+V6m28sshBwAB0SDmOe0u44ne1vFU66+gx/28RsBVQ==", "cpu": [ "arm64" ], @@ -808,9 +808,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.8.tgz", - "integrity": "sha512-PUXzEzjTTlUh3b5VAn1nlpwvujTnuCMMwbiCnaTazoVlN1nA3kWjlmp42IfURA2N/nyrlVEw7pURa/o4Qxj1cw==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.13.tgz", + "integrity": "sha512-V26ezyjPqQpDBV4lcWIh8B/QICQ4v+M5Bo9ykLN+sqeKKBxJVDpEc6biDVyluTXTC40f5IqCU0ttth7Es2ZuMw==", "cpu": [ "ia32" ], @@ -823,9 +823,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.8.tgz", - "integrity": "sha512-EnPKv0ttq02E9/1KZ/8Dn7kuutv6hy1CKc0HlNcvzOQcm4/SQtvfws5gY0zrG9tuupd3HfC2L/zcTrnBhpjTuQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.13.tgz", + "integrity": "sha512-WwzOEAFBGhlDHE5Z73mNU8CO8mqMNLqaG+AO9ETmzdCQlJhVtWZnOl2+rqgVQS+YHunjOWptdFmNfbpwcUuEsw==", "cpu": [ "x64" ], @@ -838,9 +838,9 @@ } }, "node_modules/@next/third-parties": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/@next/third-parties/-/third-parties-14.2.8.tgz", - "integrity": "sha512-Vus4MYsb+7B2X4Mks9aCztZwgnzTxU9sHEm1Y35z7Vw1seh43ummniD9CBk7A8dVJZf8NGpx8re6YSZLkaSQiQ==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/@next/third-parties/-/third-parties-14.2.13.tgz", + "integrity": "sha512-OSqD2E9JO0/GE8HT5QAUsYVXwjWtPLScAX70kO2xopwDAdRzakrsQS55Cihd862X/4bUB37ApVZ9DlHcExzeOg==", "dependencies": { "third-party-capital": "1.0.20" }, @@ -944,9 +944,9 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" }, "node_modules/@types/prop-types": { - "version": "15.7.12", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" + "version": "15.7.13", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", + "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" }, "node_modules/@types/react": { "version": "18.0.28", @@ -991,9 +991,9 @@ "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" }, "node_modules/@types/validator": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.1.tgz", - "integrity": "sha512-w0URwf7BQb0rD/EuiG12KP0bailHKHP5YVviJG9zw3ykAokL0TuxU2TUqMB7EwZ59bDHYdeTIvjI5m0S7qHfOA==" + "version": "13.12.2", + "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.12.2.tgz", + "integrity": "sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==" }, "node_modules/@typescript-eslint/parser": { "version": "5.62.0", @@ -1156,18 +1156,6 @@ "node": ">=4" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1402,9 +1390,9 @@ "optional": true }, "node_modules/bare-fs": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.3.tgz", - "integrity": "sha512-7RYKL+vZVCyAsMLi5SPu7QGauGGT8avnP/HO571ndEuV4MYdGXvLhtW67FuLPeEI8EiIY7zbbRR9x7x7HU0kgw==", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", + "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", "optional": true, "dependencies": { "bare-events": "^2.0.0", @@ -1413,9 +1401,9 @@ } }, "node_modules/bare-os": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.2.tgz", - "integrity": "sha512-HZoJwzC+rZ9lqEemTMiO0luOePoGYNBgsLLgegKR/cljiJvcDNhDZQkzC+NC5Oh0aHbdBNSOHpghwMuB5tqhjg==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", + "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", "optional": true }, "node_modules/bare-path": { @@ -1428,13 +1416,13 @@ } }, "node_modules/bare-stream": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.2.1.tgz", - "integrity": "sha512-YTB47kHwBW9zSG8LD77MIBAAQXjU2WjAkMHeeb7hUplVs6+IoM5I7uEVQNPMB7lj9r8I76UMdoMkGnCodHOLqg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", + "integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", "optional": true, "dependencies": { "b4a": "^1.6.6", - "streamx": "^2.18.0" + "streamx": "^2.20.0" } }, "node_modules/base64-js": { @@ -1456,17 +1444,6 @@ } ] }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -1477,6 +1454,19 @@ "readable-stream": "^3.4.0" } }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1558,9 +1548,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001659", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001659.tgz", - "integrity": "sha512-Qxxyfv3RdHAfJcXelgf0hU4DFUVXBGTjqrBUZLUh8AtlGnsDo+CnncYtTd95+ZKfnANUOzxyIQCuU/UeBZBYoA==", + "version": "1.0.30001662", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001662.tgz", + "integrity": "sha512-sgMUVwLmGseH8ZIrm1d51UbrhqMCH3jvS7gF/M6byuHOnKyLOBL7W8yz5V02OHwgLGA36o/AFhWzzh4uc5aqTA==", "funding": [ { "type": "opencollective", @@ -1598,37 +1588,17 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.0.tgz", + "integrity": "sha512-mxIojEAQcuEvT/lyXq+jf/3cO/KoA6z4CeNDGGevTybECPOMFCnQy3OPahluUkbqgPNGw5Bi78UC7Po6Lhy+NA==", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/chownr": { @@ -2467,9 +2437,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.35.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.2.tgz", - "integrity": "sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==", + "version": "7.36.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz", + "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==", "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -2870,19 +2840,6 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -2951,9 +2908,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.0.tgz", - "integrity": "sha512-Pgba6TExTZ0FJAn1qkJAjIeKoDJ3CsI2ChuLohJnZl/tTU8MVrq3b+2t5UOPfRa4RMsorClBjJALkJUMjG1PAw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -3305,17 +3262,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-boolean-object": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", @@ -3721,38 +3667,6 @@ "setimmediate": "^1.0.5" } }, - "node_modules/jszip/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" - }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/jwt-decode": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", @@ -3783,7 +3697,7 @@ } }, "node_modules/le-coffre-resources": { - "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#6c3cb06f1dc5307bf491e5f17289379c8e0b8ffc", + "resolved": "git+ssh://git@github.com/smart-chain-fr/leCoffre-resources.git#2684918e1b3a18a3746218f452e75e0a6153544c", "license": "MIT", "dependencies": { "class-transformer": "^0.5.1", @@ -3804,9 +3718,9 @@ } }, "node_modules/libphonenumber-js": { - "version": "1.11.7", - "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.7.tgz", - "integrity": "sha512-x2xON4/Qg2bRIS11KIN9yCNYUjhtiEjNyptjX0mX+pyKHecxuJVLIpfX1lq9ZD6CrC/rB+y4GBi18c6CEcUR+A==" + "version": "1.11.8", + "resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.8.tgz", + "integrity": "sha512-0fv/YKpJBAgXKy0kaS3fnqoUVN8901vUYAKIGD/MWZaDfhJt1nZjPL3ZzdZBt/G8G8Hw2J1xOIrXWdNHFHPAvg==" }, "node_modules/lie": { "version": "3.3.0", @@ -3963,11 +3877,11 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/next": { - "version": "14.2.8", - "resolved": "https://registry.npmjs.org/next/-/next-14.2.8.tgz", - "integrity": "sha512-EyEyJZ89r8C5FPlS/401AiF3O8jeMtHIE+bLom9MwcdWJJFBgRl+MR/2VgO0v5bI6tQORNY0a0DR5sjpFNrjbg==", + "version": "14.2.13", + "resolved": "https://registry.npmjs.org/next/-/next-14.2.13.tgz", + "integrity": "sha512-BseY9YNw8QJSwLYD7hlZzl6QVDoSFHL/URN5K64kVEVpCsSOWeyjbIGK+dZUaRViHTaMQX8aqmnn0PHBbGZezg==", "dependencies": { - "@next/env": "14.2.8", + "@next/env": "14.2.13", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -3982,15 +3896,15 @@ "node": ">=18.17.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "14.2.8", - "@next/swc-darwin-x64": "14.2.8", - "@next/swc-linux-arm64-gnu": "14.2.8", - "@next/swc-linux-arm64-musl": "14.2.8", - "@next/swc-linux-x64-gnu": "14.2.8", - "@next/swc-linux-x64-musl": "14.2.8", - "@next/swc-win32-arm64-msvc": "14.2.8", - "@next/swc-win32-ia32-msvc": "14.2.8", - "@next/swc-win32-x64-msvc": "14.2.8" + "@next/swc-darwin-arm64": "14.2.13", + "@next/swc-darwin-x64": "14.2.13", + "@next/swc-linux-arm64-gnu": "14.2.13", + "@next/swc-linux-arm64-musl": "14.2.13", + "@next/swc-linux-x64-gnu": "14.2.13", + "@next/swc-linux-x64-musl": "14.2.13", + "@next/swc-win32-arm64-msvc": "14.2.13", + "@next/swc-win32-ia32-msvc": "14.2.13", + "@next/swc-win32-x64-msvc": "14.2.13" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -4012,9 +3926,9 @@ } }, "node_modules/node-abi": { - "version": "3.67.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.67.0.tgz", - "integrity": "sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==", + "version": "3.68.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.68.0.tgz", + "integrity": "sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A==", "dependencies": { "semver": "^7.3.5" }, @@ -4027,14 +3941,6 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4351,6 +4257,19 @@ "node": ">=10" } }, + "node_modules/prebuild-install/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/prebuild-install/node_modules/tar-fs": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", @@ -4420,9 +4339,9 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -4521,9 +4440,9 @@ "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/react-select": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", - "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.1.tgz", + "integrity": "sha512-RT1CJmuc+ejqm5MPgzyZujqDskdvB9a9ZqrdnVLsvAHjJ3Tj0hELnLeVPQlmYdVKCdCpxanepl6z7R5KhXhWzg==", "dependencies": { "@babel/runtime": "^7.12.0", "@emotion/cache": "^11.4.0", @@ -4576,27 +4495,34 @@ } }, "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.1.tgz", + "integrity": "sha512-GkMg9uOTpIWWKbSsgwb5fA4EavTR+SG/PMPoAY8hkhHfEEY0/vqljY+XHqtDf2cr2IJtoNRDbrrEpZUiZCkYRw==", "engines": { - "node": ">=8.10.0" + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/reflect-metadata": { @@ -4742,23 +4668,9 @@ } }, "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safe-regex-test": { "version": "1.0.3", @@ -4777,11 +4689,11 @@ } }, "node_modules/sass": { - "version": "1.78.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.78.0.tgz", - "integrity": "sha512-AaIqGSrjo5lA2Yg7RvFZrlXDBCp3nV4XP73GrLGvdRWWwk+8H3l0SDvq/5bA4eF+0RFPLuWUk3E+P1U/YqnpsQ==", + "version": "1.79.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.79.2.tgz", + "integrity": "sha512-YmT1aoF1MwHsZEu/eXhbAJNsPGAhNP4UixW9ckEwWCvPcVdVF0/C104OGDVEqtoctKq0N+wM20O/rj+sSPsWeg==", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", + "chokidar": "^4.0.0", "immutable": "^4.0.0", "source-map-js": ">=0.6.2 <2.0.0" }, @@ -5004,9 +4916,9 @@ } }, "node_modules/streamx": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.0.tgz", - "integrity": "sha512-ZGd1LhDeGFucr1CUCTBOS58ZhEendd0ttpGT3usTvosS4ntIwKN9LJFp+OeCSprsCPL14BXVRZlHGRY1V9PVzQ==", + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", + "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", "dependencies": { "fast-fifo": "^1.3.2", "queue-tick": "^1.0.1", @@ -5017,11 +4929,11 @@ } }, "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dependencies": { - "safe-buffer": "~5.2.0" + "safe-buffer": "~5.1.0" } }, "node_modules/string.prototype.includes": { @@ -5224,9 +5136,9 @@ } }, "node_modules/text-decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.1.tgz", - "integrity": "sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz", + "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==", "dependencies": { "b4a": "^1.6.4" } diff --git a/package.json b/package.json index 50e41004..fe4f4409 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "heroicons": "^2.1.5", "jszip": "^3.10.1", "jwt-decode": "^3.1.2", - "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.160", + "le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.167", "next": "^14.2.3", "prettier": "^2.8.7", "react": "18.2.0", diff --git a/src/front/Api/LeCoffreApi/Customer/DocumentsNotary/DocumentsNotary.ts b/src/front/Api/LeCoffreApi/Customer/DocumentsNotary/DocumentsNotary.ts new file mode 100644 index 00000000..508ffd71 --- /dev/null +++ b/src/front/Api/LeCoffreApi/Customer/DocumentsNotary/DocumentsNotary.ts @@ -0,0 +1,38 @@ +import DocumentNotary from "le-coffre-resources/dist/Notary/DocumentNotary"; + +import BaseCustomer from "../BaseCustomer"; + +export interface IGetDocumentNotaryparams { + where?: {}; + include?: {}; + orderBy?: {}; +} + +export default class DocumentsNotary extends BaseCustomer { + private static instance: DocumentsNotary; + private readonly baseURl = this.namespaceUrl.concat("/documents_notary"); + + private constructor() { + super(); + } + + public static getInstance() { + if (!this.instance) { + return new this(); + } else { + return this.instance; + } + } + + public async get(q: IGetDocumentNotaryparams): Promise { + const url = new URL(this.baseURl); + const query = { q }; + Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Api/LeCoffreApi/Customer/FilesNotary/Files.ts b/src/front/Api/LeCoffreApi/Customer/FilesNotary/Files.ts new file mode 100644 index 00000000..ba830290 --- /dev/null +++ b/src/front/Api/LeCoffreApi/Customer/FilesNotary/Files.ts @@ -0,0 +1,33 @@ +import BaseCustomer from "../BaseCustomer"; + +export interface IGetFilesparams { + where?: {}; + include?: {}; +} + +export type IPutFilesParams = {}; + +export interface IPostFilesParams {} + +export default class FilesNotary extends BaseCustomer { + private static instance: FilesNotary; + private readonly baseURl = this.namespaceUrl.concat("/files-notary"); + + private constructor() { + super(); + } + + public static getInstance() { + return (this.instance ??= new this()); + } + + public async download(filesNotaryUid: string, documentsNotaryUid: string): Promise { + const url = new URL(this.baseURl.concat(`/${filesNotaryUid}/documents-notary/${documentsNotaryUid}/download`)); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx index 25af1c60..7c7f49fd 100644 --- a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx @@ -1,5 +1,5 @@ -import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; -import FilesNotary from "@Front/Api/LeCoffreApi/Notary/FilesNotary/Files"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Customer/DocumentsNotary/DocumentsNotary"; +import FilesNotary from "@Front/Api/LeCoffreApi/Customer/FilesNotary/Files"; import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import IconButton from "@Front/Components/DesignSystem/IconButton"; import Table from "@Front/Components/DesignSystem/Table"; @@ -12,7 +12,7 @@ import JwtService from "@Front/Services/JwtService/JwtService"; import { ArrowDownTrayIcon } from "@heroicons/react/24/outline"; import { saveAs } from "file-saver"; import JSZip from "jszip"; -import { DocumentNotary } from "le-coffre-resources/dist/Notary"; +import DocumentNotary from "le-coffre-resources/dist/Notary/DocumentNotary"; import { useRouter } from "next/router"; import React, { useCallback, useEffect, useState } from "react"; @@ -48,10 +48,10 @@ export default function ReceivedDocuments() { const onDownload = useCallback((doc: DocumentNotary) => { const file = doc.files?.[0]; - if (!file || !file?.uid) return; + if (!file || !file?.uid || !doc.uid) return; return FilesNotary.getInstance() - .download(file.uid) + .download(file.uid, doc.uid) .then((blob) => { const url = URL.createObjectURL(blob); const a = document.createElement("a"); @@ -71,8 +71,8 @@ export default function ReceivedDocuments() { const downloadPromises = documentsNotary.map(async (doc) => { const file = doc.files?.[0]; - if (file && file.uid) { - const blob = await FilesNotary.getInstance().download(file.uid); + if (file && file.uid && doc.uid) { + const blob = await FilesNotary.getInstance().download(file.uid, doc.uid); folder.file(file.file_name ?? "file", blob); } }); @@ -117,8 +117,12 @@ export default function ReceivedDocuments() { function buildRows(documentsNotary: DocumentNotary[], onDownloadFileNotary: (doc: DocumentNotary) => void): IRowProps[] { return documentsNotary.map((documentNotary) => ({ key: documentNotary.uid ?? "", - name: documentNotary.files?.[0]?.file_name?.split(".")?.[0] ?? "_", + name: formatName(documentNotary.files?.[0]?.file_name?.split(".")?.[0] ?? "") || "_", sentAt: new Date(documentNotary.created_at!).toLocaleDateString(), actions: onDownloadFileNotary(documentNotary)} icon={} />, })); } + +function formatName(text: string): string { + return text.replace(/[^a-zA-Z0-9 ]/g, ""); +} diff --git a/src/front/Components/Layouts/ClientDashboard/index.tsx b/src/front/Components/Layouts/ClientDashboard/index.tsx index 3808b83b..69a36c32 100644 --- a/src/front/Components/Layouts/ClientDashboard/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/index.tsx @@ -4,7 +4,7 @@ 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, useState } from "react"; +import React, { useCallback, useEffect, useMemo, useState } from "react"; import { DocumentNotary, type OfficeFolder as OfficeFolderNotary } from "le-coffre-resources/dist/Notary"; import classes from "./classes.module.scss"; @@ -21,7 +21,8 @@ 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"; +import DocumentsNotary from "@Front/Api/LeCoffreApi/Customer/DocumentsNotary/DocumentsNotary"; +import { EDocumentNotaryStatus } from "le-coffre-resources/dist/Notary/DocumentNotary"; type IProps = {}; @@ -112,6 +113,11 @@ export default function ClientDashboard(props: IProps) { .then((documentsNotary) => setDocumentsNotary(documentsNotary)); }, [folderUid]); + const documentsNotaryNotRead = useMemo( + () => documentsNotary.filter((doc) => doc.document_status === EDocumentNotaryStatus.SENT), + [documentsNotary], + ); + return (
@@ -140,9 +146,9 @@ export default function ClientDashboard(props: IProps) { size={142} color={ESeperatorColor.LIGHT} /> - {(documentsNotary?.length ?? 0) > 0 && ( + {(documentsNotaryNotRead?.length ?? 0) > 0 && ( )} + {(documentsNotaryNotRead?.length ?? 0) === 0 && (documentsNotary?.length ?? 0) > 0 && ( + + router.push( + Module.getInstance() + .get() + .modules.pages.ClientDashboard.pages.ReceiveDocuments.props.path.replace( + "[folderUid]", + folderUid as string, + ), + ), + }} + read={true} + /> + )}
{customer && folder && } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index e52b7adf..66f3ec71 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -14,7 +14,7 @@ import { ArrowDownTrayIcon, EyeIcon, TrashIcon } from "@heroicons/react/24/outli import { useMediaQuery } from "@mui/material"; import { Document } from "le-coffre-resources/dist/Customer"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; -import { DocumentNotary } from "le-coffre-resources/dist/Notary"; +import DocumentNotary, { EDocumentNotaryStatus } from "le-coffre-resources/dist/Notary/DocumentNotary"; import Link from "next/link"; import { useCallback, useEffect, useMemo, useState } from "react"; @@ -35,6 +35,11 @@ const tradDocumentStatus: Record = { [EDocumentStatus.REFUSED]: "Refusé", }; +const tradDocumentsNotaryStatus: Record = { + [EDocumentNotaryStatus.SENT]: "Envoyé", + [EDocumentNotaryStatus.DOWNLOADED]: "Téléchargé", +}; + export default function DocumentTables(props: IProps) { const { folderUid, customerUid } = props; const [documents, setDocuments] = useState([]); @@ -286,7 +291,13 @@ export default function DocumentTables(props: IProps) { }, document_status: { sx: { width: 107 }, - content: , + content: ( + + ), }, date: { sx: { width: 107 }, From 842edcd4c278127d90db5724c17552aa26237f5e Mon Sep 17 00:00:00 2001 From: Max S Date: Fri, 20 Sep 2024 13:19:51 +0200 Subject: [PATCH 60/63] Refactor document status tag rendering in DocumentTables component --- .../ClientView/DocumentTables/index.tsx | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx index 66f3ec71..ebcf0bb4 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -291,13 +291,7 @@ export default function DocumentTables(props: IProps) { }, document_status: { sx: { width: 107 }, - content: ( - - ), + content: getTagForSentDocument(document.document_status as EDocumentNotaryStatus), }, date: { sx: { width: 107 }, @@ -399,3 +393,30 @@ function getHeader(dateColumnTitle: string, isMobile: boolean): IHead[] { function formatName(text: string): string { return text.replace(/[^a-zA-Z0-9 ]/g, ""); } + +function getTagForSentDocument(status: EDocumentNotaryStatus) { + if (status === EDocumentNotaryStatus.SENT) { + return ( + + ); + } else if (status === EDocumentNotaryStatus.DOWNLOADED) { + return ( + + ); + } + return ( + + ); +} From a99ad0dc948446e8da4b43df732fd572305132c5 Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 23 Sep 2024 11:32:04 +0200 Subject: [PATCH 61/63] Refactor DownloadAnchoringProofModal component --- .../elements/DownloadAnchoringProofModal/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/elements/DownloadAnchoringProofModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/elements/DownloadAnchoringProofModal/index.tsx index 460c6538..10022d04 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/elements/DownloadAnchoringProofModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/elements/DownloadAnchoringProofModal/index.tsx @@ -20,7 +20,6 @@ export default function DownloadAnchoringProofModal(props: IProps) { const downloadAnchoringProof = useCallback(async () => { if (!folder?.uid) return; try { - debugger; setError(null); setIsLoading(true); const file = await OfficeFolderAnchors.getInstance().download(folder.uid); From 96ab9ac08a1ea6b4d715e283d711cec4475cebdb Mon Sep 17 00:00:00 2001 From: Max S Date: Mon, 23 Sep 2024 15:03:22 +0200 Subject: [PATCH 62/63] wording --- .../Layouts/ClientDashboard/DepositDocumentComponent/index.tsx | 2 +- .../Folder/FolderInformation/ClientView/EmailReminder/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx index 37448dbd..46ef2cec 100644 --- a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx @@ -62,7 +62,7 @@ export default function DepositDocumentComponent(props: IProps) {
- Dernière relance: {reminders && remindersLength > 0 ? formatDateWithHours(reminders[0]!.reminder_date) : "-"} + Dernière relance manuelle: {reminders && remindersLength > 0 ? formatDateWithHours(reminders[0]!.reminder_date) : "-"} Nombre de relance: {remindersLength} From a61368030cbb1f7038ac34346e607fb3deac8543 Mon Sep 17 00:00:00 2001 From: Vins Date: Thu, 26 Sep 2024 13:09:12 +0200 Subject: [PATCH 63/63] Changed front version --- src/front/version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/front/version.json b/src/front/version.json index 445cf446..a2316497 100644 --- a/src/front/version.json +++ b/src/front/version.json @@ -1,3 +1,3 @@ { - "version": "v2.3.0" + "version": "v2.5.1" }