import DepositDocumentIcon from "@Assets/Icons/deposit-document.svg"; import PlusIcon from "@Assets/Icons/plus.svg"; import CrossIcon from "@Assets/Icons/cross.svg"; import DocumentCheckIcon from "@Assets/Icons/document-check.svg"; import Image from "next/image"; import React from "react"; import Button, { EButtonstyletype, EButtonVariant } from "../Button"; import Tooltip from "../ToolTip"; import Typography, { ETypo, ETypoColor } from "../Typography"; import classes from "./classes.module.scss"; import { Document, DocumentHistory, File as FileCustomer } from "le-coffre-resources/dist/Customer"; import Files from "@Front/Api/LeCoffreApi/Customer/Files/Files"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import classNames from "classnames"; import Confirm from "../OldModal/Confirm"; import Alert from "../OldModal/Alert"; import GreenCheckIcon from "@Assets/Icons/green-check.svg"; import Loader from "../Loader"; import TextAreaField from "../Form/TextareaField"; import { toast } from "react-toastify"; type IProps = { defaultFiles?: FileCustomer[]; onChange?: (files: File[]) => void; document: Document; }; type IFile = { index: number; file: File; uid: string; archived: Date | null; fileName: string; }; type IState = { files: IFile[]; isDragOver: boolean; currentFiles?: FileCustomer[]; refusedReason?: string; isShowRefusedReasonModalVisible: boolean; showFailedUploaded: string | null; loading: boolean; }; type fileAccepted = { extension: string; size: number; }; const filesAccepted: { [key: string]: fileAccepted } = { "application/pdf": { extension: "pdf", size: 41943040, }, "image/jpeg": { extension: "jpeg", size: 41943040, }, "image/png": { extension: "png", size: 41943040, }, "image/jpg": { extension: "jpg", size: 41943040, }, }; export default class DepositDocument extends React.Component { private inputRef = React.createRef(); private index = 0; public constructor(props: IProps) { super(props); this.state = { files: [], isDragOver: false, currentFiles: this.props.defaultFiles, refusedReason: "", isShowRefusedReasonModalVisible: false, showFailedUploaded: null, loading: false, }; this.addDocument = this.addDocument.bind(this); this.onFileChange = this.onFileChange.bind(this); this.addFile = this.addFile.bind(this); this.removeFile = this.removeFile.bind(this); this.onDragOver = this.onDragOver.bind(this); this.onDragDrop = this.onDragDrop.bind(this); this.onDragLeave = this.onDragLeave.bind(this); this.onCloseModalShowRefusedReason = this.onCloseModalShowRefusedReason.bind(this); this.onOpenModalShowRefusedReason = this.onOpenModalShowRefusedReason.bind(this); this.showRefusedReason = this.showRefusedReason.bind(this); this.onCloseAlertUpload = this.onCloseAlertUpload.bind(this); } public override render(): JSX.Element { return (
Deposit document
{this.props.document.document_type?.name}
{this.props.document.document_type?.public_description !== " " && this.props.document.document_type?.public_description !== "" && this.props.document.document_status !== EDocumentStatus.VALIDATED && ( )} {this.props.document.document_status === EDocumentStatus.VALIDATED && ( Document check )}
{this.props.document.document_status !== EDocumentStatus.VALIDATED && ( Sélectionnez des documents .jpg, .pdf ou .png )} {this.props.document.document_history?.map((history) => (
{this.renderDocumentHistory(history)}
))}
{this.state.files.map((file) => { const fileObj = file.file; if (file.archived) return; return (
Document check {this.shortName(file.fileName || fileObj.name)}
Cross icon
); })} {this.state.loading && (
Chargement...
)}
{this.props.document.document_status !== EDocumentStatus.VALIDATED && (
)}
Votre document a été refusé pour la raison suivante :
{this.props.document.document_status === EDocumentStatus.REFUSED && ( Ce document n'est pas conforme. Veuillez le déposer à nouveau. )} {this.state.showFailedUploaded && (
{this.state.showFailedUploaded}
)}
); } public override componentDidMount(): void { if (this.props.defaultFiles) { this.setState({ files: this.props.defaultFiles.map((file) => ({ index: this.index++, file: new File([""], file.file_path ?? "", {}), uid: file.uid!, fileName: file.file_name, archived: file.archived_at ? new Date(file.archived_at) : null, })), }); } } private openSuccessToast() { toast.success("Document envoyé avec succès"); } private onCloseModalShowRefusedReason() { this.setState({ isShowRefusedReasonModalVisible: false, }); } private onOpenModalShowRefusedReason() { this.setState({ isShowRefusedReasonModalVisible: true, }); } private renderDocumentHistory(history: DocumentHistory): JSX.Element | null { switch (history.document_status) { case EDocumentStatus.ASKED: return ( Demandé par votre notaire le {this.formatDate(history.created_at!)} ); case EDocumentStatus.VALIDATED: return ( Validé par votre notaire le {this.formatDate(history.created_at!)} ); case EDocumentStatus.DEPOSITED: return ( Déposé le {this.formatDate(history.created_at!)} ); case EDocumentStatus.REFUSED: return ( Document non conforme {history.refused_reason && history.refused_reason.length > 0 && ( )} ); } return null; } private shortName(name: string): string { const maxLength = 20; if (name.length > maxLength) { return name.substring(0, maxLength / 2) + "..." + name.substring(name.length - maxLength / 2, name.length); } return name; } private onDragOver(event: React.DragEvent) { if (!this.state.isDragOver) { this.setState({ isDragOver: true, }); } event.preventDefault(); } private showRefusedReason(refusedReason: string) { this.setState({ refusedReason, }); this.onOpenModalShowRefusedReason(); } private onDragLeave(event: React.DragEvent) { this.setState({ isDragOver: false, }); event.preventDefault(); } private async onDragDrop(event: React.DragEvent) { event.preventDefault(); this.setState({ isDragOver: false, }); const file = event.dataTransfer.files[0]; if (file) this.addFile(file); } private async addFile(file: File) { const fileAccepted = filesAccepted[file.type]; if (!fileAccepted) { alert("Le fichier déposé doit être au format .jpg .pdf .jpeg ou .png"); return false; } if (file.size > fileAccepted.size) { alert("Le fichier est trop volumineux et ne doit pas dépasser 32mo"); return false; } this.setState({ loading: true, }); const formData = new FormData(); formData.append("file", file, file.name); const query = JSON.stringify({ document: { uid: this.props.document.uid } }); formData.append("q", query); let newFile: FileCustomer; try { newFile = await Files.getInstance().post(formData); } catch (e) { this.setState({ showFailedUploaded: "Le fichier ne correspond pas aux critères demandés", loading: false }); return false; } const files = this.state.currentFiles ? [...this.state.currentFiles, newFile] : [newFile]; const newFileList = [ ...this.state.files, { index: this.index++, file: file, uid: newFile.uid!, archived: null, fileName: newFile?.file_name ?? "", }, ]; this.openSuccessToast(); this.setState( { currentFiles: files, loading: false, files: newFileList, }, () => { if (this.props.onChange) this.props.onChange(newFileList.map((file) => file.file)); }, ); return true; } private async removeFile(e: any) { const image = e.target as HTMLElement; const indexToRemove = image.getAttribute("data-file"); if (!indexToRemove) return; const file = this.state.files.find((file) => file.index === parseInt(indexToRemove)); if (!file) return; this.setState({ files: this.state.files.filter((file) => file.index !== parseInt(indexToRemove)), }); if (this.props.onChange) this.props.onChange(this.state.files.map((file) => file.file)); await Files.getInstance().delete(file.uid); } private async onFileChange() { if (!this.inputRef.current) return; const files = this.inputRef.current.files; if (!files) { this.setState({ loading: false }); return; } const file = files[0]; try { if (file) { await this.setState({ loading: true }, () => { this.addFile(file); }); } } catch (e) { this.setState({ loading: false }); } } private onCloseAlertUpload() { this.setState({ showFailedUploaded: null }); } private addDocument() { if (!this.inputRef.current) return; this.inputRef.current.value = ""; this.inputRef.current.click(); } private formatDate(date: Date) { const dateToConvert = new Date(date); return dateToConvert.toLocaleDateString("fr-FR"); } }