Unmocked client dashboard page

This commit is contained in:
Vins 2023-08-10 14:35:12 +02:00
parent 489cdd9685
commit 804e0d5976
13 changed files with 412 additions and 112 deletions

Binary file not shown.

View File

@ -0,0 +1,67 @@
import Customer, { Contact } from "le-coffre-resources/dist/Customer";
import BaseCustomer from "../BaseCustomer";
import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
// TODO Type get query params -> Where + inclue + orderby
export interface IGetCustomersparams {
where?: {};
include?: {};
}
// TODO Type getbyuid query params
export type IPutCustomersParams = {
uid?: Customer["uid"];
contact?: Customer["contact"];
};
export interface IPostCustomersParams {
first_name: string;
last_name: string;
email: string;
cell_phone_number: string;
civility: ECivility;
address?: Contact["address"];
}
export default class Customers extends BaseCustomer {
private static instance: Customers;
private readonly baseURl = this.namespaceUrl.concat("/customers");
private constructor() {
super();
}
public static getInstance() {
if (!this.instance) {
return new this();
} else {
return this.instance;
}
}
public async get(q: IGetCustomersparams): Promise<Customer[]> {
const url = new URL(this.baseURl);
const query = { q };
Object.entries(query).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
try {
return await this.getRequest<Customer[]>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
public async getByUid(uid: string, q?: any): Promise<Customer> {
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<Customer>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
}

View File

@ -0,0 +1,93 @@
import { Document } from "le-coffre-resources/dist/Customer";
import BaseCustomer from "../BaseCustomer";
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
// TODO Type get query params -> Where + inclue + orderby
export interface IGetDocumentsparams {
where?: {};
include?: {};
}
// TODO Type getbyuid query params
export type IPutDocumentsParams = {
document_status?: EDocumentStatus;
refused_reason?: string;
};
export interface IPostDocumentsParams {}
export default class Documents extends BaseCustomer {
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);
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);
}
}
/**
* @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);
}
}
public async delete(uid: string): Promise<Document> {
const url = new URL(this.baseURl.concat(`/${uid}`));
try {
return await this.deleteRequest<Document>(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
}

View File

@ -1,46 +1,101 @@
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Documents/Documents";
"use client";
import Customers from "@Front/Api/LeCoffreApi/Customer/Customers/Customers";
import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/Customer/Documents/Documents";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import DepositDocument from "@Front/Components/DesignSystem/DepositDocument";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import Base from "@Front/Components/Layouts/Base";
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
import Customer, { Document, DocumentType } from "le-coffre-resources/dist/Customer";
import React from "react";
import React, { useCallback, useEffect, useState } from "react";
import classes from "./classes.module.scss";
import { useRouter } from "next/router";
import JwtService from "@Front/Services/JwtService/JwtService";
type IProps = {
targetedCustormer: string; // MOCK
};
type IState = {
isAddDocumentModalVisible: boolean;
documents: Document[];
mockedCustomer: Customer | null;
type IProps = {};
export default function ClientDashboard(props: IProps) {
const router = useRouter();
let { folderUid } = router.query;
const [documents, setDocuments] = useState<Document[] | null>(null);
const [customer, setCustomer] = useState<Customer | null>(null);
const [isAddDocumentModalVisible, setIsAddDocumentModalVisible] = useState<boolean>(false);
const onCloseModalAddDocument = useCallback(() => {
setIsAddDocumentModalVisible(false);
}, []);
const onOpenModalAddDocument = useCallback(() => {
setIsAddDocumentModalVisible(true);
}, []);
useEffect(() => {
async function getDocuments() {
let jwt;
if (typeof document !== "undefined") {
jwt = JwtService.getInstance().decodeJwt();
}
if (!jwt || !jwt.email) return;
const customers = await Customers.getInstance().get({
where: { contact: { email: jwt.email }, office_folders: { some: { uid: folderUid } } },
});
const actualCustomer: Customer = customers[0]!;
const query: IGetDocumentsparams = {
where: { depositor: { uid: actualCustomer.uid }, folder_uid: folderUid as string },
include: {
files: true,
document_history: true,
document_type: true,
depositor: true,
},
};
export default class ClientDashboard extends Base<IProps, IState> {
public constructor(props: IProps) {
super(props);
this.state = {
isAddDocumentModalVisible: false,
documents: [],
mockedCustomer: null,
};
this.onCloseModalAddDocument = this.onCloseModalAddDocument.bind(this);
this.onOpenModalAddDocument = this.onOpenModalAddDocument.bind(this);
const documentList = await Documents.getInstance().get(query);
setDocuments(documentList);
setCustomer(actualCustomer);
}
public override render(): JSX.Element {
getDocuments();
}, [folderUid]);
const renderHeader = useCallback(() => {
return (
<div className={classes["header"]}>
<div className={classes["text-container"]}>
{/* TODO Get name from userStore */}
<Typography typo={ITypo.H1} className={classes["title"]}>
Bonjour {customer?.contact?.first_name.concat(" ", customer?.contact?.last_name)}
</Typography>
<Typography typo={ITypo.H2} className={classes["subtitle"]}>
Documents à envoyer
</Typography>
<Typography typo={ITypo.P_16} className={classes["text"]}>
Votre notaire est dans l'attente de documents pour valider votre dossier. Voici la liste des documents.Veuillez
glisser / déposez chaque document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
document correspondant. Si un des documents demandés ne vous concernent pas, veuillez contacter votre notaire à
laide du bouton ci-dessus.
</Typography>
</div>
<a href="mailto:g.texier@notaires.fr" target="_blank">
<Button className={classes["button"]}>Contacter mon notaire</Button>
</a>
</div>
);
}, [customer]);
return (
<DefaultTemplate title={"Mon compte"} isPadding={false} hasHeaderLinks={false}>
<div className={classes["root"]}>
{this.renderHeader()}
{renderHeader()}
<div className={classes["sub-container"]}>
<div className={classes["content"]}>
{this.state.documents?.map((document) => (
{documents?.map((document) => (
<DepositDocument document={document} key={document.uid} defaultFiles={document.files ?? []} />
))}
</div>
@ -48,14 +103,14 @@ export default class ClientDashboard extends Base<IProps, IState> {
<Typography typo={ITypo.P_16} className={classes["text"]}>
Vous souhaitez envoyer d'autres documents à votre notaire ?
</Typography>
<Button variant={EButtonVariant.GHOST} className={classes["button"]} onClick={this.onOpenModalAddDocument}>
<Button variant={EButtonVariant.GHOST} className={classes["button"]} onClick={onOpenModalAddDocument}>
Ajouter d'autres documents
</Button>
</div>
<Confirm
isOpen={this.state.isAddDocumentModalVisible}
onClose={this.onCloseModalAddDocument}
onAccept={this.onOpenModalAddDocument}
isOpen={isAddDocumentModalVisible}
onClose={onCloseModalAddDocument}
onAccept={onOpenModalAddDocument}
closeBtn
header={"Ajouter un document"}
cancelText={"Annuler"}
@ -82,57 +137,3 @@ export default class ClientDashboard extends Base<IProps, IState> {
</DefaultTemplate>
);
}
private renderHeader(): JSX.Element {
return (
<div className={classes["header"]}>
<div className={classes["text-container"]}>
{/* TODO Get name from userStore */}
<Typography typo={ITypo.H1} className={classes["title"]}>
Bonjour {this.state.mockedCustomer?.contact?.first_name.concat(" ", this.state.mockedCustomer?.contact?.last_name)}
</Typography>
<Typography typo={ITypo.H2} className={classes["subtitle"]}>
Documents à envoyer
</Typography>
<Typography typo={ITypo.P_16} className={classes["text"]}>
Votre notaire est dans l'attente de documents pour valider votre dossier. Voici la liste des documents.Veuillez
glisser / déposez chaque document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
document correspondant. Si un des documents demandés ne vous concernent pas, veuillez contacter votre notaire à
laide du bouton ci-dessus.
</Typography>
</div>
<a href="mailto:g.texier@notaires.fr" target="_blank">
<Button className={classes["button"]}>Contacter mon notaire</Button>
</a>
</div>
);
}
public override async componentDidMount() {
// TODO Get documents of the current customer according to userStore
// REMOVE this mock
const mockedCustomers = await Customers.getInstance().get({ where: { contact: { email: this.props.targetedCustormer } } });
const mockedCustomer: Customer = mockedCustomers[0]!;
const query: IGetDocumentsparams = {
where: { depositor: { uid: mockedCustomer.uid } },
include: {
files: true,
document_history: true,
document_type: true,
},
};
const documents: Document[] = await Documents.getInstance().get(query);
this.setState({ documents, mockedCustomer });
}
private onCloseModalAddDocument() {
this.setState({ isAddDocumentModalVisible: false });
}
private onOpenModalAddDocument() {
this.setState({ isAddDocumentModalVisible: true });
}
}

View File

@ -0,0 +1,141 @@
import Customers from "@Front/Api/LeCoffreApi/Customer/Customers/Customers";
import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/Customer/Documents/Documents";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import DepositDocument from "@Front/Components/DesignSystem/DepositDocument";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import Base from "@Front/Components/Layouts/Base";
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
import Customer, { Document, DocumentType } from "le-coffre-resources/dist/Customer";
import React from "react";
import classes from "./classes.module.scss";
import JwtService from "@Front/Services/JwtService/JwtService";
type IProps = {};
type IState = {
isAddDocumentModalVisible: boolean;
documents: Document[];
mockedCustomer: Customer | null;
};
export default class ClientDashboard extends Base<IProps, IState> {
public constructor(props: IProps) {
super(props);
this.state = {
isAddDocumentModalVisible: false,
documents: [],
mockedCustomer: null,
};
this.onCloseModalAddDocument = this.onCloseModalAddDocument.bind(this);
this.onOpenModalAddDocument = this.onOpenModalAddDocument.bind(this);
}
public override render(): JSX.Element {
return (
<DefaultTemplate title={"Mon compte"} isPadding={false} hasHeaderLinks={false}>
<div className={classes["root"]}>
{this.renderHeader()}
<div className={classes["sub-container"]}>
<div className={classes["content"]}>
{this.state.documents?.map((document) => (
<DepositDocument document={document} key={document.uid} defaultFiles={document.files ?? []} />
))}
</div>
<Typography typo={ITypo.H2}>Documents supplémentaires (facultatif)</Typography>
<Typography typo={ITypo.P_16} className={classes["text"]}>
Vous souhaitez envoyer d'autres documents à votre notaire ?
</Typography>
<Button variant={EButtonVariant.GHOST} className={classes["button"]} onClick={this.onOpenModalAddDocument}>
Ajouter d'autres documents
</Button>
</div>
<Confirm
isOpen={this.state.isAddDocumentModalVisible}
onClose={this.onCloseModalAddDocument}
onAccept={this.onOpenModalAddDocument}
closeBtn
header={"Ajouter un document"}
cancelText={"Annuler"}
confirmText={"Déposer le document"}>
<div className={classes["modal-content"]}>
<Typography typo={ITypo.P_16} className={classes["text"]}>
Vous souhaitez envoyer un autre document à votre notaire ?
</Typography>
<TextField placeholder="Nom du document" />
<Typography typo={ITypo.P_16} className={classes["text"]}>
Glissez / Déposez votre document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
document correspondant.
</Typography>
<DepositDocument
document={Document.hydrate<Document>({
document_type: DocumentType.hydrate<DocumentType>({
name: "Document annexe",
}),
})}
/>
</div>
</Confirm>
</div>
</DefaultTemplate>
);
}
private renderHeader(): JSX.Element {
return (
<div className={classes["header"]}>
<div className={classes["text-container"]}>
{/* TODO Get name from userStore */}
<Typography typo={ITypo.H1} className={classes["title"]}>
Bonjour {this.state.mockedCustomer?.contact?.first_name.concat(" ", this.state.mockedCustomer?.contact?.last_name)}
</Typography>
<Typography typo={ITypo.H2} className={classes["subtitle"]}>
Documents à envoyer
</Typography>
<Typography typo={ITypo.P_16} className={classes["text"]}>
Votre notaire est dans l'attente de documents pour valider votre dossier. Voici la liste des documents.Veuillez
glisser / déposez chaque document dans la zone prévue à cet effet ou cliquez sur la zone puis sélectionnez le
document correspondant. Si un des documents demandés ne vous concernent pas, veuillez contacter votre notaire à
laide du bouton ci-dessus.
</Typography>
</div>
<a href="mailto:g.texier@notaires.fr" target="_blank">
<Button className={classes["button"]}>Contacter mon notaire</Button>
</a>
</div>
);
}
public override async componentDidMount() {
// TODO Get documents of the current customer according to userStore
// REMOVE this mock
const jwt = JwtService.getInstance().decodeJwt();
const mockedCustomers = await Customers.getInstance().get({
where: { contact: { email: jwt?.email } },
});
const mockedCustomer: Customer = mockedCustomers[0]!;
const query: IGetDocumentsparams = {
where: { depositor: { uid: mockedCustomer.uid } },
include: {
files: true,
document_history: true,
document_type: true,
},
};
const documents: Document[] = await Documents.getInstance().get(query);
this.setState({ documents, mockedCustomer });
}
private onCloseModalAddDocument() {
this.setState({ isAddDocumentModalVisible: false });
}
private onOpenModalAddDocument() {
this.setState({ isAddDocumentModalVisible: true });
}
}

View File

@ -31,7 +31,7 @@ export default function Login() {
}, [router]);
const redirectCustomerOnConnection = useCallback(() => {
async function getUser() {
async function getCustomer() {
try {
await UserStore.instance.connectCustomer("antoine.bernard@outlook.com");
await JwtService.getInstance().checkJwt();
@ -41,7 +41,7 @@ export default function Login() {
}
}
getUser();
getCustomer();
}, [router]);
return (

View File

@ -18,7 +18,6 @@ export default function SelectFolder() {
async function getFolders() {
const jwt = JwtService.getInstance().decodeJwt();
if (!jwt) return;
console.log(jwt);
const folders = await Folders.getInstance().get({
q: {
@ -32,7 +31,6 @@ export default function SelectFolder() {
},
});
setFolders(folders);
console.log(folders);
}
getFolders();
@ -40,7 +38,7 @@ export default function SelectFolder() {
const handleSelectBlock = useCallback(
(block: IBlock) => {
router.push("/client-dashboard");
router.push("/client-dashboard/" + block.id);
},
[router],
);

View File

@ -8,6 +8,7 @@ enum PROVIDER_OPENID {
interface IUserJwtPayload {
userId: string;
email: string | null;
openId: {
providerName: PROVIDER_OPENID;
userId: string | number;
@ -38,7 +39,6 @@ export default class JwtService {
*/
public async checkJwt() {
const decodedToken = this.decodeJwt();
console.log(decodedToken);
if (!decodedToken) return;

View File

@ -1,5 +1,5 @@
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard";
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard/index";
export default function Route() {
return <ClientDashboard targetedCustormer="lucie.chevalier@outlook.com" />;
return <ClientDashboard />;
}

View File

@ -1,4 +1,4 @@
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard";
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard/index2";
export default function Route() {
return <ClientDashboard targetedCustormer="manon.simon@gmail.com" />;

View File

@ -1,4 +1,4 @@
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard";
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard/index2";
export default function Route() {
return <ClientDashboard targetedCustormer="vincent.brognard@gmail.com" />;

View File

@ -1,4 +1,4 @@
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard";
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard/index2";
export default function Route() {
return <ClientDashboard targetedCustormer="maxime.lalo@gmail.com" />;

View File

@ -1,4 +1,4 @@
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard";
import ClientDashboard from "@Front/Components/Layouts/ClientDashboard/index2";
export default function Route() {
return <ClientDashboard targetedCustormer="kevin.hautefaye@gmail.com" />;