88 lines
2.5 KiB
TypeScript
88 lines
2.5 KiB
TypeScript
import useOpenable from "@Front/Hooks/useOpenable";
|
|
import { useCallback, useEffect, useState } from "react";
|
|
|
|
import DropdownMenu from "../Dropdown/DropdownMenu";
|
|
import { IOption } from "../Dropdown/DropdownMenu/DropdownOption";
|
|
import SearchBar from "../SearchBar";
|
|
import Typography, { ETypo, ETypoColor } from "../Typography";
|
|
import classes from "./classes.module.scss";
|
|
import { getLabel } from "../Dropdown";
|
|
|
|
type IProps = {
|
|
options: IOption[];
|
|
placeholder?: string;
|
|
disabled?: boolean;
|
|
label?: string;
|
|
onSelect?: (option: IOption) => void;
|
|
selectedOption?: IOption | null;
|
|
};
|
|
|
|
export default function Autocomplete(props: IProps) {
|
|
const { options, placeholder, disabled, label, selectedOption: selectedOptionProps } = props;
|
|
const [selectedOption, setSelectedOption] = useState<IOption | null>(selectedOptionProps ?? null);
|
|
const [searchValue, setSearchValue] = useState("");
|
|
const [filteredOptions, setFilteredOptions] = useState<IOption[]>(options);
|
|
const openable = useOpenable({ defaultOpen: false });
|
|
|
|
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);
|
|
}
|
|
return setFilteredOptions(options);
|
|
}, [searchValue, options]);
|
|
|
|
const handleSearchChange = useCallback(
|
|
(value: string) => {
|
|
setSearchValue(value);
|
|
if (value) {
|
|
openable.open();
|
|
} else {
|
|
openable.close();
|
|
}
|
|
},
|
|
[openable],
|
|
);
|
|
|
|
useEffect(() => {
|
|
setSelectedOption(selectedOptionProps ?? null);
|
|
}, [selectedOptionProps]);
|
|
|
|
const handleSelectOption = useCallback(
|
|
(newOption: IOption, _options: IOption[]) => {
|
|
setSelectedOption(newOption);
|
|
setSearchValue(getLabel(newOption) || "");
|
|
openable.close();
|
|
},
|
|
[openable],
|
|
);
|
|
|
|
return (
|
|
<DropdownMenu
|
|
options={filteredOptions}
|
|
openable={openable}
|
|
onSelect={handleSelectOption}
|
|
selectedOptions={selectedOption ? [selectedOption] : []}
|
|
>
|
|
<div className={classes["root"]}>
|
|
{label && (
|
|
<Typography className={classes["label"]} typo={ETypo.TEXT_MD_REGULAR} color={ETypoColor.CONTRAST_DEFAULT}>
|
|
{label}
|
|
</Typography>
|
|
)}
|
|
</div>
|
|
<SearchBar
|
|
placeholder={placeholder}
|
|
disabled={disabled}
|
|
onChange={handleSearchChange}
|
|
value={searchValue}
|
|
onClear={() => setSelectedOption(null)}
|
|
onFocus={openable.open}
|
|
/>
|
|
</DropdownMenu>
|
|
);
|
|
}
|