DefaultNotaryDashboard done, front services init

This commit is contained in:
Hugo Lextrait 2023-04-12 17:42:32 +02:00
parent 5c1eb01aa2
commit 48cc9e23b5
35 changed files with 580 additions and 170 deletions

View File

@ -1,3 +1,6 @@
NEXT_PUBLIC_API_URL=
NEXT_PUBLIC_RPC_GATEWAY_MAINNET_URL=
NEXT_PUBLIC_RPC_GATEWAY_TESTNET_URL=
BACK_API_PROTOCOL=
BACK_API_HOSTNAME=
BACK_API_PORT=
BACK_API_ROOT_URL=
BACK_API_VERSION=

View File

@ -1,12 +1,15 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
publicRuntimeConfig: {
// Will be available on both server and client
NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
NEXT_PUBLIC_RPC_GATEWAY_MAINNET_URL: process.env.NEXT_PUBLIC_RPC_GATEWAY_MAINNET_URL,
NEXT_PUBLIC_RPC_GATEWAY_TESTNET_URL: process.env.NEXT_PUBLIC_RPC_GATEWAY_TESTNET_URL,
},
}
module.exports = nextConfig
const nextConfig = {
reactStrictMode: false,
publicRuntimeConfig: {
// Will be available on both server and client
BACK_API_PROTOCOL: process.env.BACK_API_PROTOCOL,
BACK_API_HOST: process.env.BACK_API_HOST,
BACK_API_PORT: process.env.BACK_API_PORT,
BACK_API_ROOT_URL: process.env.BACK_API_ROOT_URL,
BACK_API_VERSION: process.env.BACK_API_VERSION,
},
};
module.exports = nextConfig;

View File

@ -1,21 +1,26 @@
import { FrontendVariables } from "@Front/Config/VariablesFront";
export enum ContentType {
JSON = "application/json",
FORM_DATA = "multipart/form-data;",
}
export default abstract class BaseApiService {
protected readonly backUrl =
process.env["NEXT_PUBLIC_API_HOSTNAME"] +
":" +
process.env["NEXT_PUBLIC_API_PORT"] +
process.env["NEXT_PUBLIC_API_ROOT_URL"];
protected readonly proxyUrl =
process.env["NEXT_PUBLIC_RPC_GATEWAY_HOSTNAME"] +
":" +
process.env["NEXT_PUBLIC_RPC_GATEWAY_PORT"] +
process.env["NEXT_PUBLIC_RPC_GATEWAY_ROOT_URL"];
private static baseUrl: string;
protected readonly variables = FrontendVariables.getInstance();
protected constructor() {}
protected constructor() {
BaseApiService.baseUrl ??=
FrontendVariables.getInstance().BACK_API_PROTOCOL +
FrontendVariables.getInstance().BACK_API_HOST +
":" +
FrontendVariables.getInstance().BACK_API_PORT ?? "" +
FrontendVariables.getInstance().BACK_API_ROOT_URL +
FrontendVariables.getInstance().BACK_API_VERSION;
}
protected getBaseUrl() {
return BaseApiService.baseUrl;
}
protected buildHeaders(contentType: ContentType) {
const headers = new Headers();
@ -35,7 +40,6 @@ export default abstract class BaseApiService {
await fetch(url, {
method: "GET",
headers: this.buildHeaders(ContentType.JSON),
mode: "no-cors",
});
console.log(request);
return this.sendRequest<T>(request);

View File

@ -1,5 +1,5 @@
import BaseApiService from "@Front/Api/BaseApiService";
export default abstract class BaseNotary extends BaseApiService {
protected readonly namespaceUrl = this.backUrl.concat("/customers");
protected readonly namespaceUrl = this.getBaseUrl().concat("/customers");
}

View File

@ -1,5 +1,5 @@
import BaseApiService from "@Front/Api/BaseApiService";
export default abstract class BaseNotary extends BaseApiService {
protected readonly namespaceUrl = this.backUrl.concat("/notary");
protected readonly namespaceUrl = this.getBaseUrl().concat("/notary");
}

View File

@ -45,7 +45,7 @@ export default class Users extends BaseNotary {
}
}
public async getOne(uid: string): Promise<User> {
public async getByUid(uid: string): Promise<User> {
const url = new URL(this.baseURl.concat("/").concat(uid));
try {
return await this.getRequest<User>(url);

View File

@ -0,0 +1,5 @@
import BaseApiService from "@Front/Api/BaseApiService";
export default abstract class BaseSuperAdmin extends BaseApiService {
protected readonly namespaceUrl = this.getBaseUrl().concat("/super-admin");
}

View File

@ -0,0 +1,67 @@
import { Service } from "typedi";
import User from "le-coffre-resources/dist/Notary";
import BaseSuperAdmin from "../BaseSuperAdmin";
@Service()
export default class Users extends BaseSuperAdmin {
private static instance: Users;
private readonly baseURl = this.namespaceUrl.concat("/Users");
private constructor() {
super();
}
public static getInstance() {
if (!this.instance) {
return new Users();
} else {
return this.instance;
}
}
public async get(): Promise<User[]> {
const url = new URL(this.baseURl);
try {
return await this.getRequest<User[]>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
public async getAuthorizationCode(): Promise<any> {
try {
const url =
new URL(`https://qual-connexion.idnot.fr/IdPOAuth2/authorize/idnot_idp_v1?
client_id=4501646203F3EF67
&redirect_uri=https://app.stg.lecoffre.smart-chain.fr/
&scope=openid,profile,offline_access
&response_type=code`);
// const url = new URL("https://jsonplaceholder.typicode.com/todos/1");
await this.getRequest(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
public async getByUid(uid: string): Promise<User> {
const url = new URL(this.baseURl.concat("/").concat(uid));
try {
return await this.getRequest<User>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
// public async post(params: User): Promise<User> {
// const url = new URL(this.baseURl);
// try {
// return await this.postRequest<User>(url, params);
// } catch (err) {
// this.onError(err);
// return Promise.reject(err);
// }
// }
}

View File

@ -1,5 +1,6 @@
import React from "react";
import React, { CSSProperties } from "react";
import classes from "./classes.module.scss";
import Image from "next/image";
export enum EButtonVariant {
PRIMARY = "primary",
@ -13,7 +14,8 @@ type IProps = {
children?: React.ReactNode;
variant?: EButtonVariant;
fullwidth?: "true" | "false";
icon?: React.ReactNode;
icon? : string;
iconStyle?: CSSProperties;
disabled?: boolean;
type: "button" | "submit";
isloading: string;
@ -33,12 +35,10 @@ export default class Button extends React.Component<IProps, IState> {
public override render(): JSX.Element {
const attributes = { ...this.props };
delete attributes.icon;
// let icon = this.props.isloading === "true" ? <Loader /> : this.props.icon; // Notion de loader
let icon = this.props.icon;
return (
<button {...attributes} onClick={this.props.onClick} className={classes["root"]} type={this.props.type}>
{this.props.children}
{this.props.icon && icon}
{this.props.icon && <Image src={this.props.icon} style={this.props.iconStyle} alt={"button icon"}/>}
</button>
);
}

View File

@ -0,0 +1,27 @@
@import "@Themes/constants.scss";
.root {
background-color: $grey-soft;
padding: 24px;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
.content {
display:grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
gap: 32px;
@media (max-width: $screen-l) {
grid-template-columns: 1fr 1fr;
}
&.isSignleDescription {
grid-template-columns: 1fr;
}
}
.edit-icon{
margin-left: 48px;
}
}

View File

@ -0,0 +1,61 @@
import React from "react";
import classes from "./classes.module.scss";
import classNames from "classnames";
import Image from "next/image";
import PenICon from "@Assets/Icons/pen.svg";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Typography, { ITypo } from "../../Typography";
type IProps = {
folder: IDashBoardFolder;
isDescription: boolean;
};
type IState = {};
export default class FolderBoxInformation extends React.Component<IProps, IState> {
public static defaultProps = {
isDescription: false,
};
public override render(): JSX.Element {
return <div className={classNames(classes["root"], this.props.isDescription && classes["isSignleDescription"])}>
<div className={classes["content"]}>
{this.props.isDescription ?
<div className={classes["text-container"]}>
<Typography typo={ITypo.NAV_INPUT_16}>Note dossier :</Typography>
<Typography typo={ITypo.P_18}>{this.props.folder.description ?? "..."}</Typography>
</div>
:
<>
<div className={classes["text-container"]}>
<Typography typo={ITypo.NAV_INPUT_16}>Intitulé du dossier</Typography>
<Typography typo={ITypo.P_18}>{this.props.folder.name ?? "..."}</Typography>
</div>
<div className={classes["text-container"]}>
<Typography typo={ITypo.NAV_INPUT_16}>Numéro de dossier</Typography>
<Typography typo={ITypo.P_18}>{this.props.folder.folder_number ?? "..."}</Typography>
</div>
<div className={classes["text-container"]}>
<Typography typo={ITypo.NAV_INPUT_16}>Type dacte</Typography>
<Typography typo={ITypo.P_18}>{this.props.folder.deed.deed_type.name ?? "..."}</Typography>
</div>
<div className={classes["text-container"]}>
<Typography typo={ITypo.NAV_INPUT_16}>Ouverture du dossier</Typography>
<Typography typo={ITypo.P_18}>{this.formatDate(this.props.folder.created_at)}</Typography>
</div>
</>
}
</div>
<Image src={PenICon} alt="edit informations" className={classes["edit-icon"]}/>
</div>;
}
private formatDate(date: Date | null): string {
if(!date) return "...";
return date.toLocaleDateString("fr-FR", {
year: "numeric",
month: "long",
day: "numeric",
});
}
}

View File

@ -7,6 +7,7 @@
width: 100%;
padding: 24px;
border: 1px solid $grey-medium;
cursor: pointer;
&:hover{
background-color: $grey-medium;

View File

@ -3,20 +3,23 @@ import classes from "./classes.module.scss";
import Typography, { ITypo } from "../Typography";
import Image from "next/image";
import ChevronIcon from "@Assets/Icons/chevron.svg";
import { OfficeFolder } from "le-coffre-resources/dist/Notary";
import WarningBadge from "../WarningBadge";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
type IProps = {
folder: {
folder_number: OfficeFolder["folder_number"] ;
documents?: OfficeFolder["documents"];
};
folder: IDashBoardFolder;
onSelectedFolder?: (folder: IDashBoardFolder) => void;
}
type IState = {};
export default class FolderContainer extends React.Component<IProps, IState> {
public constructor(props: IProps) {
super(props);
this.onSelectedFolder = this.onSelectedFolder.bind(this);
}
public override render(): JSX.Element {
return <div className={classes["root"]}>
return <div className={classes["root"]} onClick={this.onSelectedFolder}>
<div className={classes["left-side"]}>
<Typography typo={ITypo.P_16}>{"Dossier ".concat(this.props.folder.folder_number)}</Typography>
{this.countPendingDocuments() > 0 && <div className={classes["warning"]}><WarningBadge /></div>}
@ -29,4 +32,8 @@ export default class FolderContainer extends React.Component<IProps, IState> {
if (!this.props.folder.documents) return 0;
return this.props.folder.documents?.filter((document) => document.document_status === "PENDING").length ?? 0;
}
private onSelectedFolder(): void {
this.props.onSelectedFolder && this.props.onSelectedFolder(this.props.folder);
}
}

View File

@ -1,10 +1,11 @@
import React from "react";
import classes from "./classes.module.scss";
import FolderContainer from "../FolderContainer";
import { IFolder } from "../SearchBar";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
type IProps = {
folders: IFolder[];
folders: IDashBoardFolder[];
onSelectedFolder?: (folder: IDashBoardFolder) => void;
};
type IState = {};
@ -12,9 +13,8 @@ type IState = {};
export default class FolderList extends React.Component<IProps, IState> {
public override render(): JSX.Element {
return <div className={classes["root"]}>
{this.props.folders.map((folder, key) => {
return <FolderContainer folder={folder} key={key}/>;
{this.props.folders.map((folder) => {
return <FolderContainer folder={folder} key={folder.uid} onSelectedFolder={this.props.onSelectedFolder}/>;
})};
</div>;
}

View File

@ -2,6 +2,7 @@
.root {
min-height: 100%;
width: 389px;
display: flex;
flex-direction: column;
justify-content: space-between;

View File

@ -1,14 +1,16 @@
import React from "react";
import classes from "./classes.module.scss";
import SearchBar, { IFolder } from "../SearchBar";
import SearchBar from "../SearchBar";
import Button from "../Button";
import FolderList from "../FolderList";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
type IProps = {
folders: IFolder[];
folders: IDashBoardFolder[];
onSelectedFolder?: (folder: IDashBoardFolder) => void;
};
type IState = {
filteredFolders: IFolder[];
filteredFolders: IDashBoardFolder[];
};
export default class FolderListContainer extends React.Component<IProps, IState> {
@ -26,7 +28,7 @@ export default class FolderListContainer extends React.Component<IProps, IState>
<div className={classes["searchbar"]}>
<SearchBar folders={this.props.folders} onChange={this.filterFolders} />
</div>
<FolderList folders={this.state.filteredFolders} />
<FolderList folders={this.state.filteredFolders} onSelectedFolder={this.props.onSelectedFolder && this.props.onSelectedFolder} />
</div>
<div>
@ -35,7 +37,7 @@ export default class FolderListContainer extends React.Component<IProps, IState>
</div>;
}
private filterFolders(folders: IFolder[]): IFolder[] {
private filterFolders(folders: IDashBoardFolder[]): IDashBoardFolder[] {
this.setState({ filteredFolders: folders })
return folders;
}

View File

@ -15,13 +15,13 @@ type IFolderInformation = {
export default class InformationBox extends React.Component<IProps, IState> {
public override render(): JSX.Element {
return <div className={classes["root"]}>
{this.props.informations.map((information, key) => {
{/* {this.props.informations.map((information, key) => {
const output = <div className={classes["information"] } key={key}>
<span className={classes["label"]}>{information.label}</span>
<span className={classes["value"]}>{information.value}</span>
</div>;
return output;
})};
})}; */}
</div>;
}
}

View File

@ -3,20 +3,16 @@ import classes from "./classes.module.scss";
import LoopIcon from "@Assets/Icons/loop.svg";
import Image from "next/image";
import Typography, { ITypo } from "../Typography";
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
type IProps = {
folders: IFolder[];
onChange?: (folders: IFolder[]) => IFolder[];
folders: IDashBoardFolder[];
onChange?: (folders: IDashBoardFolder[]) => IDashBoardFolder[];
};
type IState = {
hasValue: boolean;
};
export type IFolder = {
folder_number: OfficeFolder["folder_number"];
documents?: OfficeFolder["documents"];
};
export default class SearchBar extends React.Component<IProps, IState> {
public constructor(props: IProps) {
@ -47,7 +43,7 @@ export default class SearchBar extends React.Component<IProps, IState> {
}
private filterFolders(event: React.ChangeEvent<HTMLInputElement>) {
const filteredFolders: IFolder[] = this.props.folders.filter((folder) => folder.folder_number.includes(event.target.value));
const filteredFolders: IDashBoardFolder[] = this.props.folders.filter((folder) => folder.folder_number.includes(event.target.value));
return filteredFolders;
}
}

View File

@ -10,10 +10,12 @@ import DocumentList from "./DocumentList";
import Button, { EButtonVariant } from "../Button";
import PlusIcon from "@Assets/Icons/plus.svg"
import Confirm from "../Modal/Confirm";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
type IProps = {
customer: Customer
animationDelay?: number;
folder: IDashBoardFolder;
};
type IState = {
isOpen: boolean;
@ -44,7 +46,7 @@ export default class UserFolder extends React.Component<IProps, IState> {
public override render(): JSX.Element {
const documentsAsked: Document[] | null = this.getDocumentsByStatus("ASKED");
const otherDocuments: Document[] | null = this.getOtherDocuments(documentsAsked);
const otherDocuments: Document[] | null = this.getValidatedAndPendindDocuments();
return <div className={classes["root"]}>
<Confirm
@ -71,7 +73,7 @@ export default class UserFolder extends React.Component<IProps, IState> {
<DocumentList documents={otherDocuments} title="Documents à valider / validés" subtitle="Vous avez des documents à valider." openDeletionModal={this.openDeletionModal} />
</div>
<div className={classes["button-container"]}>
<Button variant={EButtonVariant.LINE} icon={<Image src={PlusIcon} alt="plus icon" />}>Demander un autre document </Button>
<Button variant={EButtonVariant.LINE} icon={PlusIcon}>Demander un autre document </Button>
<Button>Envoyer un mail de demande de documents</Button>
</div>
</div>
@ -87,23 +89,32 @@ export default class UserFolder extends React.Component<IProps, IState> {
if (!this.props.customer.documents) return 0;
const totalDocuments: number = this.props.customer.documents.length;
const numberDocumentsAsked: number = this.getDocumentsByStatus("ASKED")?.length || 0;
return Math.round((numberDocumentsAsked / totalDocuments) * 100);
return Math.round(((totalDocuments - numberDocumentsAsked) / totalDocuments) * 100);
}
private getDocumentsByStatus(status: string): Document[] | null {
if (!this.props.customer.documents) return null;
return this.props.customer.documents.filter((document) => document.document_status === status);
return this.props.customer.documents.filter((document) => document.document_status === status && document.folder.uid === this.props.folder.uid);
}
private getOtherDocuments(documentToExclude: Document[] | null): Document[] | null {
if (!this.props.customer.documents) return null;
if (!documentToExclude) return this.props.customer.documents;
return this.props.customer.documents.filter((document) => !documentToExclude.includes(document));
// Get all documents Validated, pending
private getValidatedAndPendindDocuments(): Document[] | null {
const pendingDocuments = this.getDocumentsByStatus("PENDING");
const validatedDocuments = this.getDocumentsByStatus("VALIDATED");
if (!pendingDocuments && !validatedDocuments) return null;
pendingDocuments?.push(...validatedDocuments!);
return pendingDocuments;
}
// TODO: REFACTO this because the other documents should only be correspond to other documents of the props folders
// private getOtherDocuments(documentToExclude: Document[] | null): Document[] | null {
// if (!this.props.customer.documents) return null;
// if (!documentToExclude) return this.props.customer.documents;
// return this.props.customer.documents.filter((document) => !documentToExclude.includes(document));
// }
private toggleOpen(): void {
if (this.state.isOpen) {
this.closeComponent();
}

View File

@ -2,13 +2,15 @@
.root {
.content {
display: flex;
.left-side {
max-width: 389px;
width: 389px;
height: calc(100vh - 83px);
}
.right-side {
width: 100%;
padding: 64px 48px;
}
}
}

View File

@ -1,26 +1,36 @@
import 'reflect-metadata';
import React, { ReactNode } from "react";
import classes from "./classes.module.scss";
import { IFolder } from "@Front/Components/DesignSystem/SearchBar";
import { folders } from "@Front/Components/Layouts/DesignSystem/dummyData"
import FolderListContainer from "@Front/Components/DesignSystem/FolderListContainer";
import Header from "@Front/Components/DesignSystem/Header";
import Version from "@Front/Components/DesignSystem/Version";
import { folders } from "@Front/Components/Layouts/DesignSystem/dummyData"
import { OfficeFolder } from 'le-coffre-resources/dist/Customer';
type IProps = {
title: string;
children?: ReactNode;
onSelectedFolder: (folder: IDashBoardFolder) => void;
};
type IState = {
folders: IFolder[];
folders: IDashBoardFolder[];
};
export type IDashBoardFolder = {
uid: OfficeFolder["uid"];
name: OfficeFolder["name"];
folder_number: OfficeFolder["folder_number"];
documents?: OfficeFolder["documents"]
description: OfficeFolder["description"];
deed: OfficeFolder["deed"];
created_at: OfficeFolder["created_at"];
office_folder_has_customers?: OfficeFolder["office_folder_has_customers"];
};
export default class DefaultNotaryDashboard extends React.Component<IProps, IState> {
public static defaultProps = {
scrollTop: 0,
};
public constructor(props: IProps) {
public constructor(props: IProps) {
super(props);
this.state = {
folders: folders,
@ -32,7 +42,7 @@ export default class DefaultNotaryDashboard extends React.Component<IProps, ISta
<div className={classes["root"]}>
<Header isUserConnected={true} />
<div className={classes["content"]}>
<div className={classes["left-side"]}><FolderListContainer folders={this.state.folders} /></div>
<div className={classes["left-side"]}><FolderListContainer folders={this.state.folders} onSelectedFolder={this.props.onSelectedFolder}/></div>
<div className={classes["right-side"]}>{this.props.children}</div>
</div>
<Version />

View File

@ -8,12 +8,13 @@ import {
Customer,
DocumentType,
Document,
OfficeFolderHasCustomer,
} from "le-coffre-resources/dist/Notary";
import { ECustomerStatus } from "le-coffre-resources/dist/Customer/Customer";
import { EFolderStatus } from "le-coffre-resources/dist/Customer/OfficeFolder";
export const address: Address = {
uid: "a&23",
uid: "a&2azedzaa3",
address: "123",
city: "France",
zip_code: 78140,
@ -22,7 +23,7 @@ export const address: Address = {
};
export const office: Office = {
uid: "111213",
uid: "111zdazaefez213",
idNot: "12EE12",
name: "Office 1",
crpcen: "AZezdz",
@ -32,7 +33,7 @@ export const office: Office = {
office_status: "ACTIVATED",
};
export const deedType: DeedType = {
uid: "123312",
uid: "123azefezgzeg312",
name: "Acte mariage",
description: "dzsdaf",
archived_at: new Date(),
@ -42,14 +43,14 @@ export const deedType: DeedType = {
};
export const deed: Deed = {
uid: "123124",
uid: "zegefzeferg",
deed_type: deedType,
created_at: new Date(),
updated_at: new Date(),
};
export const contact: Contact = {
uid: "123123",
uid: "g('yeh(grgrezg",
first_name: "John",
last_name: "Doe",
email: "johnDoe@gmail.com",
@ -61,9 +62,22 @@ export const contact: Contact = {
civility: "MALE",
};
export const contact2: Contact = {
uid: "g('yeh(grgrezg",
first_name: "Customer2",
last_name: "Doe",
email: "johnDoe@gmail.com",
address: address,
created_at: new Date(),
updated_at: new Date(),
cell_phone_number: "0132249865",
phone_number: "0132249865",
civility: "MALE",
};
export const docType: DocumentType = {
name: "Acte de naissance",
uid: "123123",
uid: "fezezfazegezrgrezg",
created_at: new Date(),
updated_at: new Date(),
public_description: "Acte de naissance public description",
@ -71,14 +85,14 @@ export const docType: DocumentType = {
archived_at: new Date(),
};
export const customer: Customer = {
uid: "123123",
uid: "erhtgerfzeare",
contact: contact,
created_at: new Date(),
updated_at: new Date(),
status: ECustomerStatus.VALIDATED,
};
export const folder: OfficeFolder = {
uid: "11123312",
uid: "zfaefergregrezterf",
folder_number: "12331",
name: "Mon dossier",
status: EFolderStatus.ARCHIVED,
@ -91,17 +105,7 @@ export const folder: OfficeFolder = {
};
export const document: Document = {
uid: "0",
depositor: customer,
document_status: "ASKED",
folder: folder,
document_type: docType,
updated_at: new Date(),
created_at: new Date(),
};
export const document2: Document = {
uid: "1",
uid: "fzeafergreztyzgrf",
depositor: customer,
document_status: "ASKED",
folder: folder,
@ -111,7 +115,7 @@ export const document2: Document = {
};
export const documentPending: Document = {
uid: "2",
uid: "fzefeazdagrtetrury",
depositor: customer,
document_status: "PENDING",
folder: folder,
@ -121,7 +125,7 @@ export const documentPending: Document = {
};
export const documentDeposited: Document = {
uid: "3",
uid: "uè§u§htfgrthytrgr",
depositor: customer,
document_status: "VALIDATED",
folder: folder,
@ -131,18 +135,16 @@ export const documentDeposited: Document = {
};
export const customer2: Customer = {
uid: "123123",
contact: contact,
uid: "yregrgetergrt",
contact: contact2,
created_at: new Date(),
updated_at: new Date(),
status: ECustomerStatus.VALIDATED,
documents: [document, document2, documentPending, documentDeposited],
documents: [document, documentPending, documentDeposited, ],
};
export const folderWithPendingDocument: OfficeFolder = {
uid: "11123312",
uid: "ferzferzfezeefzdd",
folder_number: "00001",
name: "Mon dossier",
status: EFolderStatus.ARCHIVED,
@ -152,10 +154,10 @@ export const folderWithPendingDocument: OfficeFolder = {
updated_at: new Date(),
description: "Description",
archived_description: "Archived description",
documents: [document, document2, documentPending, documentDeposited],
documents: [document, documentPending, documentDeposited],
};
export const folderWithPendingDocument1: OfficeFolder = {
uid: "11123312",
uid: "gtrtyutyhretgytu",
folder_number: "00002",
name: "Mon dossier",
status: EFolderStatus.ARCHIVED,
@ -168,7 +170,7 @@ export const folderWithPendingDocument1: OfficeFolder = {
documents: [documentDeposited],
};
export const folderWithPendingDocument2: OfficeFolder = {
uid: "11123312",
uid: "adzefzefsfrefzrtgtr",
folder_number: "00003",
name: "Mon dossier",
status: EFolderStatus.ARCHIVED,
@ -178,10 +180,37 @@ export const folderWithPendingDocument2: OfficeFolder = {
updated_at: new Date(),
description: "Description",
archived_description: "Archived description",
documents: [document, document2],
documents: [document],
};
export const officeFolderHasCustomer1: OfficeFolderHasCustomer = {
uid: "ferzfergrzeyerezrz",
customer: customer,
office_folder: folderWithPendingDocument,
created_at: new Date(),
updated_at: new Date(),
};
export const officeFolderHasCustomer2: OfficeFolderHasCustomer = {
uid: "tezrfzdfgrggeerry",
customer: customer2,
office_folder: folderWithPendingDocument,
created_at: new Date(),
updated_at: new Date(),
};
export const document8: Document = {
uid: "eztreggrgbyunjukhg",
depositor: customer,
document_status: "ASKED",
folder: folderWithPendingDocument,
document_type: docType,
updated_at: new Date(),
created_at: new Date(),
};
export const folderWithPendingDocument3: OfficeFolder = {
uid: "11123312",
uid: "mkovrijvrezviev",
folder_number: "00014",
name: "Mon dossier",
status: EFolderStatus.ARCHIVED,
@ -191,6 +220,24 @@ export const folderWithPendingDocument3: OfficeFolder = {
updated_at: new Date(),
description: "Description",
archived_description: "Archived description",
documents: [document, document2, documentDeposited, documentPending],
documents: [document, documentDeposited, documentPending],
office_folder_has_customers: [officeFolderHasCustomer1, officeFolderHasCustomer2],
};
export const folders : OfficeFolder[] = [folderWithPendingDocument, folderWithPendingDocument1, folderWithPendingDocument2, folderWithPendingDocument3]
export const document2: Document = {
uid: "mejfihruehfoire",
depositor: customer,
document_status: "ASKED",
folder: folderWithPendingDocument3,
document_type: docType,
updated_at: new Date(),
created_at: new Date(),
};
export const folders: OfficeFolder[] = [
folderWithPendingDocument,
folderWithPendingDocument1,
folderWithPendingDocument2,
folderWithPendingDocument3,
];

View File

@ -172,7 +172,7 @@ export default class DesignSystem extends BasePage<IProps, IState> {
<div className={classes["sub-section"]}>
<Typography typo={ITypo.P_16}>Folder with no document to validate</Typography>
<div className={classes["folder-conatainer"]}>
<FolderContainer folder={folder} />
<FolderContainer folder={folder}/>
</div>
</div>
<div className={classes["sub-section"]}>
@ -225,7 +225,7 @@ export default class DesignSystem extends BasePage<IProps, IState> {
<Typography typo={ITypo.H3}>Notary Documents</Typography>
</div>
<div className={classes["sub-section"]}>
<UserFolder customer={customer2} />
<UserFolder customer={customer2} folder={folder}/>
</div>
</div>

View File

@ -0,0 +1,19 @@
@import "@Themes/constants.scss";
.root {
width: 100%;
.no-client{
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.title{
margin-bottom: 16px;
}
}
.client{
display: grid;
gap: 32px;
}
}

View File

@ -0,0 +1,43 @@
import React from "react";
import classes from "./classes.module.scss";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import PlusIcon from "@Assets/Icons/plus.svg";
import UserFolder from "@Front/Components/DesignSystem/UserFolder";
type IProps = {
folder: IDashBoardFolder;
};
type IState = {};
export default class ClientSection extends React.Component<IProps, IState> {
public override render(): JSX.Element {
return <div className={classes["root"]}>
{this.doesFolderHaveCustomer() ?
<div className={classes["client"]}>
{this.renderCustomerFolders()}
</div>
:
<div className={classes["no-client"]}>
<div className={classes["title"]}>
<Typography typo={ITypo.P_18}>Aucun client nest associé au dossier.</Typography>
</div>
<Button variant={EButtonVariant.LINE} icon={PlusIcon}>Ajouter un client</Button>
</div>}
</div>;
}
private renderCustomerFolders() {
const output = this.props.folder.office_folder_has_customers?.map((folderHasCustomer) => {
if (!folderHasCustomer.customer) return null;
// TODO : Les documents ASKED fonctionne mais les autres documents ne doivcent etre seulement ceux qui correspondent au folder
return <div className={classes["user-folder"]}><UserFolder folder={this.props.folder} customer={folderHasCustomer.customer} key={folderHasCustomer.customer.uid} /></div>;
})
return output ?? null;
}
private doesFolderHaveCustomer(): boolean {
return this.props.folder.office_folder_has_customers !== undefined;
}
}

View File

@ -0,0 +1,44 @@
.root {
display: flex;
align-items: center;
flex-direction: column;
min-height: 100%;
.folder-informations {
width: 100%;
min-height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: column;
flex-grow: 1;
.folder-header {
width: 100%;
.header {
margin-bottom: 32px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
}
.second-box {
margin-top: 24px;
margin-bottom: 32px;
}
.progress-bar{
margin-bottom: 32px;
}
.button-container{
:first-child{
margin-right: 12px;
}
}
}
}

View File

@ -0,0 +1,69 @@
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import BasePage from "../Base";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import classes from "./classes.module.scss";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import FolderBoxInformation from "@Front/Components/DesignSystem/Elements/FolderBoxInformation";
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
import ClientSection from "./ClientSection";
import ChevronIcon from "@Assets/Icons/chevron.svg";
import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
type IProps = {};
type IState = {
selectedFolder: IDashBoardFolder | null;
};
export default class Folder extends BasePage<IProps, IState>{
public constructor(props: IProps) {
super(props);
this.state = {
selectedFolder: null,
};
this.onSelectedFolder = this.onSelectedFolder.bind(this);
}
public override render(): JSX.Element {
return (
<DefaultNotaryDashboard title={"Dossier"} onSelectedFolder={this.onSelectedFolder}>
<div className={classes["root"]}>
{this.state.selectedFolder && <div className={classes["folder-informations"]}>
<div className={classes["folder-header"]}>
<div className={classes["header"]}>
<Typography typo={ITypo.H1Bis}>Informations du dossier</Typography>
<Button variant={EButtonVariant.LINE} icon={ChevronIcon}>Modifier les collaborateurs</Button>
</div>
<FolderBoxInformation folder={this.state.selectedFolder} />
<div className={classes["second-box"]}>
<FolderBoxInformation folder={this.state.selectedFolder} isDescription />
</div>
<div className={classes["progress-bar"]}>
<QuantityProgressBar title="Complétion du dossier" total={100} currentNumber={0} />
</div>
{this.doesFolderHaveCustomer() && <ClientSection folder={this.state.selectedFolder} />}
</div>
{!this.doesFolderHaveCustomer() && <ClientSection folder={this.state.selectedFolder} />}
<div className={classes["button-container"]}>
<Button variant={EButtonVariant.GHOST}>Archiver le dossier</Button>
<Button variant={EButtonVariant.SECONDARY}>Supprimer le dossier</Button>
</div>
</div>}
</div>
</DefaultNotaryDashboard>
);
}
public override async componentDidMount() {
const users = await Users.getInstance().getByUid("5rOlvAleeX");
console.log(users);
}
private doesFolderHaveCustomer(): boolean {
return this.state.selectedFolder?.office_folder_has_customers !== undefined;
}
private onSelectedFolder(folder: IDashBoardFolder): void {
this.setState({ selectedFolder: folder });
}
}

View File

@ -1,16 +0,0 @@
.root {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
.title {
margin: 32px 0;
text-align: center;
}
.forget-password {
margin-top: 32px;
margin-bottom: 8px;
}
}

View File

@ -1,11 +0,0 @@
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import BasePage from "../Base";
export default class FolderInfomations extends BasePage {
public override render(): JSX.Element {
return (
<DefaultNotaryDashboard title={""}>
</DefaultNotaryDashboard>
);
}
}

View File

@ -1,31 +1,22 @@
import { Service } from "typedi";
@Service()
export class FrontendVariables {
private static instance: FrontendVariables;
private static instance: FrontendVariables;
public readonly WEB_LABEL: string;
public BACK_API_PROTOCOL!: string;
public readonly WEB_PORT!: string;
public BACK_API_HOST!: string;
public readonly WEB_ROOT_URL!: string;
public BACK_API_PORT!: string;
public readonly NEXT_PUBLIC_API_URL!: string;
public BACK_API_ROOT_URL!: string;
public readonly NODE_ENV!: string;
public BACK_API_VERSION!: string;
constructor() {
this.NODE_ENV = process.env["NODE_ENV"]!;
this.WEB_LABEL = process.env["WEB_LABEL"]!;
this.WEB_PORT = process.env["WEB_PORT"]!;
this.WEB_ROOT_URL = process.env["WEB_ROOT_URL"]!;
this.NEXT_PUBLIC_API_URL = process.env["NEXT_PUBLIC_API_URL"]!;
}
private constructor() {}
public static getInstance(): FrontendVariables {
if (!this.instance) {
this.instance = new this();
}
return this.instance;
}
public static getInstance(): FrontendVariables {
if (!this.instance) {
this.instance = new this();
}
return this.instance;
}
}

View File

@ -1,4 +1,5 @@
import { DefaultLayout } from "@Front/Components/LayoutTemplates/DefaultLayout";
import { FrontendVariables } from "@Front/Config/VariablesFront";
import "@Front/index.scss";
import type { NextPage } from "next";
import type { AppType, AppProps } from "next/app";
@ -10,12 +11,34 @@ export type NextPageWithLayout<TProps = Record<string, unknown>, TInitialProps =
type AppPropsWithLayout = AppProps & {
Component: NextPageWithLayout;
} & {
backApiProtocol: string,
backApiHost: string,
backApiPort: string,
backApiRootUrl: string,
backApiVersion: string,
};
const MyApp = (({ Component, pageProps }: AppPropsWithLayout) => {
const MyApp = (({ Component, pageProps, backApiProtocol, backApiHost, backApiPort, backApiRootUrl, backApiVersion }: AppPropsWithLayout) => {
const getLayout = Component.getLayout ?? ((page) => <DefaultLayout children={page}></DefaultLayout>);
FrontendVariables.getInstance().BACK_API_PROTOCOL = backApiProtocol;
FrontendVariables.getInstance().BACK_API_HOST = backApiHost;
FrontendVariables.getInstance().BACK_API_PORT = backApiPort;
FrontendVariables.getInstance().BACK_API_ROOT_URL = backApiRootUrl;
FrontendVariables.getInstance().BACK_API_VERSION = backApiVersion;
return getLayout(<Component {...pageProps} />);
}) as AppType;
MyApp.getInitialProps = async () => {
return {
backApiProtocol: process.env["BACK_API_PROTOCOL"],
backApiHost: process.env["BACK_API_HOST"],
backApiPort: process.env["BACK_API_PORT"],
backApiRootUrl: process.env["BACK_API_ROOT_URL"],
backApiVersion: process.env["BACK_API_VERSION"],
};
}
export default MyApp;

5
src/pages/dossier.tsx Normal file
View File

@ -0,0 +1,5 @@
import Folder from "@Front/Components/Layouts/Folder";
export default function Route() {
return <Folder />;
}

View File

@ -1,5 +0,0 @@
import FolderInfomations from "@Front/Components/Layouts/FolderInfomations";
export default function Route() {
return <FolderInfomations />;
}

View File

@ -75,3 +75,4 @@
"node_modules"
]
}