diff --git a/src/common/Api/LeCoffreApi/sdk/CustomerService.ts b/src/common/Api/LeCoffreApi/sdk/CustomerService.ts index 37d9051e..5bf3a3b7 100644 --- a/src/common/Api/LeCoffreApi/sdk/CustomerService.ts +++ b/src/common/Api/LeCoffreApi/sdk/CustomerService.ts @@ -1,4 +1,3 @@ - import { v4 as uuidv4 } from 'uuid'; import MessageBus from 'src/sdk/MessageBus'; diff --git a/src/common/Api/LeCoffreApi/sdk/DeedTypeService.ts b/src/common/Api/LeCoffreApi/sdk/DeedTypeService.ts index 2e9a32ab..0a868b4c 100644 --- a/src/common/Api/LeCoffreApi/sdk/DeedTypeService.ts +++ b/src/common/Api/LeCoffreApi/sdk/DeedTypeService.ts @@ -1,4 +1,3 @@ - import { v4 as uuidv4 } from 'uuid'; import MessageBus from 'src/sdk/MessageBus'; diff --git a/src/common/Api/LeCoffreApi/sdk/DocumentService.ts b/src/common/Api/LeCoffreApi/sdk/DocumentService.ts index 5726ca23..987ca689 100644 --- a/src/common/Api/LeCoffreApi/sdk/DocumentService.ts +++ b/src/common/Api/LeCoffreApi/sdk/DocumentService.ts @@ -1,4 +1,3 @@ - import { v4 as uuidv4 } from 'uuid'; import MessageBus from 'src/sdk/MessageBus'; diff --git a/src/common/Api/LeCoffreApi/sdk/DocumentTypeService.ts b/src/common/Api/LeCoffreApi/sdk/DocumentTypeService.ts index 13846c2a..1f663663 100644 --- a/src/common/Api/LeCoffreApi/sdk/DocumentTypeService.ts +++ b/src/common/Api/LeCoffreApi/sdk/DocumentTypeService.ts @@ -1,4 +1,3 @@ - import { v4 as uuidv4 } from 'uuid'; import MessageBus from 'src/sdk/MessageBus'; @@ -10,7 +9,7 @@ export default class DocumentTypeService { private constructor() { } - public static createDocumentType(documentData: any, validatorId: string): Promise { + public static createDocumentType(documentTypeData: any, validatorId: string): Promise { const ownerId = User.getInstance().getPairingId()!; const processData: any = { @@ -19,7 +18,7 @@ export default class DocumentTypeService { isDeleted: 'false', created_at: new Date().toISOString(), updated_at: new Date().toISOString(), - ...documentData, + ...documentTypeData, }; const privateFields: string[] = Object.keys(processData); diff --git a/src/common/Api/LeCoffreApi/sdk/FileService.ts b/src/common/Api/LeCoffreApi/sdk/FileService.ts index e013ae20..9b639cf9 100644 --- a/src/common/Api/LeCoffreApi/sdk/FileService.ts +++ b/src/common/Api/LeCoffreApi/sdk/FileService.ts @@ -1,4 +1,3 @@ - import { v4 as uuidv4 } from 'uuid'; import MessageBus from 'src/sdk/MessageBus'; diff --git a/src/common/Api/LeCoffreApi/sdk/FolderService.ts b/src/common/Api/LeCoffreApi/sdk/FolderService.ts index 74e0bb92..e8e49afb 100644 --- a/src/common/Api/LeCoffreApi/sdk/FolderService.ts +++ b/src/common/Api/LeCoffreApi/sdk/FolderService.ts @@ -1,4 +1,3 @@ - import { v4 as uuidv4 } from 'uuid'; import MessageBus from 'src/sdk/MessageBus'; diff --git a/src/common/Api/LeCoffreApi/sdk/Loader/LoaderService.ts b/src/common/Api/LeCoffreApi/sdk/Loader/LoaderService.ts new file mode 100644 index 00000000..8d1da8a4 --- /dev/null +++ b/src/common/Api/LeCoffreApi/sdk/Loader/LoaderService.ts @@ -0,0 +1,45 @@ +class LoaderService { + private static instance: LoaderService; + private _isVisible: boolean = false; + private _callbacks: Array<(isVisible: boolean) => void> = []; + + private constructor() { } + + public static getInstance(): LoaderService { + if (!LoaderService.instance) { + LoaderService.instance = new LoaderService(); + } + return LoaderService.instance; + } + + public show(): void { + this._isVisible = true; + this._notifySubscribers(); + } + + public hide(): void { + this._isVisible = false; + this._notifySubscribers(); + } + + public get isVisible(): boolean { + return this._isVisible; + } + + public subscribe(callback: (isVisible: boolean) => void): () => void { + this._callbacks.push(callback); + + // Return unsubscribe function + return () => { + this._callbacks = this._callbacks.filter(cb => cb !== callback); + }; + } + + private _notifySubscribers(): void { + this._callbacks.forEach(callback => { + callback(this._isVisible); + }); + } +} + +export default LoaderService; diff --git a/src/common/Api/LeCoffreApi/sdk/Loader/classes.module.scss b/src/common/Api/LeCoffreApi/sdk/Loader/classes.module.scss new file mode 100644 index 00000000..744a53a1 --- /dev/null +++ b/src/common/Api/LeCoffreApi/sdk/Loader/classes.module.scss @@ -0,0 +1,38 @@ +@keyframes spin { + to { + transform: rotate(1turn); + } +} + +.loader-container { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(255, 255, 255, 0.7); + z-index: 9999; + display: flex; + justify-content: center; + align-items: center; +} + +.loader { + display: flex; + flex-direction: column; + align-items: center; + background-color: white; + padding: 2rem; + border-radius: 8px; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); +} + +.message { + margin-top: 1rem; + font-size: 1rem; + color: #333; +} + +.spinner { + animation: spin 1s infinite linear; +} diff --git a/src/common/Api/LeCoffreApi/sdk/Loader/index.tsx b/src/common/Api/LeCoffreApi/sdk/Loader/index.tsx new file mode 100644 index 00000000..81b1b733 --- /dev/null +++ b/src/common/Api/LeCoffreApi/sdk/Loader/index.tsx @@ -0,0 +1,37 @@ +import React, { useEffect, useState } from "react"; + +import { ArrowPathIcon } from "@heroicons/react/24/outline"; + +import LoaderService from "./LoaderService"; +import classes from "./classes.module.scss"; + +// Composant fusionné qui gère à la fois l'abonnement au service et l'affichage +const Loader: React.FC = () => { + const [isVisible, setIsVisible] = useState(false); + + useEffect(() => { + // S'abonner aux changements d'état du loader + const unsubscribe = LoaderService.getInstance().subscribe((visible) => { + setIsVisible(visible); + }); + + // Nettoyage de l'abonnement + return () => { + unsubscribe(); + }; + }, []); + + // Ne rien afficher si le loader n'est pas visible + if (!isVisible) return null; + + // Affichage du loader avec overlay + return ( +
+
+ +
+
+ ); +}; + +export default Loader; diff --git a/src/common/Api/LeCoffreApi/sdk/NoteService.ts b/src/common/Api/LeCoffreApi/sdk/NoteService.ts index 623fb781..b80fec38 100644 --- a/src/common/Api/LeCoffreApi/sdk/NoteService.ts +++ b/src/common/Api/LeCoffreApi/sdk/NoteService.ts @@ -1,4 +1,3 @@ - import { v4 as uuidv4 } from 'uuid'; import MessageBus from 'src/sdk/MessageBus'; diff --git a/src/common/Api/LeCoffreApi/sdk/RoleService.ts b/src/common/Api/LeCoffreApi/sdk/RoleService.ts new file mode 100644 index 00000000..30dea627 --- /dev/null +++ b/src/common/Api/LeCoffreApi/sdk/RoleService.ts @@ -0,0 +1,109 @@ +import { v4 as uuidv4 } from 'uuid'; + +import MessageBus from 'src/sdk/MessageBus'; +import User from 'src/sdk/User'; + +export default class RoleService { + + private static readonly messageBus: MessageBus = MessageBus.getInstance(); + + private constructor() { } + + public static createRole(roleData: any, validatorId: string): Promise { + const ownerId = User.getInstance().getPairingId()!; + + const processData: any = { + uid: uuidv4(), + utype: 'role', + isDeleted: 'false', + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + ...roleData, + }; + + const privateFields: string[] = Object.keys(processData); + privateFields.splice(privateFields.indexOf('uid'), 1); + privateFields.splice(privateFields.indexOf('utype'), 1); + privateFields.splice(privateFields.indexOf('isDeleted'), 1); + + const roles: any = { + demiurge: { + members: [...[ownerId], validatorId], + validation_rules: [], + storages: [] + }, + owner: { + members: [ownerId], + validation_rules: [ + { + quorum: 0.5, + fields: [...privateFields, 'roles', 'uid', 'utype'], + min_sig_member: 1, + }, + ], + storages: [] + }, + validator: { + members: [validatorId], + validation_rules: [ + { + quorum: 0.5, + fields: ['idCertified', 'roles'], + min_sig_member: 1, + }, + { + quorum: 0.0, + fields: [...privateFields], + min_sig_member: 0, + }, + ], + storages: [] + }, + apophis: { + members: [ownerId], + validation_rules: [], + storages: [] + } + }; + + return new Promise((resolve: (processCreated: any) => void, reject: (error: string) => void) => { + this.messageBus.createProcess(processData, privateFields, roles).then((processCreated: any) => { + this.messageBus.notifyUpdate(processCreated.processId, processCreated.process.states[0].state_id).then(() => { + this.messageBus.validateState(processCreated.processId, processCreated.process.states[0].state_id).then((_stateValidated: any) => { + resolve(processCreated); + }).catch(reject); + }).catch(reject); + }).catch(reject); + }); + } + + public static getRoles(): Promise { + return this.messageBus.getProcessesDecoded((publicValues: any) => publicValues['uid'] && publicValues['utype'] && publicValues['utype'] === 'role' && publicValues['isDeleted'] && publicValues['isDeleted'] === 'false'); + } + + public static getRoleByUid(uid: string): Promise { + return new Promise((resolve: (process: any) => void, reject: (error: string) => void) => { + this.messageBus.getProcessesDecoded((publicValues: any) => publicValues['uid'] && publicValues['uid'] === uid && publicValues['utype'] && publicValues['utype'] === 'role' && publicValues['isDeleted'] && publicValues['isDeleted'] === 'false').then(async (processes: any[]) => { + if (processes.length === 0) { + resolve(null); + } else { + const process: any = processes[0]; + resolve(process); + } + }).catch(reject); + }); + } + + public static updateRole(process: any, newData: any): Promise { + return new Promise((resolve: () => void, reject: (error: string) => void) => { + this.messageBus.updateProcess(process.processId, { updated_at: new Date().toISOString(), ...newData }, [], null).then((processUpdated: any) => { + const newStateId: string = processUpdated.diffs[0]?.state_id; + this.messageBus.notifyUpdate(process.processId, newStateId).then(() => { + this.messageBus.validateState(process.processId, newStateId).then((_stateValidated) => { + resolve(); + }).catch(reject); + }).catch(reject); + }).catch(reject); + }); + } +} diff --git a/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx b/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx index 15f143a7..c6398dfa 100644 --- a/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx +++ b/src/front/Components/DesignSystem/DepositOtherDocument/index.tsx @@ -14,10 +14,12 @@ import classNames from "classnames"; import Button, { EButtonstyletype, EButtonVariant } from "../Button"; import Confirm from "../OldModal/Confirm"; -import Documents from "@Front/Api/LeCoffreApi/Customer/Documents/Documents"; -import Files from "@Front/Api/LeCoffreApi/Customer/Files/Files"; import Alert from "../OldModal/Alert"; +import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; +import FileService from "src/common/Api/LeCoffreApi/sdk/FileService"; + type IProps = { onChange?: (files: File[]) => void; open: boolean; @@ -196,7 +198,7 @@ export default class DepositOtherDocument extends React.Component((resolve: (document: any) => void) => { + const documentTypeData: any = { + folder: { + uid: this.props.folder_uid, + }, + depositor: { + uid: this.props.customer_uid, + } + }; + const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + + DocumentService.createDocument(documentTypeData, validatorId).then((processCreated: any) => { + if (processCreated) { + const document: any = processCreated.processData; + resolve(document); + } + }); }); } catch (e) { this.setState({ showFailedDocument: "Le dossier est vérifié aucune modification n'est acceptée", isLoading: false }); @@ -225,16 +239,46 @@ export default class DepositOtherDocument extends React.Component((resolve: () => void) => { + const reader = new FileReader(); + reader.onload = (event) => { + if (event.target?.result) { + const arrayBuffer = event.target.result as ArrayBuffer; + const uint8Array = new Uint8Array(arrayBuffer); + + const fileBlob: any = { + type: file.type, + data: uint8Array + }; + + const fileData: any = { + file_blob: fileBlob, + file_name: file.name + }; + const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + + FileService.createFile(fileData, validatorId).then((processCreated: any) => { + const fileUid: string = processCreated.processData.uid; + + DocumentService.getDocumentByUid(documentCreated.uid).then((process: any) => { + if (process) { + const document: any = process.processData; + + let files: any[] = document.files; + if (!files) { + files = []; + } + files.push({ uid: fileUid }); + + DocumentService.updateDocument(process, { files: files, document_status: EDocumentStatus.DEPOSITED }).then(() => resolve()); + } + }); + }); + } + }; + reader.readAsArrayBuffer(file); + }); } this.setState({ diff --git a/src/front/Components/DesignSystem/Header/Navigation/index.tsx b/src/front/Components/DesignSystem/Header/Navigation/index.tsx index 3d4c10ce..d72b3a15 100644 --- a/src/front/Components/DesignSystem/Header/Navigation/index.tsx +++ b/src/front/Components/DesignSystem/Header/Navigation/index.tsx @@ -31,6 +31,7 @@ export default function Navigation() { */ const anchors = [] as any[]; + /* TODO: review try { for (const anchor of anchors) { await OfficeFolderAnchors.getInstance().getByUid(anchor.folder?.uid as string); @@ -38,6 +39,7 @@ export default function Navigation() { } catch (e) { console.error(e); } + */ }, []); const getNotifications = useCallback(async () => { diff --git a/src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx b/src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx index 89d8c1fe..d539fb3b 100644 --- a/src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultCustomerDashboard/index.tsx @@ -1,4 +1,3 @@ -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"; @@ -14,7 +13,7 @@ type IProps = IPropsDashboardWithList & {}; export default function DefaultCustomerDashboard(props: IProps) { const router = useRouter(); - const { folderUid } = router.query; + const { folderUid, profileUid } = router.query; const [folders, setFolders] = useState([]); useEffect(() => { @@ -61,7 +60,9 @@ export default function DefaultCustomerDashboard(props: IProps) { router.push( Module.getInstance() .get() - .modules.pages.ClientDashboard.props.path.replace("[folderUid]", folder.uid ?? ""), + .modules.pages.ClientDashboard.props.path + .replace("[folderUid]", folder.uid ?? "") + .replace("[profileUid]", profileUid as string ?? ""), ); }; return ; diff --git a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx index e566d69d..00f3d709 100644 --- a/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx +++ b/src/front/Components/LayoutTemplates/DefaultRoleDashboard/index.tsx @@ -7,6 +7,8 @@ import DefaultDashboardWithList, { IPropsDashboardWithList } from "../DefaultDas import { OfficeRole } from "le-coffre-resources/dist/Notary"; import OfficeRoles, { IGetRolesParams } from "@Front/Api/LeCoffreApi/Admin/OfficeRoles/OfficeRoles"; +import RoleService from "src/common/Api/LeCoffreApi/sdk/RoleService"; + type IProps = IPropsDashboardWithList; export default function DefaultRoleDashboard(props: IProps) { @@ -23,7 +25,13 @@ export default function DefaultRoleDashboard(props: IProps) { .get(query) .then((roles) => setRoles(roles)); */ - setRoles([]); + + RoleService.getRoles().then((processes: any[]) => { + if (processes.length > 0) { + const roles: any[] = processes.map((process: any) => process.processData); + setRoles(roles); + } + }); }, []); const onSelectedBlock = (block: IBlock) => { @@ -37,10 +45,10 @@ export default function DefaultRoleDashboard(props: IProps) { blocks={ roles ? roles.map((role) => ({ - id: role.uid!, - primaryText: role.name, - isActive: role.uid === roleUid, - })) + id: role.uid!, + primaryText: role.name, + isActive: role.uid === roleUid, + })) : [] } bottomButton={{ diff --git a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx index a967c7c3..3f9ae3e6 100644 --- a/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/DepositDocumentComponent/index.tsx @@ -110,7 +110,8 @@ export default function DepositDocumentComponent(props: IProps) { ); const onOpenModal = useCallback(async () => { - const refused_reason = document.document_history?.find((history: any) => history.document_status === "REFUSED")?.refused_reason; + if (document.document_status !== "REFUSED") return; + const refused_reason = document.refused_reason; if (!refused_reason) return; setRefusedReason(refused_reason); setIsModalOpen(true); diff --git a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx index 001ea71a..c137971e 100644 --- a/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/ReceivedDocuments/index.tsx @@ -1,5 +1,3 @@ -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"; @@ -16,10 +14,14 @@ import { useRouter } from "next/router"; import React, { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; import Link from "next/link"; -import Folders from "@Front/Api/LeCoffreApi/Customer/Folders/Folders"; import Customer from "le-coffre-resources/dist/Customer"; import { DocumentNotary } from "le-coffre-resources/dist/Notary"; +import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; +import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import FileService from "src/common/Api/LeCoffreApi/sdk/FileService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; + const header: readonly IHead[] = [ { key: "name", @@ -47,6 +49,26 @@ export default function ReceivedDocuments() { jwt = JwtService.getInstance().decodeCustomerJwt(); } + // TODO: review + LoaderService.getInstance().show(); + const folder: any = await new Promise((resolve: (folder: any) => void) => { + FolderService.getFolderByUid(folderUid as string).then((process: any) => { + if (process) { + const folder: any = process.processData; + resolve(folder); + } + }); + }); + + //const customer = folder?.customers?.find((customer) => customer.contact?.email === jwt?.email); + const customer = folder?.customers?.[0]; + if (!customer) throw new Error("Customer not found"); + + setCustomer(customer); + + return { folder, customer }; + + /* const folder = await Folders.getInstance().getByUid(folderUid as string, { q: { office: true, @@ -76,32 +98,58 @@ export default function ReceivedDocuments() { setCustomer(customer); return { folder, customer }; + */ }, [folderUid]); useEffect(() => { fetchFolderAndCustomer(); + }, [folderUid]); // Ne dépend que de folderUid + + // Effet séparé pour charger les documents lorsque customer change + useEffect(() => { const customerUid = customer?.uid; if (!folderUid || !customerUid) return; - DocumentsNotary.getInstance() - .get({ where: { folder: { uid: folderUid }, customer: { uid: customerUid } }, include: { files: true } }) - .then((documentsNotary) => setDocumentsNotary(documentsNotary)); - }, [folderUid, customer, fetchFolderAndCustomer]); - const onDownload = useCallback((doc: DocumentNotary) => { + DocumentService.getDocuments().then(async (processes: any[]) => { + if (processes.length > 0) { + let documents: any[] = processes.map((process: any) => process.processData); + + // FilterBy folder.uid & customer.uid + documents = documents.filter((document: any) => document.folder.uid === folderUid && document.customer && document.customer.uid === customerUid); + + for (const document of documents) { + if (document.files && document.files.length > 0) { + const files: any[] = []; + for (const file of document.files) { + files.push((await FileService.getFileByUid(file.uid)).processData); + } + document.files = files; + } + } + + setDocumentsNotary(documents); + LoaderService.getInstance().hide(); + } + }); + }, [folderUid, customer]); + + const onDownload = useCallback((doc: any) => { const file = doc.files?.[0]; - if (!file || !file?.uid || !doc.uid) return; + if (!file) return; - return FilesNotary.getInstance() - .download(file.uid, doc.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)); + return new Promise((resolve: () => void) => { + const blob = new Blob([file.file_blob.data], { type: file.file_blob.type }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = file.file_name; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + + resolve(); + }).catch((e) => console.warn(e)); }, []); const onDownloadAll = useCallback(async () => { @@ -110,16 +158,14 @@ export default function ReceivedDocuments() { const zip = new JSZip(); const folder = zip.folder("documents") || zip; - const downloadPromises = documentsNotary.map(async (doc) => { + documentsNotary.map((doc: any) => { const file = doc.files?.[0]; - if (file && file.uid && doc.uid) { - const blob = await FilesNotary.getInstance().download(file.uid, doc.uid); + if (file) { + const blob = new Blob([file.file_blob.data], { type: file.file_blob.type }); folder.file(file.file_name ?? "file", blob); } }); - await Promise.all(downloadPromises); - zip.generateAsync({ type: "blob" }) .then((blob: any) => { saveAs(blob, "documents.zip"); diff --git a/src/front/Components/Layouts/ClientDashboard/ViewDocumentsNotary/index.tsx b/src/front/Components/Layouts/ClientDashboard/ViewDocumentsNotary/index.tsx index 843ded9f..89a6af09 100644 --- a/src/front/Components/Layouts/ClientDashboard/ViewDocumentsNotary/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/ViewDocumentsNotary/index.tsx @@ -10,9 +10,12 @@ import React from "react"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; -import DocumentsNotary from "@Front/Api/LeCoffreApi/Customer/DocumentsNotary/DocumentsNotary"; + import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate"; -import FilesNotary from "@Front/Api/LeCoffreApi/Customer/FilesNotary/Files"; + +import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import FileService from "src/common/Api/LeCoffreApi/sdk/FileService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = {}; type IPropsClass = { @@ -123,11 +126,26 @@ class ViewDocumentsNotaryClass extends BasePage { override async componentDidMount() { try { - const documentNotary = await DocumentsNotary.getInstance().getByUid(this.props.documentUid, { - files: true, - folder: true, - depositor: true, + LoaderService.getInstance().show(); + const documentNotary: any = await new Promise((resolve: (document: any) => void) => { + DocumentService.getDocumentByUid(this.props.documentUid).then(async (process: any) => { + if (process) { + const document: any = process.processData; + + if (document.files && document.files.length > 0) { + const files: any[] = []; + for (const file of document.files) { + files.push((await FileService.getFileByUid(file.uid)).processData); + } + document.files = files; + } + + resolve(document); + } + }); }); + LoaderService.getInstance().hide(); + this.setState( { documentNotary, @@ -149,8 +167,7 @@ class ViewDocumentsNotaryClass extends BasePage { private async getFilePreview(): Promise { try { - const fileBlob: Blob = await FilesNotary.getInstance().download(this.state.selectedFile?.uid as string, this.props.documentUid); - + const fileBlob: Blob = new Blob([this.state.selectedFile.file_blob.data], { type: this.state.selectedFile.file_blob.type }); this.setState({ fileBlob, }); diff --git a/src/front/Components/Layouts/ClientDashboard/index.tsx b/src/front/Components/Layouts/ClientDashboard/index.tsx index f992be52..c02202dd 100644 --- a/src/front/Components/Layouts/ClientDashboard/index.tsx +++ b/src/front/Components/Layouts/ClientDashboard/index.tsx @@ -1,5 +1,4 @@ "use client"; -import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/Customer/Documents/Documents"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; @@ -10,7 +9,6 @@ import { DocumentNotary, OfficeFolder as OfficeFolderNotary } from "le-coffre-re 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 Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag"; import DefaultCustomerDashboard from "@Front/Components/LayoutTemplates/DefaultCustomerDashboard"; @@ -21,16 +19,19 @@ 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/Customer/DocumentsNotary/DocumentsNotary"; import { EDocumentNotaryStatus } from "le-coffre-resources/dist/Notary/DocumentNotary"; import DepositOtherDocument from "@Front/Components/DesignSystem/DepositOtherDocument"; +import Modal from "@Front/Components/DesignSystem/Modal"; +import TextField from "@Front/Components/DesignSystem/Form/TextField"; + import AuthModal from "src/sdk/AuthModal"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService"; import FileService from "src/common/Api/LeCoffreApi/sdk/FileService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = {}; @@ -46,6 +47,30 @@ export default function ClientDashboard(props: IProps) { const [isAddDocumentModalVisible, setIsAddDocumentModalVisible] = useState(false); const [isAuthModalOpen, setIsAuthModalOpen] = useState(false); + const [isSmsModalOpen, setIsSmsModalOpen] = useState(false); + const [smsCode, setSmsCode] = useState(""); + const [smsError, setSmsError] = useState(""); + + const verifySmsCode = useCallback(() => { + if (smsCode === "1234") { + setIsSmsModalOpen(false); + } else { + setSmsError("Code incorrect. Le code valide est 1234."); + } + }, [smsCode]); + + useEffect(() => { + const handleKeyPress = (e: KeyboardEvent) => { + if (e.key === "Enter" && isSmsModalOpen) { + verifySmsCode(); + } + }; + + window.addEventListener("keypress", handleKeyPress); + return () => { + window.removeEventListener("keypress", handleKeyPress); + }; + }, [isSmsModalOpen, smsCode, verifySmsCode]); const fetchFolderAndCustomer = useCallback(async () => { let jwt: ICustomerJwtPayload | undefined; @@ -54,6 +79,7 @@ export default function ClientDashboard(props: IProps) { } // TODO: review + LoaderService.getInstance().show(); const { folder, customer } = await new Promise((resolve) => { FolderService.getFolderByUid(folderUid as string).then((process: any) => { if (process) { @@ -72,6 +98,7 @@ export default function ClientDashboard(props: IProps) { setFolder(folder); setIsAuthModalOpen(true); + LoaderService.getInstance().hide(); return { folder, customer }; @@ -111,52 +138,34 @@ export default function ClientDashboard(props: IProps) { const fetchDocuments = useCallback( async (customerUid: string | undefined) => { - /* TODO: review - 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, - }, - }, - }, - }, - }, - }; + LoaderService.getInstance().show(); + return new Promise((resolve: () => void) => { + DocumentService.getDocuments().then(async (processes: any[]) => { + if (processes.length > 0) { + let documents: any[] = processes.map((process: any) => process.processData); - return Documents.getInstance() - .get(query) - .then((documents) => setDocuments(documents)); - */ + // FilterBy folder.uid & depositor.uid + documents = documents.filter((document: any) => document.folder.uid === folderUid && document.depositor && document.depositor.uid === customerUid); - return DocumentService.getDocuments().then(async (processes: any[]) => { - if (processes.length > 0) { - let documents: any[] = processes.map((process: any) => process.processData); - - // FilterBy folder_uid - documents = documents.filter((document: any) => document.folder.uid === folderUid); - - for (const document of documents) { - document.document_type = (await DocumentTypeService.getDocumentTypeByUid(document.document_type.uid)).processData; - - if (document.files && document.files.length > 0) { - const files: any[] = []; - for (const file of document.files) { - files.push((await FileService.getFileByUid(file.uid)).processData); + for (const document of documents) { + if (document.document_type) { + document.document_type = (await DocumentTypeService.getDocumentTypeByUid(document.document_type.uid)).processData; } - document.files = files; - } - } - setDocuments(documents); - } + if (document.files && document.files.length > 0) { + const files: any[] = []; + for (const file of document.files) { + files.push((await FileService.getFileByUid(file.uid)).processData); + } + document.files = files; + } + } + + setDocuments(documents); + } + LoaderService.getInstance().hide(); + resolve(); + }); }); }, [folderUid], @@ -170,12 +179,28 @@ export default function ClientDashboard(props: IProps) { const customerUid = customer?.uid; if (!folderUid || !customerUid) return; - /* TODO: review - DocumentsNotary.getInstance() - .get({ where: { folder: { uid: folderUid }, customer: { uid: customerUid } }, include: { files: true } }) - .then((documentsNotary) => setDocumentsNotary(documentsNotary)); - */ + LoaderService.getInstance().show(); + DocumentService.getDocuments().then(async (processes: any[]) => { + if (processes.length > 0) { + let documents: any[] = processes.map((process: any) => process.processData); + // FilterBy folder.uid & customer.uid + documents = documents.filter((document: any) => document.folder.uid === folderUid && document.customer && document.customer.uid === customerUid); + + for (const document of documents) { + if (document.files && document.files.length > 0) { + const files: any[] = []; + for (const file of document.files) { + files.push((await FileService.getFileByUid(file.uid)).processData); + } + document.files = files; + } + } + + setDocumentsNotary(documents); + LoaderService.getInstance().hide(); + } + }); }, [folderUid, customer?.uid]); const documentsNotaryNotRead = useMemo( @@ -312,8 +337,52 @@ export default function ClientDashboard(props: IProps) { isOpen={isAuthModalOpen} onClose={() => { setIsAuthModalOpen(false); + setIsSmsModalOpen(true); }} />} + + {isSmsModalOpen && ( + setIsSmsModalOpen(false)} + title="Vérification SMS" + > +
+ + Veuillez saisir le code à 4 chiffres que vous avez reçu par SMS + + + { + const value = e.target.value; + // Only allow digits + if (value === "" || /^\d+$/.test(value)) { + setSmsCode(value); + setSmsError(""); + } + }} + /> + + {smsError && ( + + {smsError} + + )} + +
+ +
+
+
+ )} ); diff --git a/src/front/Components/Layouts/DeedTypes/DeedTypesCreate/index.tsx b/src/front/Components/Layouts/DeedTypes/DeedTypesCreate/index.tsx index ffee55fc..96a68be9 100644 --- a/src/front/Components/Layouts/DeedTypes/DeedTypesCreate/index.tsx +++ b/src/front/Components/Layouts/DeedTypes/DeedTypesCreate/index.tsx @@ -5,6 +5,7 @@ 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 DefaultDeedTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDeedTypeDashboard"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import Module from "@Front/Config/Module"; import JwtService from "@Front/Services/JwtService/JwtService"; import { DeedType, Office } from "le-coffre-resources/dist/Admin"; @@ -15,6 +16,7 @@ import classes from "./classes.module.scss"; import { validateOrReject, ValidationError } from "class-validator"; import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = {}; export default function DeedTypesCreate(props: IProps) { @@ -52,7 +54,13 @@ export default function DeedTypesCreate(props: IProps) { }; const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + LoaderService.getInstance().show(); DeedTypeService.createDeedType(deedTypeData, validatorId).then((processCreated: any) => { + ToasterService.getInstance().success({ + title: "Succès !", + description: "Type d'acte créé avec succès" + }); + setTimeout(() => LoaderService.getInstance().hide(), 2000); router.push( Module.getInstance() .get() diff --git a/src/front/Components/Layouts/DeedTypes/DeedTypesEdit/index.tsx b/src/front/Components/Layouts/DeedTypes/DeedTypesEdit/index.tsx index fb4a4946..064509a3 100644 --- a/src/front/Components/Layouts/DeedTypes/DeedTypesEdit/index.tsx +++ b/src/front/Components/Layouts/DeedTypes/DeedTypesEdit/index.tsx @@ -14,6 +14,9 @@ import { ValidationError } from "class-validator"; import classes from "./classes.module.scss"; +import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; + export default function DeedTypesEdit() { const router = useRouter(); let { deedTypeUid } = router.query; @@ -27,12 +30,14 @@ export default function DeedTypesEdit() { setHasChanged(false); async function getDeedType() { if (!deedTypeUid) return; - const deedType = await DeedTypes.getInstance().getByUid(deedTypeUid as string, { - q: { - document_types: true, - }, + LoaderService.getInstance().show(); + DeedTypeService.getDeedTypeByUid(deedTypeUid as string).then((process: any) => { + if (process) { + const deedType: any = process.processData; + setDeedTypeSelected(deedType); + } + setTimeout(() => LoaderService.getInstance().hide(), 2000); }); - setDeedTypeSelected(deedType); } getDeedType(); @@ -57,19 +62,19 @@ export default function DeedTypesEdit() { return; } try { - await DeedTypes.getInstance().put( - deedTypeUid as string, - DeedType.hydrate({ - uid: deedTypeUid as string, - name: values["name"], - description: values["description"], - }), - ); - router.push( - Module.getInstance() - .get() - .modules.pages.DeedTypes.pages.DeedTypesInformations.props.path.replace("[uid]", deedTypeUid as string), - ); + LoaderService.getInstance().show(); + DeedTypeService.getDeedTypeByUid(deedTypeUid as string).then((process: any) => { + if (process) { + DeedTypeService.updateDeedType(process, { name: values["name"], description: values["description"] }).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); + router.push( + Module.getInstance() + .get() + .modules.pages.DeedTypes.pages.DeedTypesInformations.props.path.replace("[uid]", deedTypeUid as string), + ); + }); + } + }); } catch (validationErrors) { if (!Array.isArray(validationErrors)) return; setValidationError(validationErrors as ValidationError[]); diff --git a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx index e55ad29c..778758f7 100644 --- a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx +++ b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx @@ -20,6 +20,7 @@ import classes from "./classes.module.scss"; import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService"; import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = {}; export default function DeedTypesInformations(props: IProps) { @@ -50,9 +51,11 @@ export default function DeedTypesInformations(props: IProps) { }, []); const deleteDeedType = useCallback(async () => { + LoaderService.getInstance().show(); DeedTypeService.getDeedTypeByUid(deedTypeUid as string).then((process: any) => { if (process) { DeedTypeService.updateDeedType(process, { archived_at: new Date().toISOString() }).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); router.push(Module.getInstance().get().modules.pages.DeedTypes.props.path); }); } @@ -103,6 +106,7 @@ export default function DeedTypesInformations(props: IProps) { ); const saveDocumentTypes = useCallback(() => { + LoaderService.getInstance().show(); DeedTypeService.getDeedTypeByUid(deedTypeUid as string, false).then((process: any) => { if (process) { const deedType: any = process.processData; @@ -115,6 +119,7 @@ export default function DeedTypesInformations(props: IProps) { .forEach((selectedDocument: any) => document_types.push(selectedDocument)); DeedTypeService.updateDeedType(process, { document_types: document_types }).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); closeSaveModal(); }); } diff --git a/src/front/Components/Layouts/DocumentTypes/DocumentTypesCreate/index.tsx b/src/front/Components/Layouts/DocumentTypes/DocumentTypesCreate/index.tsx index 91906073..eba9773d 100644 --- a/src/front/Components/Layouts/DocumentTypes/DocumentTypesCreate/index.tsx +++ b/src/front/Components/Layouts/DocumentTypes/DocumentTypesCreate/index.tsx @@ -4,6 +4,7 @@ import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import DefaultDocumentTypesDashboard from "@Front/Components/LayoutTemplates/DefaultDocumentTypesDashboard"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import Module from "@Front/Config/Module"; import JwtService from "@Front/Services/JwtService/JwtService"; import { validateOrReject, ValidationError } from "class-validator"; @@ -14,6 +15,7 @@ import { useCallback, useState } from "react"; import classes from "./classes.module.scss"; import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = {}; export default function DocumentTypesCreate(props: IProps) { @@ -37,7 +39,7 @@ export default function DocumentTypesCreate(props: IProps) { }); await validateOrReject(documentFormModel, { groups: ["createDocumentType"] }); - const documentData: any = { + const documentTypeData: any = { ...values, office: { uid: officeId, @@ -45,7 +47,13 @@ export default function DocumentTypesCreate(props: IProps) { }; const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; - DocumentTypeService.createDocumentType(documentData, validatorId).then((processCreated: any) => { + LoaderService.getInstance().show(); + DocumentTypeService.createDocumentType(documentTypeData, validatorId).then((processCreated: any) => { + ToasterService.getInstance().success({ + title: "Succès !", + description: "Type de document créé avec succès" + }); + setTimeout(() => LoaderService.getInstance().hide(), 2000); router.push( Module.getInstance() .get() diff --git a/src/front/Components/Layouts/DocumentTypes/DocumentTypesEdit/index.tsx b/src/front/Components/Layouts/DocumentTypes/DocumentTypesEdit/index.tsx index 9bc489bd..3fe6de1b 100644 --- a/src/front/Components/Layouts/DocumentTypes/DocumentTypesEdit/index.tsx +++ b/src/front/Components/Layouts/DocumentTypes/DocumentTypesEdit/index.tsx @@ -1,4 +1,3 @@ -import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Form from "@Front/Components/DesignSystem/Form"; import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; @@ -13,6 +12,9 @@ import { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; +import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; + export default function DocumentTypesEdit() { const router = useRouter(); let { documentTypeUid } = router.query; @@ -23,10 +25,14 @@ export default function DocumentTypesEdit() { useEffect(() => { async function getDocumentType() { if (!documentTypeUid) return; - const documentType = await DocumentTypes.getInstance().getByUid(documentTypeUid as string, { - _count: true, + LoaderService.getInstance().show(); + DocumentTypeService.getDocumentTypeByUid(documentTypeUid as string).then((process: any) => { + if (process) { + const documentType: any = process.processData; + setDocumentTypeSelected(documentType); + } + setTimeout(() => LoaderService.getInstance().hide(), 2000); }); - setDocumentTypeSelected(documentType); } getDocumentType(); @@ -46,16 +52,22 @@ export default function DocumentTypesEdit() { setValidationError(validationErrors as ValidationError[]); return; } - - const documentTypeUpdated = await DocumentTypes.getInstance().put(documentTypeUid as string, documentToUpdate); - router.push( - Module.getInstance() - .get() - .modules.pages.DocumentTypes.pages.DocumentTypesInformations.props.path.replace( - "[uid]", - documentTypeUpdated.uid ?? "", - ), - ); + LoaderService.getInstance().show(); + DocumentTypeService.getDocumentTypeByUid(documentTypeUid as string).then((process: any) => { + if (process) { + DocumentTypeService.updateDocumentType(process, values).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); + router.push( + Module.getInstance() + .get() + .modules.pages.DocumentTypes.pages.DocumentTypesInformations.props.path.replace( + "[uid]", + documentTypeUid as string ?? "", + ) + ); + }); + } + }); } catch (validationErrors: Array | any) { if (!Array.isArray(validationErrors)) return; setValidationError(validationErrors as ValidationError[]); diff --git a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx index 607245a9..358cc6c1 100644 --- a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx +++ b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx @@ -7,6 +7,7 @@ import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; import Module from "@Front/Config/Module"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import { ValidationError } from "class-validator"; import { ECivility } from "le-coffre-resources/dist/Customer/Contact"; import { Contact, Customer } from "le-coffre-resources/dist/Notary"; @@ -17,6 +18,7 @@ import classes from "./classes.module.scss"; import { useCallback, useEffect, useState } from "react"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; @@ -78,6 +80,7 @@ export default function AddClientToFolder(props: IProps) { }; const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + LoaderService.getInstance().show(); CustomerService.createCustomer(customerData, validatorId).then((processCreated: any) => { FolderService.getFolderByUid(folderUid as string, false, false).then((process: any) => { if (process) { @@ -88,6 +91,11 @@ export default function AddClientToFolder(props: IProps) { customers.push(processCreated.processData.uid); FolderService.updateFolder(process, { customers: customers }).then(() => { + ToasterService.getInstance().success({ + title: "Succès !", + description: "Client ajouté avec succès au dossier" + }); + setTimeout(() => LoaderService.getInstance().hide(), 2000); router.push(`/folders/${folderUid}`); }); } @@ -99,11 +107,17 @@ export default function AddClientToFolder(props: IProps) { return; } } else { + LoaderService.getInstance().show(); FolderService.getFolderByUid(folderUid as string, false, false).then((process: any) => { if (process) { const customers: any[] = customersToLink.map((customer: any) => customer.uid); FolderService.updateFolder(process, { customers: customers }).then(() => { + ToasterService.getInstance().success({ + title: "Succès !", + description: selectedCustomers.length > 1 ? "Clients associés avec succès au dossier" : "Client associé avec succès au dossier" + }); + setTimeout(() => LoaderService.getInstance().hide(), 2000); router.push(`/folders/${folderUid}`); }); } @@ -142,6 +156,7 @@ export default function AddClientToFolder(props: IProps) { ); const loadCustomers = useCallback(async () => { + LoaderService.getInstance().show(); CustomerService.getCustomers().then(async (processes: any[]) => { const availableCustomers: any[] = processes.map((process: any) => process.processData); @@ -162,6 +177,8 @@ export default function AddClientToFolder(props: IProps) { setExistingCustomers(existingCustomers); setIsLoaded(true); setSelectedOption(selectedOption); + + LoaderService.getInstance().hide(); }); }, [folderUid, getFolderPreSelectedCustomers]); diff --git a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx index 3ab37262..56512953 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/AskDocuments/ParameterDocuments/index.tsx @@ -1,5 +1,3 @@ -import Deeds from "@Front/Api/LeCoffreApi/Notary/Deeds/Deeds"; -import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes"; import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption"; import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; import { IOption as IFormOption } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; @@ -7,12 +5,14 @@ import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import Modal from "@Front/Components/DesignSystem/Modal"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; -import { DocumentType, OfficeFolder } from "le-coffre-resources/dist/Notary"; +import { OfficeFolder } from "le-coffre-resources/dist/Notary"; import { ChangeEvent, useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService"; +import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = { isCreateDocumentModalVisible: boolean; @@ -75,18 +75,38 @@ export default function ParameterDocuments(props: IProps) { const addDocument = useCallback(async () => { if (addOrEditDocument === "add") { try { - const documentType = await DocumentTypes.getInstance().post({ + LoaderService.getInstance().show(); + + const documentTypeData: any = { name: documentName, private_description: visibleDescription, office: { uid: props.folder.office!.uid!, }, public_description: visibleDescription, + }; + const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + + const documentType: any = await new Promise((resolve: (documentType: any) => void) => { + DocumentTypeService.createDocumentType(documentTypeData, validatorId).then((processCreated: any) => { + const documentType: any = processCreated.processData; + resolve(documentType); + }); }); const oldDocumentsType = props.folder.deed?.document_types!; - await Deeds.getInstance().put(props.folder.deed?.uid!, { - document_types: [...oldDocumentsType, documentType], + + await new Promise((resolve: () => void) => { + DeedTypeService.getDeedTypeByUid(props.folder.deed?.deed_type?.uid!).then((process: any) => { + if (process) { + DeedTypeService.updateDeedType(process, { + document_types: [ + ...oldDocumentsType.map((document: any) => ({ uid: document.uid })), + { uid: documentType.uid } + ] + }).then(() => resolve()); + } + }); }); // Create a new document type in the format expected by the parent component @@ -100,28 +120,44 @@ export default function ParameterDocuments(props: IProps) { props.onDocumentsUpdated([newDocumentType]); } + LoaderService.getInstance().hide(); handleClose(); } catch (e) { console.error(e); } } else { try { + LoaderService.getInstance().show(); + const oldDocumentsType = props.folder.deed?.document_types!; - await Deeds.getInstance().put(props.folder.deed?.uid!, { - document_types: [ - ...oldDocumentsType, - ...selectedDocuments.map((document) => DocumentType.hydrate({ uid: document.id as string })), - ], + await new Promise((resolve: () => void) => { + DeedTypeService.getDeedTypeByUid(props.folder.deed?.deed_type?.uid!).then((process: any) => { + if (process) { + DeedTypeService.updateDeedType(process, { + document_types: [ + ...oldDocumentsType.map((document: any) => ({ uid: document.uid })), + ...selectedDocuments.map((document: any) => ({ uid: document.id as string })) + ] + }).then(() => resolve()); + } + }); }); // Get the full document details for the selected documents const documentsById = await Promise.all( selectedDocuments.map(async (doc) => { - const fullDoc = await DocumentTypes.getInstance().getByUid(doc.id as string); + const documentType: any = await new Promise((resolve: (documentType: any) => void) => { + DocumentTypeService.getDocumentTypeByUid(doc.id as string).then((process: any) => { + if (process) { + const documentType: any = process.processData; + resolve(documentType); + } + }); + }); return { - label: fullDoc.name!, - value: fullDoc.uid!, - description: fullDoc.private_description!, + label: documentType.name!, + value: documentType.uid!, + description: documentType.private_description!, } as IFormOption; }) ); @@ -130,6 +166,7 @@ export default function ParameterDocuments(props: IProps) { props.onDocumentsUpdated(documentsById); } + LoaderService.getInstance().hide(); handleClose(); } catch (e) { console.error(e); diff --git a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx index 9897aed5..949c1ca4 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx @@ -17,6 +17,7 @@ import backgroundImage from "@Assets/images/background_refonte.svg"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; export default function AskDocuments() { const router = useRouter(); @@ -58,8 +59,8 @@ export default function AskDocuments() { ) => { try { // TODO: review + LoaderService.getInstance().show(); const documentAsked: [] = values["document_types"] as []; - for (let i = 0; i < documentAsked.length; i++) { const documentData: any = { folder: { @@ -77,7 +78,6 @@ export default function AskDocuments() { await DocumentService.createDocument(documentData, validatorId); } - router.push( Module.getInstance() .get() @@ -127,11 +127,13 @@ export default function AskDocuments() { const loadData = useCallback(async () => { try { + LoaderService.getInstance().show(); FolderService.getFolderByUid(folderUid as string).then(async (process: any) => { if (process) { const folder: any = process.processData; setFolder(folder); setDocumentTypes(await getAvailableDocuments(folder)); + LoaderService.getInstance().hide(); } }); } catch (e) { diff --git a/src/front/Components/Layouts/Folder/CreateCustomerNote/index.tsx b/src/front/Components/Layouts/Folder/CreateCustomerNote/index.tsx index ea17b9a4..55c9db9d 100644 --- a/src/front/Components/Layouts/Folder/CreateCustomerNote/index.tsx +++ b/src/front/Components/Layouts/Folder/CreateCustomerNote/index.tsx @@ -17,6 +17,7 @@ import Note from "le-coffre-resources/dist/Customer/Note"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService"; import NoteService from "src/common/Api/LeCoffreApi/sdk/NoteService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = {}; @@ -83,6 +84,8 @@ class CreateCustomerNoteClass extends BasePage { const customer = await Customers.getInstance().getByUid(this.props.customerUid); */ + LoaderService.getInstance().show(); + const folder: any = await FolderService.getFolderByUid(this.props.folderUid).then((process: any) => { if (process) { const folder: any = process.processData; @@ -97,6 +100,8 @@ class CreateCustomerNoteClass extends BasePage { } }); + LoaderService.getInstance().hide(); + //get the note of the folder that has customer_uid = this.props.customer.uid // const folderNote = folder.notes?.find((note) => note.customer?.uid === this.props.customerUid); // this.setState({ note, folder: note.office_folder || null, customer: note.customer || null }); @@ -121,6 +126,7 @@ class CreateCustomerNoteClass extends BasePage { }; const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + LoaderService.getInstance().show(); NoteService.createNote(noteData, validatorId).then(() => { this.props.router.push(this.backwardPath); }); diff --git a/src/front/Components/Layouts/Folder/CreateFolder/index.tsx b/src/front/Components/Layouts/Folder/CreateFolder/index.tsx index 7063f195..e41a625d 100644 --- a/src/front/Components/Layouts/Folder/CreateFolder/index.tsx +++ b/src/front/Components/Layouts/Folder/CreateFolder/index.tsx @@ -8,6 +8,7 @@ import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextField from "@Front/Components/DesignSystem/Form/TextField"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import BackArrow from "@Front/Components/Elements/BackArrow"; import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage"; import JwtService from "@Front/Services/JwtService/JwtService"; @@ -22,6 +23,7 @@ import classes from "./classes.module.scss"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; export default function CreateFolder(): JSX.Element { /** @@ -95,7 +97,13 @@ export default function CreateFolder(): JSX.Element { status: EFolderStatus.LIVE }; + LoaderService.getInstance().show(); FolderService.createFolder(folderData, [], []).then((processCreated: any) => { + ToasterService.getInstance().success({ + title: "Succès !", + description: "Dossier créé avec succès" + }); + setTimeout(() => LoaderService.getInstance().hide(), 2000); const folderUid: string = processCreated.processData.uid; router.push(`/folders/${folderUid}`); }); 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 80c54530..fd44a797 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/ClientBox/index.tsx @@ -14,6 +14,7 @@ import classes from "./classes.module.scss"; import DeleteCustomerModal from "./DeleteCustomerModal"; import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = { customer: Customer; @@ -37,12 +38,13 @@ export default function ClientBox(props: IProps) { const handleDelete = useCallback( (customerUid: string) => { + LoaderService.getInstance().show(); DocumentService.getDocuments().then((processes: any[]) => { if (processes.length > 0) { let documents: any[] = processes.map((process: any) => process.processData); - // FilterBy depositor_uid & folder_uid - documents = documents.filter((document: any) => document.depositor.uid === customerUid && document.folder.uid === folderUid); + // FilterBy folder.uid & depositor.uid + documents = documents.filter((document: any) => document.folder.uid === folderUid && document.depositor && document.depositor.uid === customerUid); if (documents && documents.length > 0) { closeDeleteModal(); 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 86c332df..95983ee9 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 @@ -4,6 +4,7 @@ import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import React, { useCallback } from "react"; import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = { documentUid: string; @@ -16,7 +17,8 @@ export default function DeleteAskedDocumentModal(props: IProps) { const { isOpen, onClose, documentUid, onDeleteSuccess } = props; const onDelete = useCallback( - () => + () => { + LoaderService.getInstance().show(); new Promise( (resolve: () => void) => { DocumentService.getDocumentByUid(documentUid).then((process: any) => { @@ -27,8 +29,10 @@ export default function DeleteAskedDocumentModal(props: IProps) { }) .then(() => onDeleteSuccess(documentUid)) .then(() => ToasterService.getInstance().success({ title: "Succès !", description: "Le document a été supprimé avec succès." })) + .then(() => LoaderService.getInstance().hide()) .then(onClose) - .catch((error) => console.warn(error)), + .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 e3d6296e..233c9566 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,9 +1,11 @@ -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"; +import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; + type IProps = { documentUid: string; isOpen: boolean; @@ -15,13 +17,18 @@ export default function DeleteSentDocumentModal(props: IProps) { const { isOpen, onClose, documentUid, onDeleteSuccess } = props; const onDelete = useCallback( - () => - 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)), + () => { + LoaderService.getInstance().show(); + DocumentService.getDocumentByUid(documentUid).then((process: any) => { + if (process) { + DocumentService.updateDocument(process, { isDeleted: 'true' }) + .then(() => onDeleteSuccess(documentUid)) + .then(() => ToasterService.getInstance().success({ title: "Succès !", description: "Le document a été supprimé avec succès." })) + .then(() => LoaderService.getInstance().hide()) + .then(onClose); + } + }); + }, [documentUid, onClose, onDeleteSuccess], ); 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 f38d5e35..9f99eb02 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/DocumentTables/index.tsx @@ -1,5 +1,3 @@ -import DocumentsNotary from "@Front/Api/LeCoffreApi/Notary/DocumentsNotary/DocumentsNotary"; -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"; @@ -10,7 +8,6 @@ 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, { EDocumentNotaryStatus } from "le-coffre-resources/dist/Notary/DocumentNotary"; import Link from "next/link"; @@ -24,6 +21,7 @@ import DeleteSentDocumentModal from "./DeleteSentDocumentModal"; import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService"; import FileService from "src/common/Api/LeCoffreApi/sdk/FileService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = { customerUid: string; @@ -44,7 +42,7 @@ const tradDocumentsNotaryStatus: Record = { export default function DocumentTables(props: IProps) { const { folderUid, customerUid } = props; - const [documents, setDocuments] = useState([]); + const [documents, setDocuments] = useState([]); const [documentsNotary, setDocumentsNotary] = useState([]); const [focusedDocumentUid, setFocusedDocumentUid] = useState(null); @@ -55,17 +53,18 @@ export default function DocumentTables(props: IProps) { const fetchDocuments = useCallback( () => { - setDocuments([]); - + LoaderService.getInstance().show(); DocumentService.getDocuments().then(async (processes: any[]) => { if (processes.length > 0) { let documents: any[] = processes.map((process: any) => process.processData); // FilterBy folder.uid & depositor.uid - documents = documents.filter((document: any) => document.folder.uid === folderUid && document.depositor.uid === customerUid); + documents = documents.filter((document: any) => document.folder.uid === folderUid && document.depositor && document.depositor.uid === customerUid); for (const document of documents) { - document.document_type = (await DocumentTypeService.getDocumentTypeByUid(document.document_type.uid)).processData; + if (document.document_type) { + document.document_type = (await DocumentTypeService.getDocumentTypeByUid(document.document_type.uid)).processData; + } if (document.files && document.files.length > 0) { const files: any[] = []; @@ -80,24 +79,45 @@ export default function DocumentTables(props: IProps) { } else { setDocuments([]); } - }) + LoaderService.getInstance().hide(); + }); }, [customerUid, folderUid], ); const fetchDocumentsNotary = useCallback( - () => - DocumentsNotary.getInstance() - .get({ where: { folder: { uid: folderUid }, customer: { uid: customerUid } }, include: { files: true } }) - .then(setDocumentsNotary) - .catch(console.warn), + () => { + LoaderService.getInstance().show(); + DocumentService.getDocuments().then(async (processes: any[]) => { + if (processes.length > 0) { + let documents: any[] = processes.map((process: any) => process.processData); + + // FilterBy folder.uid & customer.uid + documents = documents.filter((document: any) => document.folder.uid === folderUid && document.customer && document.customer.uid === customerUid); + + for (const document of documents) { + if (document.files && document.files.length > 0) { + const files: any[] = []; + for (const file of document.files) { + files.push((await FileService.getFileByUid(file.uid)).processData); + } + document.files = files; + } + } + + setDocumentsNotary(documents); + } else { + setDocumentsNotary([]); + } + LoaderService.getInstance().hide(); + }); + }, [customerUid, folderUid], ); useEffect(() => { - // TODO: review fetchDocuments(); - //fetchDocumentsNotary(); + fetchDocumentsNotary(); }, [fetchDocuments, fetchDocumentsNotary]); const openDeleteAskedDocumentModal = useCallback( @@ -137,21 +157,23 @@ export default function DocumentTables(props: IProps) { }).catch((e) => console.warn(e)); }, []); - const onDownloadFileNotary = useCallback((doc: DocumentNotary) => { + const onDownloadFileNotary = useCallback((doc: any) => { const file = doc.files?.[0]; - if (!file || !file?.uid) return; + if (!file) 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)); + return new Promise((resolve: () => void) => { + const blob = new Blob([file.file_blob.data], { type: file.file_blob.type }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = file.file_name; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); + + resolve(); + }).catch((e) => console.warn(e)); }, []); const askedDocuments: IRowProps[] = useMemo( @@ -161,21 +183,25 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.ASKED) return null; return { key: document.uid, - document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_type: { sx: { width: 300 }, content: document.document_type?.name ?? "_" }, document_status: { sx: { width: 107 }, content: ( ), }, date: { - sx: { width: 107 }, + sx: { width: 120 }, content: document.created_at ? new Date(document.created_at).toLocaleDateString() : "_", }, + file: { + sx: { width: 120 }, + content: "_", + }, actions: { sx: { width: 76 }, content: ( @@ -197,21 +223,25 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.DEPOSITED) return null; return { key: document.uid, - document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_type: { sx: { width: 300 }, content: document.document_type?.name ?? "_" }, document_status: { sx: { width: 107 }, content: ( ), }, date: { - sx: { width: 107 }, + sx: { width: 120 }, content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", }, + file: { + sx: { width: 120 }, + content: document.files?.[0]?.file_name ?? "_", + }, actions: { sx: { width: 76 }, content: ( @@ -239,21 +269,25 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.VALIDATED) return null; return { key: document.uid, - document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_type: { sx: { width: 300 }, content: document.document_type?.name ?? "_" }, document_status: { sx: { width: 107 }, content: ( ), }, date: { - sx: { width: 107 }, + sx: { width: 120 }, content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", }, + file: { + sx: { width: 120 }, + content: document.files?.[0]?.file_name ?? "_", + }, actions: { sx: { width: 76 }, content: ( @@ -282,21 +316,25 @@ export default function DocumentTables(props: IProps) { if (document.document_status !== EDocumentStatus.REFUSED) return null; return { key: document.uid, - document_type: { sx: { width: 400 }, content: document.document_type?.name ?? "_" }, + document_type: { sx: { width: 300 }, content: document.document_type?.name ?? "_" }, document_status: { sx: { width: 107 }, content: ( ), }, date: { - sx: { width: 107 }, + sx: { width: 120 }, content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", }, + file: { + sx: { width: 120 }, + content: document.files?.[0]?.file_name ?? "_", + }, actions: { sx: { width: 76 }, content: "" }, }; }) @@ -311,7 +349,7 @@ export default function DocumentTables(props: IProps) { return { key: document.uid, document_type: { - sx: { width: 400 }, + sx: { width: 300 }, content: formatName(document.files?.[0]?.file_name?.split(".")?.[0] ?? "") || "_", }, document_status: { @@ -319,9 +357,13 @@ export default function DocumentTables(props: IProps) { content: getTagForSentDocument(document.document_status as EDocumentNotaryStatus), }, date: { - sx: { width: 107 }, + sx: { width: 120 }, content: document.updated_at ? new Date(document.updated_at).toLocaleDateString() : "_", }, + file: { + sx: { width: 120 }, + content: document.files?.[0]?.file_name ?? "_", + }, actions: { sx: { width: 76 }, content: ( @@ -408,6 +450,10 @@ function getHeader(dateColumnTitle: string, isMobile: boolean): IHead[] { key: "date", title: dateColumnTitle, }, + { + key: "file", + title: "Fichier", + }, { key: "actions", title: "Action", diff --git a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx index b060b849..61677356 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/ClientView/index.tsx @@ -16,6 +16,7 @@ import DocumentTables from "./DocumentTables"; import EmailReminder from "./EmailReminder"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = { folder: OfficeFolder; @@ -62,7 +63,7 @@ export default function ClientView(props: IProps) { const handleClientDelete = useCallback( (customerUid: string) => { if (!folder.uid) return; - + LoaderService.getInstance().show(); FolderService.getFolderByUid(folder.uid, false, false).then((process: any) => { if (process) { const folder: any = process.processData; @@ -71,6 +72,7 @@ export default function ClientView(props: IProps) { const customers = folder.customers.filter((uid: string) => uid !== customerUid); FolderService.updateFolder(process, { customers: customers }).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); window.location.reload(); }); } diff --git a/src/front/Components/Layouts/Folder/FolderInformation/NoClientView/DeleteFolderModal/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/NoClientView/DeleteFolderModal/index.tsx index 00fcab8d..ec0958e6 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/NoClientView/DeleteFolderModal/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/NoClientView/DeleteFolderModal/index.tsx @@ -6,6 +6,7 @@ import { useRouter } from "next/router"; import React, { useCallback } from "react"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = { isOpen: boolean; @@ -24,9 +25,13 @@ export default function DeleteFolderModal(props: IProps) { return new Promise( (resolve: () => void) => { + LoaderService.getInstance().show(); FolderService.getFolderByUid(folder.uid!).then((process: any) => { if (process) { - FolderService.updateFolder(process, { isDeleted: 'true' }).then(() => resolve()); + FolderService.updateFolder(process, { isDeleted: 'true' }).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); + resolve(); + }); } }); }) diff --git a/src/front/Components/Layouts/Folder/FolderInformation/index.tsx b/src/front/Components/Layouts/Folder/FolderInformation/index.tsx index aee4d974..e2cb8518 100644 --- a/src/front/Components/Layouts/Folder/FolderInformation/index.tsx +++ b/src/front/Components/Layouts/Folder/FolderInformation/index.tsx @@ -24,6 +24,7 @@ import AnchoringProcessingInfo from "./elements/AnchoringProcessingInfo"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; import NoteService from "src/common/Api/LeCoffreApi/sdk/NoteService"; import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; export enum AnchorStatus { "VERIFIED_ON_CHAIN" = "VERIFIED_ON_CHAIN", @@ -108,6 +109,7 @@ export default function FolderInformation(props: IProps) { */ // TODO: review + LoaderService.getInstance().show(); return FolderService.getFolderByUid(folderUid).then(async (process: any) => { if (process) { const folder: any = process.processData; @@ -133,7 +135,7 @@ export default function FolderInformation(props: IProps) { if (processes.length > 0) { const documents: any[] = processes.map((process: any) => process.processData); for (const customer of folder.customers) { - customer.documents = documents.filter((document: any) => document.depositor.uid === customer.uid); + customer.documents = documents.filter((document: any) => document.depositor && document.depositor.uid === customer.uid); } } resolve(); @@ -141,6 +143,7 @@ export default function FolderInformation(props: IProps) { }); setFolder(folder); + setTimeout(() => LoaderService.getInstance().hide(), 2000); } }); }, [folderUid]); diff --git a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx index cb34d08e..81f50e1c 100644 --- a/src/front/Components/Layouts/Folder/SendDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/SendDocuments/index.tsx @@ -1,6 +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 { EDocumentNotaryStatus } from "le-coffre-resources/dist/Notary/DocumentNotary"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import DragAndDrop from "@Front/Components/DesignSystem/DragAndDrop"; import Form from "@Front/Components/DesignSystem/Form"; @@ -19,6 +18,11 @@ import React, { useCallback, useEffect, useMemo, useState } from "react"; import classes from "./classes.module.scss"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; +import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; +import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService"; +import FileService from "src/common/Api/LeCoffreApi/sdk/FileService"; + enum EClientSelection { ALL_CLIENTS = "all_clients", SELECTED_CLIENTS = "selected_clients", @@ -59,6 +63,64 @@ export default function SendDocuments() { throw new Error("No clients selected"); } + LoaderService.getInstance().show(); + for (const selectedClient of selectedClients) { + for (const file of files) { + await new Promise((resolve: () => void) => { + const reader = new FileReader(); + reader.onload = (event) => { + if (event.target?.result) { + const arrayBuffer = event.target.result as ArrayBuffer; + const uint8Array = new Uint8Array(arrayBuffer); + + const fileBlob: any = { + type: file.type, + data: uint8Array + }; + + const fileData: any = { + file_blob: fileBlob, + file_name: file.name + }; + const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + + FileService.createFile(fileData, validatorId).then((processCreated: any) => { + const fileUid: string = processCreated.processData.uid; + + const documentData: any = { + folder: { + uid: folderUid as string + }, + customer: { + uid: selectedClient as string + }, + files: [ + { + uid: fileUid + } + ], + document_status: EDocumentNotaryStatus.SENT + }; + + DocumentService.createDocument(documentData, validatorId).then(() => resolve()); + }); + } + }; + reader.readAsArrayBuffer(file); + }); + } + } + LoaderService.getInstance().hide(); + + router.push( + Module.getInstance() + .get() + .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid as string), + ); + setIsSending(false); + ToasterService.getInstance().success({ title: "Succès !", description: "Votre document a été envoyée avec succès." }); + + /* await Promise.all( selectedClients.map(async (customer) => { const promises = files.map(async (file) => { @@ -83,6 +145,7 @@ export default function SendDocuments() { ); setIsSending(false); ToasterService.getInstance().success({ title: "Succès !", description: "Votre document a été envoyée avec succès." }); + */ } catch (error) { setIsSending(false); console.warn("Error while sending files: ", error); @@ -92,18 +155,14 @@ export default function SendDocuments() { ); const fetchFolder = useCallback(async () => { - Folders.getInstance() - .getByUid(folderUid as string, { - q: { - customers: { - include: { - contact: true, - }, - }, - }, - }) - .then((folder) => setFolder(folder)) - .catch((e) => console.warn(e)); + LoaderService.getInstance().show(); + FolderService.getFolderByUid(folderUid as string).then((process: any) => { + if (process) { + const folder: any = process.processData; + setFolder(folder); + LoaderService.getInstance().hide(); + } + }); }, [folderUid]); const onClientSelectionChange = useCallback( diff --git a/src/front/Components/Layouts/Folder/UpdateClient/index.tsx b/src/front/Components/Layouts/Folder/UpdateClient/index.tsx index baddb59c..1272a6a3 100644 --- a/src/front/Components/Layouts/Folder/UpdateClient/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateClient/index.tsx @@ -17,6 +17,7 @@ import { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; export default function UpdateClient() { const router = useRouter(); @@ -35,12 +36,12 @@ export default function UpdateClient() { useEffect(() => { const fetchCustomer = async () => { try { + LoaderService.getInstance().show(); CustomerService.getCustomerByUid(customerUid as string).then((process: any) => { if (process) { const customer: any = process.processData; - if (customer) { - setCustomer(customer); - } + setCustomer(customer); + setTimeout(() => LoaderService.getInstance().hide(), 2000); } }); } catch (error) { @@ -70,10 +71,13 @@ export default function UpdateClient() { try { await contact.validateOrReject?.({ groups: ["createCustomer"], forbidUnknownValues: false }); + + LoaderService.getInstance().show(); CustomerService.getCustomerByUid(customerUid as string).then((process: any) => { if (process) { // TODO: review - address CustomerService.updateCustomer(process, { contact: contact }).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); router.push(backwardPath); }); } diff --git a/src/front/Components/Layouts/Folder/UpdateCustomerNote/index.tsx b/src/front/Components/Layouts/Folder/UpdateCustomerNote/index.tsx index 1ea2323e..56ff7f2d 100644 --- a/src/front/Components/Layouts/Folder/UpdateCustomerNote/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateCustomerNote/index.tsx @@ -13,6 +13,7 @@ import classes from "./classes.module.scss"; import Note from "le-coffre-resources/dist/Customer/Note"; import NoteService from "src/common/Api/LeCoffreApi/sdk/NoteService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; type IProps = {}; @@ -67,6 +68,7 @@ class UpdateCustomerNoteClass extends BasePage { } public override async componentDidMount() { + LoaderService.getInstance().show(); NoteService.getNoteByUid(this.props.noteUid).then((process: any) => { if (process) { const note: any = process.processData; @@ -80,15 +82,17 @@ class UpdateCustomerNoteClass extends BasePage { .get() .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", note.folder?.uid!), }); + + LoaderService.getInstance().hide(); } }); } private async onFormSubmit(e: React.FormEvent | null, values: { [key: string]: string }) { try { + LoaderService.getInstance().show(); NoteService.getNoteByUid(this.props.noteUid).then((process: any) => { if (process) { - NoteService.updateNote(process, { content: values["content"] }).then(() => { this.props.router.push(this.state.backwardPath); }); diff --git a/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx b/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx index 9287bbb8..163d7197 100644 --- a/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateFolderMetadata/index.tsx @@ -19,6 +19,7 @@ import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import { isArray } from "class-validator"; import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; export default function UpdateFolderMetadata() { const router = useRouter(); @@ -48,14 +49,18 @@ export default function UpdateFolderMetadata() { setValidationError(validationErrors as ValidationError[]); return; } - try { - await Folders.getInstance().put(folderUid, newValues); - const url = Module.getInstance() - .get() - .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid); - - router.push(url); + LoaderService.getInstance().show(); + FolderService.getFolderByUid(folderUid).then((process: any) => { + if (process) { + FolderService.updateFolder(process, { ...values, deed: { uid: values["deed"] } }).then(() => { + setTimeout(() => LoaderService.getInstance().hide(), 2000); + router.push(Module.getInstance() + .get() + .modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", folderUid)); + }); + } + }); } catch (backError) { if (!Array.isArray(backError)) return; setValidationError(backError); @@ -65,24 +70,12 @@ export default function UpdateFolderMetadata() { useEffect(() => { if (!folderUid || isArray(folderUid)) return; - - /* TODO: review - const query = { - q: { - deed: { include: { deed_type: true } }, - office: true, - customers: { include: { contact: true } }, - }, - }; - Folders.getInstance() - .getByUid(folderUid, query) - .then((folder) => setSelectedFolder(folder)); - */ - + LoaderService.getInstance().show(); FolderService.getFolderByUid(folderUid).then((process: any) => { if (process) { const folder: any = process.processData; setSelectedFolder(folder); + setTimeout(() => LoaderService.getInstance().hide(), 2000); } }); }, [folderUid]); diff --git a/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx b/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx index 59ad2998..dd3f5312 100644 --- a/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx @@ -6,7 +6,7 @@ import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import Module from "@Front/Config/Module"; -import { Document, File } from "le-coffre-resources/dist/Notary"; +import { Document } from "le-coffre-resources/dist/Notary"; import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document"; import Image from "next/image"; import { NextRouter, useRouter } from "next/router"; diff --git a/src/front/Components/Layouts/Roles/RolesCreate/index.tsx b/src/front/Components/Layouts/Roles/RolesCreate/index.tsx index 46c92282..1ed07e3a 100644 --- a/src/front/Components/Layouts/Roles/RolesCreate/index.tsx +++ b/src/front/Components/Layouts/Roles/RolesCreate/index.tsx @@ -5,6 +5,7 @@ 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 DefaultRolesDashboard from "@Front/Components/LayoutTemplates/DefaultRoleDashboard"; +import { ToasterService } from "@Front/Components/DesignSystem/Toaster"; import Module from "@Front/Config/Module"; import { Office, OfficeRole } from "le-coffre-resources/dist/Admin"; import { useRouter } from "next/router"; @@ -16,6 +17,9 @@ import Rules, { RulesMode } from "@Front/Components/Elements/Rules"; import { AppRuleActions, AppRuleNames } from "@Front/Api/Entities/rule"; import { ValidationError } from "class-validator"; +import RoleService from "src/common/Api/LeCoffreApi/sdk/RoleService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; + type IProps = {}; export default function RolesCreate(props: IProps) { const [hasChanged, setHasChanged] = useState(false); @@ -26,12 +30,17 @@ export default function RolesCreate(props: IProps) { const onSubmitHandler = useCallback( async (e: React.FormEvent | null, values: { [key: string]: string }) => { const jwt = JwtService.getInstance().decodeJwt(); + + // TODO: review + const officeId = 'demo_notary_office_id'; //jwt?.office_Id; + const officeRole = OfficeRole.hydrate({ name: values["name"], office: Office.hydrate({ - uid: jwt?.office_Id, + uid: officeId, }), }); + try { await officeRole.validateOrReject?.({ groups: ["createOfficeRole"], forbidUnknownValues: true }); } catch (validationErrors: Array | any) { @@ -39,6 +48,29 @@ export default function RolesCreate(props: IProps) { setValidationError(validationErrors as ValidationError[]); return; } + + const roleData: any = { + name: values["name"], + office: { + uid: officeId, + } + }; + const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0'; + + LoaderService.getInstance().show(); + RoleService.createRole(roleData, validatorId).then((processCreated: any) => { + if (processCreated) { + ToasterService.getInstance().success({ + title: "Succès !", + description: "Rôle créé avec succès" + }); + setTimeout(() => LoaderService.getInstance().hide(), 2000); + const role: any = processCreated.processData; + router.push(Module.getInstance().get().modules.pages.Roles.pages.RolesInformations.props.path.replace("[uid]", role.uid!)); + } + }); + + /* try { const role = await OfficeRoles.getInstance().post( OfficeRole.hydrate({ @@ -55,6 +87,7 @@ export default function RolesCreate(props: IProps) { setValidationError(validationErrors as ValidationError[]); return; } + */ }, [router], ); diff --git a/src/front/Components/Layouts/Roles/RolesInformations/index.tsx b/src/front/Components/Layouts/Roles/RolesInformations/index.tsx index f8cd78af..490908a6 100644 --- a/src/front/Components/Layouts/Roles/RolesInformations/index.tsx +++ b/src/front/Components/Layouts/Roles/RolesInformations/index.tsx @@ -13,6 +13,9 @@ import React from "react"; import classes from "./classes.module.scss"; import RulesGroups from "@Front/Api/LeCoffreApi/Admin/RulesGroups/RulesGroups"; +import RoleService from "src/common/Api/LeCoffreApi/sdk/RoleService"; +import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService"; + type RuleGroupsCheckbox = RulesGroup & { checked: boolean; }; @@ -39,24 +42,60 @@ export default function RolesInformations() { setSelectAll(false); async function getUser() { if (!roleUid) return; + + /* const role = await OfficeRoles.getInstance().getByUid(roleUid as string, { q: { rules: true, }, }); + */ + LoaderService.getInstance().show(); + const role: any = await new Promise((resolve: (role: any) => void) => { + RoleService.getRoleByUid(roleUid as string).then((process: any) => { + if (process) { + const role: any = process.processData; + resolve(role); + setTimeout(() => LoaderService.getInstance().hide(), 2000); + } + }); + }) + + /* TODO: review const rulesGroups = await RulesGroups.getInstance().get({ include: { rules: true, }, }); + */ + const rulesGroups: RulesGroup[] = [ + { + uid: 'toto', + name: 'toto', + rules: [ + { + uid: 'toto', + name: 'toto', + label: 'toto', + namespace: 'toto', + created_at: new Date(), + updated_at: new Date(), + } + ], + created_at: new Date(), + updated_at: new Date(), + } + ]; if (!role) return; setRoleSelected(role); + + // TODO: review if (!role.rules) return; const rulesCheckboxes = rulesGroups .map((ruleGroup) => { - if (ruleGroup.rules?.every((rule) => role.rules?.find((r) => r.uid === rule.uid))) { + if (ruleGroup.rules?.every((rule) => role.rules?.find((r: any) => r.uid === rule.uid))) { return { ...ruleGroup, checked: true }; } return { ...ruleGroup, checked: false }; diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 5270afc4..508fba63 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -8,6 +8,8 @@ import getConfig from "next/config"; import { GoogleTagManager } from "@next/third-parties/google"; import { hotjar } from "react-hotjar"; +import Loader from "src/common/Api/LeCoffreApi/sdk/Loader"; + import IframeReference from "src/sdk/IframeReference"; import Iframe from "src/sdk/Iframe"; import MessageBus from "src/sdk/MessageBus"; @@ -115,6 +117,7 @@ const MyApp = (({ } {isConnected &&