2024-02-12 14:53:10 +01:00

333 lines
10 KiB
TypeScript

import backgroundImage from "@Assets/images/404-background-image.jpeg";
import DeedTypes from "@Front/Api/LeCoffreApi/Notary/DeedTypes/DeedTypes";
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users";
import Button from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultDoubleSidePage from "@Front/Components/LayoutTemplates/DefaultDoubleSidePage";
import { ValidationError } from "class-validator/types/validation/ValidationError";
import { Deed, DeedType, Office, OfficeFolder } from "le-coffre-resources/dist/Notary";
import User from "le-coffre-resources/dist/Notary";
import { NextRouter, useRouter } from "next/router";
import React from "react";
import { ActionMeta, MultiValue } from "react-select";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import JwtService from "@Front/Services/JwtService/JwtService";
type IFormValues = {
folder_number: string;
entitled: string;
act_typ: IOption | null;
personal_note: string;
collaborators: MultiValue<IOption>;
};
type IProps = {};
type IPropsClass = IProps & {
router: NextRouter;
};
type IState = {
folder_access: string;
formValues: IFormValues;
deedTypes: DeedType[];
deedTypesOptions: IOption[];
collaborators: User[];
collaboratorsOptions: IOption[];
validationError: ValidationError[];
};
class CreateFolderClass extends BasePage<IPropsClass, IState> {
public constructor(props: IPropsClass) {
super(props);
this.state = {
folder_access: "select_collaborators",
formValues: {
folder_number: "",
entitled: "",
act_typ: null,
personal_note: "",
collaborators: [],
},
deedTypes: [],
deedTypesOptions: [],
collaborators: [],
collaboratorsOptions: [],
validationError: [],
};
this.radioOnChange = this.radioOnChange.bind(this);
this.onFolderNumberChange = this.onFolderNumberChange.bind(this);
this.onEntitleChange = this.onEntitleChange.bind(this);
this.onActTypeChange = this.onActTypeChange.bind(this);
this.onPersonalNoteChange = this.onPersonalNoteChange.bind(this);
this.onCollaboratorsChange = this.onCollaboratorsChange.bind(this);
this.isFormSubmittable = this.isFormSubmittable.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
this.renderSelectCollaborators = this.renderSelectCollaborators.bind(this);
}
public override render(): JSX.Element {
return (
<DefaultDoubleSidePage title={"Dossier"} image={backgroundImage} type="background" showHeader={true}>
<div className={classes["root"]}>
<BackArrow />
<Typography typo={ITypo.H1} color={ITypoColor.BLACK} className={classes["title"]}>
Créer un dossier
</Typography>
<Typography typo={ITypo.H3} color={ITypoColor.PURPLE_FLASH} className={classes["subtitle"]}>
Informations dossier
</Typography>
<Form onSubmit={this.onFormSubmit}>
<div className={classes["form-container"]}>
<TextField
name="folder_number"
placeholder="Numéro de dossier"
onChange={this.onFolderNumberChange}
validationError={this.state.validationError.find((error) => error.property === "folder_number")}
/>
<TextField
name="name"
placeholder="Intitulé"
onChange={this.onEntitleChange}
validationError={this.state.validationError.find((error) => error.property === "name")}
/>
<SelectField
options={this.state.deedTypesOptions}
name="deed"
placeholder={"Type d'acte"}
onChange={this.onActTypeChange}
errors={this.state.validationError.find((error) => error.property === "deed")}
/>
<TextAreaField
name="description"
placeholder="Note du dossier"
onChange={this.onPersonalNoteChange}
validationError={this.state.validationError.find((error) => error.property === "description")}
required={false}
/>
<div className={classes["access-container"]}>
<Typography typo={ITypo.H3} color={ITypoColor.PURPLE_FLASH}>
Accès au dossier
</Typography>
<div className={classes["radio-container"]}>
<RadioBox name="file_access" onChange={this.radioOnChange} value="whole_office">
Sélectionner tout l'office
</RadioBox>
<RadioBox name="file_access" defaultChecked onChange={this.radioOnChange} value="select_collaborators">
Sélectionner certains collaborateurs
</RadioBox>
</div>
{this.renderSelectCollaborators()}
<div className={classes["buttons-container"]}>
<Button fullwidth type="submit">
Créer un dossier
</Button>
</div>
</div>
</div>
</Form>
</div>
</DefaultDoubleSidePage>
);
}
public override async componentDidMount() {
const deedTypes = await DeedTypes.getInstance().get();
// no need to pass query 'where' param here, default query for notaries include only users which are in the same office as the caller
const collaborators = await Users.getInstance().get({
include: { contact: true },
});
const collaboratorsOptions = this.mapUsersOptions(collaborators);
this.setState({
deedTypes,
deedTypesOptions: this.mapDeedOptions(deedTypes),
collaborators,
collaboratorsOptions: collaboratorsOptions,
});
const userId = JwtService.getInstance().decodeJwt()?.userId;
const currentCollaborator = collaboratorsOptions.find(({ value }) => value === userId);
if (!currentCollaborator) return;
this.setState({
formValues: {
...this.state.formValues,
collaborators: [{ label: currentCollaborator.label, value: currentCollaborator.value }],
},
});
}
private mapDeedOptions(deedTypes: DeedType[]) {
return deedTypes.map((deedType) => ({
label: deedType.name,
value: deedType.uid,
})) as IOption[];
}
private mapUsersOptions(collaborators: User[]) {
return collaborators.map((collaborator) => ({
label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name),
value: collaborator.uid,
})) as IOption[];
}
private onFolderNumberChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
formValues: {
...this.state.formValues,
folder_number: e.target.value,
},
});
}
private onEntitleChange(e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({
formValues: {
...this.state.formValues,
entitled: e.target.value,
},
});
}
private onActTypeChange(selectedOption: IOption) {
this.setState({
formValues: {
...this.state.formValues,
act_typ: selectedOption,
},
});
}
private onPersonalNoteChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
formValues: {
...this.state.formValues,
personal_note: e.target.value,
},
});
}
private onCollaboratorsChange(newValue: MultiValue<IOption>, actionMeta: ActionMeta<IOption>) {
this.setState({
formValues: {
...this.state.formValues,
collaborators: newValue,
},
});
}
private async onFormSubmit(
e: React.FormEvent<HTMLFormElement> | null,
values: {
[key: string]: any;
},
) {
const officeId = JwtService.getInstance().decodeJwt()?.office_Id;
const selectedDeedTypeUid: DeedType | undefined = this.state.deedTypes.find(
(deedType) => deedType.uid === this.state.formValues.act_typ?.value,
);
let stakeholders = this.state.collaborators;
if (this.state.folder_access === "select_collaborators") {
stakeholders = this.state.collaborators.filter((collaborator) => {
return this.state.formValues.collaborators?.some((selectedCollaborator) => {
return selectedCollaborator.value === collaborator.uid;
});
});
}
const officeFolderForm = OfficeFolder.hydrate<OfficeFolder>({
folder_number: values["folder_number"],
name: values["name"],
description: values["description"],
deed: Deed.hydrate<Deed>({
deed_type: DeedType.hydrate<DeedType>({
uid: selectedDeedTypeUid?.uid,
}),
}),
office: Office.hydrate<Office>({
uid: officeId,
}),
customers: [],
stakeholders,
});
try {
await officeFolderForm.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: true });
} catch (validationErrors) {
this.setState({
validationError: validationErrors as ValidationError[],
});
return;
}
try {
const newOfficeFolder = await Folders.getInstance().post(officeFolderForm);
if (!newOfficeFolder) return;
this.props.router.push(`/folders/${newOfficeFolder.uid}`);
} catch (backError) {
if (!Array.isArray(backError)) return;
this.setState({
validationError: backError as ValidationError[],
});
return;
}
}
private renderSelectCollaborators() {
if (this.state.folder_access !== "select_collaborators") return null;
return (
<div className={classes["collaborators-container"]}>
<MultiSelect
options={this.state.collaboratorsOptions}
placeholder="Sélectionner les collaborateurs"
onChange={this.onCollaboratorsChange}
defaultValue={this.state.formValues.collaborators ?? []}
validationError={this.state.validationError.find((error) => error.property === "stakeholders")}
/>
</div>
);
}
private isFormSubmittable(): boolean {
if (
this.state.formValues.entitled === "" ||
this.state.formValues.personal_note === "" ||
this.state.formValues.folder_number === "" ||
this.state.formValues.act_typ === null
) {
return false;
}
if (this.state.folder_access === "select_collaborators" && this.state.formValues.collaborators.length === 0) {
return false;
}
return true;
}
private radioOnChange(e: React.ChangeEvent<HTMLInputElement>) {
this.setState({
folder_access: e.target.value,
});
}
}
export default function CreateFolder(props: IProps): JSX.Element {
const router = useRouter();
return <CreateFolderClass {...props} router={router} />;
}