change old multiselect with new autocomplete multi select

This commit is contained in:
Max S 2024-07-29 13:23:39 +02:00
parent b33037d8df
commit 67ffca67f8
18 changed files with 252 additions and 463 deletions

View File

@ -13,12 +13,12 @@ type IProps = {
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
label?: string; label?: string;
onSelect?: (option: IOption) => void; onSelectionChange?: (option: IOption | null) => void;
selectedOption?: IOption | null; selectedOption?: IOption | null;
}; };
export default function Autocomplete(props: IProps) { export default function Autocomplete(props: IProps) {
const { options, placeholder, disabled, label, selectedOption: selectedOptionProps } = props; const { onSelectionChange, options, placeholder, disabled, label, selectedOption: selectedOptionProps } = props;
const [selectedOption, setSelectedOption] = useState<IOption | null>(selectedOptionProps ?? null); const [selectedOption, setSelectedOption] = useState<IOption | null>(selectedOptionProps ?? null);
const [searchValue, setSearchValue] = useState(""); const [searchValue, setSearchValue] = useState("");
const [filteredOptions, setFilteredOptions] = useState<IOption[]>(options); const [filteredOptions, setFilteredOptions] = useState<IOption[]>(options);
@ -47,17 +47,25 @@ export default function Autocomplete(props: IProps) {
[openable], [openable],
); );
const handleChange = useCallback(
(option: IOption | null) => {
setSelectedOption(option);
onSelectionChange?.(option);
},
[onSelectionChange],
);
useEffect(() => { useEffect(() => {
setSelectedOption(selectedOptionProps ?? null); setSelectedOption(selectedOptionProps ?? null);
}, [selectedOptionProps]); }, [selectedOptionProps]);
const handleSelectOption = useCallback( const handleSelectOption = useCallback(
(newOption: IOption, _options: IOption[]) => { (newOption: IOption, _options: IOption[]) => {
setSelectedOption(newOption); handleChange(newOption);
setSearchValue(getLabel(newOption) || ""); setSearchValue(getLabel(newOption) || "");
openable.close(); openable.close();
}, },
[openable], [handleChange, openable],
); );
return ( return (
@ -65,8 +73,7 @@ export default function Autocomplete(props: IProps) {
options={filteredOptions} options={filteredOptions}
openable={openable} openable={openable}
onSelect={handleSelectOption} onSelect={handleSelectOption}
selectedOptions={selectedOption ? [selectedOption] : []} selectedOptions={selectedOption ? [selectedOption] : []}>
>
<div className={classes["root"]}> <div className={classes["root"]}>
{label && ( {label && (
<Typography className={classes["label"]} typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.CONTRAST_DEFAULT}> <Typography className={classes["label"]} typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.CONTRAST_DEFAULT}>
@ -79,7 +86,7 @@ export default function Autocomplete(props: IProps) {
disabled={disabled} disabled={disabled}
onChange={handleSearchChange} onChange={handleSearchChange}
value={searchValue} value={searchValue}
onClear={() => setSelectedOption(null)} onClear={() => handleChange(null)}
onFocus={openable.open} onFocus={openable.open}
/> />
</DropdownMenu> </DropdownMenu>

View File

@ -1,24 +1,24 @@
import useOpenable from "@Front/Hooks/useOpenable"; import useOpenable from "@Front/Hooks/useOpenable";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { getLabel } from "../Dropdown";
import DropdownMenu from "../Dropdown/DropdownMenu"; import DropdownMenu from "../Dropdown/DropdownMenu";
import { IOption } from "../Dropdown/DropdownMenu/DropdownOption"; import { IOption } from "../Dropdown/DropdownMenu/DropdownOption";
import Typography, { ETypo, ETypoColor } from "../Typography"; import Typography, { ETypo, ETypoColor } from "../Typography";
import classes from "./classes.module.scss";
import ChipContainer from "./ChipContainer"; import ChipContainer from "./ChipContainer";
import { getLabel } from "../Dropdown"; import classes from "./classes.module.scss";
type IProps = { type IProps = {
options: IOption[]; options: IOption[];
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
label?: string; label?: string;
onSelect?: (option: IOption) => void; onSelectionChange?: (options: IOption[] | null) => void;
selectedOptions?: IOption[] | null; selectedOptions?: IOption[] | null;
}; };
export default function AutocompleteMultiSelect(props: IProps) { export default function AutocompleteMultiSelect(props: IProps) {
const { options, placeholder, disabled, label, selectedOptions: selectedOptionsProps } = props; const { onSelectionChange, options, placeholder, disabled, label, selectedOptions: selectedOptionsProps } = props;
const [selectedOptions, setSelectedOptions] = useState<IOption[] | null>(selectedOptionsProps ?? null); const [selectedOptions, setSelectedOptions] = useState<IOption[] | null>(selectedOptionsProps ?? null);
const [searchValue, setSearchValue] = useState(""); const [searchValue, setSearchValue] = useState("");
const [filteredOptions, setFilteredOptions] = useState<IOption[]>(options); const [filteredOptions, setFilteredOptions] = useState<IOption[]>(options);
@ -27,7 +27,6 @@ export default function AutocompleteMultiSelect(props: IProps) {
useEffect(() => { useEffect(() => {
if (searchValue) { if (searchValue) {
const filteredOptions = options.filter((option) => getLabel(option)?.toLowerCase().includes(searchValue.toLowerCase())); const filteredOptions = options.filter((option) => getLabel(option)?.toLowerCase().includes(searchValue.toLowerCase()));
console.log(filteredOptions);
if (filteredOptions.length === 0) if (filteredOptions.length === 0)
return setFilteredOptions([{ id: "no-results", label: "Aucun résulats", notSelectable: true }]); return setFilteredOptions([{ id: "no-results", label: "Aucun résulats", notSelectable: true }]);
return setFilteredOptions(filteredOptions); return setFilteredOptions(filteredOptions);
@ -47,17 +46,25 @@ export default function AutocompleteMultiSelect(props: IProps) {
[openable], [openable],
); );
const handleChange = useCallback(
(options: IOption[] | null) => {
setSelectedOptions(options);
onSelectionChange?.(options);
},
[onSelectionChange],
);
useEffect(() => { useEffect(() => {
setSelectedOptions(selectedOptionsProps ?? null); setSelectedOptions(selectedOptionsProps ?? null);
}, [selectedOptionsProps]); }, [selectedOptionsProps]);
const handleSelectOption = useCallback( const handleSelectOption = useCallback(
(_newOption: IOption, options: IOption[]) => { (_newOption: IOption, options: IOption[]) => {
setSelectedOptions(options); handleChange(options);
setSearchValue(""); setSearchValue("");
openable.close(); openable.close();
}, },
[openable], [handleChange, openable],
); );
return ( return (
@ -78,10 +85,10 @@ export default function AutocompleteMultiSelect(props: IProps) {
disabled={disabled} disabled={disabled}
onChange={handleSearchChange} onChange={handleSearchChange}
value={searchValue} value={searchValue}
onClear={() => setSelectedOptions(null)} onClear={() => handleChange(null)}
onFocus={openable.open} onFocus={openable.open}
selectedOptions={selectedOptions ?? []} selectedOptions={selectedOptions ?? []}
onSelectedOptionsChange={setSelectedOptions} onSelectedOptionsChange={handleChange}
/> />
</DropdownMenu> </DropdownMenu>
); );

View File

@ -30,6 +30,7 @@
padding: 0px var(--spacing-2, 16px); padding: 0px var(--spacing-2, 16px);
align-items: center; align-items: center;
flex: 1 0 0; flex: 1 0 0;
gap: 4px;
} }
svg { svg {

View File

@ -13,12 +13,12 @@ type IProps = {
label?: string; label?: string;
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
onSelect?: (option: IOption) => void; onSelectionChange?: (option: IOption) => void;
selectedOption?: IOption | null; selectedOption?: IOption | null;
}; };
export default function Dropdown(props: IProps) { export default function Dropdown(props: IProps) {
const { options, placeholder, disabled, onSelect, selectedOption: selectedOptionProps, label } = props; const { options, placeholder, disabled, onSelectionChange, selectedOption: selectedOptionProps, label } = props;
const [selectedOption, setSelectedOption] = useState<IOption | null>(selectedOptionProps ?? null); const [selectedOption, setSelectedOption] = useState<IOption | null>(selectedOptionProps ?? null);
const openable = useOpenable({ defaultOpen: false }); const openable = useOpenable({ defaultOpen: false });
@ -29,9 +29,9 @@ export default function Dropdown(props: IProps) {
const handleOnSelect = useCallback( const handleOnSelect = useCallback(
(newOption: IOption, _options: IOption[]) => { (newOption: IOption, _options: IOption[]) => {
setSelectedOption(newOption); setSelectedOption(newOption);
onSelect?.(newOption); onSelectionChange?.(newOption);
}, },
[onSelect], [onSelectionChange],
); );
return ( return (
@ -55,12 +55,7 @@ export default function Dropdown(props: IProps) {
])} ])}
onClick={openable.toggle}> onClick={openable.toggle}>
<div className={classes["content"]}> <div className={classes["content"]}>
<Typography {getLabelContent(selectedOption, placeholder)}
className={classes["value"]}
typo={!!selectedOption ? ETypo.TEXT_MD_SEMIBOLD : ETypo.TEXT_MD_REGULAR}
color={!!selectedOption ? ETypoColor.DROPDOWN_CONTRAST_ACTIVE : ETypoColor.DROPDOWN_CONTRAST_DEFAULT}>
{getLabel(selectedOption) ?? placeholder}
</Typography>
<ChevronDownIcon /> <ChevronDownIcon />
</div> </div>
</div> </div>
@ -74,5 +69,44 @@ export function getLabel(option: IOption | null): string | null {
if (typeof option.label === "string") { if (typeof option.label === "string") {
return option.label; return option.label;
} }
return `${option.label.text} ${option.label.subtext}`; return `${option.label.text}, ${option.label.subtext}`;
}
function getLabelContent(option: IOption | null, placeholder?: string) {
if (!option)
return (
<Typography
className={classes["value"]}
typo={!!option ? ETypo.TEXT_MD_SEMIBOLD : ETypo.TEXT_MD_REGULAR}
color={!!option ? ETypoColor.DROPDOWN_CONTRAST_ACTIVE : ETypoColor.DROPDOWN_CONTRAST_DEFAULT}>
{placeholder}
</Typography>
);
if (typeof option.label === "string") {
return (
<Typography
className={classes["value"]}
typo={!!option ? ETypo.TEXT_MD_SEMIBOLD : ETypo.TEXT_MD_REGULAR}
color={!!option ? ETypoColor.DROPDOWN_CONTRAST_ACTIVE : ETypoColor.DROPDOWN_CONTRAST_DEFAULT}>
{option.label}
</Typography>
);
}
return (
<span className={classes["value"]}>
<Typography
typo={ETypo.TEXT_MD_LIGHT}
color={!!option ? ETypoColor.NAVIGATION_BUTTON_CONTRAST_ACTIVE : ETypoColor.NAVIGATION_BUTTON_CONTRAST_DEFAULT}>
{`${option.label.text} , `}
</Typography>
<Typography
typo={ETypo.TEXT_MD_BOLD}
type="span"
color={!!option ? ETypoColor.NAVIGATION_BUTTON_CONTRAST_ACTIVE : ETypoColor.NAVIGATION_BUTTON_CONTRAST_DEFAULT}>
{option.label.subtext}
</Typography>
</span>
);
} }

View File

@ -7,7 +7,7 @@ import BaseField, { IProps as IBaseFieldProps, IState as IBaseFieldState } from
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
export type IProps = IBaseFieldProps & { export type IProps = IBaseFieldProps & {
onSelect?: (option: IOption) => void; onSelectionChange?: (option: IOption | null) => void;
options: IOption[]; options: IOption[];
selectedOption?: IOption | null; selectedOption?: IOption | null;
label?: string; label?: string;
@ -28,9 +28,9 @@ export default class AutocompleteField extends BaseField<IProps, IState> {
this.handleOnChange = this.handleOnChange.bind(this); this.handleOnChange = this.handleOnChange.bind(this);
} }
private handleOnChange = (option: IOption) => { private handleOnChange = (option: IOption | null) => {
this.setState({ selectedOption: option }); this.setState({ selectedOption: option });
this.props.onSelect?.(option); this.props.onSelectionChange?.(option);
}; };
public override componentDidUpdate(prevProps: IProps): void { public override componentDidUpdate(prevProps: IProps): void {
@ -45,9 +45,10 @@ export default class AutocompleteField extends BaseField<IProps, IState> {
<Autocomplete <Autocomplete
options={this.props.options} options={this.props.options}
placeholder={this.props.placeholder} placeholder={this.props.placeholder}
onSelect={this.handleOnChange} onSelectionChange={this.handleOnChange}
selectedOption={this.state.selectedOption} selectedOption={this.state.selectedOption}
label={this.props.label} label={this.props.label}
disabled={this.props.disabled}
/> />
{this.state.selectedOption && ( {this.state.selectedOption && (
<input <input

View File

@ -0,0 +1,11 @@
@import "@Themes/constants.scss";
.root {
.hidden-input {
position: absolute;
opacity: 0;
}
.errors-container {
margin-top: 8px;
}
}

View File

@ -0,0 +1,66 @@
import React from "react";
import { ReactNode } from "react";
import { IOption } from "../../Dropdown/DropdownMenu/DropdownOption";
import BaseField, { IProps as IBaseFieldProps, IState as IBaseFieldState } from "../BaseField";
import classes from "./classes.module.scss";
import AutocompleteMultiSelect from "../../AutocompleteMultiSelect";
export type IProps = IBaseFieldProps & {
onSelectionChange?: (options: IOption[] | null) => void;
options: IOption[];
selectedOptions?: IOption[] | null;
label?: string;
};
type IState = IBaseFieldState & {
selectedOptions: IOption[] | null;
};
export default class AutocompleteMultiSelectField extends BaseField<IProps, IState> {
constructor(props: IProps) {
super(props);
this.state = {
selectedOptions: this.props.selectedOptions ?? null,
...this.getDefaultState(),
};
this.handleOnChange = this.handleOnChange.bind(this);
}
private handleOnChange = (options: IOption[] | null) => {
this.setState({ selectedOptions: options });
this.props.onSelectionChange?.(options);
};
public override componentDidUpdate(prevProps: IProps): void {
if (prevProps.selectedOptions !== this.props.selectedOptions) {
this.setState({ selectedOptions: this.props.selectedOptions ?? null });
}
}
public override render(): ReactNode {
return (
<div className={classes["root"]}>
<AutocompleteMultiSelect
options={this.props.options}
placeholder={this.props.placeholder}
onSelectionChange={this.handleOnChange}
selectedOptions={this.state.selectedOptions}
label={this.props.label}
disabled={this.props.disabled}
/>
{this.state.selectedOptions && (
<input
className={classes["hidden-input"]}
name={this.props.name}
type="text"
defaultValue={JSON.stringify(this.state.selectedOptions)}
hidden
/>
)}
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
</div>
);
}
}

View File

@ -7,7 +7,7 @@ import classes from "./classes.module.scss";
import Dropdown from "../../Dropdown"; import Dropdown from "../../Dropdown";
export type IProps = IBaseFieldProps & { export type IProps = IBaseFieldProps & {
onSelect?: (option: IOption) => void; onSelectionChange?: (option: IOption) => void;
options: IOption[]; options: IOption[];
selectedOption?: IOption | null; selectedOption?: IOption | null;
label?: string; label?: string;
@ -30,7 +30,7 @@ export default class SelectField extends BaseField<IProps, IState> {
private handleOnChange = (option: IOption) => { private handleOnChange = (option: IOption) => {
this.setState({ selectedOption: option }); this.setState({ selectedOption: option });
this.props.onSelect?.(option); this.props.onSelectionChange?.(option);
}; };
public override componentDidUpdate(prevProps: IProps): void { public override componentDidUpdate(prevProps: IProps): void {
@ -45,9 +45,10 @@ export default class SelectField extends BaseField<IProps, IState> {
<Dropdown <Dropdown
options={this.props.options} options={this.props.options}
placeholder={this.props.placeholder} placeholder={this.props.placeholder}
onSelect={this.handleOnChange} onSelectionChange={this.handleOnChange}
selectedOption={this.state.selectedOption} selectedOption={this.state.selectedOption}
label={this.props.label} label={this.props.label}
disabled={this.props.disabled}
/> />
{this.state.selectedOption && ( {this.state.selectedOption && (
<input <input

View File

@ -1,79 +0,0 @@
@import "@Themes/constants.scss";
.root {
.label-container {
cursor: pointer;
display: flex;
flex-direction: column;
flex: 1;
position: relative;
border: 1px solid var(--color-neutral-200);
background-color: transparent;
.placeholder {
position: absolute;
top: 24px;
left: 24px;
pointer-events: none;
display: flex;
align-items: center;
transition: top 0.3s ease-in-out;
background-color: white;
padding: 0 4px;
&[data-selected="true"] {
top: -12px;
}
}
.label {
font-family: var(--font-text-family);
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 18px;
text-transform: uppercase;
color: var(--color-primary-8);
pointer-events: none;
}
.input-container {
display: flex;
outline: none;
gap: 16px;
border: none;
width: 100%;
> div {
width: 100%;
> div:first-of-type > div:first-of-type {
padding: 24px;
}
}
}
&.active {
.input-container {
> div > div > div {
padding: 24px 16px 16px 16px !important;
}
}
}
.is-active-placeholder {
position: absolute;
top: -11px;
left: 8px;
background-color: #ffffff;
z-index: 1;
padding: 0 16px;
}
&[data-is-errored="true"] {
.input {
border: 1px solid var(--color-error-600);
~ .fake-placeholder {
color: var(--color-error-600);
}
}
}
}
}

View File

@ -1,158 +0,0 @@
import { ValidationError } from "class-validator";
import classNames from "classnames";
import React from "react";
import ReactSelect, { ActionMeta, MultiValue, Options, PropsValue } from "react-select";
import { IOptionOld } from "../Form/SelectFieldOld";
import Typography, { ETypo, ETypoColor } from "../Typography";
import classes from "./classes.module.scss";
import { styles } from "./styles";
type IProps = {
options: IOptionOld[];
label?: string | JSX.Element;
placeholder?: string;
onChange?: (newValue: MultiValue<IOptionOld>, actionMeta: ActionMeta<IOptionOld>) => void;
defaultValue?: PropsValue<IOptionOld>;
value?: PropsValue<IOptionOld>;
isMulti?: boolean;
shouldCloseMenuOnSelect: boolean;
isOptionDisabled?: (option: IOptionOld, selectValue: Options<IOptionOld>) => boolean;
validationError?: ValidationError;
};
type IState = {
isFocused: boolean;
selectedOptions: MultiValue<IOptionOld>;
validationError: ValidationError | null;
};
export default class MultiSelect extends React.Component<IProps, IState> {
public static defaultProps: Partial<IProps> = {
placeholder: "Sélectionner une option...",
shouldCloseMenuOnSelect: false,
};
constructor(props: IProps) {
super(props);
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 (
<div className={classes["root"]}>
<div className={classNames(classes["label-container"], this.state.selectedOptions.length >= 1 && classes["active"])}>
{this.props.label && <div className={classes["label"]}>{this.props.label}</div>}
{this.props.placeholder && (
<div
className={classes["placeholder"]}
data-selected={(this.state.isFocused || this.state.selectedOptions.length >= 1).toString()}>
<Typography typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.COLOR_NEUTRAL_500}>
{this.props.placeholder}
</Typography>
</div>
)}
<div className={classes["input-container"]}>
<ReactSelect
placeholder={""}
options={this.props.options}
styles={styles}
onChange={this.onChange}
value={this.props.defaultValue}
defaultValue={this.state.selectedOptions}
closeMenuOnSelect={this.props.shouldCloseMenuOnSelect}
isMulti
isOptionDisabled={this.props.isOptionDisabled}
noOptionsMessage={this.onEmptyResearch}
onFocus={this.onFocus}
onBlur={this.onBlur}
classNamePrefix="react-select"
/>
</div>
</div>
{this.hasError() && <div className={classes["errors-container"]}>{this.renderErrors()}</div>}
</div>
);
}
public override componentDidMount(): void {
if (this.props.defaultValue) {
// If default value contains multiple IOptions
if (Array.isArray(this.props.defaultValue)) {
this.setState({ selectedOptions: this.props.defaultValue });
}
// If default value is a single IOption
if ("label" in this.props.defaultValue) {
this.setState({ selectedOptions: [this.props.defaultValue] });
}
}
}
public override componentDidUpdate(prevProps: IProps): void {
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 });
}
// If default value is a single IOption
if ("label" in this.props.defaultValue) {
this.setState({ selectedOptions: [this.props.defaultValue] });
}
}
}
private onFocus() {
this.setState({ isFocused: true });
}
private onBlur() {
this.setState({ isFocused: false });
}
private onChange(newValue: MultiValue<IOptionOld>, actionMeta: ActionMeta<IOptionOld>) {
this.props.onChange && this.props.onChange(newValue, actionMeta);
this.setState({
selectedOptions: newValue,
validationError: null,
});
}
private onEmptyResearch() {
if (this.state.selectedOptions.length === this.props.options.length) {
return null;
}
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={ETypo.TEXT_SM_REGULAR} color={ETypoColor.COLOR_ERROR_600}>
{value}
</Typography>,
);
});
return errors;
}
}

View File

@ -1,100 +0,0 @@
export const styles = {
option: (provided: any, props: { isSelected: boolean; isFocused: boolean }) => ({
...provided,
cursor: "pointer",
padding: "8px 24px",
fontFamily: "var(--font-text-family)",
fontStyle: "normal",
fontWeight: "400",
fontSize: "18px",
lineHeight: "21.78px",
color: "#939393",
backgroundColor: props.isSelected ? "var(--color-primary-3)" : props.isFocused ? "var(--color-primary-3)" : undefined,
":active": {
...provided[":active"],
backgroundColor: props.isSelected ? "var(--color-primary-3)" : undefined,
},
}),
control: () => ({
width: "100%",
display: "flex",
background: "transparent",
}),
valueContainer: (provided: any) => ({
...provided,
padding: 0,
minWidth: "100px",
fontFamily: "var(--font-text-family)",
fontStyle: "normal",
fontWeight: "600",
fontSize: "16px",
lineHeight: "22px",
color: "#939393",
letter: "0.5 px",
}),
multiValue: (provided: any) => ({
...provided,
margin: "4px",
padding: "8px 16px",
fontStyle: "normal",
fontWeight: "400",
fontSize: "16px",
lineHeight: "22px",
background: "transparent",
border: "1px solid black",
borderRadius: "100px",
}),
multiValueLabel: (provided: any) => ({
...provided,
fontSize: "16px",
color: "#939393",
fontWeight: "400",
}),
input: (provided: any) => ({
...provided,
margin: 0,
padding: 0,
}),
placeholder: (provided: any) => ({
...provided,
fontSize: "16px",
lineHeight: "22px",
fontWeight: "400",
color: "#939393",
}),
indicatorSeparator: () => ({
display: "none",
}),
menu: (provided: any) => ({
...provided,
position: "static",
border: "0",
boxShadow: "none",
}),
menuList: (provided: any) => ({
...provided,
}),
multiValueRemove: (provided: any) => ({
...provided,
backgroundColor: "transparent",
color: "black",
"&:hover": {
color: "grey",
backgroundColor: "transparent",
},
">svg": {
width: "20px",
height: "20px",
},
}),
indicatorsContainer: (provided: any) => ({
...provided,
display: "none",
}),
listBox: (provided: any) => ({
...provided,
color: "red",
fontSize: "16px",
}),
};

View File

@ -38,8 +38,12 @@ export default function DropdownNavigation({ blocks, onSelectedBlock, defaultSel
}, },
} as IOption; } as IOption;
})} })}
onSelect={handleDropDownSelect} onSelectionChange={handleDropDownSelect}
selectedOption={selectedBlock ? { id: selectedBlock.id, label: selectedBlock.primaryText } : undefined} selectedOption={
selectedBlock
? { id: selectedBlock.id, label: { text: selectedBlock.secondaryText ?? "", subtext: selectedBlock.primaryText } }
: undefined
}
/> />
</div> </div>
); );

View File

@ -208,7 +208,7 @@ export default function CollaboratorInformations(props: IProps) {
options={availableRoles.filter((role) => { options={availableRoles.filter((role) => {
return role.label !== "admin"; return role.label !== "admin";
})} })}
onSelect={handleRoleChange} onSelectionChange={handleRoleChange}
selectedOption={selectedOption} selectedOption={selectedOption}
/> />
</div> </div>

View File

@ -3,9 +3,9 @@ import PenICon from "@Assets/Icons/pen.svg";
import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes"; import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes";
import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes"; import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption";
import Form from "@Front/Components/DesignSystem/Form"; import Form from "@Front/Components/DesignSystem/Form";
import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm";
import Tooltip from "@Front/Components/DesignSystem/ToolTip"; import Tooltip from "@Front/Components/DesignSystem/ToolTip";
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
@ -17,7 +17,6 @@ import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { MultiValue } from "react-select";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
@ -28,7 +27,7 @@ export default function DeedTypesInformations(props: IProps) {
const [deedTypeSelected, setDeedTypeSelected] = useState<DeedType | null>(null); const [deedTypeSelected, setDeedTypeSelected] = useState<DeedType | null>(null);
const [availableDocuments, setAvailableDocuments] = useState<DocumentType[]>([]); const [availableDocuments, setAvailableDocuments] = useState<DocumentType[]>([]);
const [selectedDocuments, setSelectedDocuments] = useState<IOptionOld[]>([]); const [selectedDocuments, setSelectedDocuments] = useState<IOption[]>([]);
const [isDeleteModalOpened, setIsDeleteModalOpened] = useState<boolean>(false); const [isDeleteModalOpened, setIsDeleteModalOpened] = useState<boolean>(false);
const [isSaveModalOpened, setIsSaveModalOpened] = useState<boolean>(false); const [isSaveModalOpened, setIsSaveModalOpened] = useState<boolean>(false);
@ -71,11 +70,11 @@ export default function DeedTypesInformations(props: IProps) {
setDeedTypeSelected(deedType); setDeedTypeSelected(deedType);
if (!deedType.document_types) return; if (!deedType.document_types) return;
const documentsOptions: IOptionOld[] = deedType.document_types const documentsOptions: IOption[] = deedType.document_types
?.map((documentType) => { ?.map((documentType) => {
return { return {
label: documentType.name, label: documentType.name,
value: documentType.uid, id: documentType.uid ?? "",
}; };
}) })
.sort((a, b) => a.label.localeCompare(b.label)); .sort((a, b) => a.label.localeCompare(b.label));
@ -101,19 +100,19 @@ export default function DeedTypesInformations(props: IProps) {
const saveDocumentTypes = useCallback(async () => { const saveDocumentTypes = useCallback(async () => {
await DeedTypes.getInstance().put(deedTypeUid as string, { await DeedTypes.getInstance().put(deedTypeUid as string, {
uid: deedTypeUid as string, uid: deedTypeUid as string,
document_types: selectedDocuments.map((document) => DocumentType.hydrate<DocumentType>({ uid: document.value as string })), document_types: selectedDocuments.map((document) => DocumentType.hydrate<DocumentType>({ uid: document.id as string })),
}); });
closeSaveModal(); closeSaveModal();
}, [closeSaveModal, deedTypeUid, selectedDocuments]); }, [closeSaveModal, deedTypeUid, selectedDocuments]);
const onDocumentChangeHandler = useCallback((values: MultiValue<IOptionOld>) => { const onDocumentChangeHandler = useCallback((options: IOption[] | null) => {
setSelectedDocuments(values as IOptionOld[]); options && setSelectedDocuments(options);
}, []); }, []);
const formattedOptions: IOptionOld[] = availableDocuments const formattedOptions: IOption[] = availableDocuments
.map((document) => ({ .map((document) => ({
label: document.name, label: document.name,
value: document.uid, id: document.uid ?? "",
})) }))
.sort((a, b) => a.label.localeCompare(b.label)); .sort((a, b) => a.label.localeCompare(b.label));
@ -161,11 +160,11 @@ export default function DeedTypesInformations(props: IProps) {
<Tooltip text="Si vous ne trouvez pas le document que vous souhaitez dans la liste, cliquez sur « Modifier la liste des documents » pour créer ce type de document à la liste" /> <Tooltip text="Si vous ne trouvez pas le document que vous souhaitez dans la liste, cliquez sur « Modifier la liste des documents » pour créer ce type de document à la liste" />
</div> </div>
<div className={classes["documents"]}> <div className={classes["documents"]}>
<MultiSelect <AutocompleteMultiSelectField
label="Sélectionner des documents"
options={formattedOptions} options={formattedOptions}
placeholder="Cliquez pour sélectionner des documents" onSelectionChange={onDocumentChangeHandler}
onChange={onDocumentChangeHandler} selectedOptions={selectedDocuments}
defaultValue={selectedDocuments}
/> />
</div> </div>
<div className={classes["button-container"]}> <div className={classes["button-container"]}>

View File

@ -1,14 +1,16 @@
import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers";
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
import AutocompleteMultiSelect from "@Front/Components/DesignSystem/AutocompleteMultiSelect";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption";
import Form from "@Front/Components/DesignSystem/Form"; import Form from "@Front/Components/DesignSystem/Form";
import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import TextField from "@Front/Components/DesignSystem/Form/TextField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow"; import BackArrow from "@Front/Components/Elements/BackArrow";
import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard"; import DefaultNotaryDashboard from "@Front/Components/LayoutTemplates/DefaultNotaryDashboard";
import Module from "@Front/Config/Module"; import Module from "@Front/Config/Module";
import { ValidationError } from "class-validator";
import { ECivility } from "le-coffre-resources/dist/Customer/Contact"; import { ECivility } from "le-coffre-resources/dist/Customer/Contact";
import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary";
import Link from "next/link"; import Link from "next/link";
@ -16,8 +18,6 @@ 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 TextField from "@Front/Components/DesignSystem/Form/TextField";
import { ValidationError } from "class-validator";
enum ESelectedOption { enum ESelectedOption {
EXISTING_CUSTOMER = "existing_customer", EXISTING_CUSTOMER = "existing_customer",
@ -27,8 +27,8 @@ type IProps = {};
type IState = { type IState = {
selectedOption: ESelectedOption; selectedOption: ESelectedOption;
availableCustomers: Customer[]; availableCustomers: Customer[];
selectedCustomers: readonly IOptionOld[]; selectedCustomers: IOption[];
existingCustomers: IOptionOld[]; existingCustomers: IOption[];
isLoaded: boolean; isLoaded: boolean;
validationError: ValidationError[]; validationError: ValidationError[];
}; };
@ -54,7 +54,7 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
this.onFormSubmit = this.onFormSubmit.bind(this); this.onFormSubmit = this.onFormSubmit.bind(this);
} }
public override render(): JSX.Element { public override render(): JSX.Element {
const selectOptions: IOptionOld[] = this.getSelectedOptions(); const selectOptions: IOption[] = this.getSelectedOptions();
const backwardPath = Module.getInstance() const backwardPath = Module.getInstance()
.get() .get()
@ -91,12 +91,13 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
<Form className={classes["form"]} onSubmit={this.onFormSubmit}> <Form className={classes["form"]} onSubmit={this.onFormSubmit}>
{this.state.selectedOption === "existing_customer" && ( {this.state.selectedOption === "existing_customer" && (
<div className={classes["existing-client"]}> <div className={classes["existing-client"]}>
<MultiSelect <AutocompleteMultiSelect
label="Clients"
options={selectOptions} options={selectOptions}
placeholder="Clients" selectedOptions={this.state.selectedCustomers}
onChange={this.onMutiSelectChange} onSelectionChange={this.onMutiSelectChange}
defaultValue={this.state.selectedCustomers}
/> />
<div className={classes["button-container"]}> <div className={classes["button-container"]}>
<Link href={backwardPath} className={classes["cancel-button"]}> <Link href={backwardPath} className={classes["cancel-button"]}>
<Button variant={EButtonVariant.PRIMARY} styletype={EButtonstyletype.OUTLINED}> <Button variant={EButtonVariant.PRIMARY} styletype={EButtonstyletype.OUTLINED}>
@ -153,11 +154,11 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
public override async componentDidMount() { public override async componentDidMount() {
const query = {}; const query = {};
const availableCustomers = await Customers.getInstance().get(query); const availableCustomers = await Customers.getInstance().get(query);
let preExistingCustomers: IOptionOld[] | undefined = await this.getFolderPreSelectedCustomers(this.props.selectedFolderUid); let preExistingCustomers: IOption[] | undefined = await this.getFolderPreSelectedCustomers(this.props.selectedFolderUid);
const existingCustomers = preExistingCustomers ?? []; const existingCustomers = preExistingCustomers ?? [];
existingCustomers.forEach((customer) => { existingCustomers.forEach((customer) => {
const index = availableCustomers.findIndex((availableCustomer) => availableCustomer.uid === customer.value); const index = availableCustomers.findIndex((availableCustomer) => availableCustomer.uid === customer.id);
if (index !== -1) availableCustomers.splice(index, 1); if (index !== -1) availableCustomers.splice(index, 1);
}); });
@ -169,7 +170,7 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
this.setState({ availableCustomers, existingCustomers, isLoaded: true, selectedOption }); this.setState({ availableCustomers, existingCustomers, isLoaded: true, selectedOption });
} }
private async getFolderPreSelectedCustomers(folderUid: string): Promise<IOptionOld[] | undefined> { private async getFolderPreSelectedCustomers(folderUid: string): Promise<IOption[] | undefined> {
const query = { const query = {
q: { q: {
customers: { customers: {
@ -179,13 +180,13 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
}, },
}, },
}; };
let preExistingCustomers: IOptionOld[] = []; let preExistingCustomers: IOption[] = [];
try { try {
const folder = await Folders.getInstance().getByUid(folderUid, query); const folder = await Folders.getInstance().getByUid(folderUid, query);
preExistingCustomers = folder.customers!.map((customer) => { preExistingCustomers = folder.customers!.map((customer) => {
return { return {
label: customer.contact?.first_name + " " + customer.contact?.last_name, label: customer.contact?.first_name + " " + customer.contact?.last_name,
value: customer.uid, id: customer.uid ?? "",
}; };
}); });
} catch (error) { } catch (error) {
@ -195,19 +196,19 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
return preExistingCustomers; return preExistingCustomers;
} }
private getSelectedOptions(): IOptionOld[] { private getSelectedOptions(): IOption[] {
let options = this.state.availableCustomers?.map((customer) => { let options = this.state.availableCustomers?.map((customer) => {
return { return {
label: customer.contact?.first_name + " " + customer.contact?.last_name, label: customer.contact?.first_name + " " + customer.contact?.last_name,
value: customer.uid, id: customer.uid ?? "",
}; };
}); });
if (!options) options = []; if (!options) options = [];
return options; return options;
} }
private onMutiSelectChange(selectedCustomers: readonly IOptionOld[]): void { private onMutiSelectChange(selectedCustomers: IOption[] | null): void {
this.setState({ selectedCustomers }); selectedCustomers && this.setState({ selectedCustomers });
} }
private onExistingClientSelected(): void { private onExistingClientSelected(): void {
@ -228,7 +229,7 @@ class AddClientToFolderClass extends BasePage<IPropsClass, IState> {
const allCustomersToLink = this.state.selectedCustomers.concat(this.state.existingCustomers); const allCustomersToLink = this.state.selectedCustomers.concat(this.state.existingCustomers);
let customersToLink: Partial<Customer>[] = allCustomersToLink.map((customer) => { let customersToLink: Partial<Customer>[] = allCustomersToLink.map((customer) => {
return Customer.hydrate<Customer>({ uid: customer.value as string }); return Customer.hydrate<Customer>({ uid: customer.id as string });
}) as Partial<Customer>[]; }) as Partial<Customer>[];
if (this.state.selectedOption === "new_customer") { if (this.state.selectedOption === "new_customer") {

View File

@ -1,15 +1,14 @@
import Deeds from "@Front/Api/LeCoffreApi/Notary/Deeds/Deeds"; import Deeds from "@Front/Api/LeCoffreApi/Notary/Deeds/Deeds";
import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes"; import DocumentTypes from "@Front/Api/LeCoffreApi/Notary/DocumentTypes/DocumentTypes";
import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption";
import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
import TextField from "@Front/Components/DesignSystem/Form/TextField"; import TextField from "@Front/Components/DesignSystem/Form/TextField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm";
import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
import { DocumentType, OfficeFolder } from "le-coffre-resources/dist/Notary"; import { DocumentType, OfficeFolder } from "le-coffre-resources/dist/Notary";
import { ChangeEvent, useCallback, useEffect, useState } from "react"; import { ChangeEvent, useCallback, useEffect, useState } from "react";
import { MultiValue } from "react-select";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
@ -25,20 +24,20 @@ export default function ParameterDocuments(props: IProps) {
const [addOrEditDocument, setAddOrEditDocument] = useState<"add" | "edit">("edit"); const [addOrEditDocument, setAddOrEditDocument] = useState<"add" | "edit">("edit");
const [selectedDocuments, setSelectedDocuments] = useState<IOptionOld[]>([]); const [selectedDocuments, setSelectedDocuments] = useState<IOption[]>([]);
const [formattedOptions, setFormattedOptions] = useState<IOptionOld[]>([]); const [formattedOptions, setFormattedOptions] = useState<IOption[]>([]);
const getAvailableDocuments = useCallback(async () => { const getAvailableDocuments = useCallback(async () => {
const documents = await DocumentTypes.getInstance().get({}); const documents = await DocumentTypes.getInstance().get({});
const formattedOptions: IOptionOld[] = documents const formattedOptions: IOption[] = documents
.filter((document) => { .filter((document) => {
return !props.folder.deed?.document_types?.some((documentType) => documentType.uid === document.uid); return !props.folder.deed?.document_types?.some((documentType) => documentType.uid === document.uid);
}) })
.map((document) => { .map((document) => {
return { return {
label: document.name, label: document.name,
value: document.uid, id: document.uid ?? "",
}; };
}); });
formattedOptions.sort((a, b) => (a.label > b.label ? 1 : -1)); formattedOptions.sort((a, b) => (a.label > b.label ? 1 : -1));
@ -53,8 +52,8 @@ export default function ParameterDocuments(props: IProps) {
setDocumentName(event.target.value); setDocumentName(event.target.value);
}; };
const onDocumentChangeHandler = useCallback((values: MultiValue<IOptionOld>) => { const onDocumentChangeHandler = useCallback((options: IOption[] | null) => {
setSelectedDocuments(values as IOptionOld[]); options && setSelectedDocuments(options);
}, []); }, []);
const handleClose = useCallback(() => { const handleClose = useCallback(() => {
@ -94,7 +93,7 @@ export default function ParameterDocuments(props: IProps) {
await Deeds.getInstance().put(props.folder.deed?.uid!, { await Deeds.getInstance().put(props.folder.deed?.uid!, {
document_types: [ document_types: [
...oldDocumentsType, ...oldDocumentsType,
...selectedDocuments.map((document) => DocumentType.hydrate<DocumentType>({ uid: document.value as string })), ...selectedDocuments.map((document) => DocumentType.hydrate<DocumentType>({ uid: document.id as string })),
], ],
}); });
@ -148,11 +147,11 @@ export default function ParameterDocuments(props: IProps) {
</> </>
)} )}
{addOrEditDocument === "edit" && ( {addOrEditDocument === "edit" && (
<MultiSelect <AutocompleteMultiSelectField
label="Sélectionner des documents"
options={formattedOptions} options={formattedOptions}
placeholder="Cliquez pour sélectionner des documents" onSelectionChange={onDocumentChangeHandler}
onChange={onDocumentChangeHandler} selectedOptions={selectedDocuments}
defaultValue={selectedDocuments}
/> />
)} )}
</div> </div>

View File

@ -5,11 +5,10 @@ import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users";
import Button from "@Front/Components/DesignSystem/Button"; import Button from "@Front/Components/DesignSystem/Button";
import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption"; import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption";
import Form from "@Front/Components/DesignSystem/Form"; import Form from "@Front/Components/DesignSystem/Form";
import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField";
import SelectField from "@Front/Components/DesignSystem/Form/SelectField"; import SelectField from "@Front/Components/DesignSystem/Form/SelectField";
import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld";
import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField"; import TextAreaField from "@Front/Components/DesignSystem/Form/TextareaField";
import TextField from "@Front/Components/DesignSystem/Form/TextField"; import TextField from "@Front/Components/DesignSystem/Form/TextField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow"; import BackArrow from "@Front/Components/Elements/BackArrow";
@ -20,8 +19,7 @@ import { Deed, Office, OfficeFolder } from "le-coffre-resources/dist/Notary";
import User from "le-coffre-resources/dist/Notary"; import User from "le-coffre-resources/dist/Notary";
import { DeedType } from "le-coffre-resources/dist/Notary"; import { DeedType } from "le-coffre-resources/dist/Notary";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import React, { useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { MultiValue } from "react-select";
import classes from "./classes.module.scss"; import classes from "./classes.module.scss";
@ -89,12 +87,14 @@ export default function CreateFolder(): JSX.Element {
const radioOnChange = (e: React.ChangeEvent<HTMLInputElement>) => const radioOnChange = (e: React.ChangeEvent<HTMLInputElement>) =>
setFolderAccessType(e.target.value as "whole_office" | "select_collaborators"); setFolderAccessType(e.target.value as "whole_office" | "select_collaborators");
const onSelectedCollaboratorsChange = (values: MultiValue<IOptionOld>) => { const onSelectedCollaboratorsChange = useCallback(
const selectedCollaborators = availableCollaborators.filter((collaborator) => (options: IOption[] | null) => {
values.some((value) => value.value === collaborator.uid), if (!options) return;
const collaborators = availableCollaborators.filter((collaborator) => options.find((option) => option.id === collaborator.uid));
setSelectedCollaborators(collaborators);
},
[availableCollaborators],
); );
setSelectedCollaborators(selectedCollaborators);
};
/** /**
* UseEffect * UseEffect
@ -178,19 +178,17 @@ export default function CreateFolder(): JSX.Element {
</div> </div>
{folderAccessType === "select_collaborators" && ( {folderAccessType === "select_collaborators" && (
<div className={classes["collaborators-container"]}> <div className={classes["collaborators-container"]}>
<MultiSelect <AutocompleteMultiSelectField
options={ label="Sélectionner les collaborateurs"
availableCollaborators.map((collaborator) => ({ options={availableCollaborators.map((collaborator) => ({
label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name), label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name) ?? "",
value: collaborator.uid, id: collaborator.uid ?? "",
})) as IOptionOld[]
}
defaultValue={selectedCollaborators.map((collaborator) => ({
label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name) as string,
value: collaborator.uid!,
}))} }))}
onChange={onSelectedCollaboratorsChange} selectedOptions={selectedCollaborators.map((collaborator) => ({
placeholder="Sélectionner les collaborateurs" label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name) ?? "",
id: collaborator.uid ?? "",
}))}
onSelectionChange={onSelectedCollaboratorsChange}
validationError={validationError.find((error) => error.property === "stakeholders")} validationError={validationError.find((error) => error.property === "stakeholders")}
/> />
</div> </div>

View File

@ -2,9 +2,9 @@ import backgroundImage from "@Assets/images/background_refonte.svg";
import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders";
import Users, { IGetUsersParams } from "@Front/Api/LeCoffreApi/Notary/Users/Users"; import Users, { IGetUsersParams } from "@Front/Api/LeCoffreApi/Notary/Users/Users";
import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button"; import Button, { EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption";
import Form from "@Front/Components/DesignSystem/Form"; import Form from "@Front/Components/DesignSystem/Form";
import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField";
import MultiSelect from "@Front/Components/DesignSystem/MultiSelect";
import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import RadioBox from "@Front/Components/DesignSystem/RadioBox";
import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography";
import BackArrow from "@Front/Components/Elements/BackArrow"; import BackArrow from "@Front/Components/Elements/BackArrow";
@ -26,9 +26,8 @@ enum ERadioBoxValue {
export default function UpdateFolderCollaborators() { export default function UpdateFolderCollaborators() {
const router = useRouter(); const router = useRouter();
let { folderUid } = router.query; let { folderUid } = router.query;
const [availableCollaborators, setAvailableCollaborators] = useState<User[]>([]); const [availableCollaborators, setAvailableCollaborators] = useState<User[]>([]);
const [selectedCollaborators, setSelectedCollaborators] = useState<readonly IOptionOld[]>([]); const [selectedCollaborators, setSelectedCollaborators] = useState<IOption[]>([]);
const [defaultCheckedAllOffice, setDefaultCheckedAllOffice] = useState<boolean>(false); const [defaultCheckedAllOffice, setDefaultCheckedAllOffice] = useState<boolean>(false);
const [selectedOption, setSelectedOption] = useState<ERadioBoxValue>(ERadioBoxValue.SELECTION); const [selectedOption, setSelectedOption] = useState<ERadioBoxValue>(ERadioBoxValue.SELECTION);
const [loading, setLoading] = useState<boolean>(true); const [loading, setLoading] = useState<boolean>(true);
@ -40,9 +39,7 @@ export default function UpdateFolderCollaborators() {
try { try {
let collaboratorsUid: User[] = availableCollaborators; let collaboratorsUid: User[] = availableCollaborators;
if (selectedOption === ERadioBoxValue.SELECTION) { if (selectedOption === ERadioBoxValue.SELECTION) {
collaboratorsUid = selectedCollaborators.map((collaborator) => collaboratorsUid = selectedCollaborators.map((collaborator) => User.hydrate<User>({ uid: collaborator.id as string }));
User.hydrate<User>({ uid: collaborator.value as string }),
);
} }
await Folders.getInstance().put(folderUid, { stakeholders: collaboratorsUid }); await Folders.getInstance().put(folderUid, { stakeholders: collaboratorsUid });
router.push( router.push(
@ -61,8 +58,8 @@ export default function UpdateFolderCollaborators() {
setSelectedOption(ERadioBoxValue.ALL); setSelectedOption(ERadioBoxValue.ALL);
}, []); }, []);
const onChangeSelectedCollaborators = useCallback((selectedCollaborators: readonly IOptionOld[]) => { const onChangeSelectedCollaborators = useCallback((selectedCollaborators: IOption[] | null) => {
setSelectedCollaborators(selectedCollaborators); selectedCollaborators && setSelectedCollaborators(selectedCollaborators);
}, []); }, []);
const onSelectedOptionSpecific = useCallback((event: React.ChangeEvent<HTMLInputElement>) => { const onSelectedOptionSpecific = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
@ -86,10 +83,10 @@ export default function UpdateFolderCollaborators() {
let folder = null; let folder = null;
try { try {
folder = await Folders.getInstance().getByUid(folderUid, query); folder = await Folders.getInstance().getByUid(folderUid, query);
const preSelectedCollaborators: IOptionOld[] = folder.stakeholders!.map((collaborator) => { const preSelectedCollaborators: IOption[] = folder.stakeholders!.map((collaborator) => {
return { return {
label: collaborator.contact?.first_name + " " + collaborator.contact?.last_name, label: collaborator.contact?.first_name + " " + collaborator.contact?.last_name,
value: collaborator.uid, id: collaborator.uid ?? "",
}; };
}); });
@ -126,10 +123,10 @@ export default function UpdateFolderCollaborators() {
const foldersInformationPath = Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path; const foldersInformationPath = Module.getInstance().get().modules.pages.Folder.pages.FolderInformation.props.path;
const backwardPath = foldersInformationPath.replace("[folderUid]", folderUid as string); const backwardPath = foldersInformationPath.replace("[folderUid]", folderUid as string);
const selectOptions: IOptionOld[] = availableCollaborators.map((collaborator) => { const selectOptions: IOption[] = availableCollaborators.map((collaborator) => {
return { return {
label: collaborator.contact?.first_name + " " + collaborator.contact?.last_name, label: collaborator.contact?.first_name + " " + collaborator.contact?.last_name,
value: collaborator.uid, id: collaborator.uid ?? "",
}; };
}); });
@ -162,11 +159,11 @@ export default function UpdateFolderCollaborators() {
{selectedOption === ERadioBoxValue.SELECTION && ( {selectedOption === ERadioBoxValue.SELECTION && (
<div className={classes["sub-content"]}> <div className={classes["sub-content"]}>
<MultiSelect <AutocompleteMultiSelectField
onChange={onChangeSelectedCollaborators} label="Collaborateurs"
options={selectOptions} options={selectOptions}
placeholder="Collaborateurs" selectedOptions={selectedCollaborators}
defaultValue={selectedCollaborators} onSelectionChange={onChangeSelectedCollaborators}
validationError={validationError?.find((error) => error.property === "stakeholders")} validationError={validationError?.find((error) => error.property === "stakeholders")}
/> />
</div> </div>