import MaterialIcons from "@expo/vector-icons/MaterialIcons"; import { useState, useEffect, type ReactNode } from "react"; import { styles } from "@/styles/components/select"; import CheckBox from "@/components/CheckBox"; import { Text, View, TouchableOpacity, FlatList, Modal, type DimensionValue, } from "react-native"; export interface SelectProps { data: Array<{ label: string; value: string; [key: string]: string | number | boolean | null; }>; placeholder: string; onSelect: (selectedItem: SelectProps["data"], id?: SelectProps["id"]) => void; showScrollIndicator?: boolean; disabled?: boolean; defaultValue?: SelectProps["data"][0]; defaultValues?: SelectProps["data"]; maxHeight?: number; multiple?: boolean; renderSelectedItem?: ( item: SelectProps["data"][0], key: string, ) => ReactNode | string; renderItem?: ( item: SelectProps["data"][0], closeSelect: () => void, ) => ReactNode; id?: string; width?: DimensionValue; margin?: { top?: DimensionValue; bottom?: DimensionValue; left?: DimensionValue; right?: DimensionValue; }; title?: string; description?: string; } export default function Select({ data, placeholder, showScrollIndicator, defaultValue, onSelect, defaultValues, disabled = false, maxHeight = 200, multiple = false, width, title, description, margin = {}, renderSelectedItem = (item, key) => ( {item.label} ), renderItem = (item) => {item.label}, id, }: SelectProps) { const [selectedItems, setSelectedItems] = useState( getDefaultValues(), ); const [isOpen, setIsOpen] = useState(false); /* biome-ignore lint/correctness/useExhaustiveDependencies: this hook has to update the default values when they are changed, and those values are used in the function it uses */ useEffect(() => { setSelectedItems(getDefaultValues()); }, [defaultValue, defaultValues, multiple]); function getDefaultValues(): SelectProps["data"] { if (multiple) { if (defaultValues) return defaultValues; if (defaultValue) return [defaultValue]; return []; } if (defaultValue) return [defaultValue]; if (defaultValues?.length) return [defaultValues[0]]; return []; } function handleSelect(item: SelectProps["data"][0], index: number) { if (multiple) { setSelectedItems((prevItems) => { const isSelected = prevItems.some( (selectedItem) => selectedItem.value === item.value, ); if (isSelected) { return prevItems.filter( (selectedItem) => selectedItem.value !== item.value, ); } return [...prevItems, item]; }); } else { setSelectedItems([item]); setIsOpen(false); onSelect([item], id); } } return ( {title && ( <> {title} {description && ( {description} )} )} { const open = !isOpen; setIsOpen(open); if (!open) onSelect(selectedItems, id); }} disabled={disabled} > {selectedItems.length ? ( selectedItems.map((item) => ( {renderSelectedItem(item, item.value)} )) ) : ( {placeholder} )} {isOpen && ( { setIsOpen(false); onSelect(selectedItems, id); }} > { setIsOpen(false); onSelect(selectedItems, id); }} > index.toString()} showsVerticalScrollIndicator={showScrollIndicator} renderItem={({ item, index }) => ( selectedItem.value === item.value, ) && styles.menuItemSelected), }} onPress={() => handleSelect(item, index)} > {multiple && ( selectedItem.value === item.value, )} onValueChange={() => handleSelect(item, index)} /> )} {renderItem(item, () => { setIsOpen(false); })} )} /> )} ); }