127 lines
3.3 KiB
TypeScript
127 lines
3.3 KiB
TypeScript
import { useMemo, useState } from 'react';
|
|
|
|
import {
|
|
Flex,
|
|
Input,
|
|
InputGroup,
|
|
InputRightElement,
|
|
Spinner,
|
|
Tag,
|
|
TagCloseButton,
|
|
TagLabel,
|
|
Wrap,
|
|
WrapItem,
|
|
} from '@chakra-ui/react';
|
|
import { MdSearch } from 'react-icons/md';
|
|
|
|
import {
|
|
FormSelectList,
|
|
SelectMultipleValueDisplayType,
|
|
} from '@/components/form/FormSelectList';
|
|
import { isNullOrUndefined } from '@/utils/validator';
|
|
|
|
export type SelectMultipleProps = {
|
|
options?: object[];
|
|
values?: (number | string)[];
|
|
onChange?: (value: (number | string)[] | undefined) => void;
|
|
keyKey?: string;
|
|
keyValue?: string;
|
|
};
|
|
|
|
export const SelectMultiple = ({
|
|
options,
|
|
onChange,
|
|
values,
|
|
keyKey = 'id',
|
|
keyValue = keyKey,
|
|
}: SelectMultipleProps) => {
|
|
const [showList, setShowList] = useState(false);
|
|
const transformedOption = useMemo(() => {
|
|
return options?.map((element) => {
|
|
return {
|
|
id: element[keyKey],
|
|
name: element[keyValue],
|
|
isSelected: false,
|
|
} as SelectMultipleValueDisplayType;
|
|
});
|
|
}, [options, keyKey, keyValue]);
|
|
const [currentSearch, setCurrentSearch] = useState<string | undefined>(
|
|
undefined
|
|
);
|
|
|
|
const selectedOptions = useMemo(() => {
|
|
if (isNullOrUndefined(values) || !transformedOption) {
|
|
return [];
|
|
}
|
|
return transformedOption.filter((element) => {
|
|
return values.includes(element[keyKey]);
|
|
});
|
|
}, [values, transformedOption]);
|
|
|
|
const selectValue = (data: SelectMultipleValueDisplayType) => {
|
|
const newValues = values?.includes(data.id)
|
|
? values.filter((elem) => data.id !== elem)
|
|
: [...(values ?? []), data.id];
|
|
setShowList(false);
|
|
if (onChange) {
|
|
if (newValues.length == 0) {
|
|
onChange(undefined);
|
|
} else {
|
|
onChange(newValues);
|
|
}
|
|
}
|
|
};
|
|
if (!options) {
|
|
return <Spinner />;
|
|
}
|
|
function onChangeInput(value: string): void {
|
|
if (value === '') {
|
|
setCurrentSearch(undefined);
|
|
} else {
|
|
setCurrentSearch(value);
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Flex direction="column" width="full" gap="0px">
|
|
{selectedOptions && (
|
|
<Wrap spacing="5px" justify="left" width="full" marginBottom="2px">
|
|
{selectedOptions.map((data) => (
|
|
<WrapItem key={data[keyKey]}>
|
|
<Tag
|
|
size="md"
|
|
key="md"
|
|
borderRadius="5px"
|
|
variant="solid"
|
|
backgroundColor="green.500"
|
|
>
|
|
<TagLabel>{data[keyValue] ?? `id=${data[keyKey]}`}</TagLabel>
|
|
<TagCloseButton onClick={() => selectValue(data)} />
|
|
</Tag>
|
|
</WrapItem>
|
|
))}
|
|
</Wrap>
|
|
)}
|
|
<InputGroup minWidth="50%" marginLeft="auto">
|
|
<InputRightElement pointerEvents="none">
|
|
<MdSearch color="gray.300" />
|
|
</InputRightElement>
|
|
<Input
|
|
onChange={(e) => onChangeInput(e.target.value)}
|
|
//onSubmit={onSubmit}
|
|
onFocus={() => setShowList(true)}
|
|
onBlur={() => setTimeout(() => setShowList(false), 200)}
|
|
/>
|
|
</InputGroup>
|
|
{showList && (
|
|
<FormSelectList
|
|
options={transformedOption}
|
|
selected={selectedOptions}
|
|
search={currentSearch}
|
|
onSelectValue={selectValue}
|
|
/>
|
|
)}
|
|
</Flex>
|
|
);
|
|
};
|