358 lines
11 KiB
TypeScript

import LeftArrowIcon from "@Assets/Icons/left-arrow.svg";
import RightArrowIcon from "@Assets/Icons/right-arrow.svg";
import Documents from "@Front/Api/LeCoffreApi/Notary/Documents/Documents";
import ValidateAnchoringGif from "@Front/Assets/images/validate_anchoring.gif";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
import FilePreview from "@Front/Components/DesignSystem/FilePreview";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import Typography, { ITypo, ITypoColor } 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 { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
import Image from "next/image";
import { NextRouter, useRouter } from "next/router";
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 TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
type IProps = {};
type IPropsClass = {
documentUid: string;
router: NextRouter;
folderUid: string;
};
type IState = {
isRefuseModalVisible: boolean;
isValidateModalVisible: boolean;
refuseText: string;
hasValidateAnchoring: boolean;
selectedFileIndex: number;
selectedFile: File | null;
validatedPercentage: number;
document: Document | null;
};
class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
public constructor(props: IPropsClass) {
super(props);
this.state = {
isValidateModalVisible: false,
isRefuseModalVisible: false,
refuseText: "",
hasValidateAnchoring: false,
selectedFileIndex: 0,
selectedFile: null,
validatedPercentage: this.getRandomPercentageForOcr(),
document: null,
};
this.closeModals = this.closeModals.bind(this);
this.openValidateModal = this.openValidateModal.bind(this);
this.openRefuseModal = this.openRefuseModal.bind(this);
this.onRefuseTextChange = this.onRefuseTextChange.bind(this);
this.validateAnchoring = this.validateAnchoring.bind(this);
this.goToNext = this.goToNext.bind(this);
this.goToPrevious = this.goToPrevious.bind(this);
this.hasPrevious = this.hasPrevious.bind(this);
this.hasNext = this.hasNext.bind(this);
this.downloadFile = this.downloadFile.bind(this);
this.refuseDocument = this.refuseDocument.bind(this);
}
public override render(): JSX.Element | null {
return (
<DefaultNotaryDashboard title={"Demander des documents"} hasBackArrow mobileBackText="Retour aux documents">
{this.state.document && this.state.document.files && this.state.selectedFile && (
<div className={classes["root"]}>
<Typography typo={ITypo.H1} color={ITypoColor.BLACK} className={classes["title"]}>
{this.state.document.folder?.name}
</Typography>
<Typography typo={ITypo.H3} color={ITypoColor.BLACK} className={classes["subtitle"]}>
{this.state.document.document_type?.name}
</Typography>
<div className={classes["document-container"]}>
{this.state.document.files.length > 1 && (
<div
className={classes["arrow-container"]}
onClick={this.goToPrevious}
data-disabled={(!this.hasPrevious()).toString()}>
<Image src={LeftArrowIcon} alt="left arrow" />
</div>
)}
<div className={classes["file-container"]}>
<FilePreview
href={Files.getInstance().getUploadLink(this.state.selectedFile?.uid as string)}
fileName={this.state.selectedFile.file_name}
key={this.state.selectedFile.uid}
/>
</div>
{this.state.document.files.length > 1 && (
<div
className={classes["arrow-container"]}
onClick={this.goToNext}
data-disabled={(!this.hasNext()).toString()}>
<Image src={RightArrowIcon} alt="right arrow" />
</div>
)}
</div>
<div className={classes["footer"]}>
{this.state.document?.document_type?.name === "Document d'identité" && (
<div className={classes["ocr-container"]}>
<OcrResult percentage={this.state.validatedPercentage} />
</div>
)}
<div className={classes["buttons-container"]}>
{this.state.document?.document_status === EDocumentStatus.DEPOSITED && (
<>
<Button variant={EButtonVariant.GHOST} onClick={this.openRefuseModal}>
Refuser
</Button>
<Button onClick={this.openValidateModal}>Valider et ancrer</Button>
<Button disabled>Télécharger</Button>
</>
)}
{this.state.document?.document_status === "VALIDATED" && (
<Button onClick={this.downloadFile}>Télécharger</Button>
)}
</div>
</div>
<Confirm
isOpen={this.state.isValidateModalVisible}
onClose={this.closeModals}
onAccept={this.validateAnchoring}
closeBtn={true}
hasContainerClosable={true}
header={this.state.hasValidateAnchoring ? "Document en cours de validation" : "Ancrer le document"}
cancelText={"Annuler"}
confirmText={"Confirmer"}
showButtons={!this.state.hasValidateAnchoring}>
<div className={classes["validate-document-container"]}>
{!this.state.hasValidateAnchoring && (
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK} className={classes["validate-text"]}>
Êtes-vous sûr de vouloir ancrer ce document ?
</Typography>
)}
{this.state.hasValidateAnchoring && (
<div className={classes["document-validating-container"]}>
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK} className={classes["validate-text"]}>
Le document s'ancre dans la blockchain.
</Typography>
<Image src={ValidateAnchoringGif} alt="Anchoring animation" className={classes["validate-gif"]} />
<div className={classes["dont-show-again"]}>
<CheckBox option={{ label: "Ne plus afficher ce message", value: false }} />
</div>
</div>
)}
</div>
</Confirm>
<Confirm
isOpen={this.state.isRefuseModalVisible}
onClose={this.closeModals}
onAccept={this.refuseDocument}
closeBtn
header={"Refuser le document ?"}
cancelText={"Annuler"}
confirmText={"Refuser"}>
<div className={classes["refuse-document-container"]}>
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK} className={classes["refuse-text"]}>
Veuillez indiquer au client le motif du refus de son document afin qu'il puisse vous renvoyer une bonne
version.
</Typography>
<TextAreaField placeholder="Motif du refus" onChange={this.onRefuseTextChange} />
</div>
</Confirm>
</div>
)}
{(!this.state.selectedFile || !this.state.document) && (
<div className={classes["root"]}>
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK} className={classes["refuse-text"]}>
Document non trouvé
</Typography>
</div>
)}
</DefaultNotaryDashboard>
);
}
override async componentDidMount() {
try {
const document = await Documents.getInstance().getByUid(this.props.documentUid, {
files: {
where: { archived_at: null },
},
document_type: true,
folder: true,
});
this.setState({
document,
selectedFileIndex: 0,
selectedFile: document.files![0]!,
});
} catch (e) {
console.error(e);
}
}
private downloadFile() {
const fileName = this.state.selectedFile?.file_path?.split("/").pop();
fetch(Files.getInstance().getUploadLink(this.state.selectedFile?.uid as string))
.then((resp) => resp.blob())
.then((blob) => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.style.display = "none";
a.href = url;
// the filename you want
a.download = fileName as string;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
})
.catch((e) => {
const a = document.createElement("a");
a.href = this.state.selectedFile?.file_path as string;
a.target = "_blank";
a.click();
console.error(e);
});
}
private getRandomPercentageForOcr() {
// find diff
let difference = 100 - 90;
// generate random number
let rand = Math.random();
// multiply with difference
rand = Math.floor(rand * difference);
// add with min value
rand = rand + 90;
return rand;
}
private goToPrevious() {
const index = this.state.selectedFileIndex - 1;
if (this.hasPrevious()) {
this.setState({
selectedFile: this.state.document!.files![index]!,
selectedFileIndex: index,
});
}
}
private goToNext() {
if (this.hasNext()) {
const index = this.state.selectedFileIndex + 1;
this.setState({
selectedFile: this.state.document!.files![index]!,
selectedFileIndex: index,
});
}
}
private hasPrevious() {
const index = this.state.selectedFileIndex - 1;
return index >= 0;
}
private hasNext() {
const index = this.state.selectedFileIndex + 1;
return index < this.state.document!.files!.length;
}
private async refuseDocument() {
try {
await Documents.getInstance().put(this.props.documentUid, {
document_status: EDocumentStatus.REFUSED,
refused_reason: this.state.refuseText,
});
this.props.router.push(
Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folderUid),
);
} catch (e) {
console.error(e);
}
}
private async validateAnchoring() {
this.setState({
hasValidateAnchoring: true,
});
try {
await Documents.getInstance().put(this.props.documentUid, {
document_status: EDocumentStatus.VALIDATED,
});
const timeoutDelay = 9800;
setTimeout(() => {
this.setState({
isValidateModalVisible: false,
});
this.props.router.push(
Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folderUid),
);
}, timeoutDelay);
setTimeout(() => {
this.setState({
hasValidateAnchoring: false,
});
}, timeoutDelay + 1000);
} catch (e) {
console.error(e);
}
}
private onRefuseTextChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
refuseText: e.target.value,
});
}
private openValidateModal() {
this.setState({
isValidateModalVisible: true,
});
}
private openRefuseModal() {
this.setState({
isRefuseModalVisible: true,
});
}
private closeModals() {
this.setState({
isValidateModalVisible: false,
isRefuseModalVisible: false,
});
}
}
export default function ViewDocuments(props: IProps) {
const router = useRouter();
let { folderUid, documentUid } = router.query;
documentUid = documentUid as string;
folderUid = folderUid as string;
return <ViewDocumentsClass {...props} documentUid={documentUid} router={router} folderUid={folderUid as string} />;
}