This commit is contained in:
OxSaitama 2023-06-19 09:18:47 +02:00
commit be23295fe7
36 changed files with 752 additions and 1039 deletions

View File

@ -13,6 +13,16 @@ const nextConfig = {
NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT: process.env.NEXT_PUBLIC_IDNOT_AUTHORIZE_ENDPOINT,
NEXT_PUBLIC_IDNOT_CLIENT_ID: process.env.NEXT_PUBLIC_IDNOT_CLIENT_ID,
},
webpack: config => {
config.node = {
fs: 'empty',
child_process: 'empty',
net: 'empty',
dns: 'empty',
tls: 'empty',
};
return config;
},
};
module.exports = nextConfig;

View File

@ -23,7 +23,7 @@
"eslint": "8.36.0",
"eslint-config-next": "13.2.4",
"form-data": "^4.0.0",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.47",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.52",
"next": "13.2.4",
"prettier": "^2.8.7",
"react": "18.2.0",

View File

@ -119,17 +119,18 @@ export default abstract class BaseApiService {
responseJson = await response.json();
} catch (err: unknown) {
responseJson = null;
return Promise.reject(err);
}
if (!response.ok) {
return Promise.reject(response);
return Promise.reject(responseJson);
}
return responseJson as T;
}
protected onError(error: unknown) {
console.error(error);
//console.error(error);
}
}

View File

@ -1,6 +1,7 @@
import User, { Customer, DeedType, Office, OfficeFolder } from "le-coffre-resources/dist/Notary";
import { type OfficeFolder } from "le-coffre-resources/dist/Notary";
import BaseSuperAdmin from "../BaseSuperAdmin";
import { EFolderStatus } from "le-coffre-resources/dist/Customer/OfficeFolder";
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
// TODO Type get query params -> Where + inclue + orderby
export interface IGetFoldersParams {
@ -11,36 +12,6 @@ export interface IGetFoldersParams {
};
}
export interface IPostFoldersParams {
folder_number: OfficeFolder["folder_number"];
name: OfficeFolder["name"];
description: OfficeFolder["description"];
deed: {
deed_type: {
uid: DeedType["uid"];
};
};
office: {
uid: Office["uid"];
};
office_folder_has_stakeholder: {
user_stakeholder: {
uid: User["uid"];
};
}[];
}
export type IPutFoldersParams = {
uid?: OfficeFolder["uid"];
folder_number?: OfficeFolder["folder_number"];
name?: OfficeFolder["name"];
description?: OfficeFolder["description"];
archived_description?: OfficeFolder["archived_description"];
status?: OfficeFolder["status"];
office_folder_has_stakeholder?: OfficeFolder["office_folder_has_stakeholder"];
office_folder_has_customers?: { customer: { uid: Customer["uid"] } }[];
};
export default class Folders extends BaseSuperAdmin {
private static instance: Folders;
private readonly baseURl = this.namespaceUrl.concat("/folders");
@ -88,10 +59,10 @@ export default class Folders extends BaseSuperAdmin {
/**
* @description : Create a folder
*/
public async post(body: any): Promise<OfficeFolder> {
public async post(officeFolder: Partial<OfficeFolder>): Promise<OfficeFolder> {
const url = new URL(this.baseURl);
try {
return await this.postRequest<OfficeFolder>(url, body);
return await this.postRequest(url, officeFolder);
} catch (err) {
this.onError(err);
return Promise.reject(err);
@ -101,10 +72,10 @@ export default class Folders extends BaseSuperAdmin {
/**
* @description : Update the folder description
*/
public async put(uid: string, body: IPutFoldersParams): Promise<OfficeFolder> {
public async put(uid: string, body: Partial<OfficeFolder>): Promise<OfficeFolder> {
const url = new URL(this.baseURl.concat(`/${uid}`));
try {
return await this.putRequest<OfficeFolder>(url, body);
return await this.putRequest(url, body);
} catch (err) {
this.onError(err);
return Promise.reject(err);
@ -119,14 +90,14 @@ export default class Folders extends BaseSuperAdmin {
const targetedFolder = await this.getByUid(uid);
if (targetedFolder.office_folder_has_customers) return Promise.reject(`The folder ${uid} contains customers`);
try {
return await this.deleteRequest<OfficeFolder>(url);
return await this.deleteRequest(url);
} catch (err) {
this.onError(err);
return Promise.reject(err);
}
}
public async archive(uid: string, body: IPutFoldersParams): Promise<OfficeFolder> {
public async archive(uid: string, body: Partial<OfficeFolder>): Promise<OfficeFolder> {
body.status = EFolderStatus.ARCHIVED;
try {
return await this.put(uid, body);
@ -136,7 +107,7 @@ export default class Folders extends BaseSuperAdmin {
}
}
public async restore(uid: string, body: IPutFoldersParams): Promise<OfficeFolder> {
public async restore(uid: string, body: Partial<OfficeFolder>): Promise<OfficeFolder> {
body.status = EFolderStatus.LIVE;
try {
return await this.put(uid, body);

View File

@ -1,6 +1,6 @@
import React from "react";
import { IOption } from "../Select";
import { IOption } from "../Form/SelectField";
import Tooltip from "../ToolTip";
import Typography, { ITypo, ITypoColor } from "../Typography";
import classes from "./classes.module.scss";

View File

@ -14,9 +14,9 @@ import Files from "@Front/Api/LeCoffreApi/SuperAdmin/Files/Files";
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
import classNames from "classnames";
import Confirm from "../Modal/Confirm";
import InputField from "../Form/Elements/InputField";
import GreenCheckIcon from "@Assets/Icons/green-check.svg";
import Loader from "../Loader";
import TextAreaField from "../Form/TextareaField";
type IProps = {
defaultFiles?: FileCustomer[];
@ -69,7 +69,6 @@ export default class DepositDocument extends React.Component<IProps, IState> {
}
public override render(): JSX.Element {
console.log("Loading :", this.state.loading);
return (
<div className={classes["container"]}>
<div
@ -172,7 +171,7 @@ export default class DepositDocument extends React.Component<IProps, IState> {
<Typography typo={ITypo.P_16} className={classes["text"]}>
Votre document a é refusé pour la raison suivante :
</Typography>
<InputField textarea fakeplaceholder={"Description"} defaultValue={this.state.refusedReason} readOnly />
<TextAreaField placeholder="Description" defaultValue={this.state.refusedReason} readonly />
</div>
</Confirm>
</div>

View File

@ -0,0 +1,111 @@
import React from "react";
import { FormContext, IFormContext } from ".";
import { ValidationError } from "class-validator";
import Typography, { ITypo, ITypoColor } from "../Typography";
export type IProps = {
value?: string;
onChange?: (event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) => void;
name: string;
required?: boolean;
placeholder?: string;
readonly?: boolean;
className?: string;
defaultValue?: string;
disableValidation?: boolean;
validationError?: ValidationError;
disabled?: boolean;
};
type IState = {
value: string;
validationError: ValidationError | null;
};
export default abstract class BaseField<P extends IProps, S extends IState = IState> extends React.Component<P, S> {
public static override contextType = FormContext;
public override context: IFormContext | null = null;
public fieldRef: React.RefObject<any> = React.createRef();
static defaultProps: Partial<IProps> = {
disableValidation: false,
required: true,
};
constructor(props: P) {
super(props);
this.onChange = this.onChange.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.hasError = this.hasError.bind(this);
this.renderErrors = this.renderErrors.bind(this);
}
public override componentDidMount() {
this.context?.setField(this.props.name, this);
this.setState({
value: this.props.defaultValue ?? "",
});
}
public override componentDidUpdate(prevProps: IProps) {
if (this.props.value !== prevProps.value) {
this.setState({
value: this.props.value ?? "",
});
}
if (this.props.validationError !== prevProps.validationError) {
this.setState({
validationError: this.props.validationError ?? null,
});
}
}
public override componentWillUnmount() {
this.context?.unSetField(this.props.name);
}
protected getDefaultState(): IState {
return {
value: this.props.value ?? "",
validationError: this.props.validationError ?? null,
};
}
protected onFocus(event: React.FocusEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.context?.onFieldFocusChange(this.props.name, this, true);
}
protected onBlur(event: React.FocusEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.context?.onFieldFocusChange(this.props.name, this, false);
}
protected onChange(event: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.context?.onFieldChange(this.props.name, this);
this.setState({ value: event.currentTarget.value, validationError: null });
if (this.props.onChange) {
this.props.onChange(event);
}
}
protected hasError(): boolean {
return this.state.validationError !== null;
// if(!this.context) return false;
// if(!this.context.hasOneFocusedInput() && this.state.validationError !== null) return true;
// return this.state.validationError !== null && this.context.isInputFocused(this.props.name);
}
protected renderErrors(): JSX.Element[] | null {
if (!this.state.validationError || !this.state.validationError.constraints) return null;
let errors: JSX.Element[] = [];
Object.entries(this.state.validationError.constraints).forEach(([key, value]) => {
errors.push(
<Typography key={key} typo={ITypo.CAPTION_14} color={ITypoColor.RED_FLASH}>
{value}
</Typography>,
);
});
return errors;
}
}

View File

@ -1,154 +0,0 @@
import { ChangeEvent, Component, createRef } from "react";
import { FormContext, IFormContext } from "..";
// elements
import Validators, { IValidationTypes } from "../Validators/Validators";
export type IError = {
message: string;
validator: string;
value: string | number | readonly string[];
args: any[];
isErrored?: (hasError: boolean) => void;
};
export type INewBasefieldProps = {
onChange?: (event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) => void;
name: string;
regex?: RegExp;
onCancel?: () => void;
disableValidation?: boolean;
onErrors?: (errors: IError[]) => void;
fieldRef?: React.RefObject<any>;
};
export type IProps = IValidationTypes & React.InputHTMLAttributes<HTMLInputElement> & INewBasefieldProps;
type IState = {
value?: string | number | readonly string[];
errors: IError[];
};
export default abstract class BaseField<P extends IProps> extends Component<P, IState> {
public static override contextType = FormContext;
public override context: IFormContext | null = null;
public fieldRef: React.RefObject<any> = createRef();
static defaultProps: Partial<IProps> = {
disableValidation: false,
};
constructor(props: P) {
super(props);
this.onChange = this.onChange.bind(this);
this.validate = this.validate.bind(this);
this.state = {
value: this.props.value ?? this.props.defaultValue ?? "",
errors: [],
};
}
public override componentDidMount() {
this.context?.setField(this.props.name, this);
}
public override componentDidUpdate(prevProps: P) {
if (prevProps.value !== this.props.value || prevProps.defaultValue !== this.props.defaultValue) {
this.setState({ value: this.props.value ?? this.props.defaultValue ?? "" });
}
}
public override componentWillUnmount() {
this.context?.unSetField(this.props.name);
}
public async onBlur(event: React.FocusEvent<HTMLInputElement, Element>) {
// this.validate();
// if (this.props.onBlur) {
// this.props.onBlur(event);
// }
}
public async validate(isOnSubmit?: boolean) {
if (this.props.disableValidation) return;
if (this.props.readOnly) return;
const errorArray: IError[] = [];
const props: { [key: string]: any } = this.props;
const validators = Object.entries(Validators).filter(([key]) => props[key]);
const isValidable = isOnSubmit
? this.props.required || (this.state.value && this.state.value !== "")
: this.state.value && this.state.value !== "";
if (isValidable) {
const validations = await Promise.all(
validators.map(async ([key, validator]) => {
const validation = await (validator.validate as any)(this.state.value, ...(props[key].args ?? []));
if (props[key].isErrored) {
props[key].isErrored(!validation);
}
return [key, validator, validation];
}),
);
const unValidateds = validations.filter(([key, validator, validation]) => !validation);
const errors: IError[] = unValidateds.map(([key, unValidated]) => {
let message = unValidated.message;
if (typeof props[key] === "object" && props[key].message) message = props[key].message;
return { message, validator: key, value: this.state.value!, args: props[key].args ?? [] };
});
errorArray.push(...errors);
} else {
validators.forEach(async ([key]) => {
if (props[key].isErrored) {
props[key].isErrored(false);
}
});
}
this.setState({ errors: errorArray });
this.onErrors(errorArray);
return errorArray;
}
public setErrors(errors: IError[]) {
this.setState({ ...this.state, errors });
}
/**
* It is automatically called by the parent form when the user cancelled the
* form and all of its changes.
*
* Override the method for custom cancelling logic, or pass a custom onCancel
* callback.
*/
public cancel() {
if (this.props.onCancel) {
this.props.onCancel();
}
}
public onErrors(errors: IError[]) {
if (this.props.onErrors) {
this.props.onErrors(errors);
}
}
protected onChange(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
if (this.props.regex) {
if (!this.props.regex.test(event.currentTarget.value)) {
event.currentTarget.value = event.currentTarget.value.substring(0, event.currentTarget.value.length - 1);
}
}
this.setState({ value: event.currentTarget.value }, () => {
this.validate();
this.context?.onFieldChange(this.props.name, this);
});
if (this.props.onChange) {
this.props.onChange(event);
}
}
}

View File

@ -1,111 +0,0 @@
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import { ReactNode } from "react";
import Validators from "../../Validators/Validators";
import BaseField, { IProps as IBaseFieldProps } from "../BaseField";
import classes from "./classes.module.scss";
export type IProps = IBaseFieldProps & {
fakeplaceholder: string;
textarea?: boolean;
};
// @ts-ignore TODO: typing error on IProps (validator class?? cf Massi 22/02/23)
export default class InputField extends BaseField<IProps> {
static override defaultProps: Partial<IBaseFieldProps> = {
...BaseField.defaultProps,
required: true,
};
public override render(): ReactNode {
let pattern;
if (this.props.type === "number") {
pattern = "(^[0-9]*)(\\.{0,1})([0-9]*)$";
}
if (this.props.pattern) {
pattern = this.props.pattern;
}
if (this.props.fieldRef) {
this.fieldRef = this.props.fieldRef;
}
// we always need to control the input so we need to set the value as "" by default
const value = this.state.value ?? "";
if (this.props.textarea === true) {
return (
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
<div className={classes["root"]}>
<textarea
maxLength={this.props.maxLength}
name={this.props.name}
required={this.props.required}
ref={this.props.fieldRef}
rows={4}
data-value={value}
onChange={this.onChange}
data-has-validation-errors={this.state.errors.length > 0}
className={
this.props.className ? [classes["textarea"], classes[this.props.className]].join(" ") : classes["textarea"]
}
value={value}
readOnly={this.props.readOnly} />
<div className={classes["fake-placeholder"]}>
{this.props.fakeplaceholder} {!this.props.required && " (Facultatif)"}
</div>
</div>
</Typography>
);
} else {
return (
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
<div className={classes["root"]}>
<input
{...this.getHtmlAttributes()}
ref={this.props.fieldRef}
pattern={pattern}
onChange={this.onChange}
onBlur={this.onBlur}
data-value={value}
data-has-validation-errors={this.state.errors.length > 0}
className={
this.props.className ? [classes["input"], classes[this.props.className]].join(" ") : classes["input"]
}
value={value}
/>
<div className={classes["fake-placeholder"]}>
{this.props.fakeplaceholder} {!this.props.required && " (Facultatif)"}
</div>
</div>
</Typography>
);
}
}
public override componentDidMount() {
this.setState({
value: this.props.defaultValue ?? "",
});
}
// We filter the props we'll pass to the primitive input as they're useless for it
// It also avoids the console warning because of passing useless props to a primitive DOM element
private getHtmlAttributes() {
const htmlAttributes = { ...this.props };
delete htmlAttributes.disableValidation;
delete htmlAttributes.onErrors;
delete htmlAttributes.fieldRef;
delete htmlAttributes.className;
delete htmlAttributes.defaultValue;
for (const validator in Validators) {
delete (htmlAttributes as { [key: string]: any })[validator];
}
return htmlAttributes;
}
}

View File

@ -1,77 +0,0 @@
import { ReactNode } from "react";
import Validators from "../Validators/Validators";
//import { IProps as IBaseFieldProps } from "../.";
import classes from "./classes.module.scss";
import BaseField, { IProps as IBaseFieldProps } from "../Elements/BaseField";
export type IProps = IBaseFieldProps & {
large?: boolean;
};
export default class InputField extends BaseField<IProps> {
public override render(): ReactNode {
let pattern;
if (this.props.type === "number") {
pattern = "(^[0-9]*)(\\.{0,1})([0-9]*)$";
}
if (this.props.pattern) {
pattern = this.props.pattern;
}
if (this.props.fieldRef) {
this.fieldRef = this.props.fieldRef;
}
// we always need to control the input so we need to set the value as "" by default
const value = this.state.value ?? "";
if (this.props.large === true) {
return (
<textarea
maxLength={this.props.maxLength}
name={this.props.name}
required={this.props.required}
ref={this.props.fieldRef}
rows={4}
value={value}
onChange={this.onChange}
data-has-validation-errors={this.state.errors.length > 0}
className={this.props.className ? [classes["textarea"], classes[this.props.className]].join(" ") : classes["textarea"]}
/>
);
} else {
return (
<input
{...this.getHtmlAttributes()}
ref={this.props.fieldRef}
pattern={pattern}
onChange={this.onChange}
value={value}
data-has-validation-errors={this.state.errors.length > 0}
className={this.props.className ? [classes["input"], classes[this.props.className]].join(" ") : classes["input"]}
/>
);
}
}
// We filter the props we'll pass to the primitive input as they're useless for it
// It also avoids the console warning because of passing useless props to a primitive DOM element
private getHtmlAttributes() {
const htmlAttributes = { ...this.props };
delete htmlAttributes.disableValidation;
delete htmlAttributes.onErrors;
delete htmlAttributes.fieldRef;
delete htmlAttributes.className;
delete htmlAttributes.defaultValue;
for (const validator in Validators) {
delete (htmlAttributes as { [key: string]: any })[validator];
}
return htmlAttributes;
}
}

View File

@ -5,7 +5,11 @@
position: relative;
flex-direction: column;
width: 100%;
border: 1px solid $grey-medium;
border: 1px solid var(--grey-medium);
&[data-errored="true"]{
border: 1px solid var(--red-flash);
}
&[data-disabled="true"]{
.container-label{

View File

@ -0,0 +1,188 @@
import ChevronIcon from "@Assets/Icons/chevron.svg";
import WindowStore from "@Front/Stores/WindowStore";
import { ValidationError } from "class-validator";
import classNames from "classnames";
import Image from "next/image";
import React, { FormEvent, ReactNode } from "react";
import Typography, { ITypo, ITypoColor } from "../../Typography";
import classes from "./classes.module.scss";
type IProps = {
selectedOption?: IOption;
onChange?: (selectedOption: IOption) => void;
options: IOption[];
hasBorderRightCollapsed?: boolean;
placeholder?: string;
className?: string;
name: string;
disabled: boolean;
errors?: ValidationError;
};
export type IOption = {
value: unknown;
label: string;
icon?: ReactNode;
description?: string;
};
type IState = {
isOpen: boolean;
listWidth: number;
listHeight: number;
selectedOption: IOption | null;
errors: ValidationError | null;
};
export default class SelectField extends React.Component<IProps, IState> {
private contentRef = React.createRef<HTMLUListElement>();
private rootRef = React.createRef<HTMLDivElement>();
private removeOnresize = () => {};
static defaultProps = {
disabled: false,
};
constructor(props: IProps) {
super(props);
this.state = {
isOpen: false,
listHeight: 0,
listWidth: 0,
selectedOption: null,
errors: this.props.errors ?? null,
};
this.toggle = this.toggle.bind(this);
this.onSelect = this.onSelect.bind(this);
}
public override render(): JSX.Element {
const selectedOption = this.state.selectedOption ?? this.props.selectedOption;
return (
<div className={classes["container"]}>
<div
className={classNames(classes["root"], this.props.className)}
ref={this.rootRef}
data-disabled={this.props.disabled.toString()}
data-errored={(this.state.errors !== null).toString()}>
{selectedOption && <input type="text" defaultValue={selectedOption.value as string} name={this.props.name} hidden />}
<label
className={classNames(classes["container-label"])}
data-open={this.state.isOpen}
onClick={this.toggle}
data-border-right-collapsed={this.props.hasBorderRightCollapsed}>
<div className={classNames(classes["container-input"])}>
{selectedOption && (
<>
<span className={classNames(classes["icon"], classes["token-icon"])}>{selectedOption?.icon}</span>
<Typography typo={ITypo.P_18}>
<span className={classes["text"]}>{selectedOption?.label}</span>
</Typography>
</>
)}
{!selectedOption && (
<div className={classes["placeholder"]} data-open={(selectedOption ? true : false).toString()}>
<Typography typo={ITypo.NAV_INPUT_16}>
<span className={classes["text"]}>{this.props.placeholder ?? ""}</span>
</Typography>
</div>
)}
</div>
<Image className={classes["chevron-icon"]} data-open={this.state.isOpen} src={ChevronIcon} alt="chevron icon" />
</label>
<ul
className={classes["container-ul"]}
data-open={this.state.isOpen}
ref={this.contentRef}
style={{
height: this.state.listHeight + "px",
}}>
{this.props.options.map((option, index) => (
<li
key={`${index}-${option.value}`}
className={classes["container-li"]}
onClick={(e) => this.onSelect(option, e)}>
<div className={classes["token-icon"]}>{option.icon}</div>
<Typography typo={ITypo.P_18}>{option.label}</Typography>
</li>
))}
</ul>
{this.state.isOpen && <div className={classes["backdrop"]} onClick={this.toggle} />}
</div>
{this.state.errors !== null && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
</div>
);
}
public override componentDidUpdate(prevProps: IProps) {
if (this.props.errors !== prevProps.errors) {
this.setState({
errors: this.props.errors ?? null,
});
}
}
static getDerivedStateFromProps(props: IProps, state: IState) {
if (props.selectedOption?.value) {
return {
value: props.selectedOption?.value,
};
}
return null;
}
public override componentDidMount(): void {
this.onResize();
this.removeOnresize = WindowStore.getInstance().onResize(() => this.onResize());
}
public override componentWillUnmount() {
this.removeOnresize();
}
private onResize() {
let listHeight = 0;
let listWidth = 0;
listWidth = this.rootRef.current?.scrollWidth ?? 0;
if (this.state.listHeight) {
listHeight = this.contentRef.current?.scrollHeight ?? 0;
}
this.setState({ listHeight, listWidth });
}
private toggle(e: FormEvent) {
if (this.props.disabled) return;
e.preventDefault();
let listHeight = 0;
let listWidth = this.rootRef.current?.scrollWidth ?? 0;
if (!this.state.listHeight) {
listHeight = this.contentRef.current?.scrollHeight ?? 0;
}
this.setState((state) => {
return { isOpen: !state.isOpen, listHeight, listWidth };
});
}
private onSelect(option: IOption, e: React.MouseEvent<HTMLLIElement, MouseEvent>) {
if (this.props.disabled) return;
this.props.onChange && this.props.onChange(option);
this.setState({
selectedOption: option,
});
this.toggle(e);
}
private renderErrors(): JSX.Element | null {
if (!this.state.errors) return null;
return (
<Typography typo={ITypo.CAPTION_14} color={ITypoColor.RED_FLASH}>
{this.props.placeholder} est requis
</Typography>
);
}
}

View File

@ -3,21 +3,6 @@
.root {
position: relative;
textarea {
resize: none;
height: auto;
box-sizing: border-box;
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-size: 18px;
line-height: 22px;
&:read-only{
cursor: not-allowed;
}
}
.input {
z-index: 1;
display: flex;
@ -27,7 +12,7 @@
gap: 10px;
width: 100%;
height: 70px;
border: 1px solid $grey-medium;
border: 1px solid var(--grey-medium);
&:disabled {
cursor: not-allowed;
@ -104,41 +89,14 @@
transition: transform 0.3s ease-in-out;
}
}
}
.textarea {
z-index: 1;
display: flex;
flex-direction: row;
align-items: center;
padding: 24px;
gap: 10px;
width: 100%;
height: 70px;
border: 1px solid $grey-medium;
~ .fake-placeholder {
z-index: 2;
top: -12px;
margin-left: 8px;
padding: 0 16px;
pointer-events: none;
position: absolute;
background: $white;
transform: translateY(35px);
transition: transform 0.3s ease-in-out;
}
&:focus {
~ .fake-placeholder {
transform: translateY(0px);
&[data-is-errored="true"] {
.input{
border: 1px solid var(--red-flash);
~ .fake-placeholder{
color: var(--red-flash);
}
}
}
&:not([data-value=""]) {
~ .fake-placeholder {
transform: translateY(0px);
}
}
}

View File

@ -0,0 +1,40 @@
import React from "react";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import { ReactNode } from "react";
import BaseField, { IProps as IBaseFieldProps } from "../BaseField";
import classes from "./classes.module.scss";
import classnames from "classnames";
export type IProps = IBaseFieldProps & {};
export default class TextField extends BaseField<IProps> {
constructor(props: IProps){
super(props);
this.state = this.getDefaultState();
}
public override render(): ReactNode {
const value = this.state.value ?? "";
return (
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
<div className={classes["root"]} data-is-errored={this.hasError().toString()}>
<input
onChange={this.onChange}
data-value={value}
data-has-validation-errors={(this.state.validationError === null).toString()}
className={classnames(classes["input"], this.props.className)}
value={value}
onFocus={this.onFocus}
onBlur={this.onBlur}
name={this.props.name}
/>
<div className={classes["fake-placeholder"]}>
{this.props.placeholder} {!this.props.required && " (Facultatif)"}
</div>
</div>
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
</Typography>
);
}
}

View File

@ -0,0 +1,63 @@
@import "@Themes/constants.scss";
.root {
position: relative;
.textarea {
resize: none;
height: auto;
box-sizing: border-box;
font-family: "Inter";
font-style: normal;
font-weight: 400;
font-size: 18px;
line-height: 22px;
&:read-only{
cursor: not-allowed;
}
z-index: 1;
display: flex;
flex-direction: row;
align-items: center;
padding: 24px;
gap: 10px;
width: 100%;
height: 100px;
border: 1px solid var(--grey-medium);
~ .fake-placeholder {
z-index: 2;
top: -12px;
margin-left: 8px;
padding: 0 16px;
pointer-events: none;
position: absolute;
background: $white;
transform: translateY(35px);
transition: transform 0.3s ease-in-out;
}
&:focus {
~ .fake-placeholder {
transform: translateY(0px);
}
}
&:not([data-value=""]) {
~ .fake-placeholder {
transform: translateY(0px);
}
}
}
&[data-is-errored="true"] {
.textarea {
border: 1px solid var(--red-flash);
~ .fake-placeholder {
color: var(--red-flash);
}
}
}
}

View File

@ -0,0 +1,47 @@
import BaseField, { IProps as IBaseFieldProps } from "../BaseField";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import React from "react";
import { ReactNode } from "react";
import classes from "./classes.module.scss";
import classnames from "classnames";
export type IProps = IBaseFieldProps & {};
export default class TextAreaField extends BaseField<IProps> {
constructor(props: IProps) {
super(props);
this.state = this.getDefaultState();
}
public override render(): ReactNode {
const value = this.state.value ?? "";
return (
<Typography typo={ITypo.NAV_INPUT_16} color={ITypoColor.GREY}>
<div className={classes["root"]} data-is-errored={this.hasError().toString()}>
<textarea
name={this.props.name}
rows={4}
data-value={value}
onChange={this.onChange}
className={classnames(classes["textarea"], this.props.className)}
value={value}
readOnly={this.props.readonly}
onFocus={this.onFocus}
onBlur={this.onBlur}
/>
<div className={classes["fake-placeholder"]}>
{this.props.placeholder} {!this.props.required && " (Facultatif)"}
</div>
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
</div>
</Typography>
);
}
public override componentDidMount() {
this.setState({
value: this.props.defaultValue ?? "",
});
}
}

View File

@ -1,180 +0,0 @@
import { isEmail, isNotEmpty, isNumberString, isString, max, maxLength, min, minLength } from "class-validator";
const Validators = {
/**
* **Parameters** : boolean
*
* This validator verifies the value is not empty
*/
required: { validate: isNotEmpty, message: "validation_messages.field_required" },
/**
* **Parameters** : boolean
*
* This validator verifies the value is a number
*/
numbersOnly: { validate: isNumberString, message: "validation_messages.only_numbers" },
/**
* **Parameters** : boolean
*
* This validator verifies the value is a number
*/
intOnly: {
validate: function (value: string) {
const regex = /^[0-9]*$/;
return regex.test(value);
},
message: "validation_messages.only_integers",
},
/**
* **Parameters** : number
*
* This validator verifies the number is not below the parameter
*/
minNumber: { validate: (value: string, minVal: number) => min(Number(value), minVal), message: "validation_messages.below_min" },
/**
* **Parameters** : number
*
* This validator verifies the number is not above the parameter
*/
maxNumber: { validate: (value: string, maxVal: number) => max(Number(value), maxVal), message: "validation_messages.above_max" },
/**
* **Parameters** : number
*
* This validator verifies the string minimum length is conform to the parameter
*/
minLength: {
validate: minLength,
message: "validation_messages.min_string_length",
},
/**
* **Parameters** : number
*
* This validator verifies the string maximum length is conform to the parameter
*/
maxLength: {
validate: maxLength,
message: "validation_messages.max_string_length",
},
/**
* **Parameters** : boolean
*
* This validator verifies the input's value is a string.
*/
isString: { validate: (value: string) => isString(value), message: "validation_messages.only_letters" },
/**
* **Parameters** : boolean
*
* This validator verifies the input's value is conform to the tag regex.
*/
isTag: {
validate: function (value: string) {
const regex = /^[a-zA-Z0-9][a-zA-Z0-9 ]*(,[a-zA-Z0-9][a-zA-Z0-9 ]*)*$/;
const isValid = regex.test(value);
if (!isValid) return false;
const splittedTag = value.split(",");
if (splittedTag.length !== new Set(splittedTag).size) {
return false;
}
return true;
},
message: "validation_messages.not_valid_tag",
},
/**
* **Parameters** : boolean
*
* This validator verifies the input's value is a valid email.
*
* If the **input is empty, it is considered valid**. If you do not wish this
* to happen please refer to the `required` validator.
*/
isEmail: {
validate: (value: string) => (Boolean(value) ? isEmail(value) : true),
message: "validation_messages.invalid_email",
},
isPseudo: {
validate: (value: string) => {
const pseudoRegex = /^[a-zA-Z][a-zA-Z0-9_-]{2,19}$/;
return pseudoRegex.test(value);
},
message: "validation_messages.is_pseudo",
},
noSpaceInString: {
validate: (value: string) => {
const regex = /^\S*$/;
return regex.test(value);
},
message: "validation_messages.no_space_in_string",
},
isPositiveNumber: {
validate: (value: string) => {
let nbr = parseFloat(value);
return !(isNaN(nbr) || nbr <= 0);
},
message: "validation_messages.positive_number",
},
floatPrecision: {
validate: (value: string, precision: number) => {
// If value is not a float
if (isNaN(parseFloat(value))) return false;
let splittedValue = value.split(".");
// If there is no decimals
if (!splittedValue[1]) return true;
// If there is more decimals than the required precision
if (splittedValue[1].length > precision) return false;
return true;
},
message: "validation_messages.float_precision",
},
isUrl: {
validate: (value: string, root: string | string[]) => {
try {
const url = new URL(value);
if (root) {
if (typeof root === "string") {
return url.hostname === root || url.hostname === `www.${root}`;
} else {
return root.some((r) => url.hostname === r || url.hostname === `www.${r}`);
}
}
return true;
} catch (e) {
return false;
}
},
message: "validation_messages.invalid_url",
},
// isUniqueEmail: { TODO : uncomment and implement DB request
// validate: async (value: string, actual: string) => {
// try {
// const users = await AppUser.getInstance().getUsers({email: value});
// if (!users.metadata.count) return true;
// if (users.data.length > 1) return false;
// if (users.data[0]?.email === actual) return true;
// return false;
// } catch {
// return true;
// }
// },
// message: "validation_messages.unique_email",
// },
};
export default Validators;
export type IValidationTypes = Partial<
Record<keyof typeof Validators, boolean | Partial<{ message: string; args: any[]; isErrored: (errored: boolean) => void }>>
>;

View File

@ -1,6 +1,6 @@
import React, { ReactNode } from "react";
import BaseField, { IProps as IBaseFieldProps, IError } from "./Elements/BaseField";
import BaseField, { IProps as IBaseFieldProps } from "./BaseField";
export type IBaseField = BaseField<IBaseFieldProps>;
@ -8,42 +8,39 @@ export type IFormContext = {
setField: (name: string, field: IBaseField) => void;
unSetField: (name: string) => void;
onFieldChange: (name: string, field: IBaseField) => void;
onFieldFocusChange: (name: string, field: IBaseField, focused: boolean) => void;
isInputFocused: (name: string) => boolean;
hasOneFocusedInput: () => boolean;
};
type IFields = {
[key: string]: IBaseField;
};
export type IApiFormErrors = {
[fieldName: string]: string;
};
export type IFormErrors = {
[key: string]: {
type IState = {
inputFocused: {
name: string;
field: IBaseField;
errors: IError[] | undefined;
focused: boolean;
};
};
type IState = {};
export type IProps = {
onFieldChange?: (name: string, field: IBaseField, errors: IFormErrors | null) => void;
onSubmit?: (
e: React.FormEvent<HTMLFormElement> | null,
values: { [key: string]: string },
onApiErrors: (apiFormErrors: IApiFormErrors | null) => void,
) => void;
onValidated?: () => void;
onErrors?: (errors: IFormErrors) => void;
/**
* @description Url, No redirection without action
*/
action?: string;
onFieldFocusChange?: (name: string, field: IBaseField, focused: boolean) => void;
onFieldChange?: (name: string, field: IBaseField) => void;
onSubmit?: (e: React.FormEvent<HTMLFormElement> | null, values: { [key: string]: string }) => void;
className?: string;
children?: ReactNode;
};
export const FormContext = React.createContext<IFormContext>({ setField: () => {}, unSetField: () => {}, onFieldChange: () => {} });
export const FormContext = React.createContext<IFormContext>({
setField: () => {},
unSetField: () => {},
onFieldChange: () => {},
onFieldFocusChange: () => {},
isInputFocused: () => false,
hasOneFocusedInput: () => false,
});
export default class Form extends React.Component<IProps, IState> {
protected fields: IFields = {};
@ -52,13 +49,22 @@ export default class Form extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {};
this.state = {
inputFocused: {
name: "",
field: {} as IBaseField,
focused: false,
},
};
this.setField = this.setField.bind(this);
this.unSetField = this.unSetField.bind(this);
this.onFieldChange = this.onFieldChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onSubmitErrorApi = this.onSubmitErrorApi.bind(this);
this.formRef = React.createRef();
this.onFieldFocusChange = this.onFieldFocusChange.bind(this);
this.isInputFocused = this.isInputFocused.bind(this);
this.hasOneFocusedInput = this.hasOneFocusedInput.bind(this);
}
public override render() {
@ -68,8 +74,11 @@ export default class Form extends React.Component<IProps, IState> {
setField: this.setField,
unSetField: this.unSetField,
onFieldChange: this.onFieldChange,
onFieldFocusChange: this.onFieldFocusChange,
isInputFocused: this.isInputFocused,
hasOneFocusedInput: this.hasOneFocusedInput,
}}>
<form className={this.props.className} ref={this.formRef} onSubmit={this.onSubmit} action={this.props.action ?? ""}>
<form className={this.props.className} ref={this.formRef} onSubmit={this.onSubmit}>
{this.props.children}
</form>
</FormContext.Provider>
@ -77,20 +86,7 @@ export default class Form extends React.Component<IProps, IState> {
}
public async onSubmit(e: React.FormEvent<HTMLFormElement> | null) {
if (!this.props.action) e?.preventDefault();
const errors = await this.validate();
if (errors) {
e?.preventDefault();
this.onErrors(errors);
return { errors };
}
if (this.props.onValidated) this.props.onValidated();
e?.preventDefault();
const allChildren = this.getAllChildrenFields(e);
const elementsValues = allChildren
.filter((e) => {
@ -108,7 +104,7 @@ export default class Form extends React.Component<IProps, IState> {
const checkBoxesValues = checkBoxesInput.reduce((obj, element) => {
const inputName = element.getAttribute("name") ?? "";
const inputValue = (element as any).value as string;
const newValue = (obj as any)[inputName] as string[] ?? [];
const newValue = ((obj as any)[inputName] as string[]) ?? [];
newValue.push(inputValue);
return {
...obj,
@ -125,51 +121,12 @@ export default class Form extends React.Component<IProps, IState> {
// Deleting empty input
delete (allInputs as any)[""];
if (this.props.onSubmit) {
this.props.onSubmit(e, allInputs, this.onSubmitErrorApi);
this.props.onSubmit(e, allInputs);
}
return { values: elementsValues };
}
protected onSubmitErrorApi(apiFormErrors: IApiFormErrors | null) {
if (!apiFormErrors) return;
const errors: IFormErrors = {};
for (const [key, message] of Object.entries(apiFormErrors)) {
if (!this.fields[key]) continue;
this.fields[key]?.setErrors([
{
message,
validator: "",
value: this.fields[key]?.state.value ?? "",
args: [],
},
]);
}
this.onErrors(errors);
}
protected async validate() {
const errors = (
await Promise.all(
Object.entries(this.fields).map(async ([name, field]) => {
return { name, validation: await field.validate(true), field };
}),
)
).filter(({ validation }) => validation?.length);
if (!errors.length) {
return null;
}
const errorsObject: IFormErrors = {};
errors.forEach(({ name, validation, field }) => (errorsObject[name] = { errors: validation, field }));
return errorsObject;
}
protected onErrors(errors: IFormErrors) {
if (this.props.onErrors) this.props.onErrors(errors);
}
protected setField(name: string, field: IBaseField) {
this.fields[name] = field;
}
@ -178,10 +135,31 @@ export default class Form extends React.Component<IProps, IState> {
delete this.fields[name];
}
protected async onFieldChange(name: string, field: IBaseField) {
protected hasOneFocusedInput() {
return this.state.inputFocused.focused;
}
protected isInputFocused(name: string) {
return this.state.inputFocused.name === name && this.state.inputFocused.focused;
}
protected onFieldFocusChange(name: string, field: IBaseField, focused: boolean) {
this.setState({
inputFocused: {
name,
field,
focused,
},
});
if (this.props.onFieldFocusChange) {
this.props.onFieldFocusChange(name, field, focused);
}
}
protected onFieldChange(name: string, field: IBaseField) {
if (this.props.onFieldChange) {
const errors = await this.validate();
this.props.onFieldChange(name, field, errors);
this.props.onFieldChange(name, field);
}
}

View File

@ -2,7 +2,7 @@ import classNames from "classnames";
import React from "react";
import ReactSelect, { ActionMeta, MultiValue, Options, PropsValue } from "react-select";
import { IOption } from "../Select";
import { IOption } from "../Form/SelectField";
import Typography, { ITypo } from "../Typography";
import classes from "./classes.module.scss";
import { styles } from "./styles";

View File

@ -1,160 +0,0 @@
import ChevronIcon from "@Assets/Icons/chevron.svg";
import WindowStore from "@Front/Stores/WindowStore";
import classNames from "classnames";
import Image from "next/image";
import React, { FormEvent, ReactNode } from "react";
import Typography, { ITypo } from "../Typography";
import classes from "./classes.module.scss";
type IProps = {
selectedOption?: IOption;
onChange?: (selectedOption: IOption) => void;
options: IOption[];
hasBorderRightCollapsed?: boolean;
placeholder?: string;
className?: string;
name?: string;
disabled: boolean;
};
export type IOption = {
value: unknown;
label: string;
icon?: ReactNode;
description?: string;
};
type IState = {
isOpen: boolean;
listWidth: number;
listHeight: number;
selectedOption: IOption | null;
};
export default class Select extends React.Component<IProps, IState> {
private contentRef = React.createRef<HTMLUListElement>();
private rootRef = React.createRef<HTMLDivElement>();
private removeOnresize = () => {};
static defaultProps = {
disabled: false,
};
constructor(props: IProps) {
super(props);
this.state = {
isOpen: false,
listHeight: 0,
listWidth: 0,
selectedOption: null,
};
this.toggle = this.toggle.bind(this);
this.onSelect = this.onSelect.bind(this);
}
public override render(): JSX.Element {
const selectedOption = this.state.selectedOption ?? this.props.selectedOption;
return (
<div
className={classNames(classes["root"], this.props.className)}
ref={this.rootRef}
data-disabled={this.props.disabled.toString()}>
{selectedOption && <input type="text" defaultValue={selectedOption.value as string} name={this.props.name} hidden />}
<label
className={classNames(classes["container-label"])}
data-open={this.state.isOpen}
onClick={this.toggle}
data-border-right-collapsed={this.props.hasBorderRightCollapsed}>
<div className={classNames(classes["container-input"])}>
{selectedOption && (
<>
<span className={classNames(classes["icon"], classes["token-icon"])}>{selectedOption?.icon}</span>
<Typography typo={ITypo.P_18}>
<span className={classes["text"]}>{selectedOption?.label}</span>
</Typography>
</>
)}
{!selectedOption && (
<div className={classes["placeholder"]} data-open={(selectedOption ? true : false).toString()}>
<Typography typo={ITypo.NAV_INPUT_16}>
<span className={classes["text"]}>{this.props.placeholder ?? ""}</span>
</Typography>
</div>
)}
</div>
<Image className={classes["chevron-icon"]} data-open={this.state.isOpen} src={ChevronIcon} alt="chevron icon" />
</label>
<ul
className={classes["container-ul"]}
data-open={this.state.isOpen}
ref={this.contentRef}
style={{
height: this.state.listHeight + "px",
}}>
{this.props.options.map((option, index) => (
<li key={`${index}-${option.value}`} className={classes["container-li"]} onClick={(e) => this.onSelect(option, e)}>
<div className={classes["token-icon"]}>{option.icon}</div>
<Typography typo={ITypo.P_18}>{option.label}</Typography>
</li>
))}
</ul>
{this.state.isOpen && <div className={classes["backdrop"]} onClick={this.toggle} />}
</div>
);
}
static getDerivedStateFromProps(props: IProps, state: IState) {
if (props.selectedOption?.value) {
return {
value: props.selectedOption?.value,
};
}
return null;
}
public override componentDidMount(): void {
this.onResize();
this.removeOnresize = WindowStore.getInstance().onResize(() => this.onResize());
}
public override componentWillUnmount() {
this.removeOnresize();
}
private onResize() {
let listHeight = 0;
let listWidth = 0;
listWidth = this.rootRef.current?.scrollWidth ?? 0;
if (this.state.listHeight) {
listHeight = this.contentRef.current?.scrollHeight ?? 0;
}
this.setState({ listHeight, listWidth });
}
private toggle(e: FormEvent) {
if (this.props.disabled) return;
e.preventDefault();
let listHeight = 0;
let listWidth = this.rootRef.current?.scrollWidth ?? 0;
if (!this.state.listHeight) {
listHeight = this.contentRef.current?.scrollHeight ?? 0;
}
this.setState((state) => {
return { isOpen: !state.isOpen, listHeight, listWidth };
});
}
private onSelect(option: IOption, e: React.MouseEvent<HTMLLIElement, MouseEvent>) {
if (this.props.disabled) return;
this.props.onChange && this.props.onChange(option);
this.setState({
selectedOption: option,
});
this.toggle(e);
}
}

View File

@ -9,11 +9,11 @@ import BackArrow from "@Front/Components/Elements/BackArrow";
import WindowStore from "@Front/Stores/WindowStore";
import classNames from "classnames";
import { OfficeFolder } from "le-coffre-resources/dist/Customer";
import { EFolderStatus } from "le-coffre-resources/dist/Customer/OfficeFolder";
import Image from "next/image";
import React, { ReactNode } from "react";
import classes from "./classes.module.scss";
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
type IProps = {

View File

@ -1,7 +1,7 @@
import Documents, { IGetDocumentsparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Documents/Documents";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import DepositDocument from "@Front/Components/DesignSystem/DepositDocument";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
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";
@ -64,7 +64,7 @@ export default class ClientDashboard extends Base<IProps, IState> {
<Typography typo={ITypo.P_16} className={classes["text"]}>
Vous souhaitez envoyer un autre document à votre notaire ?
</Typography>
<InputField fakeplaceholder={"Nom du document"} />
<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.

View File

@ -1,6 +1,6 @@
import { ECustomerStatus } from "le-coffre-resources/dist/Customer/Customer";
import { EDocumentStatus } from "le-coffre-resources/dist/Customer/Document";
import { EFolderStatus } from "le-coffre-resources/dist/Customer/OfficeFolder";
import EFolderStatus from "le-coffre-resources/dist/Customer/EFolderStatus";
import {
Address,
Contact,
@ -147,6 +147,8 @@ export const fileMock: File = {
file_path:
"https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/Qmf_Yb_Eh_X9st_F_Srq_Ve_Bj_Yb_Aj56xv_AV_Nj6_Wjypo_B4r5ubce_U_ae3303e7ab.pdf",
archived_at: null,
mimetype: "image/png",
size: 0,
};
export const fileMock2: File = {
@ -158,6 +160,8 @@ export const fileMock2: File = {
file_path:
"https://minteed-prod-euwest3-s3.s3.eu-west-3.amazonaws.com/Qm_Wq_En1_DCA_8yt_RX_Qx_QFA_9_Fm_ZKZH_Qqb_VH_1_Q_Mnv_G_Jtt1_FS_Xp_2a35a36e19",
archived_at: null,
mimetype: "image/png",
size: 0,
};
export const identityFile: File = {
@ -168,6 +172,8 @@ export const identityFile: File = {
file_name: "file_3",
file_path: "https://minteed-stg-euwest3-s3.s3.eu-west-3.amazonaws.com/cni_fake_c7259d4923.png",
archived_at: null,
mimetype: "image/png",
size: 0,
};
export const documentIdentity: Document = {

View File

@ -1,18 +1,15 @@
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
import DocumentNotary from "@Front/Components/DesignSystem/Document/DocumentNotary";
import FilePreview from "@Front/Components/DesignSystem/FilePreview";
import FolderContainer from "@Front/Components/DesignSystem/FolderContainer";
import FolderList from "@Front/Components/DesignSystem/FolderListContainer";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import HeaderLink from "@Front/Components/DesignSystem/Header/HeaderLink";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import SearchBar from "@Front/Components/DesignSystem/SearchBar";
import Select, { IOption } from "@Front/Components/DesignSystem/Select";
import ToolTip from "@Front/Components/DesignSystem/ToolTip";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import UserFolder from "@Front/Components/DesignSystem/UserFolder";
@ -23,6 +20,9 @@ import Toasts, { IToast } from "@Front/Stores/Toasts";
import classes from "./classes.module.scss";
import { customer2, document, documentDeposited, documentPending, folder, folders, folderWithPendingDocument } from "./dummyData";
import { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import SelectField, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
type IState = {
isModalDisplayed: boolean;
@ -150,13 +150,13 @@ export default class DesignSystem extends BasePage<IProps, IState> {
<Typography typo={ITypo.H3}>Input component</Typography>
</div>
<div className={classes["sub-section"]}>
<InputField name="input field" fakeplaceholder="input place hodler" />
<TextField name="input field" placeholder="input place hodler" />
</div>
<div className={classes["sub-section"]}>
<InputField name="input field" fakeplaceholder="text area place hodler" textarea />
<TextAreaField name="input field" placeholder="text area place hodler" />
</div>
<div className={classes["sub-section"]}>
<InputField name="input field" fakeplaceholder="number place hodler" type="number" />
<TextField name="input field" placeholder="number place hodler" />
</div>
</div>
@ -199,7 +199,8 @@ export default class DesignSystem extends BasePage<IProps, IState> {
</div>
<div className={classes["sub-section"]}>
<div className={classes["folder-conatainer"]}>
<Select
<SelectField
name="select"
options={selectOptions}
onChange={this.onSelectedOption}
placeholder={"Type d'acte"}
@ -222,7 +223,7 @@ export default class DesignSystem extends BasePage<IProps, IState> {
<div className={classes["sub-section"]}>
<Typography typo={ITypo.P_16}>Documents Depoited</Typography>
<div className={classes["folder-conatainer"]}>
<DocumentNotary document={documentPending} folderUid=""/>
<DocumentNotary document={documentPending} folderUid="" />
</div>
</div>
<div className={classes["sub-section"]}>
@ -239,7 +240,14 @@ export default class DesignSystem extends BasePage<IProps, IState> {
<Typography typo={ITypo.H3}>Notary Documents</Typography>
</div>
<div className={classes["sub-section"]}>
<UserFolder customer={customer2} folder={folder as IDashBoardFolder} isOpened={true} onChange={() => {return}}/>
<UserFolder
customer={customer2}
folder={folder as IDashBoardFolder}
isOpened={true}
onChange={() => {
return;
}}
/>
</div>
</div>

View File

@ -1,24 +1,22 @@
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
import Folders, { IPutFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import { IOption } from "@Front/Components/DesignSystem/Select";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Module from "@Front/Config/Module";
import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
import { Customer } from "le-coffre-resources/dist/Notary";
import { Customer, OfficeFolder, OfficeFolderHasCustomer } from "le-coffre-resources/dist/Notary";
import Link from "next/link";
import { NextRouter, useRouter } from "next/router";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import { TextField } from "@mui/material";
enum ESelectedOption {
EXISTING_CUSTOMER = "existing_customer",
@ -107,14 +105,12 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
{this.state.selectedOption === "new_customer" && (
<div className={classes["new-client"]}>
<InputField name="last_name" fakeplaceholder="Nom" />
<InputField name="first_name" fakeplaceholder="Prénom" />
<InputField name="email" fakeplaceholder="E-mail" isEmail />
<InputField
<TextField name="last_name" placeholder="Nom" />
<TextField name="first_name" placeholder="Prénom" />
<TextField name="email" placeholder="E-mail" />
<TextField
name="cell_phone_number"
fakeplaceholder="Numéro de téléphone"
numbersOnly
maxLength={10}
placeholder="Numéro de téléphone"
/>
<div className={classes["button-container"]}>
<Link href={backwardPath} className={classes["cancel-button"]}>
@ -213,24 +209,24 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
values["civility"] = ECivility.MALE; // TODO: should maybe be deleted later or added to the form
const allCustomersToLink = this.state.selectedCustomers.concat(this.state.existingCustomers);
let customersToLink: IPutFoldersParams["office_folder_has_customers"] = allCustomersToLink.map((customer) => {
let customersToLink: Partial<OfficeFolderHasCustomer>[] = allCustomersToLink.map((customer) => {
return {
customer: { uid: customer.value },
};
}) as IPutFoldersParams["office_folder_has_customers"];
}) as Partial<OfficeFolderHasCustomer>[];
if (this.state.selectedOption === "new_customer") {
const customer: Customer = await Customers.getInstance().post({
contact: values,
});
if (!customer.uid) return;
customersToLink?.push({ customer: { uid: customer.uid } });
customersToLink?.push({ customer: { uid: customer.uid } } as Partial<OfficeFolderHasCustomer>);
}
if (customersToLink) {
const body = {
office_folder_has_customers: customersToLink,
};
const body = OfficeFolder.hydrate<OfficeFolder>({ office_folder_has_customers: customersToLink.map((customer) => {
return OfficeFolderHasCustomer.hydrate<OfficeFolderHasCustomer>(customer);
}) });
await Folders.getInstance().put(this.props.selectedFolderUid, body);
this.props.router.push(`/folders/${this.props.selectedFolderUid}`);

View File

@ -6,9 +6,7 @@ import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
import Form from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import { IOption } from "@Front/Components/DesignSystem/Select";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
@ -19,6 +17,9 @@ import React from "react";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
type IProps = {};
type IPropsClass = IProps & {
@ -109,17 +110,14 @@ class AskDocumentsClass extends BasePage<IPropsClass, IState> {
cancelText={"Annuler"}
confirmText={"Ajouter"}>
<div className={classes["add-document-form-container"]}>
<InputField
<TextField
name="document_name"
fakeplaceholder="Nom du document à ajouter"
type="text"
placeholder="Nom du document à ajouter"
onChange={this.onDocumentNameChange}
/>
<InputField
<TextAreaField
name="description"
fakeplaceholder="Description visible par le client"
type="text"
textarea
placeholder="Description visible par le client"
onChange={this.onVisibleDescriptionChange}
/>
</div>
@ -232,13 +230,13 @@ class AskDocumentsClass extends BasePage<IPropsClass, IState> {
}
}
private onVisibleDescriptionChange(e: React.ChangeEvent<HTMLInputElement>) {
private onVisibleDescriptionChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
visibleDescription: e.target.value,
});
}
private onDocumentNameChange(e: React.ChangeEvent<HTMLInputElement>) {
private onDocumentNameChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
documentName: e.target.value,
});
@ -275,7 +273,7 @@ class AskDocumentsClass extends BasePage<IPropsClass, IState> {
) {
try {
const documentAsked: [] = values["document_types"] as [];
for(let i = 0; i < documentAsked.length; i++){
for (let i = 0; i < documentAsked.length; i++) {
await Documents.getInstance().post({
folder: {
uid: this.props.folderUid,

View File

@ -1,24 +1,26 @@
import backgroundImage from "@Assets/images/404-background-image.jpeg";
import DeedTypes from "@Front/Api/LeCoffreApi/SuperAdmin/DeedTypes/DeedTypes";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
import Button from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
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 Select, { IOption } from "@Front/Components/DesignSystem/Select";
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";
import { Deed, DeedType, Office, OfficeFolder, OfficeFolderHasStakeholder } 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 { DeedType, OfficeFolderHasStakeholder } from "le-coffre-resources/dist/Notary";
import DeedTypes from "@Front/Api/LeCoffreApi/SuperAdmin/DeedTypes/DeedTypes";
import Users from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
import User from "le-coffre-resources/dist/Notary";
import Folders, { IPostFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import { NextRouter, useRouter } from "next/router";
import backgroundImage from "@Assets/images/404-background-image.jpeg";
type IFormValues = {
folder_number: string;
@ -41,6 +43,7 @@ type IState = {
deedTypesOptions: IOption[];
collaborators: User[];
collaboratorsOptions: IOption[];
validationError: ValidationError[];
};
class CreateFolderClass extends BasePage<IPropsClass, IState> {
public constructor(props: IPropsClass) {
@ -59,6 +62,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
deedTypesOptions: [],
collaborators: [],
collaboratorsOptions: [],
validationError: [],
};
this.radioOnChange = this.radioOnChange.bind(this);
@ -84,19 +88,31 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
</Typography>
<Form onSubmit={this.onFormSubmit}>
<div className={classes["form-container"]}>
<InputField
<TextField
name="folder_number"
fakeplaceholder="Numéro de dossier"
type="text"
placeholder="Numéro de dossier"
onChange={this.onFolderNumberChange}
validationError={this.state.validationError.find((error) => error.property === "folder_number")}
/>
<InputField name="name" fakeplaceholder="Intitulé" onChange={this.onEntitleChange} />
<Select options={this.state.deedTypesOptions} placeholder={"Type dacte"} onChange={this.onActTypeChange} />
<InputField
<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"
fakeplaceholder="Note du dossier"
textarea
placeholder="Note du dossier"
onChange={this.onPersonalNoteChange}
validationError={this.state.validationError.find((error) => error.property === "description")}
required={false}
/>
</div>
<div className={classes["access-container"]}>
@ -122,7 +138,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
</div>
)}
<div className={classes["buttons-container"]}>
<Button fullwidth disabled={!this.isFormSubmittable()} type="submit">
<Button fullwidth type="submit">
Créer un dossier
</Button>
</div>
@ -166,7 +182,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
})) as IOption[];
}
private onFolderNumberChange(e: React.ChangeEvent<HTMLInputElement>) {
private onFolderNumberChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
formValues: {
...this.state.formValues,
@ -175,7 +191,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
});
}
private onEntitleChange(e: React.ChangeEvent<HTMLInputElement>) {
private onEntitleChange(e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({
formValues: {
...this.state.formValues,
@ -193,7 +209,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
});
}
private onPersonalNoteChange(e: React.ChangeEvent<HTMLInputElement>) {
private onPersonalNoteChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
formValues: {
...this.state.formValues,
@ -226,35 +242,52 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
*/
const usersMock = await Users.getInstance().get({ include: { office_membership: true } });
const userMock = usersMock[0];
// -----
if (!selectedDeedTypeUid) return;
if (!userMock?.office_membership?.uid) return;
let stakeholders = this.getStakeholders();
let test = stakeholders.map((stakeholder) => ({
let testUsers = stakeholders.map((stakeholder) => ({
user_stakeholder: {
uid: stakeholder.user_stakeholder.uid,
},
}));
const output: IPostFoldersParams = {
const officeFolderForm = OfficeFolder.hydrate<OfficeFolder>({
folder_number: values["folder_number"],
name: values["name"],
description: values["description"],
deed: {
deed_type: {
uid: selectedDeedTypeUid.uid,
},
},
office: {
uid: userMock?.office_membership.uid,
},
office_folder_has_stakeholder: test,
};
deed: Deed.hydrate<Deed>({
deed_type: DeedType.hydrate<DeedType>({
uid: selectedDeedTypeUid?.uid,
}),
}),
office: Office.hydrate<Office>({
uid: userMock?.office_membership?.uid,
}),
office_folder_has_stakeholder: testUsers.map((user) => {
return OfficeFolderHasStakeholder.hydrate<OfficeFolderHasStakeholder>({
user_stakeholder: User.hydrate<User>({
uid: user.user_stakeholder.uid,
}),
});
}),
});
const created = await Folders.getInstance().post(output);
if (created) {
this.props.router.push(`/folders/${created.uid}`);
try {
await officeFolderForm.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false });
} 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: any) {
this.setState({
validationError: backError as ValidationError[],
});
}
}

View File

@ -1,8 +1,7 @@
import ChevronIcon from "@Assets/Icons/chevron.svg";
import Folders, { IPutFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import FolderBoxInformation, { EFolderBoxInformationType } from "@Front/Components/DesignSystem/FolderBoxInformation";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
@ -17,6 +16,7 @@ import { ChangeEvent } from "react";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import ClientSection from "./ClientSection";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
type IProps = {};
@ -110,10 +110,9 @@ 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
<TextAreaField
name="archived_description"
fakeplaceholder="Description"
textarea
placeholder="Description"
onChange={this.onArchivedDescriptionInputChange}
/>
</Confirm>
@ -172,15 +171,15 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
this.setState({ isArchivedModalOpen: false });
}
private onArchivedDescriptionInputChange(e: ChangeEvent<HTMLInputElement>) {
private onArchivedDescriptionInputChange(e: ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
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 as IPutFoldersParams);
const ressourceFolder = OfficeFolder.hydrate<OfficeFolder>(this.state.selectedFolder);
ressourceFolder.archived_description = this.state.inputArchivedDescripton;
await Folders.getInstance().archive(this.state.selectedFolder.uid ?? "", ressourceFolder);
this.closeArchivedModal();
this.props.router.push(Module.getInstance().get().modules.pages.Folder.props.path);
}

View File

@ -1,7 +1,9 @@
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import Customers from "@Front/Api/LeCoffreApi/SuperAdmin/Customers/Customers";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
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 BackArrow from "@Front/Components/Elements/BackArrow";
@ -12,9 +14,6 @@ import Link from "next/link";
import { NextRouter, useRouter } from "next/router";
import { ChangeEvent } from "react";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
type IProps = {};
type IPropsClass = IProps & {
@ -78,44 +77,40 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
<Typography typo={ITypo.H1Bis}>Modifier les informations du client</Typography>
<Form className={classes["form"]} onSubmit={this.onFormSubmit}>
<div className={classes["content"]}>
<InputField
<TextField
name="first_name"
fakeplaceholder="Nom"
placeholder="Nom"
onChange={this.onChangeNameInput}
defaultValue={this.state.customer?.contact?.first_name}
/>
<InputField
<TextField
name="last_name"
fakeplaceholder="Prénom"
placeholder="Prénom"
onChange={this.onChangeFirstNameInput}
defaultValue={this.state.customer?.contact?.last_name}
/>
<InputField
<TextField
name="email"
fakeplaceholder="E-mail"
isEmail
placeholder="E-mail"
onChange={this.onChangeEmailInput}
defaultValue={this.state.customer?.contact?.email}
/>
<InputField
<TextField
name="cell_phone_number"
fakeplaceholder="Numéro de téléphone"
isPositiveNumber
placeholder="Numéro de téléphone"
onChange={this.onChangePhoneNumberInput}
defaultValue={this.state.customer?.contact?.cell_phone_number ?? ""}
/>
<InputField
<TextField
name="birthdate"
type="text"
fakeplaceholder="Date de naissance"
placeholder="Date de naissance"
required={false}
onChange={this.onChangeBirthDateInput}
defaultValue={this.state.customer?.contact?.birthdate?.toString() ?? ""}
/>
<InputField
<TextField
name="address"
type="text"
fakeplaceholder="Adresse"
placeholder="Adresse"
required={false}
onChange={this.onChangeAddressInput}
defaultValue={this.state.customer?.contact?.address?.address ?? ""}
@ -185,11 +180,11 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
},
} as Contact;
try{
await Customers.getInstance().put(this.props.customerUid, { contact })
try {
await Customers.getInstance().put(this.props.customerUid, { contact });
this.props.router.push(this.backwardPath);
} catch (e) {
console.error(e)
console.error(e);
}
}
@ -205,25 +200,25 @@ class UpdateClientClass extends BasePage<IPropsClass, IState> {
this.setState({ isOpenLeavingModal: false });
}
private onChangeBirthDateInput(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
private onChangeBirthDateInput(event: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({ inputBirthdate: new Date(event.target.value) });
}
private onChangeAddressInput(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
private onChangeAddressInput(event: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({ inputAddress: event.target.value });
}
private onChangeNameInput(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
private onChangeNameInput(event: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({ inputNameValue: event.target.value });
}
private onChangeFirstNameInput(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
private onChangeFirstNameInput(event: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({ inputFirstNameValue: event.target.value });
}
private onChangeEmailInput(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
private onChangeEmailInput(event: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({ inputEmailValue: event.target.value });
}
private onChangePhoneNumberInput(event: ChangeEvent<HTMLInputElement & HTMLSelectElement & HTMLTextAreaElement>) {
private onChangePhoneNumberInput(event: ChangeEvent<HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement>) {
this.setState({ inputPhoneNumberValue: event.target.value });
}

View File

@ -13,7 +13,7 @@ import Module from "@Front/Config/Module";
import Users, { IGetUsersparams } from "@Front/Api/LeCoffreApi/SuperAdmin/Users/Users";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import { OfficeFolderHasStakeholder } from "le-coffre-resources/dist/Customer";
import { IOption } from "@Front/Components/DesignSystem/Select";
import { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import User from "le-coffre-resources/dist/Notary";
type IPropsClass = {

View File

@ -1,6 +1,5 @@
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
@ -11,6 +10,7 @@ import { NextRouter, useRouter } from "next/router";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
type IProps = {};
@ -23,7 +23,9 @@ type IState = {
folder: IDashBoardFolder | null;
};
class UpdateFolderDescriptionClass extends BasePage<IPropsClass, IState> {
private backwardPath = Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folderUid);
private backwardPath = Module.getInstance()
.get()
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.folderUid);
constructor(props: IPropsClass) {
super(props);
this.state = {
@ -42,10 +44,9 @@ class UpdateFolderDescriptionClass extends BasePage<IPropsClass, IState> {
<Form className={classes["form"]} onSubmit={this.onFormSubmit}>
<div className={classes["content"]}>
<InputField
<TextAreaField
name="description"
fakeplaceholder="Note du dossier"
textarea
placeholder="Note du dossier"
defaultValue={this.state.folder?.description ?? ""}
/>
</div>
@ -72,7 +73,7 @@ class UpdateFolderDescriptionClass extends BasePage<IPropsClass, IState> {
await Folders.getInstance().put(this.props.folderUid, values);
this.props.router.push(this.backwardPath);
} catch (error) {
console.error(error)
console.error(error);
}
}
}

View File

@ -1,9 +1,8 @@
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Select, { IOption } from "@Front/Components/DesignSystem/Select";
import Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
@ -14,7 +13,6 @@ import { NextRouter, useRouter } from "next/router";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
type IProps = {};
type IPropsClass = IProps & {
@ -54,18 +52,14 @@ class UpdateFolderMetadataClass extends BasePage<IPropsClass, IState> {
<Form className={classes["form"]} onSubmit={this.onFormSubmit}>
<div className={classes["content"]}>
<InputField name="name" fakeplaceholder="Intitulé du dossier" defaultValue={this.state.selectedFolder?.name} />
<InputField
<TextField name="name" placeholder="Intitulé du dossier" defaultValue={this.state.selectedFolder?.name} />
<TextField
name="folder_number"
fakeplaceholder="Numéro de dossier"
placeholder="Numéro de dossier"
defaultValue={this.state.selectedFolder?.folder_number}
/>
<Select options={[]} placeholder={"Type d'acte"} selectedOption={deedOption} disabled />
<InputField
fakeplaceholder="Ouverture du dossier"
defaultValue={openingDate.toLocaleDateString("fr-FR")}
disabled
/>
<Select name="deed" options={[]} placeholder={"Type d'acte"} selectedOption={deedOption} disabled />
<TextField placeholder="Ouverture du dossier" defaultValue={openingDate.toLocaleDateString("fr-FR")} disabled />
</div>
<div className={classes["button-container"]}>

View File

@ -5,7 +5,6 @@ import ValidateAnchoringGif from "@Front/Assets/images/validate_anchoring.gif";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import CheckBox from "@Front/Components/DesignSystem/CheckBox";
import FilePreview from "@Front/Components/DesignSystem/FilePreview";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Confirm from "@Front/Components/DesignSystem/Modal/Confirm";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
@ -20,6 +19,7 @@ import BasePage from "../../Base";
import classes from "./classes.module.scss";
import OcrResult from "./OcrResult";
import Files from "@Front/Api/LeCoffreApi/SuperAdmin/Files/Files";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
type IProps = {};
type IPropsClass = {
@ -168,7 +168,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
Veuillez indiquer au client le motif du refus de son document afin qu'il puisse vous renvoyer une bonne
version.
</Typography>
<InputField fakeplaceholder="Motif du refus" textarea onChange={this.onRefuseTextChange} />
<TextAreaField placeholder="Motif du refus" onChange={this.onRefuseTextChange} />
</div>
</Confirm>
</div>
@ -322,7 +322,7 @@ class ViewDocumentsClass extends BasePage<IPropsClass, IState> {
}
}
private onRefuseTextChange(e: React.ChangeEvent<HTMLInputElement>) {
private onRefuseTextChange(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>) {
this.setState({
refuseText: e.target.value,
});

View File

@ -1,5 +1,5 @@
import ChevronIcon from "@Assets/Icons/chevron.svg";
import Folders, { IPutFoldersParams } from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Folders from "@Front/Api/LeCoffreApi/SuperAdmin/Folders/Folders";
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import FolderBoxInformation, { EFolderBoxInformationType } from "@Front/Components/DesignSystem/FolderBoxInformation";
import QuantityProgressBar from "@Front/Components/DesignSystem/QuantityProgressBar";
@ -117,9 +117,9 @@ class FolderInformationClass extends BasePage<IPropsClass, IState> {
private async restoreFolder() {
if (!this.state.selectedFolder) return;
const folder = this.state.selectedFolder;
folder.archived_description = null;
await Folders.getInstance().restore(this.state.selectedFolder.uid ?? "", folder as IPutFoldersParams);
const ressourceFolder = OfficeFolder.hydrate<OfficeFolder>(this.state.selectedFolder);
ressourceFolder.archived_description = null;
await Folders.getInstance().restore(this.state.selectedFolder.uid ?? "", ressourceFolder);
this.props.router.push(
Module.getInstance()
.get()

View File

@ -1,7 +1,7 @@
import Button, { EButtonVariant } from "@Front/Components/DesignSystem/Button";
import Form from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Select, { IOption } from "@Front/Components/DesignSystem/Select";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Select, { IOption } from "@Front/Components/DesignSystem/Form/SelectField";
import Typography, { ITypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard, { IDashBoardFolder } from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
@ -47,15 +47,16 @@ class UpdateFolderMetadataClass extends BasePage<IProps, IState> {
<Form className={classes["form"]}>
<div className={classes["content"]}>
<InputField name="input field" fakeplaceholder="Intitulé du dossier" />
<InputField name="input field" fakeplaceholder="Numéro de dossier" />
<TextField name="input field" placeholder="Intitulé du dossier" />
<TextField name="input field" placeholder="Numéro de dossier" />
<Select
name="deed"
options={selectOptions}
onChange={this.onSelectedOption}
placeholder={"Type d'acte"}
selectedOption={this.state.selectedOption}
/>
<InputField name="input field" fakeplaceholder="Ouverture du dossier" />
<TextField name="input field" placeholder="Ouverture du dossier" />
</div>
<div className={classes["button-container"]}>

View File

@ -1,5 +1,5 @@
import Form, { IApiFormErrors } from "@Front/Components/DesignSystem/Form";
import InputField from "@Front/Components/DesignSystem/Form/Elements/InputField";
import Form from "@Front/Components/DesignSystem/Form";
import TextField from "@Front/Components/DesignSystem/Form/TextField";
import Typography, { ITypo, ITypoColor } from "@Front/Components/DesignSystem/Typography";
import Base from "@Front/Components/Layouts/Base";
import DefaultTemplate from "@Front/Components/LayoutTemplates/DefaultTemplate";
@ -25,19 +25,17 @@ export default class MyAccount extends Base<IProps, IState> {
</Typography>
<Form onSubmit={this.onFormSubmit}>
<div className={classes["form-container"]}>
<InputField name="name" fakeplaceholder="Nom" type="text" defaultValue={"BIHR"} disabled />
<InputField name="surname" fakeplaceholder="Prénom" type="text" defaultValue={"Nicolas"} disabled />
<InputField
<TextField name="name" placeholder="Nom" defaultValue={"BIHR"} disabled />
<TextField name="surname" placeholder="Prénom" defaultValue={"Nicolas"} disabled />
<TextField
name="email"
fakeplaceholder="E-mail"
type="email"
placeholder="E-mail"
defaultValue={"nicolas.bihr@notaires.fr"}
disabled
/>
<InputField
<TextField
name="phone"
fakeplaceholder="Numéro de téléphone"
type="tel"
placeholder="Numéro de téléphone"
defaultValue={"06 74 83 90 23"}
disabled
/>
@ -50,25 +48,22 @@ export default class MyAccount extends Base<IProps, IState> {
</Typography>
<Form onSubmit={this.onFormSubmit}>
<div className={classes["form-container"]}>
<InputField
<TextField
name="office_denomination"
fakeplaceholder="Dénomination de l'office"
type="text"
placeholder="Dénomination de l'office"
defaultValue="Etude Office notarial du Cormier"
disabled
/>
<InputField name="crpcen" fakeplaceholder="CRPCEN" type="number" defaultValue="35137" disabled />
<InputField
<TextField name="crpcen" placeholder="CRPCEN" defaultValue="35137" disabled />
<TextField
name="cp_address"
fakeplaceholder="Adresse CP"
placeholder="Adresse CP"
defaultValue="2 RUE DE RENNES"
type="text"
disabled
/>
<InputField
<TextField
name="city"
fakeplaceholder="Ville"
type="text"
placeholder="Ville"
defaultValue="35140 ST AUBIN DU CORMIER"
disabled
/>
@ -85,7 +80,6 @@ export default class MyAccount extends Base<IProps, IState> {
e: React.FormEvent<HTMLFormElement> | null,
values: {
[key: string]: string;
},
onApiErrors: (apiFormErrors: IApiFormErrors | null) => void,
}
) {}
}