add customers, create customers to a folder

This commit is contained in:
Hugo Lextrait 2023-05-05 11:28:10 +02:00
parent 9f8e00ca85
commit 03c79c197e
9 changed files with 194 additions and 94 deletions

1
.gitignore vendored
View File

@ -4,6 +4,7 @@
/node_modules
/.pnp
.pnp.js
dist/
# testing
/coverage

View File

@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"dev": "tsc && next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",

View File

@ -6,8 +6,8 @@ import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
// TODO Type get query params -> Where + inclue + orderby
export interface IGetCustomersparams {
where?:{},
include?:{},
where?: {};
include?: {};
}
// TODO Type getbyuid query params
@ -45,7 +45,8 @@ export default class Customers extends BaseSuperAdmin {
public async get(q: IGetCustomersparams): Promise<Customer[]> {
const url = new URL(this.baseURl);
Object.entries(q).forEach(([key, value]) => url.searchParams.set(key, JSON.stringify(value)));
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) {

View File

@ -58,8 +58,8 @@ export default class MultiSelect extends React.Component<IProps, IState> {
options={this.props.options}
styles={styles}
onChange={this.onChange}
value={this.props.value}
defaultValue={this.props.defaultValue}
value={this.props.defaultValue}
defaultValue={this.state.selectedOptions}
closeMenuOnSelect={this.props.shouldCloseMenuOnSelect}
isMulti
isOptionDisabled={this.props.isOptionDisabled}
@ -88,6 +88,21 @@ export default class MultiSelect extends React.Component<IProps, IState> {
}
}
public override componentDidUpdate(prevProps: IProps): void {
if (this.props.defaultValue === prevProps.defaultValue) return;
if (this.props.defaultValue) {
// If default value contains multiple IOptions
if (Array.isArray(this.props.defaultValue)) {
this.setState({ selectedOptions: this.props.defaultValue });
}
// If default value is a single IOption
if ("label" in this.props.defaultValue) {
this.setState({ selectedOptions: [this.props.defaultValue] });
}
}
}
private onFocus() {
this.setState({ isFocused: true });
}

View File

@ -44,8 +44,8 @@ export default class UserFolderHeader extends React.Component<IProps, IState> {
<div className={classes["container"]}>
<Typography typo={ITypo.NAV_INPUT_16}>Numéro de téléphone</Typography>
<Typography typo={ITypo.P_18}>
{this.formatPhoneNumber(this.props.customer.contact.phone_number ?? "") ??
this.formatPhoneNumber(this.props.customer.contact.cell_phone_number)}
{this.formatPhoneNumber(this.props.customer.contact.cell_phone_number) ??
this.formatPhoneNumber(this.props.customer.contact.phone_number?.toString() ?? "")}
</Typography>
</div>
@ -82,6 +82,5 @@ export default class UserFolderHeader extends React.Component<IProps, IState> {
return output.join("");
}
private onEditClick(): void {
}
private onEditClick(): void {}
}

View File

@ -8,14 +8,13 @@ import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import { NextRouter, useRouter } from "next/router";
import { ActionMeta, MultiValue } from "react-select";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import Link from "next/link";
import Module from "@Front/Config/Module";
import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Folders, { IPutFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
import { Customer } from "le-coffre-resources/dist/Notary";
@ -24,7 +23,8 @@ type IState = {
selectedFolder: IDashBoardFolder | null;
isExistingClientSelected: boolean;
isNewClientSelected: boolean;
hasNewClientSelected: boolean;
availableCustomers: Customer[] | null;
selectedCustomers: readonly IOption[];
};
type IPropsClass = IProps & {
@ -38,7 +38,8 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
selectedFolder: null,
isExistingClientSelected: true,
isNewClientSelected: false,
hasNewClientSelected: false,
availableCustomers: [],
selectedCustomers: [],
};
this.onSelectedFolder = this.onSelectedFolder.bind(this);
this.onExistingClientSelected = this.onExistingClientSelected.bind(this);
@ -47,11 +48,8 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
this.onFormSubmit = this.onFormSubmit.bind(this);
}
public override render(): JSX.Element {
const selectOptions = [
{ value: "adazzdsqaad", label: "john Doe" },
{ value: "rijgreipgje", label: "jane Doe" },
{ value: "gipjerpogkzfe", label: "Marcelino Doe" },
];
const selectOptions: IOption[] = this.getSelectedOptions();
const backwardPath = Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid);
@ -82,14 +80,17 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
<Form className={classes["form"]} onSubmit={this.onFormSubmit}>
{this.state.isExistingClientSelected && (
<div className={classes["existing-client"]}>
<MultiSelect options={selectOptions} placeholder="Client" onChange={this.onMutiSelectChange} />
<MultiSelect
options={selectOptions}
placeholder="Clients"
onChange={this.onMutiSelectChange}
defaultValue={this.state.selectedCustomers}
/>
<div className={classes["button-container"]}>
<Link href={backwardPath} className={classes["cancel-button"]}>
<Button variant={EButtonVariant.GHOST}>Annuler</Button>
</Link>
<Button disabled={!this.state.hasNewClientSelected ? true : false} type="submit">
Associer au dossier
</Button>
<Button type="submit">Associer au dossier</Button>
</div>
</div>
)}
@ -114,12 +115,57 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
);
}
private onMutiSelectChange(newValue: MultiValue<IOption>, actionMeta: ActionMeta<IOption>): void {
if (newValue.length <= 0) {
this.setState({ hasNewClientSelected: false });
public override async componentDidMount() {
const query = {};
const availableCustomers = await Customers.getInstance().get(query);
let preSelectedCustomers: IOption[] | undefined = await this.getFolderPreSelectedCustomers(this.props.selectedFolderUid);
const selectedCustomers = preSelectedCustomers ?? [];
this.setState({ availableCustomers, selectedCustomers });
}
private async getFolderPreSelectedCustomers(folderUid: string): Promise<IOption[] | undefined> {
const query = {
q: {
office_folder_has_customers: {
include: {
customer: {
include: {
contact: true,
},
},
},
},
},
};
let preSelectedCustomers: IOption[] = [];
try {
const folder = await Folders.getInstance().getByUid(folderUid, query);
preSelectedCustomers = folder.office_folder_has_customers!.map((folderHasCustomer) => {
return {
label: folderHasCustomer.customer.contact?.first_name + " " + folderHasCustomer.customer.contact?.last_name,
value: folderHasCustomer.customer.uid,
};
});
} catch (error) {
this.props.router.push(Module.getInstance().get().modules.pages["404"].props.path);
return;
}
this.setState({ hasNewClientSelected: true });
return preSelectedCustomers;
}
private getSelectedOptions(): IOption[] {
let options = this.state.availableCustomers?.map((customer) => {
return {
label: customer.contact?.first_name + " " + customer.contact?.last_name,
value: customer.uid,
};
});
if (!options) options = [];
return options;
}
private onMutiSelectChange(selectedCustomers: readonly IOption[]): void {
this.setState({ selectedCustomers });
}
private onSelectedFolder(folder: IDashBoardFolder): void {
@ -140,20 +186,30 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
[key: string]: any;
},
) {
values["civility"] = ECivility.MALE;
const customer = {
contact: values,
};
const newCustomerCreated: Customer = await Customers.getInstance().post(customer);
console.log("NEW CUSTOMER CREATED >>>", newCustomerCreated);
values["civility"] = ECivility.MALE; // TODO: should maybe be deleted later or added to the form
if (newCustomerCreated) {
let customersToLink: IPutFoldersParams["office_folder_has_customers"] = [];
if (this.state.isNewClientSelected) {
const customer: Customer = await Customers.getInstance().post({
customer: values,
});
if (!customer.uid) return;
customersToLink = [{ customer: { uid: customer.uid } }];
}
if (this.state.isExistingClientSelected) {
customersToLink = this.state.selectedCustomers.map((customer) => {
return {
customer: { uid: customer.value },
};
}) as IPutFoldersParams["office_folder_has_customers"];
}
if (customersToLink) {
const body = {
office_folder_has_customers: [{ customer: { uid: newCustomerCreated.uid } }],
office_folder_has_customers: customersToLink,
};
console.log("BODY >>>", body);
await Folders.getInstance().put(this.props.selectedFolderUid, body);
this.props.router.push(`/folders/${this.props.selectedFolderUid}`);
}

View File

@ -15,7 +15,7 @@ import BasePage from "../../Base";
import classes from "./classes.module.scss";
import ClientSection from "./ClientSection";
import { EDocumentStatus } from "le-coffre-resources/dist/Notary/Document";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Folders, { IPutFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
import { ChangeEvent } from "react";
@ -54,7 +54,11 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
.get()
.modules.pages.Folder.pages.EditCollaborators.props.path.replace("[folderUid]", this.props.selectedFolderUid);
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"]}>
{this.state.selectedFolder ? (
<div className={classes["folder-informations"]}>
@ -74,7 +78,11 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
<FolderBoxInformation folder={this.state.selectedFolder} type={EFolderBoxInformationType.DESCRIPTION} />
</div>
<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>
{this.doesFolderHaveCustomer() && <ClientSection folder={this.state.selectedFolder} />}
</div>
@ -102,7 +110,12 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
<div className={classes["modal-title"]}>
<Typography typo={ITypo.P_16}>Souhaitez-vous vraiment archiver le dossier ?</Typography>
</div>
<InputField name="archived_description" fakeplaceholder="Description" textarea onChange={this.onArchivedDescriptionInputChange}/>
<InputField
name="archived_description"
fakeplaceholder="Description"
textarea
onChange={this.onArchivedDescriptionInputChange}
/>
</Confirm>
</div>
) : (
@ -125,9 +138,9 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
});
}
private getCompletionNumber(){
private getCompletionNumber() {
const documents = this.state.selectedFolder?.documents;
if(!documents) return 0;
if (!documents) return 0;
const totalDocuments = documents.length;
const askedDocuments = documents.filter((document) => document.document_status === EDocumentStatus.ASKED).length;
const depositedDocuments = totalDocuments - askedDocuments;
@ -152,15 +165,15 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
this.setState({ isArchivedModalOpen: false });
}
private onArchivedDescriptionInputChange(e: ChangeEvent<HTMLInputElement>){
this.setState({inputArchivedDescripton: e.target.value})
private onArchivedDescriptionInputChange(e: ChangeEvent<HTMLInputElement>) {
this.setState({ inputArchivedDescripton: e.target.value });
}
private async onArchivedModalAccepted() {
if (!this.state.selectedFolder) return;
const folder = this.state.selectedFolder;
folder.archived_description = this.state.inputArchivedDescripton;
await Folders.getInstance().archive(this.state.selectedFolder.uid ?? "", folder);
await Folders.getInstance().archive(this.state.selectedFolder.uid ?? "", folder as IPutFoldersParams);
this.closeArchivedModal();
this.props.router.push(Module.getInstance().get().modules.pages.Folder.props.path);
}
@ -173,13 +186,13 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
office_folder_has_customers: { include: { customer: { include: { contact: true } } } },
documents: {
include: {
depositor:{
depositor: {
include: {
contact: true
}
}
}
}
contact: true,
},
},
},
},
},
};
const folder = await Folders.getInstance().getByUid(this.props.selectedFolderUid, query);

View File

@ -46,15 +46,15 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
this.onFormSubmit = this.onFormSubmit.bind(this);
this.onChangeSelectedCollaborators = this.onChangeSelectedCollaborators.bind(this);
}
public override render(): JSX.Element {
public override render(): JSX.Element {
const foldersInformationPath = Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path;
const backwardPath = foldersInformationPath.replace("[folderUid]", this.props.selectedFolderUid);
const selectOptions : IOption[]= this.state.availableCollaborators.map((collaborator) => {
const selectOptions: IOption[] = this.state.availableCollaborators.map((collaborator) => {
return {
label: collaborator.contact?.first_name + " " + collaborator.contact?.last_name,
value: collaborator.uid,
}
})
};
});
return (
<DefaultNotaryDashboard title={"Ajouter client(s)"} onSelectedFolder={this.onSelectedFolder}>
<div className={classes["root"]}>
@ -75,7 +75,12 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
{this.state.selectedOption === ERadioBoxValue.SELECTION && (
<div className={classes["sub-content"]}>
<MultiSelect onChange={this.onChangeSelectedCollaborators} options={selectOptions} placeholder="Collaborateurs" defaultValue={this.state.selectedCollaborators}/>
<MultiSelect
onChange={this.onChangeSelectedCollaborators}
options={selectOptions}
placeholder="Collaborateurs"
defaultValue={this.state.selectedCollaborators}
/>
</div>
)}
@ -91,11 +96,11 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
);
}
public override async componentDidMount(){
public override async componentDidMount() {
await this.getFolderAvailableCollaborators(this.props.selectedFolderUid);
}
private async getFolderAvailableCollaborators(folderUid: string){
private async getFolderAvailableCollaborators(folderUid: string) {
const query = {
q: {
office: true,
@ -104,44 +109,44 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
user_stakeholder: {
include: {
contact: true,
}
}
}
},
},
},
},
},
};
};
let folder = null;
try {
folder = await Folders.getInstance().getByUid(folderUid, query);
const preSelectedCollaborators : IOption[]= folder.office_folder_has_stakeholder!.map((collaborator) => {
folder = await Folders.getInstance().getByUid(folderUid, query);
const preSelectedCollaborators: IOption[] = folder.office_folder_has_stakeholder!.map((collaborator) => {
return {
label: collaborator.user_stakeholder.contact?.first_name + " " + collaborator.user_stakeholder.contact?.last_name,
value: collaborator.user_stakeholder.uid,
}
})
this.setState({selectedCollaborators: preSelectedCollaborators})
} catch (error) {
};
});
this.setState({ selectedCollaborators: preSelectedCollaborators });
} catch (error) {
this.props.router.push(Module.getInstance().get().modules.pages["404"].props.path);
return;
}
const userQuery: IGetUsersparams = {
where: {
where: {
office_uid: folder.office?.uid,
},
include:{
include: {
contact: {
select:{
first_name:true,
last_name:true,
}
}
}
select: {
first_name: true,
last_name: true,
},
},
},
};
const availableCollaborators = await Users.getInstance().get(userQuery);
this.setState({availableCollaborators});
const availableCollaborators = await Users.getInstance().get(userQuery);
this.setState({ availableCollaborators });
}
private onSelectedOptionAllOffice(event: React.ChangeEvent<HTMLInputElement>) {
@ -168,18 +173,24 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
private async onFormSubmit(e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) {
try {
let collaboratorsUid : OfficeFolderHasStakeholder[];
if(this.state.selectedOption === ERadioBoxValue.SELECTION){
collaboratorsUid = this.state.selectedCollaborators.map((collaborator) => ({user_stakeholder: {uid: collaborator.value}} as OfficeFolderHasStakeholder));
let collaboratorsUid: OfficeFolderHasStakeholder[];
if (this.state.selectedOption === ERadioBoxValue.SELECTION) {
collaboratorsUid = this.state.selectedCollaborators.map(
(collaborator) => ({ user_stakeholder: { uid: collaborator.value } } as OfficeFolderHasStakeholder),
);
} else {
collaboratorsUid = this.state.availableCollaborators.map(
(collaborator) => ({ user_stakeholder: { uid: collaborator.uid } } as OfficeFolderHasStakeholder),
);
}
else{
collaboratorsUid = this.state.availableCollaborators.map((collaborator) => ({user_stakeholder: {uid: collaborator.uid}} as OfficeFolderHasStakeholder));
}
await Folders.getInstance().put(this.props.selectedFolderUid, {office_folder_has_stakeholder: collaboratorsUid});
this.props.router.push(Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid));
await Folders.getInstance().put(this.props.selectedFolderUid, { office_folder_has_stakeholder: collaboratorsUid });
this.props.router.push(
Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid),
);
} catch (error) {
console.error(error)
console.error(error);
}
}
}
@ -188,5 +199,5 @@ export default function UpdateFolderCollaborators() {
const router = useRouter();
let { folderUid } = router.query;
folderUid = folderUid as string;
return <UpdateFolderCollaboratorsClass selectedFolderUid={folderUid} router={router}/>;
return <UpdateFolderCollaboratorsClass selectedFolderUid={folderUid} router={router} />;
}

View File

@ -12,7 +12,7 @@ import BasePage from "../../Base";
import classes from "./classes.module.scss";
import ClientSection from "./ClientSection";
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Folders, { IPutFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Module from "@Front/Config/Module";
type IProps = {};
@ -121,8 +121,12 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
if (!this.state.selectedFolder) return;
const folder = this.state.selectedFolder;
folder.archived_description = null;
await Folders.getInstance().restore(this.state.selectedFolder.uid ?? "", folder);
this.props.router.push(Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid));
await Folders.getInstance().restore(this.state.selectedFolder.uid ?? "", folder as IPutFoldersParams);
this.props.router.push(
Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid),
);
}
private openArchivedModal(): void {