handle empty collaborators error
This commit is contained in:
parent
ecaa7f2801
commit
f92946b668
@ -24,7 +24,7 @@
|
|||||||
"eslint-config-next": "13.2.4",
|
"eslint-config-next": "13.2.4",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
"jwt-decode": "^3.1.2",
|
"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",
|
"next": "13.2.4",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
|
@ -66,5 +66,14 @@
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&[data-is-errored="true"] {
|
||||||
|
.input {
|
||||||
|
border: 1px solid var(--red-flash);
|
||||||
|
~ .fake-placeholder {
|
||||||
|
color: var(--red-flash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,10 @@ import React from "react";
|
|||||||
import ReactSelect, { ActionMeta, MultiValue, Options, PropsValue } from "react-select";
|
import ReactSelect, { ActionMeta, MultiValue, Options, PropsValue } from "react-select";
|
||||||
|
|
||||||
import { IOption } from "../Form/SelectField";
|
import { IOption } from "../Form/SelectField";
|
||||||
import Typography, { ITypo } from "../Typography";
|
import Typography, { ITypo, ITypoColor } from "../Typography";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
import { styles } from "./styles";
|
import { styles } from "./styles";
|
||||||
|
import { ValidationError } from "class-validator";
|
||||||
|
|
||||||
type IProps = {
|
type IProps = {
|
||||||
options: IOption[];
|
options: IOption[];
|
||||||
@ -17,10 +18,12 @@ type IProps = {
|
|||||||
isMulti?: boolean;
|
isMulti?: boolean;
|
||||||
shouldCloseMenuOnSelect: boolean;
|
shouldCloseMenuOnSelect: boolean;
|
||||||
isOptionDisabled?: (option: IOption, selectValue: Options<IOption>) => boolean;
|
isOptionDisabled?: (option: IOption, selectValue: Options<IOption>) => boolean;
|
||||||
|
validationError?: ValidationError;
|
||||||
};
|
};
|
||||||
type IState = {
|
type IState = {
|
||||||
isFocused: boolean;
|
isFocused: boolean;
|
||||||
selectedOptions: MultiValue<IOption>;
|
selectedOptions: MultiValue<IOption>;
|
||||||
|
validationError: ValidationError | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class MultiSelect extends React.Component<IProps, IState> {
|
export default class MultiSelect extends React.Component<IProps, IState> {
|
||||||
@ -34,11 +37,15 @@ export default class MultiSelect extends React.Component<IProps, IState> {
|
|||||||
this.state = {
|
this.state = {
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
selectedOptions: [],
|
selectedOptions: [],
|
||||||
|
validationError: this.props.validationError ?? null
|
||||||
|
|
||||||
};
|
};
|
||||||
|
this.hasError = this.hasError.bind(this);
|
||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
this.onEmptyResearch = this.onEmptyResearch.bind(this);
|
this.onEmptyResearch = this.onEmptyResearch.bind(this);
|
||||||
this.onFocus = this.onFocus.bind(this);
|
this.onFocus = this.onFocus.bind(this);
|
||||||
this.onBlur = this.onBlur.bind(this);
|
this.onBlur = this.onBlur.bind(this);
|
||||||
|
this.renderErrors = this.renderErrors.bind(this);
|
||||||
}
|
}
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
return (
|
return (
|
||||||
@ -70,6 +77,7 @@ export default class MultiSelect extends React.Component<IProps, IState> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -89,8 +97,12 @@ export default class MultiSelect extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override componentDidUpdate(prevProps: IProps): void {
|
public override componentDidUpdate(prevProps: IProps): void {
|
||||||
if (this.props.defaultValue === prevProps.defaultValue) return;
|
if (this.props.validationError !== prevProps.validationError) {
|
||||||
if (this.props.defaultValue) {
|
this.setState({
|
||||||
|
validationError: this.props.validationError ?? null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this.props.defaultValue && this.props.defaultValue !== prevProps.defaultValue) {
|
||||||
// If default value contains multiple IOptions
|
// If default value contains multiple IOptions
|
||||||
if (Array.isArray(this.props.defaultValue)) {
|
if (Array.isArray(this.props.defaultValue)) {
|
||||||
this.setState({ selectedOptions: 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.props.onChange && this.props.onChange(newValue, actionMeta);
|
||||||
this.setState({
|
this.setState({
|
||||||
selectedOptions: newValue,
|
selectedOptions: newValue,
|
||||||
|
validationError: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,4 +137,21 @@ export default class MultiSelect extends React.Component<IProps, IState> {
|
|||||||
}
|
}
|
||||||
return "Aucune option trouvée";
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
this.onCollaboratorsChange = this.onCollaboratorsChange.bind(this);
|
this.onCollaboratorsChange = this.onCollaboratorsChange.bind(this);
|
||||||
this.isFormSubmittable = this.isFormSubmittable.bind(this);
|
this.isFormSubmittable = this.isFormSubmittable.bind(this);
|
||||||
this.onFormSubmit = this.onFormSubmit.bind(this);
|
this.onFormSubmit = this.onFormSubmit.bind(this);
|
||||||
|
this.renderSelectCollaborators = this.renderSelectCollaborators.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override render(): JSX.Element {
|
public override render(): JSX.Element {
|
||||||
@ -115,33 +116,25 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
validationError={this.state.validationError.find((error) => error.property === "description")}
|
validationError={this.state.validationError.find((error) => error.property === "description")}
|
||||||
required={false}
|
required={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
<div className={classes["access-container"]}>
|
<div className={classes["access-container"]}>
|
||||||
<Typography typo={ITypo.H3} color={ITypoColor.PURPLE_FLASH}>
|
<Typography typo={ITypo.H3} color={ITypoColor.PURPLE_FLASH}>
|
||||||
Accès au dossier
|
Accès au dossier
|
||||||
</Typography>
|
</Typography>
|
||||||
<div className={classes["radio-container"]}>
|
<div className={classes["radio-container"]}>
|
||||||
<RadioBox name="file_access" defaultChecked onChange={this.radioOnChange} value="whole_office">
|
<RadioBox name="file_access" defaultChecked onChange={this.radioOnChange} value="whole_office">
|
||||||
Sélectionner tout l'office
|
Sélectionner tout l'office
|
||||||
</RadioBox>
|
</RadioBox>
|
||||||
<RadioBox name="file_access" onChange={this.radioOnChange} value="select_collaborators">
|
<RadioBox name="file_access" onChange={this.radioOnChange} value="select_collaborators">
|
||||||
Sélectionner certains collaborateurs
|
Sélectionner certains collaborateurs
|
||||||
</RadioBox>
|
</RadioBox>
|
||||||
</div>
|
</div>
|
||||||
{this.state.folder_access === "select_collaborators" && (
|
{this.renderSelectCollaborators()}
|
||||||
<div className={classes["collaborators-container"]}>
|
<div className={classes["buttons-container"]}>
|
||||||
<MultiSelect
|
<Button fullwidth type="submit">
|
||||||
options={this.state.collaboratorsOptions}
|
Créer un dossier
|
||||||
placeholder="Sélectionner les collaborateurs"
|
</Button>
|
||||||
onChange={this.onCollaboratorsChange}
|
|
||||||
defaultValue={this.state.formValues.collaborators ?? []}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
<div className={classes["buttons-container"]}>
|
|
||||||
<Button fullwidth type="submit">
|
|
||||||
Créer un dossier
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
@ -259,9 +252,8 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await officeFolderForm.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: false });
|
await officeFolderForm.validateOrReject?.({ groups: ["createFolder"], forbidUnknownValues: true });
|
||||||
} catch (validationErrors) {
|
} catch (validationErrors) {
|
||||||
console.log(validationErrors);
|
|
||||||
this.setState({
|
this.setState({
|
||||||
validationError: validationErrors as ValidationError[],
|
validationError: validationErrors as ValidationError[],
|
||||||
});
|
});
|
||||||
@ -277,9 +269,24 @@ class CreateFolderClass extends BasePage<IPropsClass, IState> {
|
|||||||
this.setState({
|
this.setState({
|
||||||
validationError: backError as ValidationError[],
|
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 {
|
private isFormSubmittable(): boolean {
|
||||||
if (
|
if (
|
||||||
this.state.formValues.entitled === "" ||
|
this.state.formValues.entitled === "" ||
|
||||||
|
@ -16,6 +16,7 @@ import { NextRouter, useRouter } from "next/router";
|
|||||||
|
|
||||||
import BasePage from "../../Base";
|
import BasePage from "../../Base";
|
||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
import { ValidationError } from "class-validator";
|
||||||
|
|
||||||
type IPropsClass = {
|
type IPropsClass = {
|
||||||
selectedFolderUid: string;
|
selectedFolderUid: string;
|
||||||
@ -28,6 +29,7 @@ type IState = {
|
|||||||
defaultCheckedAllOffice: boolean;
|
defaultCheckedAllOffice: boolean;
|
||||||
selectedCollaborators: readonly IOption[];
|
selectedCollaborators: readonly IOption[];
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
validationError?: ValidationError[];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ERadioBoxValue {
|
enum ERadioBoxValue {
|
||||||
@ -96,6 +98,7 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
|
|||||||
options={selectOptions}
|
options={selectOptions}
|
||||||
placeholder="Collaborateurs"
|
placeholder="Collaborateurs"
|
||||||
defaultValue={this.state.selectedCollaborators}
|
defaultValue={this.state.selectedCollaborators}
|
||||||
|
validationError={this.state.validationError?.find((error) => error.property === "stakeholders")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -204,7 +207,8 @@ class UpdateFolderCollaboratorsClass extends BasePage<IPropsClass, IState> {
|
|||||||
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid),
|
.modules.pages.Folder.pages.FolderInformation.props.path.replace("[folderUid]", this.props.selectedFolderUid),
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
if(!Array.isArray(error)) return;
|
||||||
|
this.setState({ validationError: error });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user