Show documents working (#27)

This commit is contained in:
Maxime Lalo 2023-05-05 17:16:06 +02:00 committed by GitHub
parent a6633c727b
commit 5e964db73b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 162 additions and 51 deletions

View File

@ -0,0 +1,80 @@
import { Document } from "le-coffre-resources/dist/SuperAdmin";
import { Service } from "typedi";
import BaseSuperAdmin from "../BaseSuperAdmin";
// TODO Type get query params -> Where + inclue + orderby
export interface IGetDocumentsparams {
where?: {};
include?: {};
}
// TODO Type getbyuid query params
export type IPutDocumentsParams = {};
export interface IPostDocumentsParams {}
@Service()
export default class Documents extends BaseSuperAdmin {
private static instance: Documents;
private readonly baseURl = this.namespaceUrl.concat("/documents");
private constructor() {
super();
}
public static getInstance() {
if (!this.instance) {
return new this();
} else {
return this.instance;
}
}
public async get(q: IGetDocumentsparams): Promise<Document[]> {
const url = new URL(this.baseURl);
Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
try {
return await this.getRequest<Document[]>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
/**
* @description : Create a Document
*/
public async post(body: any): Promise<Document> {
const url = new URL(this.baseURl);
try {
return await this.postRequest<Document>(url, body);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
public async getByUid(uid: string, q?: any): Promise<Document> {
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 {
return await this.getRequest<Document>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
public async put(uid: string, body: IPutDocumentsParams): Promise<Document> {
const url = new URL(this.baseURl.concat(`/${uid}`));
try {
return await this.putRequest<Document>(url, body);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
}

View File

@ -6,7 +6,7 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
&.PENDING { &.DEPOSITED {
cursor: pointer; cursor: pointer;
border: 1px solid $orange-soft; border: 1px solid $orange-soft;
&:hover { &:hover {

View File

@ -12,6 +12,7 @@ import classes from "./classes.module.scss";
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
type IProps = { type IProps = {
folderUid: string;
document: { document: {
uid?: Document["uid"]; uid?: Document["uid"];
document_type?: Document["document_type"]; document_type?: Document["document_type"];
@ -52,7 +53,7 @@ class DocumentNotaryClass extends React.Component<IPropsClass, IState> {
if (documentFiles.length === 1) { if (documentFiles.length === 1) {
const fileName = documentFiles[0]?.file_path?.split("/").pop(); const fileName = documentFiles[0]?.file_path?.split("/").pop();
if (fileName && fileName.length > 20) { if (fileName && fileName.length > 20) {
return `${fileName.substr(0, 7)}...${fileName.substr(fileName.length - 7, fileName.length)}`; return `${fileName.substring(0, 7)}...${fileName.substring(fileName.length - 7, fileName.length)}`;
} else { } else {
return fileName; return fileName;
} }
@ -66,7 +67,7 @@ class DocumentNotaryClass extends React.Component<IPropsClass, IState> {
private onClick() { private onClick() {
if (this.props.document.document_status !== EDocumentStatus.VALIDATED && this.props.document.document_status !== EDocumentStatus.DEPOSITED) return; if (this.props.document.document_status !== EDocumentStatus.VALIDATED && this.props.document.document_status !== EDocumentStatus.DEPOSITED) return;
this.props.router.push(`/folders/${this.props.document.folder?.uid}/documents/${this.props.document.uid}`); this.props.router.push(`/folders/${this.props.folderUid}/documents/${this.props.document.uid}`);
} }
private renderIcon(): JSX.Element { private renderIcon(): JSX.Element {

View File

@ -16,6 +16,7 @@ type IProps = {
}[] }[]
| null; | null;
openDeletionModal: (uid: Document["uid"]) => void; openDeletionModal: (uid: Document["uid"]) => void;
folderUid: string;
}; };
type IState = {}; type IState = {};
@ -31,7 +32,7 @@ export default class DocumentList extends React.Component<IProps, IState> {
{this.props.documents && {this.props.documents &&
this.props.documents.map((document) => { this.props.documents.map((document) => {
return ( return (
<DocumentNotary document={document} key={document.uid} openDeletionModal={this.props.openDeletionModal} /> <DocumentNotary folderUid={this.props.folderUid} document={document} key={document.uid} openDeletionModal={this.props.openDeletionModal} />
); );
})} })}
</div> </div>

View File

@ -89,6 +89,7 @@ export default class UserFolder extends React.Component<IProps, IState> {
documents={documentsAsked} documents={documentsAsked}
title="Documents demandés" title="Documents demandés"
openDeletionModal={this.openDeletionModal} openDeletionModal={this.openDeletionModal}
folderUid={this.props.folder.uid!}
/> />
<DocumentList <DocumentList
documents={otherDocuments} documents={otherDocuments}
@ -99,6 +100,7 @@ export default class UserFolder extends React.Component<IProps, IState> {
: "Vous n'avez aucun document à valider" : "Vous n'avez aucun document à valider"
} }
openDeletionModal={this.openDeletionModal} openDeletionModal={this.openDeletionModal}
folderUid={this.props.folder.uid!}
/> />
</div> </div>
{!this.props.isArchived && ( {!this.props.isArchived && (
@ -139,7 +141,7 @@ export default class UserFolder extends React.Component<IProps, IState> {
private getDocumentsByStatus(status: string): Document[] | null { private getDocumentsByStatus(status: string): Document[] | null {
if (!this.props.customer.documents) return null; if (!this.props.customer.documents) return null;
const filteredDocuments = this.props.customer.documents.filter( const filteredDocuments = this.props.customer.documents.filter(
(document) => document.document_status === status && document.folder?.uid === this.props.folder.uid, (document) => document.document_status === status,
); );
return filteredDocuments; return filteredDocuments;
} }

View File

@ -217,20 +217,20 @@ export default class DesignSystem extends BasePage<IProps, IState> {
<div className={classes["sub-section"]}> <div className={classes["sub-section"]}>
<Typography typo={ITypo.P_16}>Documents ASKED</Typography> <Typography typo={ITypo.P_16}>Documents ASKED</Typography>
<div className={classes["folder-conatainer"]}> <div className={classes["folder-conatainer"]}>
<DocumentNotary document={document} /> <DocumentNotary document={document} folderUid="" />
</div> </div>
</div> </div>
<div className={classes["sub-section"]}> <div className={classes["sub-section"]}>
<Typography typo={ITypo.P_16}>Documents Depoited</Typography> <Typography typo={ITypo.P_16}>Documents Depoited</Typography>
<div className={classes["folder-conatainer"]}> <div className={classes["folder-conatainer"]}>
<DocumentNotary document={documentPending} /> <DocumentNotary document={documentPending} folderUid=""/>
</div> </div>
</div> </div>
<div className={classes["sub-section"]}> <div className={classes["sub-section"]}>
<Typography typo={ITypo.P_16}>Documents VALIDATED</Typography> <Typography typo={ITypo.P_16}>Documents VALIDATED</Typography>
<div className={classes["folder-conatainer"]}> <div className={classes["folder-conatainer"]}>
<DocumentNotary document={documentDeposited} /> <DocumentNotary document={documentDeposited} folderUid="" />
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,7 @@
import "reflect-metadata"; import "reflect-metadata";
import ChevronIcon from "@Assets/Icons/chevron.svg"; import ChevronIcon from "@Assets/Icons/chevron.svg";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import FolderBoxInformation, { EFolderBoxInformationType } from "@Front/Components/DesignSystem/FolderBoxInformation"; import FolderBoxInformation, { EFolderBoxInformationType } from "@Front/Components/DesignSystem/FolderBoxInformation";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField"; import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
@ -9,15 +10,16 @@ import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgress
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Module from "@Front/Config/Module"; import Module from "@Front/Config/Module";
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
import Link from "next/link"; import Link from "next/link";
import { NextRouter, useRouter } from "next/router"; import { NextRouter, useRouter } from "next/router";
import { ChangeEvent } from "react";
import BasePage from "../../Base"; import BasePage from "../../Base";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import ClientSection from "./ClientSection"; import ClientSection from "./ClientSection";
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
import { ChangeEvent } from "react";
type IProps = {}; type IProps = {};
@ -54,7 +56,11 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
.get() .get()
.modules.pages.Folder.pages.EditCollaborators.props.path.replace("[folderUid]", this.props.selectedFolderUid); .modules.pages.Folder.pages.EditCollaborators.props.path.replace("[folderUid]", this.props.selectedFolderUid);
return ( return (
<DefaultNotaryDashboard title={"Dossier"} onSelectedFolder={this.onSelectedFolder} isArchived={false} mobileBackText="Retour aux dossiers"> <DefaultNotaryDashboard
title={"Dossier"}
onSelectedFolder={this.onSelectedFolder}
isArchived={false}
mobileBackText="Retour aux dossiers">
<div className={classes["root"]}> <div className={classes["root"]}>
{this.state.selectedFolder ? ( {this.state.selectedFolder ? (
<div className={classes["folder-informations"]}> <div className={classes["folder-informations"]}>
@ -74,7 +80,11 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
<FolderBoxInformation folder={this.state.selectedFolder} type={EFolderBoxInformationType.DESCRIPTION} /> <FolderBoxInformation folder={this.state.selectedFolder} type={EFolderBoxInformationType.DESCRIPTION} />
</div> </div>
<div className={classes["progress-bar"]}> <div className={classes["progress-bar"]}>
<QuantityProgressBar title="Complétion du dossier" total={100} currentNumber={this.getCompletionNumber()} /> <QuantityProgressBar
title="Complétion du dossier"
total={100}
currentNumber={this.getCompletionNumber()}
/>
</div> </div>
{this.doesFolderHaveCustomer() && <ClientSection folder={this.state.selectedFolder} />} {this.doesFolderHaveCustomer() && <ClientSection folder={this.state.selectedFolder} />}
</div> </div>
@ -102,7 +112,12 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
<div className={classes["modal-title"]}> <div className={classes["modal-title"]}>
<Typography typo={ITypo.P_16}>Souhaitez-vous vraiment archiver le dossier ?</Typography> <Typography typo={ITypo.P_16}>Souhaitez-vous vraiment archiver le dossier ?</Typography>
</div> </div>
<InputField name="archived_description" fakeplaceholder="Description" textarea onChange={this.onArchivedDescriptionInputChange}/> <InputField
name="archived_description"
fakeplaceholder="Description"
textarea
onChange={this.onArchivedDescriptionInputChange}
/>
</Confirm> </Confirm>
</div> </div>
) : ( ) : (
@ -125,9 +140,9 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
}); });
} }
private getCompletionNumber(){ private getCompletionNumber() {
const documents = this.state.selectedFolder?.documents; const documents = this.state.selectedFolder?.documents;
if(!documents) return 0; if (!documents) return 0;
const totalDocuments = documents.length; const totalDocuments = documents.length;
const askedDocuments = documents.filter((document) => document.document_status === EDocumentStatus.ASKED).length; const askedDocuments = documents.filter((document) => document.document_status === EDocumentStatus.ASKED).length;
const depositedDocuments = totalDocuments - askedDocuments; const depositedDocuments = totalDocuments - askedDocuments;
@ -152,8 +167,8 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
this.setState({ isArchivedModalOpen: false }); this.setState({ isArchivedModalOpen: false });
} }
private onArchivedDescriptionInputChange(e: ChangeEvent<HTMLInputElement>){ private onArchivedDescriptionInputChange(e: ChangeEvent<HTMLInputElement>) {
this.setState({inputArchivedDescripton: e.target.value}) this.setState({ inputArchivedDescripton: e.target.value });
} }
private async onArchivedModalAccepted() { private async onArchivedModalAccepted() {
@ -170,16 +185,20 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
q: { q: {
deed: { include: { deed_type: true } }, deed: { include: { deed_type: true } },
office: true, office: true,
office_folder_has_customers: { include: { customer: { include: { contact: true } } } }, office_folder_has_customers: { include: { customer: { include: { contact: true, documents: {
include: {
files: true
}
} } } } },
documents: { documents: {
include: { include: {
depositor:{ depositor: {
include: { include: {
contact: true contact: true,
} },
} },
} },
} },
}, },
}; };
const folder = await Folders.getInstance().getByUid(this.props.selectedFolderUid, query); const folder = await Folders.getInstance().getByUid(this.props.selectedFolderUid, query);

View File

@ -9,7 +9,6 @@ import FilePreview from "@Front/Components/DesignSystem/FilePreview";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField"; import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm"; import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import { folders } from "@Front/Components/Layouts/DesignSystem/dummyData";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import { Document, File } from "le-coffre-resources/dist/Customer"; import { Document, File } from "le-coffre-resources/dist/Customer";
import Image from "next/image"; import Image from "next/image";
@ -20,11 +19,12 @@ import BasePage from "../../Base";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
import OcrResult from "./OcrResult"; import OcrResult from "./OcrResult";
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document"; import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
import Documents from "@Front/Api/LeCoffreApi/SuperAdmin/Documents/Documents";
type IProps = {}; type IProps = {};
type IPropsClass = { type IPropsClass = {
selectedDocument: Document | null; documentUid: string;
router: NextRouter; router: NextRouter;
folderUid: string; folderUid: string;
}; };
@ -37,6 +37,7 @@ type IState = {
selectedFileIndex: number; selectedFileIndex: number;
selectedFile: File | null; selectedFile: File | null;
validatedPercentage: number; validatedPercentage: number;
document: Document | null;
}; };
class ViewDocumentsClass extends BasePage<IPropsClass, IState> { class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
@ -50,7 +51,8 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
hasValidateAnchoring: false, hasValidateAnchoring: false,
selectedFileIndex: 0, selectedFileIndex: 0,
selectedFile: null, selectedFile: null,
validatedPercentage: this.getRandomPercentageForOcr() validatedPercentage: this.getRandomPercentageForOcr(),
document: null,
}; };
this.closeModals = this.closeModals.bind(this); this.closeModals = this.closeModals.bind(this);
@ -68,16 +70,16 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
public override render(): JSX.Element | null { public override render(): JSX.Element | null {
return ( return (
<DefaultNotaryDashboard title={"Demander des documents"} hasBackArrow mobileBackText="Retour aux documents"> <DefaultNotaryDashboard title={"Demander des documents"} hasBackArrow mobileBackText="Retour aux documents">
{this.props.selectedDocument && this.props.selectedDocument.files && this.state.selectedFile && ( {this.state.document && this.state.document.files && this.state.selectedFile && (
<div className={classes["root"]}> <div className={classes["root"]}>
<Typography typo={ITypo.H1} color={ITypoColor.BLACK} className={classes["title"]}> <Typography typo={ITypo.H1} color={ITypoColor.BLACK} className={classes["title"]}>
App 23 rue Torus Toulon App 23 rue Torus Toulon
</Typography> </Typography>
<Typography typo={ITypo.H3} color={ITypoColor.BLACK} className={classes["subtitle"]}> <Typography typo={ITypo.H3} color={ITypoColor.BLACK} className={classes["subtitle"]}>
{this.props.selectedDocument.document_type?.name} {this.state.document.document_type?.name}
</Typography> </Typography>
<div className={classes["document-container"]}> <div className={classes["document-container"]}>
{this.props.selectedDocument.files.length > 1 && ( {this.state.document.files.length > 1 && (
<div <div
className={classes["arrow-container"]} className={classes["arrow-container"]}
onClick={this.goToPrevious} onClick={this.goToPrevious}
@ -88,7 +90,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
<div className={classes["file-container"]}> <div className={classes["file-container"]}>
<FilePreview href={this.state.selectedFile.file_path as string} key={this.state.selectedFile.uid} /> <FilePreview href={this.state.selectedFile.file_path as string} key={this.state.selectedFile.uid} />
</div> </div>
{this.props.selectedDocument.files.length > 1 && ( {this.state.document.files.length > 1 && (
<div <div
className={classes["arrow-container"]} className={classes["arrow-container"]}
onClick={this.goToNext} onClick={this.goToNext}
@ -98,14 +100,14 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
)} )}
</div> </div>
<div className={classes["footer"]}> <div className={classes["footer"]}>
{this.props.selectedDocument?.document_type?.name === "Carte d'identité" && ( {this.state.document?.document_type?.name === "Carte d'identité" && (
<div className={classes["ocr-container"]}> <div className={classes["ocr-container"]}>
<OcrResult percentage={this.state.validatedPercentage} /> <OcrResult percentage={this.state.validatedPercentage} />
</div> </div>
)} )}
<div className={classes["buttons-container"]}> <div className={classes["buttons-container"]}>
{this.props.selectedDocument?.document_status === EDocumentStatus.DEPOSITED && ( {this.state.document?.document_status === EDocumentStatus.DEPOSITED && (
<> <>
<Button variant={EButtonVariant.GHOST} onClick={this.openRefuseModal}> <Button variant={EButtonVariant.GHOST} onClick={this.openRefuseModal}>
Refuser Refuser
@ -114,7 +116,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
<Button disabled>Télécharger</Button> <Button disabled>Télécharger</Button>
</> </>
)} )}
{this.props.selectedDocument?.document_status === "VALIDATED" && ( {this.state.document?.document_status === "VALIDATED" && (
<a href={this.state.selectedFile.file_path!} download target="_blank"> <a href={this.state.selectedFile.file_path!} download target="_blank">
<Button>Télécharger</Button> <Button>Télécharger</Button>
</a> </a>
@ -168,7 +170,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
</Confirm> </Confirm>
</div> </div>
)} )}
{(!this.state.selectedFile || !this.props.selectedDocument) && ( {(!this.state.selectedFile || !this.state.document) && (
<div className={classes["root"]}> <div className={classes["root"]}>
<Typography typo={ITypo.P_16} color={ITypoColor.BLACK} className={classes["refuse-text"]}> <Typography typo={ITypo.P_16} color={ITypoColor.BLACK} className={classes["refuse-text"]}>
Document non trouvé Document non trouvé
@ -179,12 +181,20 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
); );
} }
override componentDidMount(): void { override async componentDidMount() {
if (!this.props.selectedDocument || !this.props.selectedDocument.files || !this.props.selectedDocument.files[0]) return; try{
this.setState({ const document = await Documents.getInstance().getByUid(this.props.documentUid, {
selectedFile: this.props.selectedDocument.files[0], files: true,
selectedFileIndex: 0, document_type: true
}); });
this.setState({
document,
selectedFileIndex: 0,
selectedFile: document.files![0]!,
});
}catch(e){
console.error(e)
}
} }
private getRandomPercentageForOcr() { private getRandomPercentageForOcr() {
@ -207,7 +217,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
const index = this.state.selectedFileIndex - 1; const index = this.state.selectedFileIndex - 1;
if (this.hasPrevious()) { if (this.hasPrevious()) {
this.setState({ this.setState({
selectedFile: this.props.selectedDocument!.files![index]!, selectedFile: this.state.document!.files![index]!,
selectedFileIndex: index, selectedFileIndex: index,
}); });
} }
@ -217,7 +227,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
if (this.hasNext()) { if (this.hasNext()) {
const index = this.state.selectedFileIndex + 1; const index = this.state.selectedFileIndex + 1;
this.setState({ this.setState({
selectedFile: this.props.selectedDocument!.files![index]!, selectedFile: this.state.document!.files![index]!,
selectedFileIndex: index, selectedFileIndex: index,
}); });
} }
@ -230,7 +240,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
private hasNext() { private hasNext() {
const index = this.state.selectedFileIndex + 1; const index = this.state.selectedFileIndex + 1;
return index < this.props.selectedDocument!.files!.length; return index < this.state.document!.files!.length;
} }
private validateAnchoring() { private validateAnchoring() {
@ -281,9 +291,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
export default function ViewDocuments(props: IProps) { export default function ViewDocuments(props: IProps) {
const router = useRouter(); const router = useRouter();
let { folderUid, documentUid } = router.query; let { folderUid, documentUid } = router.query;
documentUid = documentUid as string;
const folder = folders.find((folder) => folder.uid === folderUid) ?? null; folderUid = folderUid as string;
const documents = folder?.documents!.filter((document) => document.document_status !== "ASKED") ?? []; return <ViewDocumentsClass {...props} documentUid={documentUid} router={router} folderUid={folderUid as string} />;
const selectedDocument = documents.find((document) => document.uid === documentUid) ?? null;
return <ViewDocumentsClass {...props} selectedDocument={selectedDocument} router={router} folderUid={folderUid as string} />;
} }