diff --git a/package-lock.json b/package-lock.json index c5bde9c8..e88df943 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,9 +30,9 @@ "react-select": "^5.7.2", "sass": "^1.59.2", "sharp": "^0.32.1", - "typescript": "4.9.5" - }, - "devDependencies": {} + "typescript": "4.9.5", + "uuidv4": "^6.2.13" + } }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", @@ -1028,6 +1028,11 @@ "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz", "integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==" }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==" + }, "node_modules/@types/validator": { "version": "13.11.1", "resolved": "https://registry.npmjs.org/@types/validator/-/validator-13.11.1.tgz", @@ -4866,6 +4871,23 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/uuidv4": { + "version": "6.2.13", + "resolved": "https://registry.npmjs.org/uuidv4/-/uuidv4-6.2.13.tgz", + "integrity": "sha512-AXyzMjazYB3ovL3q051VLH06Ixj//Knx7QnUSi1T//Ie3io6CpsPu9nVMOx5MoLWh6xV0B9J0hIaxungxXUbPQ==", + "dependencies": { + "@types/uuid": "8.3.4", + "uuid": "8.3.2" + } + }, "node_modules/validator": { "version": "13.11.0", "resolved": "https://registry.npmjs.org/validator/-/validator-13.11.0.tgz", diff --git a/src/front/Api/BaseApiService.ts b/src/front/Api/BaseApiService.ts index dfa17f91..999ae0f0 100644 --- a/src/front/Api/BaseApiService.ts +++ b/src/front/Api/BaseApiService.ts @@ -1,11 +1,11 @@ import { FrontendVariables } from "@Front/Config/VariablesFront"; import CookieService from "@Front/Services/CookieService/CookieService"; -import { uuid } from "uuidv4"; export enum ContentType { JSON = "application/json", PDF = "application/pdf", FORM_DATA = "multipart/form-data;", + PNG = "image/png", } export default abstract class BaseApiService { private static baseUrl: string; @@ -126,20 +126,8 @@ export default abstract class BaseApiService { // Check the Content-Type header to determine the response type const contentType = response.headers.get("Content-Type"); - if (contentType && contentType.includes("application/octet-stream")) { - // Handle PDF response - const blob = await response.blob(); - const url = URL.createObjectURL(blob); - - const anchor = document.createElement("a"); - - anchor.href = url; - anchor.download = filename ?? `${uuid()}.pdf`; - anchor.click(); - - URL.revokeObjectURL(url); - - responseContent = {} as T; + if (contentType && !contentType.includes("application/json")) { + responseContent = (await response.blob()) as T; } else { // Handle JSON response try { diff --git a/src/front/Api/LeCoffreApi/Notary/Files/Files.ts b/src/front/Api/LeCoffreApi/Notary/Files/Files.ts new file mode 100644 index 00000000..4b8027f0 --- /dev/null +++ b/src/front/Api/LeCoffreApi/Notary/Files/Files.ts @@ -0,0 +1,103 @@ +import { File } from "le-coffre-resources/dist/SuperAdmin"; +import BaseNotary from "../BaseNotary"; + +// TODO Type get query params -> Where + inclue + orderby +export interface IGetFilesparams { + where?: {}; + include?: {}; +} + +// TODO Type getbyuid query params + +export type IPutFilesParams = {}; + +export interface IPostFilesParams {} + +export default class Files extends BaseNotary { + private static instance: Files; + private readonly baseURl = this.namespaceUrl.concat("/files"); + + private constructor() { + super(); + } + + public static getInstance() { + return (this.instance ??= new this()); + } + + public async get(q: IGetFilesparams): Promise { + const url = new URL(this.baseURl); + const query = { q }; + if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + const files = await this.getRequest(url); + return files; + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + /** + * @description : Create a File + */ + public async post(body: any): Promise { + const url = new URL(this.baseURl); + try { + return await this.postRequestFormData(url, body); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public getUploadLink(uid: string): string { + return this.baseURl.concat(`/download/${uid}`); + } + + public async getByUid(uid: string, q?: any): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + const query = { q }; + if (q) Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value))); + try { + const file = await this.getRequest(url); + return file; + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async put(uid: string, body: IPutFilesParams): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + try { + return await this.putRequest(url, body); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + /** + * @description : Delete a folder only if the folder don't contains customers + */ + public async delete(uid: string): Promise { + const url = new URL(this.baseURl.concat(`/${uid}`)); + try { + return await this.deleteRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } + + public async download(uid: string): Promise { + const url = new URL(this.baseURl.concat(`/download/${uid}`)); + try { + return await this.getRequest(url); + } catch (err) { + this.onError(err); + return Promise.reject(err); + } + } +} diff --git a/src/front/Api/LeCoffreApi/Notary/OfficeFolderAnchors/OfficeFolderAnchors.ts b/src/front/Api/LeCoffreApi/Notary/OfficeFolderAnchors/OfficeFolderAnchors.ts index 24cab51f..4aa3bb4b 100644 --- a/src/front/Api/LeCoffreApi/Notary/OfficeFolderAnchors/OfficeFolderAnchors.ts +++ b/src/front/Api/LeCoffreApi/Notary/OfficeFolderAnchors/OfficeFolderAnchors.ts @@ -1,8 +1,6 @@ import { ContentType } from "@Front/Api/BaseApiService"; import BaseNotary from "../BaseNotary"; -import CookieService from "@Front/Services/CookieService/CookieService"; - export default class OfficeFolderAnchors extends BaseNotary { private static instance: OfficeFolderAnchors; private readonly baseURl = this.namespaceUrl.concat("/anchors"); @@ -48,5 +46,4 @@ export default class OfficeFolderAnchors extends BaseNotary { return Promise.reject(err); } } - } diff --git a/src/front/Components/DesignSystem/FilePreview/index.tsx b/src/front/Components/DesignSystem/FilePreview/index.tsx index d7e6f794..1511d2a7 100644 --- a/src/front/Components/DesignSystem/FilePreview/index.tsx +++ b/src/front/Components/DesignSystem/FilePreview/index.tsx @@ -20,17 +20,21 @@ export default class FilePreview extends React.Component { - {!type && ( - - Erreur lors du chargement du fichier - + {this.props.href && ( + <> + {!type && ( + + Erreur lors du chargement du fichier + + )} +
+ {type?.toLowerCase() === "pdf" && ( + + )} + {type?.toLowerCase() !== "pdf" && File preview} +
+ )} -
- {type?.toLowerCase() === "pdf" && ( - - )} - {type?.toLowerCase() !== "pdf" && File preview} -
); } diff --git a/src/front/Components/DesignSystem/UserFolder/index.tsx b/src/front/Components/DesignSystem/UserFolder/index.tsx index 805f9033..33a4ab42 100644 --- a/src/front/Components/DesignSystem/UserFolder/index.tsx +++ b/src/front/Components/DesignSystem/UserFolder/index.tsx @@ -1,6 +1,6 @@ import ChevronIcon from "@Assets/Icons/chevron.svg"; import PlusIcon from "@Assets/Icons/plus.svg"; -import Documents from "@Front/Api/LeCoffreApi/SuperAdmin/Documents/Documents"; +import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents"; import Module from "@Front/Config/Module"; import classNames from "classnames"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; diff --git a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx index 48dc1450..c77eb4ba 100644 --- a/src/front/Components/Layouts/Folder/AskDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/AskDocuments/index.tsx @@ -157,29 +157,31 @@ class AskDocumentsClass extends BasePage { } private async getAvailableDocuments(folder: OfficeFolder): Promise { + // Getting already asked documents UIDs in an array const userDocumentTypesUids = folder .documents!.filter((document) => document.depositor!.uid! === this.props.customerUid!) .map((document) => { return document.document_type!.uid!; }); + + // If those UIDs are already asked, filter them to not show them in the list and only + // show the documents that are not asked yet const documentTypes = folder.deed!.document_types!.filter((documentType) => { if (userDocumentTypesUids.includes(documentType!.uid!)) return false; return true; }); + // If there is none document type available, return an empty array if (!documentTypes) return []; - const documentTypesOptions: IOption[] = documentTypes - .filter((documentType) => { - return true; - }) - .map((documentType) => { - return { - label: documentType!.name!, - value: documentType!.uid!, - description: documentType!.private_description!, - }; - }); + // Else, return an array document types formatted as IOPtions + const documentTypesOptions: IOption[] = documentTypes.map((documentType) => { + return { + label: documentType!.name!, + value: documentType!.uid!, + description: documentType!.private_description!, + }; + }); return documentTypesOptions; } diff --git a/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx b/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx index 68faf697..f371b6d6 100644 --- a/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx +++ b/src/front/Components/Layouts/Folder/ViewDocuments/index.tsx @@ -16,7 +16,7 @@ import React from "react"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; import OcrResult from "./OcrResult"; -import Files from "@Front/Api/LeCoffreApi/SuperAdmin/Files/Files"; +import Files from "@Front/Api/LeCoffreApi/Notary/Files/Files"; import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; type IProps = {}; @@ -34,6 +34,7 @@ type IState = { selectedFile: File | null; validatedPercentage: number; document: Document | null; + fileData: string; }; class ViewDocumentsClass extends BasePage { @@ -48,6 +49,7 @@ class ViewDocumentsClass extends BasePage { selectedFile: null, validatedPercentage: this.getRandomPercentageForOcr(), document: null, + fileData: "", }; this.closeModals = this.closeModals.bind(this); @@ -86,7 +88,7 @@ class ViewDocumentsClass extends BasePage { )}
@@ -175,16 +177,33 @@ class ViewDocumentsClass extends BasePage { document_type: true, folder: true, }); - this.setState({ - document, - selectedFileIndex: 0, - selectedFile: document.files![0]!, - }); + this.setState( + { + document, + selectedFileIndex: 0, + selectedFile: document.files![0]!, + }, + () => { + this.getFilePreview(); + }, + ); } catch (e) { console.error(e); } } + private async getFilePreview(): Promise { + const setState = this.setState; + try { + const file: Blob = await Files.getInstance().download(this.state.selectedFile?.uid as string); + this.setState({ + fileData: URL.createObjectURL(file), + }); + } catch (e) { + console.log(e); + } + } + private downloadFile() { const fileName = this.state.selectedFile?.file_path?.split("/").pop(); fetch(Files.getInstance().getUploadLink(this.state.selectedFile?.uid as string))