Compare commits
No commits in common. "6e176a32e5f4b603c6e0a461591f9396126b4449" and "b6b0522b592bd65087b7eab1e27f1da0eb8df16d" have entirely different histories.
6e176a32e5
...
b6b0522b59
@ -21,7 +21,6 @@ import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService";
|
|||||||
import FileService from "src/common/Api/LeCoffreApi/sdk/FileService";
|
import FileService from "src/common/Api/LeCoffreApi/sdk/FileService";
|
||||||
import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService";
|
import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService";
|
||||||
import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService";
|
import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService";
|
||||||
import WatermarkService from "@Front/Services/WatermarkService";
|
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
onChange?: (files: File[]) => void;
|
onChange?: (files: File[]) => void;
|
||||||
@ -253,53 +252,50 @@ export default class DepositOtherDocument extends React.Component<IProps, IState
|
|||||||
for (let i = 0; i < filesArray.length; i++) {
|
for (let i = 0; i < filesArray.length; i++) {
|
||||||
const file = filesArray[i]!.file;
|
const file = filesArray[i]!.file;
|
||||||
await new Promise<void>((resolve: () => void) => {
|
await new Promise<void>((resolve: () => void) => {
|
||||||
// Add watermark to the file before processing
|
const reader = new FileReader();
|
||||||
WatermarkService.getInstance().addWatermark(file).then(async (watermarkedFile) => {
|
reader.onload = (event) => {
|
||||||
const reader = new FileReader();
|
if (event.target?.result) {
|
||||||
reader.onload = (event) => {
|
const date: Date = new Date();
|
||||||
if (event.target?.result) {
|
const strDate: string = `${date.getDate().toString().padStart(2, '0')}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getFullYear()}`;
|
||||||
const date: Date = new Date();
|
|
||||||
const strDate: string = `${date.getDate().toString().padStart(2, '0')}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getFullYear()}`;
|
|
||||||
|
|
||||||
const fileName: string = `${file.name.split('.')[0]}_${strDate}.${file.name.split('.').pop()}`;
|
const fileName: string = `${file.name.split('.')[0]}_${strDate}.${file.name.split('.').pop()}`;
|
||||||
|
|
||||||
const arrayBuffer: ArrayBuffer = event.target.result as ArrayBuffer;
|
const arrayBuffer: ArrayBuffer = event.target.result as ArrayBuffer;
|
||||||
const uint8Array: Uint8Array = new Uint8Array(arrayBuffer);
|
const uint8Array: Uint8Array = new Uint8Array(arrayBuffer);
|
||||||
|
|
||||||
const fileBlob: any = {
|
const fileBlob: any = {
|
||||||
type: watermarkedFile.type,
|
type: file.type,
|
||||||
data: uint8Array
|
data: uint8Array
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileData: any = {
|
const fileData: any = {
|
||||||
file_blob: fileBlob,
|
file_blob: fileBlob,
|
||||||
file_name: fileName
|
file_name: fileName
|
||||||
};
|
};
|
||||||
const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0';
|
const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0';
|
||||||
|
|
||||||
FileService.createFile(fileData, validatorId).then((processCreated: any) => {
|
FileService.createFile(fileData, validatorId).then((processCreated: any) => {
|
||||||
const fileUid: string = processCreated.processData.uid;
|
const fileUid: string = processCreated.processData.uid;
|
||||||
|
|
||||||
DocumentService.getDocumentByUid(documentCreated.uid).then((process: any) => {
|
DocumentService.getDocumentByUid(documentCreated.uid).then((process: any) => {
|
||||||
if (process) {
|
if (process) {
|
||||||
const document: any = process.processData;
|
const document: any = process.processData;
|
||||||
|
|
||||||
let files: any[] = document.files;
|
let files: any[] = document.files;
|
||||||
if (!files) {
|
if (!files) {
|
||||||
files = [];
|
files = [];
|
||||||
}
|
|
||||||
files.push({ uid: fileUid });
|
|
||||||
|
|
||||||
DocumentService.updateDocument(process, { files: files, document_status: EDocumentStatus.DEPOSITED }).then(() => {
|
|
||||||
FolderService.refreshFolderByUid(document.folder.uid).then(() => resolve());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
files.push({ uid: fileUid });
|
||||||
|
|
||||||
|
DocumentService.updateDocument(process, { files: files, document_status: EDocumentStatus.DEPOSITED }).then(() => {
|
||||||
|
FolderService.refreshFolderByUid(document.folder.uid).then(() => resolve());
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
};
|
}
|
||||||
reader.readAsArrayBuffer(watermarkedFile);
|
};
|
||||||
});
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import { IItem } from "@Front/Components/DesignSystem/Menu/MenuItem";
|
|||||||
import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag";
|
import Tag, { ETagColor } from "@Front/Components/DesignSystem/Tag";
|
||||||
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
import { ArchiveBoxIcon, DocumentTextIcon, EllipsisHorizontalIcon, PaperAirplaneIcon, PencilSquareIcon, ShieldCheckIcon, UsersIcon } from "@heroicons/react/24/outline";
|
import { ArchiveBoxIcon, EllipsisHorizontalIcon, PaperAirplaneIcon, PencilSquareIcon, ShieldCheckIcon, UsersIcon } from "@heroicons/react/24/outline";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
|
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
@ -21,11 +21,10 @@ type IProps = {
|
|||||||
onArchive: () => void;
|
onArchive: () => void;
|
||||||
anchorStatus: AnchorStatus;
|
anchorStatus: AnchorStatus;
|
||||||
isArchived: boolean;
|
isArchived: boolean;
|
||||||
onDownloadAllCertificates: () => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function InformationSection(props: IProps) {
|
export default function InformationSection(props: IProps) {
|
||||||
const { folder, progress, onArchive, anchorStatus, isArchived, onDownloadAllCertificates } = props;
|
const { folder, progress, onArchive, anchorStatus, isArchived } = props;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const menuItemsDekstop = useMemo(() => {
|
const menuItemsDekstop = useMemo(() => {
|
||||||
@ -57,13 +56,6 @@ export default function InformationSection(props: IProps) {
|
|||||||
.modules.pages.Folder.pages.VerifyDocuments.props.path.replace("[folderUid]", folder?.uid ?? "");
|
.modules.pages.Folder.pages.VerifyDocuments.props.path.replace("[folderUid]", folder?.uid ?? "");
|
||||||
router.push(verifyPath);
|
router.push(verifyPath);
|
||||||
},
|
},
|
||||||
hasSeparator: true,
|
|
||||||
};
|
|
||||||
|
|
||||||
const downloadAllCertificatesElement = {
|
|
||||||
icon: <DocumentTextIcon />,
|
|
||||||
text: "Télécharger tous les certificats",
|
|
||||||
onClick: () => onDownloadAllCertificates(),
|
|
||||||
hasSeparator: false,
|
hasSeparator: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -75,7 +67,6 @@ export default function InformationSection(props: IProps) {
|
|||||||
|
|
||||||
// Add verify document option
|
// Add verify document option
|
||||||
elements.push(verifyDocumentElement);
|
elements.push(verifyDocumentElement);
|
||||||
elements.push(downloadAllCertificatesElement);
|
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}, [anchorStatus, folder?.uid, router]);
|
}, [anchorStatus, folder?.uid, router]);
|
||||||
@ -112,13 +103,6 @@ export default function InformationSection(props: IProps) {
|
|||||||
hasSeparator: true,
|
hasSeparator: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const downloadAllCertificatesElement = {
|
|
||||||
icon: <DocumentTextIcon />,
|
|
||||||
text: "Télécharger tous les certificats",
|
|
||||||
onClick: () => onDownloadAllCertificates(),
|
|
||||||
hasSeparator: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the folder is not anchored, we can modify the collaborators and the informations
|
// If the folder is not anchored, we can modify the collaborators and the informations
|
||||||
if (anchorStatus === AnchorStatus.NOT_ANCHORED) {
|
if (anchorStatus === AnchorStatus.NOT_ANCHORED) {
|
||||||
elements.push(modifyCollaboratorsElement);
|
elements.push(modifyCollaboratorsElement);
|
||||||
@ -127,7 +111,6 @@ export default function InformationSection(props: IProps) {
|
|||||||
|
|
||||||
// Add verify document option
|
// Add verify document option
|
||||||
elements.push(verifyDocumentElement);
|
elements.push(verifyDocumentElement);
|
||||||
elements.push(downloadAllCertificatesElement);
|
|
||||||
|
|
||||||
elements.push({
|
elements.push({
|
||||||
icon: <PaperAirplaneIcon />,
|
icon: <PaperAirplaneIcon />,
|
||||||
@ -148,7 +131,7 @@ export default function InformationSection(props: IProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}, [anchorStatus, folder?.uid, isArchived, onArchive, onDownloadAllCertificates, router]);
|
}, [anchorStatus, folder?.uid, isArchived, onArchive, router]);
|
||||||
return (
|
return (
|
||||||
<section className={classes["root"]}>
|
<section className={classes["root"]}>
|
||||||
<div className={classes["info-box1"]}>
|
<div className={classes["info-box1"]}>
|
||||||
|
@ -21,13 +21,6 @@ import NoClientView from "./NoClientView";
|
|||||||
import AnchoringProcessingInfo from "./elements/AnchoringProcessingInfo";
|
import AnchoringProcessingInfo from "./elements/AnchoringProcessingInfo";
|
||||||
|
|
||||||
import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService";
|
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";
|
|
||||||
import { ToasterService } from "@Front/Components/DesignSystem/Toaster";
|
|
||||||
import PdfService from "@Front/Services/PdfService";
|
|
||||||
import MessageBus from "src/sdk/MessageBus";
|
|
||||||
import { saveAs } from "file-saver";
|
|
||||||
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
|
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
|
||||||
|
|
||||||
export enum AnchorStatus {
|
export enum AnchorStatus {
|
||||||
@ -152,121 +145,6 @@ export default function FolderInformation(props: IProps) {
|
|||||||
archiveModal.open();
|
archiveModal.open();
|
||||||
}, [anchorStatus, archiveModal, requireAnchoringModal]);
|
}, [anchorStatus, archiveModal, requireAnchoringModal]);
|
||||||
|
|
||||||
const onDownloadAllCertificates = useCallback(async () => {
|
|
||||||
if (!folder?.uid) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
LoaderService.getInstance().show();
|
|
||||||
|
|
||||||
// Get all documents for this folder
|
|
||||||
const allDocuments = await DocumentService.getDocuments();
|
|
||||||
const folderDocuments = allDocuments
|
|
||||||
.map((process: any) => process.processData)
|
|
||||||
.filter((doc: any) =>
|
|
||||||
doc.folder?.uid === folder.uid &&
|
|
||||||
doc.document_status === EDocumentStatus.VALIDATED
|
|
||||||
);
|
|
||||||
|
|
||||||
if (folderDocuments.length === 0) {
|
|
||||||
ToasterService.getInstance().warning({
|
|
||||||
title: "Aucun certificat",
|
|
||||||
description: "Aucun document validé trouvé pour ce dossier."
|
|
||||||
});
|
|
||||||
LoaderService.getInstance().hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate certificates for all validated documents
|
|
||||||
const certificates: any[] = [];
|
|
||||||
|
|
||||||
for (const doc of folderDocuments) {
|
|
||||||
try {
|
|
||||||
// Get customer info
|
|
||||||
const customer = doc.depositor || doc.customer;
|
|
||||||
|
|
||||||
const certificateData: any = {
|
|
||||||
customer: {
|
|
||||||
firstName: customer?.first_name || customer?.firstName || "N/A",
|
|
||||||
lastName: customer?.last_name || customer?.lastName || "N/A",
|
|
||||||
postalAddress: customer?.postal_address || customer?.address || customer?.postalAddress || "N/A",
|
|
||||||
email: customer?.email || "N/A"
|
|
||||||
},
|
|
||||||
notary: {
|
|
||||||
name: "N/A"
|
|
||||||
},
|
|
||||||
folderUid: folder.uid,
|
|
||||||
documentHash: "N/A",
|
|
||||||
metadata: {
|
|
||||||
fileName: "N/A",
|
|
||||||
isDeleted: false,
|
|
||||||
updatedAt: new Date(),
|
|
||||||
commitmentId: "N/A",
|
|
||||||
createdAt: new Date(),
|
|
||||||
documentUid: "N/A",
|
|
||||||
documentType: "N/A",
|
|
||||||
merkleProof: "N/A"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Process files for this document
|
|
||||||
if (doc.files && doc.files.length > 0) {
|
|
||||||
for (const file of doc.files) {
|
|
||||||
const fileProcess = await FileService.getFileByUid(file.uid);
|
|
||||||
|
|
||||||
if (fileProcess.lastUpdatedFileState?.pcd_commitment?.file_blob) {
|
|
||||||
const hash = fileProcess.lastUpdatedFileState.pcd_commitment.file_blob;
|
|
||||||
certificateData.documentHash = hash;
|
|
||||||
|
|
||||||
const proof = await MessageBus.getInstance().generateMerkleProof(
|
|
||||||
fileProcess.lastUpdatedFileState,
|
|
||||||
'file_blob'
|
|
||||||
);
|
|
||||||
|
|
||||||
const metadata: any = {
|
|
||||||
fileName: fileProcess.processData.file_name,
|
|
||||||
isDeleted: false,
|
|
||||||
updatedAt: new Date(fileProcess.processData.updated_at),
|
|
||||||
commitmentId: fileProcess.lastUpdatedFileState.commited_in,
|
|
||||||
createdAt: new Date(fileProcess.processData.created_at),
|
|
||||||
documentUid: doc.uid,
|
|
||||||
documentType: doc.document_type?.name || "N/A",
|
|
||||||
merkleProof: proof
|
|
||||||
};
|
|
||||||
certificateData.metadata = metadata;
|
|
||||||
break; // Use first file for now
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
certificates.push(certificateData);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error processing document ${doc.uid}:`, error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate combined PDF
|
|
||||||
const combinedPdf = await PdfService.getInstance().generateCombinedCertificates(certificates, folder);
|
|
||||||
|
|
||||||
// Download the combined PDF
|
|
||||||
const filename = `certificats_${folder.folder_number || folder.uid}_${new Date().toISOString().split('T')[0]}.pdf`;
|
|
||||||
saveAs(combinedPdf, filename);
|
|
||||||
|
|
||||||
ToasterService.getInstance().success({
|
|
||||||
title: "Succès !",
|
|
||||||
description: `${certificates.length} certificat(s) téléchargé(s) avec succès.`
|
|
||||||
});
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error downloading all certificates:', error);
|
|
||||||
ToasterService.getInstance().error({
|
|
||||||
title: "Erreur",
|
|
||||||
description: "Une erreur est survenue lors du téléchargement des certificats."
|
|
||||||
});
|
|
||||||
} finally {
|
|
||||||
LoaderService.getInstance().hide();
|
|
||||||
}
|
|
||||||
}, [folder?.uid]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DefaultNotaryDashboard title={"Dossier"} isArchived={isArchived} mobileBackText="Retour aux dossiers">
|
<DefaultNotaryDashboard title={"Dossier"} isArchived={isArchived} mobileBackText="Retour aux dossiers">
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
@ -277,7 +155,6 @@ export default function FolderInformation(props: IProps) {
|
|||||||
onArchive={onArchive}
|
onArchive={onArchive}
|
||||||
anchorStatus={anchorStatus}
|
anchorStatus={anchorStatus}
|
||||||
isArchived={isArchived}
|
isArchived={isArchived}
|
||||||
onDownloadAllCertificates={onDownloadAllCertificates}
|
|
||||||
/>
|
/>
|
||||||
{progress === 100 && /*anchorStatus === AnchorStatus.NOT_ANCHORED*/ folder.status !== EFolderStatus.ARCHIVED && (
|
{progress === 100 && /*anchorStatus === AnchorStatus.NOT_ANCHORED*/ folder.status !== EFolderStatus.ARCHIVED && (
|
||||||
<AnchoringAlertInfo onAnchor={anchoringModal.open} />
|
<AnchoringAlertInfo onAnchor={anchoringModal.open} />
|
||||||
|
@ -23,7 +23,6 @@ import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService";
|
|||||||
import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService";
|
import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService";
|
||||||
import FileService from "src/common/Api/LeCoffreApi/sdk/FileService";
|
import FileService from "src/common/Api/LeCoffreApi/sdk/FileService";
|
||||||
import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService";
|
import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService";
|
||||||
import WatermarkService from "@Front/Services/WatermarkService";
|
|
||||||
|
|
||||||
enum EClientSelection {
|
enum EClientSelection {
|
||||||
ALL_CLIENTS = "all_clients",
|
ALL_CLIENTS = "all_clients",
|
||||||
@ -78,56 +77,53 @@ export default function SendDocuments() {
|
|||||||
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
await new Promise<void>((resolve: () => void) => {
|
await new Promise<void>((resolve: () => void) => {
|
||||||
// Add watermark to the file before processing
|
const reader = new FileReader();
|
||||||
WatermarkService.getInstance().addWatermark(file).then(async (watermarkedFile) => {
|
reader.onload = (event) => {
|
||||||
const reader = new FileReader();
|
if (event.target?.result) {
|
||||||
reader.onload = (event) => {
|
const date: Date = new Date();
|
||||||
if (event.target?.result) {
|
const strDate: string = `${date.getDate().toString().padStart(2, '0')}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getFullYear()}`;
|
||||||
const date: Date = new Date();
|
|
||||||
const strDate: string = `${date.getDate().toString().padStart(2, '0')}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getFullYear()}`;
|
|
||||||
|
|
||||||
const fileName: string = `aplc_${customer.contact.last_name}_${strDate}.${file.name.split('.').pop()}`;
|
const fileName: string = `aplc_${customer.contact.last_name}_${strDate}.${file.name.split('.').pop()}`;
|
||||||
|
|
||||||
const arrayBuffer: ArrayBuffer = event.target.result as ArrayBuffer;
|
const arrayBuffer: ArrayBuffer = event.target.result as ArrayBuffer;
|
||||||
const uint8Array: Uint8Array = new Uint8Array(arrayBuffer);
|
const uint8Array: Uint8Array = new Uint8Array(arrayBuffer);
|
||||||
|
|
||||||
const fileBlob: any = {
|
const fileBlob: any = {
|
||||||
type: watermarkedFile.type,
|
type: file.type,
|
||||||
data: uint8Array
|
data: uint8Array
|
||||||
|
};
|
||||||
|
|
||||||
|
const fileData: any = {
|
||||||
|
file_blob: fileBlob,
|
||||||
|
file_name: fileName
|
||||||
|
};
|
||||||
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileData: any = {
|
DocumentService.createDocument(documentData, validatorId).then(() => {
|
||||||
file_blob: fileBlob,
|
FolderService.refreshFolderByUid(folderUid as string).then(() => resolve());
|
||||||
file_name: fileName
|
|
||||||
};
|
|
||||||
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(() => {
|
|
||||||
FolderService.refreshFolderByUid(folderUid as string).then(() => resolve());
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
};
|
}
|
||||||
reader.readAsArrayBuffer(watermarkedFile);
|
};
|
||||||
});
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import Loader from "@Front/Components/DesignSystem/Loader";
|
|||||||
|
|
||||||
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
||||||
import OfficeRibService from "src/common/Api/LeCoffreApi/sdk/OfficeRibService";
|
import OfficeRibService from "src/common/Api/LeCoffreApi/sdk/OfficeRibService";
|
||||||
import WatermarkService from "@Front/Services/WatermarkService";
|
|
||||||
|
|
||||||
export default function Rib() {
|
export default function Rib() {
|
||||||
const [documentList, setDocumentList] = useState<File[]>([]);
|
const [documentList, setDocumentList] = useState<File[]>([]);
|
||||||
@ -61,41 +60,38 @@ export default function Rib() {
|
|||||||
const file = documentList[0]!;
|
const file = documentList[0]!;
|
||||||
|
|
||||||
LoaderService.getInstance().show();
|
LoaderService.getInstance().show();
|
||||||
// Add watermark to the file before processing
|
const reader = new FileReader();
|
||||||
WatermarkService.getInstance().addWatermark(file).then(async (watermarkedFile) => {
|
reader.onload = (event) => {
|
||||||
const reader = new FileReader();
|
if (event.target?.result) {
|
||||||
reader.onload = (event) => {
|
const date: Date = new Date();
|
||||||
if (event.target?.result) {
|
const strDate: string = `${date.getDate().toString().padStart(2, '0')}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getFullYear()}`;
|
||||||
const date: Date = new Date();
|
|
||||||
const strDate: string = `${date.getDate().toString().padStart(2, '0')}-${(date.getMonth() + 1).toString().padStart(2, '0')}-${date.getFullYear()}`;
|
|
||||||
|
|
||||||
const fileName: string = `aplc_${file.name.split('.')[0]}_${strDate}.${file.name.split('.').pop()}`;
|
const fileName: string = `aplc_${file.name.split('.')[0]}_${strDate}.${file.name.split('.').pop()}`;
|
||||||
|
|
||||||
const arrayBuffer: ArrayBuffer = event.target.result as ArrayBuffer;
|
const arrayBuffer: ArrayBuffer = event.target.result as ArrayBuffer;
|
||||||
const uint8Array: Uint8Array = new Uint8Array(arrayBuffer);
|
const uint8Array: Uint8Array = new Uint8Array(arrayBuffer);
|
||||||
|
|
||||||
const fileBlob: any = {
|
const fileBlob: any = {
|
||||||
type: watermarkedFile.type,
|
type: file.type,
|
||||||
data: uint8Array
|
data: uint8Array
|
||||||
};
|
};
|
||||||
|
|
||||||
const fileData: any = {
|
const fileData: any = {
|
||||||
file_blob: fileBlob,
|
file_blob: fileBlob,
|
||||||
file_name: fileName
|
file_name: fileName
|
||||||
};
|
};
|
||||||
const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0';
|
const validatorId: string = '884cb36a346a79af8697559f16940141f068bdf1656f88fa0df0e9ecd7311fb8:0';
|
||||||
|
|
||||||
OfficeRibService.createOfficeRib(fileData, validatorId).then(() => {
|
OfficeRibService.createOfficeRib(fileData, validatorId).then(() => {
|
||||||
LoaderService.getInstance().hide();
|
LoaderService.getInstance().hide();
|
||||||
onCloseRibModal();
|
onCloseRibModal();
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setTimeout(() => fetchData(), 2000);
|
setTimeout(() => fetchData(), 2000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
reader.readAsArrayBuffer(watermarkedFile);
|
reader.readAsArrayBuffer(file);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function openRibModal(): void {
|
function openRibModal(): void {
|
||||||
|
@ -335,193 +335,4 @@ export default class PdfService {
|
|||||||
fileReader.readAsArrayBuffer(certificateFile);
|
fileReader.readAsArrayBuffer(certificateFile);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate a combined PDF with multiple certificates
|
|
||||||
* @param certificates - Array of certificate data
|
|
||||||
* @param folder - Folder information
|
|
||||||
* @returns Promise<Blob> - Combined PDF as blob
|
|
||||||
*/
|
|
||||||
public async generateCombinedCertificates(certificates: CertificateData[], folder: any): Promise<Blob> {
|
|
||||||
try {
|
|
||||||
// Import pdf-lib dynamically to avoid SSR issues
|
|
||||||
const { PDFDocument, rgb, StandardFonts } = await import('pdf-lib');
|
|
||||||
|
|
||||||
// Create a new PDF document
|
|
||||||
const pdfDoc = await PDFDocument.create();
|
|
||||||
const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica);
|
|
||||||
const helveticaBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold);
|
|
||||||
|
|
||||||
// Add a cover page
|
|
||||||
const coverPage = pdfDoc.addPage([595.28, 841.89]); // A4 size
|
|
||||||
const { width, height } = coverPage.getSize();
|
|
||||||
|
|
||||||
// Cover page title
|
|
||||||
coverPage.drawText('Certificats de Validation', {
|
|
||||||
x: 50,
|
|
||||||
y: height - 100,
|
|
||||||
size: 24,
|
|
||||||
font: helveticaBold,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Folder information
|
|
||||||
coverPage.drawText(`Dossier: ${folder.folder_number || folder.uid}`, {
|
|
||||||
x: 50,
|
|
||||||
y: height - 150,
|
|
||||||
size: 16,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
coverPage.drawText(`Nom: ${folder.name || 'N/A'}`, {
|
|
||||||
x: 50,
|
|
||||||
y: height - 180,
|
|
||||||
size: 16,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
coverPage.drawText(`Date de génération: ${new Date().toLocaleDateString('fr-FR')}`, {
|
|
||||||
x: 50,
|
|
||||||
y: height - 210,
|
|
||||||
size: 16,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
coverPage.drawText(`Nombre de certificats: ${certificates.length}`, {
|
|
||||||
x: 50,
|
|
||||||
y: height - 240,
|
|
||||||
size: 16,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add each certificate as a separate page
|
|
||||||
for (let i = 0; i < certificates.length; i++) {
|
|
||||||
const certificate = certificates[i];
|
|
||||||
if (!certificate) continue;
|
|
||||||
|
|
||||||
const page = pdfDoc.addPage([595.28, 841.89]); // A4 size
|
|
||||||
const { width: pageWidth, height: pageHeight } = page.getSize();
|
|
||||||
|
|
||||||
// Certificate title
|
|
||||||
page.drawText(`Certificat ${i + 1}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 50,
|
|
||||||
size: 20,
|
|
||||||
font: helveticaBold,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Customer information
|
|
||||||
page.drawText('Informations Client:', {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 100,
|
|
||||||
size: 16,
|
|
||||||
font: helveticaBold,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Nom: ${certificate.customer.firstName} ${certificate.customer.lastName}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 130,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Adresse: ${certificate.customer.postalAddress}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 150,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Email: ${certificate.customer.email}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 170,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Document information
|
|
||||||
page.drawText('Informations Document:', {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 200,
|
|
||||||
size: 16,
|
|
||||||
font: helveticaBold,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Type: ${certificate.metadata.documentType}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 230,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Fichier: ${certificate.metadata.fileName}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 250,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Hash: ${certificate.documentHash}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 270,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Commitment ID: ${certificate.metadata.commitmentId}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 290,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Date de création: ${certificate.metadata.createdAt.toLocaleDateString('fr-FR')}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 310,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
page.drawText(`Date de mise à jour: ${certificate.metadata.updatedAt.toLocaleDateString('fr-FR')}`, {
|
|
||||||
x: 50,
|
|
||||||
y: pageHeight - 330,
|
|
||||||
size: 12,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0, 0, 0),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add page number
|
|
||||||
page.drawText(`Page ${i + 2}`, {
|
|
||||||
x: pageWidth - 80,
|
|
||||||
y: 30,
|
|
||||||
size: 10,
|
|
||||||
font: helveticaFont,
|
|
||||||
color: rgb(0.5, 0.5, 0.5),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save the PDF
|
|
||||||
const pdfBytes = await pdfDoc.save();
|
|
||||||
return new Blob([pdfBytes], { type: 'application/pdf' });
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error generating combined certificates:', error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
export default class WatermarkService {
|
export default class WatermarkService {
|
||||||
private static instance: WatermarkService;
|
private static instance: WatermarkService;
|
||||||
private watermarkText: string = 'Certifié par LeCoffre';
|
|
||||||
|
|
||||||
public static getInstance(): WatermarkService {
|
public static getInstance(): WatermarkService {
|
||||||
if (!WatermarkService.instance) {
|
if (!WatermarkService.instance) {
|
||||||
@ -143,29 +142,18 @@ export default class WatermarkService {
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
// Set watermark properties
|
// Set watermark properties
|
||||||
ctx.fillStyle = 'rgba(204, 51, 51, 0.7)'; // Semi-transparent pale red (matching PDF color)
|
ctx.fillStyle = 'rgba(128, 128, 128, 0.7)'; // Semi-transparent gray
|
||||||
ctx.font = '10px Arial';
|
ctx.font = '12px Arial';
|
||||||
ctx.textAlign = 'right';
|
ctx.textAlign = 'right';
|
||||||
ctx.textBaseline = 'bottom';
|
ctx.textBaseline = 'bottom';
|
||||||
|
|
||||||
// Position watermark in bottom-right corner with timestamp
|
// Position watermark in bottom-right corner
|
||||||
const dateTime = new Date().toLocaleString('fr-FR', {
|
const text = 'Processed by LeCoffre';
|
||||||
year: 'numeric',
|
const x = width - 10; // 10 pixels from right edge
|
||||||
month: '2-digit',
|
const y = height - 10; // 10 pixels from bottom
|
||||||
day: '2-digit',
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
});
|
|
||||||
|
|
||||||
const lineHeight = 12; // Space between lines
|
// Add watermark text
|
||||||
const x = width - 20; // 20 pixels from right edge (matching PDF margins)
|
ctx.fillText(text, x, y);
|
||||||
const y = 20; // 20 pixels from bottom (matching PDF margins)
|
|
||||||
|
|
||||||
// Add watermark text (second line - top)
|
|
||||||
ctx.fillText(this.watermarkText, x, y + lineHeight);
|
|
||||||
|
|
||||||
// Add date/time (first line - bottom)
|
|
||||||
ctx.fillText(dateTime, x, y);
|
|
||||||
|
|
||||||
// Restore state
|
// Restore state
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
@ -180,6 +168,7 @@ export default class WatermarkService {
|
|||||||
const { width, height } = page.getSize();
|
const { width, height } = page.getSize();
|
||||||
|
|
||||||
// Calculate watermark position (bottom-right corner)
|
// Calculate watermark position (bottom-right corner)
|
||||||
|
const text = 'Processed by LeCoffre';
|
||||||
const dateTime = new Date().toLocaleString('fr-FR', {
|
const dateTime = new Date().toLocaleString('fr-FR', {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
month: '2-digit',
|
month: '2-digit',
|
||||||
@ -193,7 +182,7 @@ export default class WatermarkService {
|
|||||||
|
|
||||||
// Calculate text widths (approximate - pdf-lib doesn't have a direct method for this)
|
// Calculate text widths (approximate - pdf-lib doesn't have a direct method for this)
|
||||||
// Using a conservative estimate: ~6 points per character for 10pt font
|
// Using a conservative estimate: ~6 points per character for 10pt font
|
||||||
const estimatedTextWidth1 = this.watermarkText.length * 6;
|
const estimatedTextWidth1 = text.length * 6;
|
||||||
const estimatedTextWidth2 = dateTime.length * 6;
|
const estimatedTextWidth2 = dateTime.length * 6;
|
||||||
const maxTextWidth = Math.max(estimatedTextWidth1, estimatedTextWidth2);
|
const maxTextWidth = Math.max(estimatedTextWidth1, estimatedTextWidth2);
|
||||||
|
|
||||||
@ -202,7 +191,7 @@ export default class WatermarkService {
|
|||||||
const y = 20; // 20 points from bottom
|
const y = 20; // 20 points from bottom
|
||||||
|
|
||||||
// Add watermark text with transparency (first line)
|
// Add watermark text with transparency (first line)
|
||||||
page.drawText(this.watermarkText, {
|
page.drawText(text, {
|
||||||
x: x,
|
x: x,
|
||||||
y: y + lineHeight, // Second line (top)
|
y: y + lineHeight, // Second line (top)
|
||||||
size: fontSize,
|
size: fontSize,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user