diff --git a/src/front/Components/DesignSystem/Autocomplete/index.tsx b/src/front/Components/DesignSystem/Autocomplete/index.tsx index 7b081c11..a5169574 100644 --- a/src/front/Components/DesignSystem/Autocomplete/index.tsx +++ b/src/front/Components/DesignSystem/Autocomplete/index.tsx @@ -13,12 +13,12 @@ type IProps = { placeholder?: string; disabled?: boolean; label?: string; - onSelect?: (option: IOption) => void; + onSelectionChange?: (option: IOption | null) => void; selectedOption?: IOption | null; }; 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(selectedOptionProps ?? null); const [searchValue, setSearchValue] = useState(""); const [filteredOptions, setFilteredOptions] = useState(options); @@ -47,17 +47,25 @@ export default function Autocomplete(props: IProps) { [openable], ); + const handleChange = useCallback( + (option: IOption | null) => { + setSelectedOption(option); + onSelectionChange?.(option); + }, + [onSelectionChange], + ); + useEffect(() => { setSelectedOption(selectedOptionProps ?? null); }, [selectedOptionProps]); const handleSelectOption = useCallback( (newOption: IOption, _options: IOption[]) => { - setSelectedOption(newOption); + handleChange(newOption); setSearchValue(getLabel(newOption) || ""); openable.close(); }, - [openable], + [handleChange, openable], ); return ( @@ -65,8 +73,7 @@ export default function Autocomplete(props: IProps) { options={filteredOptions} openable={openable} onSelect={handleSelectOption} - selectedOptions={selectedOption ? [selectedOption] : []} - > + selectedOptions={selectedOption ? [selectedOption] : []}>
{label && ( @@ -79,7 +86,7 @@ export default function Autocomplete(props: IProps) { disabled={disabled} onChange={handleSearchChange} value={searchValue} - onClear={() => setSelectedOption(null)} + onClear={() => handleChange(null)} onFocus={openable.open} /> diff --git a/src/front/Components/DesignSystem/AutocompleteMultiSelect/index.tsx b/src/front/Components/DesignSystem/AutocompleteMultiSelect/index.tsx index 4274bf89..700040db 100644 --- a/src/front/Components/DesignSystem/AutocompleteMultiSelect/index.tsx +++ b/src/front/Components/DesignSystem/AutocompleteMultiSelect/index.tsx @@ -1,24 +1,24 @@ import useOpenable from "@Front/Hooks/useOpenable"; import { useCallback, useEffect, useState } from "react"; +import { getLabel } from "../Dropdown"; import DropdownMenu from "../Dropdown/DropdownMenu"; import { IOption } from "../Dropdown/DropdownMenu/DropdownOption"; import Typography, { ETypo, ETypoColor } from "../Typography"; -import classes from "./classes.module.scss"; import ChipContainer from "./ChipContainer"; -import { getLabel } from "../Dropdown"; +import classes from "./classes.module.scss"; type IProps = { options: IOption[]; placeholder?: string; disabled?: boolean; label?: string; - onSelect?: (option: IOption) => void; + onSelectionChange?: (options: IOption[] | null) => void; selectedOptions?: IOption[] | null; }; 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(selectedOptionsProps ?? null); const [searchValue, setSearchValue] = useState(""); const [filteredOptions, setFilteredOptions] = useState(options); @@ -27,7 +27,6 @@ export default function AutocompleteMultiSelect(props: IProps) { useEffect(() => { if (searchValue) { const filteredOptions = options.filter((option) => getLabel(option)?.toLowerCase().includes(searchValue.toLowerCase())); - console.log(filteredOptions); if (filteredOptions.length === 0) return setFilteredOptions([{ id: "no-results", label: "Aucun résulats", notSelectable: true }]); return setFilteredOptions(filteredOptions); @@ -47,17 +46,25 @@ export default function AutocompleteMultiSelect(props: IProps) { [openable], ); + const handleChange = useCallback( + (options: IOption[] | null) => { + setSelectedOptions(options); + onSelectionChange?.(options); + }, + [onSelectionChange], + ); + useEffect(() => { setSelectedOptions(selectedOptionsProps ?? null); }, [selectedOptionsProps]); const handleSelectOption = useCallback( (_newOption: IOption, options: IOption[]) => { - setSelectedOptions(options); + handleChange(options); setSearchValue(""); openable.close(); }, - [openable], + [handleChange, openable], ); return ( @@ -78,10 +85,10 @@ export default function AutocompleteMultiSelect(props: IProps) { disabled={disabled} onChange={handleSearchChange} value={searchValue} - onClear={() => setSelectedOptions(null)} + onClear={() => handleChange(null)} onFocus={openable.open} selectedOptions={selectedOptions ?? []} - onSelectedOptionsChange={setSelectedOptions} + onSelectedOptionsChange={handleChange} /> ); diff --git a/src/front/Components/DesignSystem/Dropdown/classes.module.scss b/src/front/Components/DesignSystem/Dropdown/classes.module.scss index ccb9c08a..d2b3d7b3 100644 --- a/src/front/Components/DesignSystem/Dropdown/classes.module.scss +++ b/src/front/Components/DesignSystem/Dropdown/classes.module.scss @@ -30,6 +30,7 @@ padding: 0px var(--spacing-2, 16px); align-items: center; flex: 1 0 0; + gap: 4px; } svg { diff --git a/src/front/Components/DesignSystem/Dropdown/index.tsx b/src/front/Components/DesignSystem/Dropdown/index.tsx index b00cacea..f325a0e5 100644 --- a/src/front/Components/DesignSystem/Dropdown/index.tsx +++ b/src/front/Components/DesignSystem/Dropdown/index.tsx @@ -13,12 +13,12 @@ type IProps = { label?: string; placeholder?: string; disabled?: boolean; - onSelect?: (option: IOption) => void; + onSelectionChange?: (option: IOption) => void; selectedOption?: IOption | null; }; 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(selectedOptionProps ?? null); const openable = useOpenable({ defaultOpen: false }); @@ -29,9 +29,9 @@ export default function Dropdown(props: IProps) { const handleOnSelect = useCallback( (newOption: IOption, _options: IOption[]) => { setSelectedOption(newOption); - onSelect?.(newOption); + onSelectionChange?.(newOption); }, - [onSelect], + [onSelectionChange], ); return ( @@ -55,12 +55,7 @@ export default function Dropdown(props: IProps) { ])} onClick={openable.toggle}>
- - {getLabel(selectedOption) ?? placeholder} - + {getLabelContent(selectedOption, placeholder)}
@@ -74,5 +69,44 @@ export function getLabel(option: IOption | null): string | null { if (typeof option.label === "string") { 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 ( + + {placeholder} + + ); + + if (typeof option.label === "string") { + return ( + + {option.label} + + ); + } + + return ( + + + {`${option.label.text} , `} + + + {option.label.subtext} + + + ); } diff --git a/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx b/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx index ce36524a..d774c9ac 100644 --- a/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx +++ b/src/front/Components/DesignSystem/Form/AutocompleteField/index.tsx @@ -7,7 +7,7 @@ import BaseField, { IProps as IBaseFieldProps, IState as IBaseFieldState } from import classes from "./classes.module.scss"; export type IProps = IBaseFieldProps & { - onSelect?: (option: IOption) => void; + onSelectionChange?: (option: IOption | null) => void; options: IOption[]; selectedOption?: IOption | null; label?: string; @@ -28,9 +28,9 @@ export default class AutocompleteField extends BaseField { this.handleOnChange = this.handleOnChange.bind(this); } - private handleOnChange = (option: IOption) => { + private handleOnChange = (option: IOption | null) => { this.setState({ selectedOption: option }); - this.props.onSelect?.(option); + this.props.onSelectionChange?.(option); }; public override componentDidUpdate(prevProps: IProps): void { @@ -45,9 +45,10 @@ export default class AutocompleteField extends BaseField { {this.state.selectedOption && ( void; + options: IOption[]; + selectedOptions?: IOption[] | null; + label?: string; +}; + +type IState = IBaseFieldState & { + selectedOptions: IOption[] | null; +}; + +export default class AutocompleteMultiSelectField extends BaseField { + 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 ( +
+ + {this.state.selectedOptions && ( + + )} + {this.hasError() &&
{this.renderErrors()}
} +
+ ); + } +} diff --git a/src/front/Components/DesignSystem/Form/SelectField/index.tsx b/src/front/Components/DesignSystem/Form/SelectField/index.tsx index 3a79d80c..d36b5486 100644 --- a/src/front/Components/DesignSystem/Form/SelectField/index.tsx +++ b/src/front/Components/DesignSystem/Form/SelectField/index.tsx @@ -7,7 +7,7 @@ import classes from "./classes.module.scss"; import Dropdown from "../../Dropdown"; export type IProps = IBaseFieldProps & { - onSelect?: (option: IOption) => void; + onSelectionChange?: (option: IOption) => void; options: IOption[]; selectedOption?: IOption | null; label?: string; @@ -30,7 +30,7 @@ export default class SelectField extends BaseField { private handleOnChange = (option: IOption) => { this.setState({ selectedOption: option }); - this.props.onSelect?.(option); + this.props.onSelectionChange?.(option); }; public override componentDidUpdate(prevProps: IProps): void { @@ -45,9 +45,10 @@ export default class SelectField extends BaseField { {this.state.selectedOption && ( 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); - } - } - } - } -} diff --git a/src/front/Components/DesignSystem/MultiSelect/index.tsx b/src/front/Components/DesignSystem/MultiSelect/index.tsx deleted file mode 100644 index d505f4f6..00000000 --- a/src/front/Components/DesignSystem/MultiSelect/index.tsx +++ /dev/null @@ -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, actionMeta: ActionMeta) => void; - defaultValue?: PropsValue; - value?: PropsValue; - isMulti?: boolean; - shouldCloseMenuOnSelect: boolean; - isOptionDisabled?: (option: IOptionOld, selectValue: Options) => boolean; - validationError?: ValidationError; -}; -type IState = { - isFocused: boolean; - selectedOptions: MultiValue; - validationError: ValidationError | null; -}; - -export default class MultiSelect extends React.Component { - public static defaultProps: Partial = { - 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 ( -
-
= 1 && classes["active"])}> - {this.props.label &&
{this.props.label}
} - {this.props.placeholder && ( -
= 1).toString()}> - - {this.props.placeholder} - -
- )} -
- -
-
- {this.hasError() &&
{this.renderErrors()}
} -
- ); - } - - 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, actionMeta: ActionMeta) { - 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( - - {value} - , - ); - }); - return errors; - } -} diff --git a/src/front/Components/DesignSystem/MultiSelect/styles.tsx b/src/front/Components/DesignSystem/MultiSelect/styles.tsx deleted file mode 100644 index cc0ca791..00000000 --- a/src/front/Components/DesignSystem/MultiSelect/styles.tsx +++ /dev/null @@ -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", - }), -}; diff --git a/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx b/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx index 458f6d67..b834da21 100644 --- a/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx +++ b/src/front/Components/DesignSystem/SearchBlockList/DropdownNavigation/index.tsx @@ -38,8 +38,12 @@ export default function DropdownNavigation({ blocks, onSelectedBlock, defaultSel }, } as IOption; })} - onSelect={handleDropDownSelect} - selectedOption={selectedBlock ? { id: selectedBlock.id, label: selectedBlock.primaryText } : undefined} + onSelectionChange={handleDropDownSelect} + selectedOption={ + selectedBlock + ? { id: selectedBlock.id, label: { text: selectedBlock.secondaryText ?? "", subtext: selectedBlock.primaryText } } + : undefined + } /> ); diff --git a/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx b/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx index bedf9614..9e6553b0 100644 --- a/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx +++ b/src/front/Components/Layouts/Collaborators/CollaboratorInformations/index.tsx @@ -208,7 +208,7 @@ export default function CollaboratorInformations(props: IProps) { options={availableRoles.filter((role) => { return role.label !== "admin"; })} - onSelect={handleRoleChange} + onSelectionChange={handleRoleChange} selectedOption={selectedOption} /> diff --git a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx index 2b21f6c1..b547d980 100644 --- a/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx +++ b/src/front/Components/Layouts/DeedTypes/DeedTypesInformations/index.tsx @@ -3,9 +3,9 @@ import PenICon from "@Assets/Icons/pen.svg"; import DeedTypes from "@Front/Api/LeCoffreApi/Admin/DeedTypes/DeedTypes"; import DocumentTypes from "@Front/Api/LeCoffreApi/Admin/DocumentTypes/DocumentTypes"; 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 { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; -import MultiSelect from "@Front/Components/DesignSystem/MultiSelect"; +import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; import Confirm from "@Front/Components/DesignSystem/OldModal/Confirm"; import Tooltip from "@Front/Components/DesignSystem/ToolTip"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; @@ -17,7 +17,6 @@ import Image from "next/image"; import Link from "next/link"; import { useRouter } from "next/router"; import { useCallback, useEffect, useState } from "react"; -import { MultiValue } from "react-select"; import classes from "./classes.module.scss"; @@ -28,7 +27,7 @@ export default function DeedTypesInformations(props: IProps) { const [deedTypeSelected, setDeedTypeSelected] = useState(null); const [availableDocuments, setAvailableDocuments] = useState([]); - const [selectedDocuments, setSelectedDocuments] = useState([]); + const [selectedDocuments, setSelectedDocuments] = useState([]); const [isDeleteModalOpened, setIsDeleteModalOpened] = useState(false); const [isSaveModalOpened, setIsSaveModalOpened] = useState(false); @@ -71,11 +70,11 @@ export default function DeedTypesInformations(props: IProps) { setDeedTypeSelected(deedType); if (!deedType.document_types) return; - const documentsOptions: IOptionOld[] = deedType.document_types + const documentsOptions: IOption[] = deedType.document_types ?.map((documentType) => { return { label: documentType.name, - value: documentType.uid, + id: documentType.uid ?? "", }; }) .sort((a, b) => a.label.localeCompare(b.label)); @@ -101,19 +100,19 @@ export default function DeedTypesInformations(props: IProps) { const saveDocumentTypes = useCallback(async () => { await DeedTypes.getInstance().put(deedTypeUid as string, { uid: deedTypeUid as string, - document_types: selectedDocuments.map((document) => DocumentType.hydrate({ uid: document.value as string })), + document_types: selectedDocuments.map((document) => DocumentType.hydrate({ uid: document.id as string })), }); closeSaveModal(); }, [closeSaveModal, deedTypeUid, selectedDocuments]); - const onDocumentChangeHandler = useCallback((values: MultiValue) => { - setSelectedDocuments(values as IOptionOld[]); + const onDocumentChangeHandler = useCallback((options: IOption[] | null) => { + options && setSelectedDocuments(options); }, []); - const formattedOptions: IOptionOld[] = availableDocuments + const formattedOptions: IOption[] = availableDocuments .map((document) => ({ label: document.name, - value: document.uid, + id: document.uid ?? "", })) .sort((a, b) => a.label.localeCompare(b.label)); @@ -161,11 +160,11 @@ export default function DeedTypesInformations(props: IProps) {
-
diff --git a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx index 0424fde9..0af9d9e9 100644 --- a/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx +++ b/src/front/Components/Layouts/Folder/AddClientToFolder/index.tsx @@ -1,14 +1,16 @@ import Customers from "@Front/Api/LeCoffreApi/Notary/Customers/Customers"; 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 { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption"; import Form from "@Front/Components/DesignSystem/Form"; -import { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; -import MultiSelect from "@Front/Components/DesignSystem/MultiSelect"; +import TextField from "@Front/Components/DesignSystem/Form/TextField"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import Typography, { ETypo } 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 { ValidationError } from "class-validator"; import { ECivility } from "le-coffre-resources/dist/Customer/Contact"; import { Contact, Customer, OfficeFolder } from "le-coffre-resources/dist/Notary"; import Link from "next/link"; @@ -16,8 +18,6 @@ import { NextRouter, useRouter } from "next/router"; import BasePage from "../../Base"; import classes from "./classes.module.scss"; -import TextField from "@Front/Components/DesignSystem/Form/TextField"; -import { ValidationError } from "class-validator"; enum ESelectedOption { EXISTING_CUSTOMER = "existing_customer", @@ -27,8 +27,8 @@ type IProps = {}; type IState = { selectedOption: ESelectedOption; availableCustomers: Customer[]; - selectedCustomers: readonly IOptionOld[]; - existingCustomers: IOptionOld[]; + selectedCustomers: IOption[]; + existingCustomers: IOption[]; isLoaded: boolean; validationError: ValidationError[]; }; @@ -54,7 +54,7 @@ class AddClientToFolderClass extends BasePage { this.onFormSubmit = this.onFormSubmit.bind(this); } public override render(): JSX.Element { - const selectOptions: IOptionOld[] = this.getSelectedOptions(); + const selectOptions: IOption[] = this.getSelectedOptions(); const backwardPath = Module.getInstance() .get() @@ -91,12 +91,13 @@ class AddClientToFolderClass extends BasePage {
{this.state.selectedOption === "existing_customer" && (
- +
diff --git a/src/front/Components/Layouts/Folder/CreateFolder/index.tsx b/src/front/Components/Layouts/Folder/CreateFolder/index.tsx index 5e6a515e..69e21fb4 100644 --- a/src/front/Components/Layouts/Folder/CreateFolder/index.tsx +++ b/src/front/Components/Layouts/Folder/CreateFolder/index.tsx @@ -5,11 +5,10 @@ import Users from "@Front/Api/LeCoffreApi/Notary/Users/Users"; import Button from "@Front/Components/DesignSystem/Button"; import { IOption } from "@Front/Components/DesignSystem/Dropdown/DropdownMenu/DropdownOption"; import Form from "@Front/Components/DesignSystem/Form"; +import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; 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 TextField from "@Front/Components/DesignSystem/Form/TextField"; -import MultiSelect from "@Front/Components/DesignSystem/MultiSelect"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import Typography, { ETypo, ETypoColor } from "@Front/Components/DesignSystem/Typography"; 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 { DeedType } from "le-coffre-resources/dist/Notary"; import { useRouter } from "next/router"; -import React, { useEffect, useState } from "react"; -import { MultiValue } from "react-select"; +import React, { useCallback, useEffect, useState } from "react"; import classes from "./classes.module.scss"; @@ -89,12 +87,14 @@ export default function CreateFolder(): JSX.Element { const radioOnChange = (e: React.ChangeEvent) => setFolderAccessType(e.target.value as "whole_office" | "select_collaborators"); - const onSelectedCollaboratorsChange = (values: MultiValue) => { - const selectedCollaborators = availableCollaborators.filter((collaborator) => - values.some((value) => value.value === collaborator.uid), - ); - setSelectedCollaborators(selectedCollaborators); - }; + const onSelectedCollaboratorsChange = useCallback( + (options: IOption[] | null) => { + if (!options) return; + const collaborators = availableCollaborators.filter((collaborator) => options.find((option) => option.id === collaborator.uid)); + setSelectedCollaborators(collaborators); + }, + [availableCollaborators], + ); /** * UseEffect @@ -178,19 +178,17 @@ export default function CreateFolder(): JSX.Element {
{folderAccessType === "select_collaborators" && (
- ({ - label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name), - value: collaborator.uid, - })) as IOptionOld[] - } - defaultValue={selectedCollaborators.map((collaborator) => ({ - label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name) as string, - value: collaborator.uid!, + ({ + label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name) ?? "", + id: collaborator.uid ?? "", }))} - onChange={onSelectedCollaboratorsChange} - placeholder="Sélectionner les collaborateurs" + selectedOptions={selectedCollaborators.map((collaborator) => ({ + label: collaborator.contact?.last_name.concat(" ", collaborator.contact.first_name) ?? "", + id: collaborator.uid ?? "", + }))} + onSelectionChange={onSelectedCollaboratorsChange} validationError={validationError.find((error) => error.property === "stakeholders")} />
diff --git a/src/front/Components/Layouts/Folder/UpdateFolderCollaborators/index.tsx b/src/front/Components/Layouts/Folder/UpdateFolderCollaborators/index.tsx index d9967e4c..cd000302 100644 --- a/src/front/Components/Layouts/Folder/UpdateFolderCollaborators/index.tsx +++ b/src/front/Components/Layouts/Folder/UpdateFolderCollaborators/index.tsx @@ -2,9 +2,9 @@ import backgroundImage from "@Assets/images/background_refonte.svg"; import Folders from "@Front/Api/LeCoffreApi/Notary/Folders/Folders"; import Users, { IGetUsersParams } from "@Front/Api/LeCoffreApi/Notary/Users/Users"; 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 { IOptionOld } from "@Front/Components/DesignSystem/Form/SelectFieldOld"; -import MultiSelect from "@Front/Components/DesignSystem/MultiSelect"; +import AutocompleteMultiSelectField from "@Front/Components/DesignSystem/Form/AutocompleteMultiSelectField"; import RadioBox from "@Front/Components/DesignSystem/RadioBox"; import Typography, { ETypo } from "@Front/Components/DesignSystem/Typography"; import BackArrow from "@Front/Components/Elements/BackArrow"; @@ -26,9 +26,8 @@ enum ERadioBoxValue { export default function UpdateFolderCollaborators() { const router = useRouter(); let { folderUid } = router.query; - const [availableCollaborators, setAvailableCollaborators] = useState([]); - const [selectedCollaborators, setSelectedCollaborators] = useState([]); + const [selectedCollaborators, setSelectedCollaborators] = useState([]); const [defaultCheckedAllOffice, setDefaultCheckedAllOffice] = useState(false); const [selectedOption, setSelectedOption] = useState(ERadioBoxValue.SELECTION); const [loading, setLoading] = useState(true); @@ -40,9 +39,7 @@ export default function UpdateFolderCollaborators() { try { let collaboratorsUid: User[] = availableCollaborators; if (selectedOption === ERadioBoxValue.SELECTION) { - collaboratorsUid = selectedCollaborators.map((collaborator) => - User.hydrate({ uid: collaborator.value as string }), - ); + collaboratorsUid = selectedCollaborators.map((collaborator) => User.hydrate({ uid: collaborator.id as string })); } await Folders.getInstance().put(folderUid, { stakeholders: collaboratorsUid }); router.push( @@ -61,8 +58,8 @@ export default function UpdateFolderCollaborators() { setSelectedOption(ERadioBoxValue.ALL); }, []); - const onChangeSelectedCollaborators = useCallback((selectedCollaborators: readonly IOptionOld[]) => { - setSelectedCollaborators(selectedCollaborators); + const onChangeSelectedCollaborators = useCallback((selectedCollaborators: IOption[] | null) => { + selectedCollaborators && setSelectedCollaborators(selectedCollaborators); }, []); const onSelectedOptionSpecific = useCallback((event: React.ChangeEvent) => { @@ -86,10 +83,10 @@ export default function UpdateFolderCollaborators() { let folder = null; try { folder = await Folders.getInstance().getByUid(folderUid, query); - const preSelectedCollaborators: IOptionOld[] = folder.stakeholders!.map((collaborator) => { + const preSelectedCollaborators: IOption[] = folder.stakeholders!.map((collaborator) => { return { 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 backwardPath = foldersInformationPath.replace("[folderUid]", folderUid as string); - const selectOptions: IOptionOld[] = availableCollaborators.map((collaborator) => { + const selectOptions: IOption[] = availableCollaborators.map((collaborator) => { return { 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 && (
- error.property === "stakeholders")} />