import { Icon } from '@/components/ui/icon'; import { ScrollView } from '@/components/ui/scroll-view'; import { Text } from '@/components/ui/text'; import { View } from '@/components/ui/view'; import { useColor } from '@/hooks/useColor'; import { BORDER_RADIUS, CORNERS, FONT_SIZE, HEIGHT } from '@/theme/globals'; import { ChevronDown, LucideProps } from 'lucide-react-native'; import React, { useState } from 'react'; import { Modal, Pressable, TextInput, TextStyle, TouchableOpacity, ViewStyle, } from 'react-native'; export interface PickerOption { label: string; value: string; description?: string; disabled?: boolean; } export interface PickerSection { title?: string; options: PickerOption[]; } interface PickerProps { options?: PickerOption[]; sections?: PickerSection[]; value?: string; placeholder?: string; error?: string; variant?: 'outline' | 'filled' | 'group'; onValueChange?: (value: string) => void; disabled?: boolean; style?: ViewStyle; multiple?: boolean; values?: string[]; onValuesChange?: (values: string[]) => void; // Styling props label?: string; icon?: React.ComponentType; rightComponent?: React.ReactNode | (() => React.ReactNode); inputStyle?: TextStyle; labelStyle?: TextStyle; errorStyle?: TextStyle; // Modal props modalTitle?: string; searchable?: boolean; searchPlaceholder?: string; } export function Picker({ options = [], sections = [], value, values = [], error, variant = 'filled', placeholder = 'Select an option...', onValueChange, onValuesChange, disabled = false, style, multiple = false, label, icon, rightComponent, inputStyle, labelStyle, errorStyle, modalTitle, searchable = false, searchPlaceholder = 'Search options...', }: PickerProps) { const [isOpen, setIsOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(''); // Move ALL theme color hooks to the top level const borderColor = useColor('border'); const text = useColor('text'); const muted = useColor('mutedForeground'); const cardColor = useColor('card'); const danger = useColor('red'); const accent = useColor('accent'); const primary = useColor('primary'); const primaryForeground = useColor('primaryForeground'); const input = useColor('input'); const mutedBg = useColor('muted'); const textMutedColor = useColor('textMuted'); // Normalize data structure - convert options to sections format const normalizedSections: PickerSection[] = sections.length > 0 ? sections : [{ options }]; // Filter sections based on search query const filteredSections = searchable && searchQuery ? normalizedSections .map((section) => ({ ...section, options: section.options.filter((option) => option.label.toLowerCase().includes(searchQuery.toLowerCase()) ), })) .filter((section) => section.options.length > 0) : normalizedSections; // Get selected options for display const getSelectedOptions = () => { const allOptions = normalizedSections.flatMap((section) => section.options); if (multiple) { return allOptions.filter((option) => values.includes(option.value)); } else { return allOptions.filter((option) => option.value === value); } }; const selectedOptions = getSelectedOptions(); const handleSelect = (optionValue: string) => { if (multiple) { const newValues = values.includes(optionValue) ? values.filter((v) => v !== optionValue) : [...values, optionValue]; onValuesChange?.(newValues); } else { onValueChange?.(optionValue); setIsOpen(false); } }; const getDisplayText = () => { if (selectedOptions.length === 0) return placeholder; if (multiple) { if (selectedOptions.length === 1) { return selectedOptions[0].label; } return `${selectedOptions.length} selected`; } return selectedOptions[0]?.label || placeholder; }; const triggerStyle: ViewStyle = { width: '100%', flexDirection: 'row', alignItems: 'center', paddingHorizontal: variant === 'group' ? 0 : 16, borderWidth: variant === 'group' ? 0 : 1, borderColor: variant === 'outline' ? borderColor : cardColor, borderRadius: CORNERS, backgroundColor: variant === 'filled' ? cardColor : 'transparent', minHeight: variant === 'group' ? 'auto' : HEIGHT, opacity: disabled ? 0.5 : 1, }; const renderOption = ( option: PickerOption, sectionIndex: number, optionIndex: number ) => { const isSelected = multiple ? values.includes(option.value) : value === option.value; return ( !option.disabled && handleSelect(option.value)} style={{ paddingVertical: 16, paddingHorizontal: 20, borderRadius: CORNERS, backgroundColor: isSelected ? primary : 'transparent', marginVertical: 2, alignItems: 'center', opacity: option.disabled ? 0.3 : 1, }} disabled={option.disabled} > {option.label} {option.description && ( {option.description} )} ); }; return ( <> !disabled && setIsOpen(true)} disabled={disabled} activeOpacity={0.8} > {/* Icon & Label */} {icon && ( )} {label && ( {label} )} 0 ? text : disabled ? muted : error ? danger : muted, }, inputStyle, ]} numberOfLines={1} ellipsizeMode='tail' > {getDisplayText()} {rightComponent ? ( typeof rightComponent === 'function' ? ( rightComponent() ) : ( rightComponent ) ) : ( )} {/* Error message */} {error && ( {error} )} setIsOpen(false)} > setIsOpen(false)} > e.stopPropagation()} > {/* Header */} {(modalTitle || multiple) && ( {modalTitle || 'Select Options'} {multiple && ( setIsOpen(false)}> Done )} )} {/* Search */} {searchable && ( )} {/* Options - Updated to match date-picker styling */} {filteredSections.map((section, sectionIndex) => ( {section.title && ( {section.title} )} {section.options.map((option, optionIndex) => renderOption(option, sectionIndex, optionIndex) )} ))} {filteredSections.every( (section) => section.options.length === 0 ) && ( {searchQuery ? 'No results found' : 'No options available'} )} ); }