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);
})}
)}
/>
)}
);
}