handle empty collaborators error

This commit is contained in:
OxSaitama 2023-10-16 16:21:54 +02:00
parent ecaa7f2801
commit f92946b668
5 changed files with 83 additions and 33 deletions

View File

@ -24,7 +24,7 @@
"eslint-config-next": "13.2.4",
"form-data": "^4.0.0",
"jwt-decode": "^3.1.2",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.93",
"le-coffre-resources": "git@github.com:smart-chain-fr/leCoffre-resources.git#v2.94",
"next": "13.2.4",
"prettier": "^2.8.7",
"react": "18.2.0",

View File

@ -66,5 +66,14 @@
z-index: 1;
padding: 0 16px;
}
&[data-is-errored="true"] {
.input {
border: 1px solid var(--red-flash);
~ .fake-placeholder {
color: var(--red-flash);
}
}
}
}
}

View File

@ -3,9 +3,10 @@ import React from "react";
import ReactSelect, { ActionMeta, MultiValue, Options, PropsValue } from "react-select";
import { IOption } from "../Form/SelectField";
import Typography, { ITypo } from "../Typography";
import Typography, { ITypo, ITypoColor } from "../Typography";
import classes from "./classes.module.scss";
import { styles } from "./styles";
import { ValidationError } from "class-validator";
type IProps = {
options: IOption[];
@ -17,10 +18,12 @@ type IProps = {
isMulti?: boolean;
shouldCloseMenuOnSelect: boolean;
isOptionDisabled?: (option: IOption, selectValue: Options<IOption>) => boolean;
validationError?: ValidationError;
};
type IState = {
isFocused: boolean;
selectedOptions: MultiValue<IOption>;
validationError: ValidationError | null;
};
export default class MultiSelect extends React.Component<IProps, IState> {
@ -34,11 +37,15 @@ export default class MultiSelect extends React.Component<IProps, IState> {
this.state = {
isFocused: false,
selectedOptions: [],
validationError: this.props.validationError ?? null
};
this.hasError = this.hasError.bind(this);
this.onChange = this.onChange.bind(this);
this.onEmptyResearch = this.onEmptyResearch.bind(this);
this.onFocus = this.onFocus.bind(this);
this.onBlur = this.onBlur.bind(this);
this.renderErrors = this.renderErrors.bind(this);
}
public override render(): JSX.Element {
return (
@ -70,6 +77,7 @@ export default class MultiSelect extends React.Component<IProps, IState> {
/>
</div>
</div>
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
</div>
);
}
@ -89,8 +97,12 @@ export default class MultiSelect extends React.Component<IProps, IState> {
}
public override componentDidUpdate(prevProps: IProps): void {
if (this.props.defaultValue === prevProps.defaultValue) return;
if (this.props.defaultValue) {
if (this.props.validationError !== prevProps.validationError) {
this.setState({
validationError: this.props.validationError ?? null,
});
}
if (this.props.defaultValue && this.props.defaultValue !== prevProps.defaultValue) {
// If default value contains multiple IOptions
if (Array.isArray(this.props.defaultValue)) {
this.setState({ selectedOptions: this.props.defaultValue });
@ -115,6 +127,7 @@ export default class MultiSelect extends React.Component<IProps, IState> {
this.props.onChange && this.props.onChange(newValue, actionMeta);
this.setState({
selectedOptions: newValue,
validationError: null,
});
}
@ -124,4 +137,21 @@ export default class MultiSelect extends React.Component<IProps, IState> {
}
return "Aucune option trouvée";
}
protected hasError(): boolean {
return this.state.validationError !== null;
}
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

@ -74,6 +74,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
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 {
@ -115,33 +116,25 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
validationError={this.state.validationError.find((error) => error.property === "description")}
required={false}
/>
</div>
<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" defaultChecked onChange={this.radioOnChange} value="whole_office">
Sélectionner tout l'office
</RadioBox>
<RadioBox name="file_access" onChange={this.radioOnChange} value="select_collaborators">
Sélectionner certains collaborateurs
</RadioBox>
</div>
{this.state.folder_access === "select_collaborators" && (
<div className={classes["collaborators-container"]}>
<MultiSelect
options={this.state.collaboratorsOptions}
placeholder="Sélectionner les collaborateurs"
onChange={this.onCollaboratorsChange}
defaultValue={this.state.formValues.collaborators ?? []}
/>
<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" defaultChecked onChange={this.radioOnChange} value="whole_office">
Sélectionner tout l'office
</RadioBox>
<RadioBox name="file_access" 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 className={classes["buttons-container"]}>
<Button fullwidth type="submit">
Créer un dossier
</Button>
</div>
</div>
</Form>
@ -259,9 +252,8 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
});
try {
await officeFolderForm.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false });
await officeFolderForm.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: true });
} catch (validationErrors) {
console.log(validationErrors);
this.setState({
validationError: validationErrors as ValidationError[],
});
@ -277,9 +269,24 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
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 === "" ||

View File

@ -16,6 +16,7 @@ import { NextRouter, useRouter } from "next/router";
import BasePage from "../../Base";
import classes from "./classes.module.scss";
import { ValidationError } from "class-validator";
type IPropsClass = {
selectedFolderUid: string;
@ -28,6 +29,7 @@ type IState = {
defaultCheckedAllOffice: boolean;
selectedCollaborators: readonly IOption[];
loading: boolean;
validationError?: ValidationError[];
};
enum ERadioBoxValue {
@ -96,6 +98,7 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
options={selectOptions}
placeholder="Collaborateurs"
defaultValue={this.state.selectedCollaborators}
validationError={this.state.validationError?.find((error) => error.property === "stakeholders")}
/>
</div>
)}
@ -204,7 +207,8 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid),
);
} catch (error) {
console.error(error);
if(!Array.isArray(error)) return;
this.setState({ validationError: error });
}
}
}