import React, { useRef, useCallback, useState, useMemo } from 'react'; import { Button, useDisclosure, Box, Flex, useOutsideClick, Checkbox } from '@chakra-ui/react'; import { ListItemType, MultipleArraySelectProps, MultipleSelectProps } from './type'; import EmptyTip from '../EmptyTip'; import { useTranslation } from 'next-i18next'; import MyIcon from '../../common/Icon'; export const MultipleRowSelect = ({ placeholder, label, value = [], list, emptyTip, maxH = 300, onSelect, popDirection = 'bottom', styles, changeOnEverySelect = false }: MultipleSelectProps) => { const { t } = useTranslation(); const ref = useRef(null); const { isOpen, onOpen, onClose } = useDisclosure(); const [cloneValue, setCloneValue] = useState(value); useOutsideClick({ ref: ref, handler: onClose }); const RenderList = useCallback( ({ index, list }: { index: number; list: MultipleSelectProps['list'] }) => { const selectedValue = cloneValue[index]; const selectedIndex = list.findIndex((item) => item.value === selectedValue); const children = list[selectedIndex]?.children || []; const hasChildren = list.some((item) => item.children && item.children?.length > 0); return ( <> {list.map((item) => ( { const newValue = [...cloneValue]; if (item.value === selectedValue) { for (let i = index; i < newValue.length; i++) { newValue[i] = undefined; } setCloneValue(newValue); onSelect(newValue); } else { newValue[index] = item.value; setCloneValue(newValue); if (changeOnEverySelect || !hasChildren) { onSelect(newValue); } if (!hasChildren) { onClose(); } } }} {...(item.value === selectedValue ? { color: 'primary.600' } : {})} > {item.label} ))} {list.length === 0 && ( )} {children.length > 0 && } ); }, [cloneValue] ); const onOpenSelect = useCallback(() => { setCloneValue(Array.isArray(value) ? value : []); onOpen(); }, [value, onOpen]); return ( {isOpen && ( )} ); }; export const MultipleRowArraySelect = ({ placeholder, label, value = [], list, emptyTip, maxH = 300, onSelect, popDirection = 'bottom', styles }: MultipleArraySelectProps) => { const { t } = useTranslation(); const ref = useRef(null); const { isOpen, onOpen, onClose } = useDisclosure(); const [navigationPath, setNavigationPath] = useState([]); // Make sure the value is an array of arrays const formatValue = useMemo(() => { return Array.isArray(value) ? value.filter((v) => Array.isArray(v)) : []; }, [value]); // Close when clicking outside useOutsideClick({ ref: ref, handler: onClose }); const onChange = useCallback( (val: any[][]) => { // Filter invalid value const validList = val.filter((item) => { const listItem = list.find((v) => v.value === item[0]); if (!listItem) return false; return listItem.children?.some((v) => v.value === item[1]); }); onSelect(validList); }, [onSelect] ); const RenderList = useCallback( ({ index, list }: { index: number; list: MultipleSelectProps['list'] }) => { const currentNavValue = navigationPath[index]; const selectedIndex = list.findIndex((item) => item.value === currentNavValue); const children = list[selectedIndex]?.children || []; const hasChildren = list.some((item) => item.children && item.children?.length > 0); const handleSelect = (item: ListItemType) => { // Has children, set parent value if (hasChildren) { const newPath = [...navigationPath]; newPath[index] = item.value; setNavigationPath(newPath); } else { const parentValue = navigationPath[0]; const newValues = [...formatValue]; const newValue = [parentValue, item.value]; if (newValues.some((v) => v[0] === parentValue && v[1] === item.value)) { onChange(newValues.filter((v) => !(v[0] === parentValue && v[1] === item.value))); } else { onChange([...newValues, newValue]); } } }; return ( <> {list.map((item) => { const isSelected = item.value === currentNavValue; const showCheckbox = !hasChildren; const isChecked = showCheckbox && formatValue.some((v) => v[1] === item.value && v[0] === navigationPath[0]); return ( handleSelect(item)} {...(isSelected ? { color: 'primary.600' } : {})} > {showCheckbox && } {item.label} ); })} {list.length === 0 && ( )} {children.length > 0 && } ); }, [navigationPath, formatValue, onSelect] ); const onOpenSelect = useCallback(() => { setNavigationPath([]); onOpen(); }, []); return ( {isOpen && ( )} ); }; export default React.memo(MultipleRowSelect);