import React, { useRef, useState, useCallback } from 'react'; import { View, Text, TouchableOpacity, StyleSheet, StyleProp, ViewStyle, FlatList, TextInput, Dimensions, Platform } from 'react-native'; import ActionSheet, { ActionSheetRef } from 'react-native-actions-sheet'; import ChevronIcon from 'assets/icons/travels-screens/down-arrow.svg'; import { Colors } from 'src/theme'; import CloseSvg from 'assets/icons/close.svg'; import CheckSvg from 'assets/icons/mark.svg'; export interface SelectSheetProps> { data: T[]; labelField: keyof T; valueField: keyof T; value?: T[keyof T] | null; onChange: (item: T) => void; placeholder?: string; searchable?: boolean; searchPlaceholder?: string; disabled?: boolean; style?: StyleProp; renderItem?: (item: T, isSelected: boolean) => React.ReactNode; name?: string; hideTitle?: boolean; initialSnapPoint?: number; } export const SelectSheet = >({ data, labelField, valueField, value, onChange, placeholder = 'Select...', searchable = false, searchPlaceholder = 'Search...', disabled = false, style, renderItem, name, hideTitle = false, initialSnapPoint = 70 }: SelectSheetProps) => { const sheetRef = useRef(null); const [query, setQuery] = useState(''); const selectedItem = value != null ? data.find((item) => item[valueField] === value) : null; const filteredData = searchable && query.trim() ? data.filter((item) => String(item[labelField]).toLowerCase().includes(query.toLowerCase())) : data; const handleSelect = useCallback( (item: T) => { sheetRef.current?.hide(); onChange(item); }, [onChange] ); const handleOpen = useCallback(() => { if (disabled) return; setQuery(''); sheetRef.current?.show(); }, [disabled]); return ( <> {selectedItem ? String(selectedItem[labelField]) : placeholder} setQuery('')} > sheetRef.current?.hide()} style={[styles.closeBtnAlone, Platform.OS === 'ios' ? { paddingTop: 6 } : {}]} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} > {!hideTitle && ( {placeholder} )} {searchable && ( )} String(item[valueField] ?? i)} keyboardShouldPersistTaps="handled" style={styles.list} contentContainerStyle={styles.listContent} initialNumToRender={20} renderItem={({ item }: { item: T }) => { const isSelected = item[valueField] === value; if (renderItem) { return ( handleSelect(item)} activeOpacity={0.7}> {renderItem(item, isSelected)} ); } return ( handleSelect(item)} activeOpacity={0.7} > {String(item[labelField])} {isSelected && ( )} ); }} /> ); }; const styles = StyleSheet.create({ trigger: { height: 40, backgroundColor: Colors.FILL_LIGHT, borderRadius: 8, paddingHorizontal: 12, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }, triggerDisabled: { opacity: 0.5 }, triggerText: { flex: 1, fontSize: 15, color: Colors.DARK_BLUE, marginRight: 6 }, placeholderText: { color: Colors.TEXT_GRAY }, sheetContent: { height: Dimensions.get('window').height * 0.9, backgroundColor: Colors.WHITE, borderTopLeftRadius: 20, borderTopRightRadius: 20, overflow: 'hidden' }, sheetContainer: { height: '90%', backgroundColor: Colors.WHITE, borderTopLeftRadius: 20, borderTopRightRadius: 20 }, indicator: { width: 44, height: 5, borderRadius: 3, backgroundColor: Colors.LIGHT_GRAY, marginTop: 8 }, searchWrapper: { paddingHorizontal: 16, paddingVertical: 12 }, searchInput: { height: 44, backgroundColor: Colors.FILL_LIGHT, borderRadius: 6, paddingHorizontal: 16, fontSize: 16, color: Colors.DARK_BLUE }, list: { flex: 1 }, listContent: { paddingBottom: 40, paddingTop: 8 }, option: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 24, paddingVertical: 16 }, optionText: { flex: 1, fontSize: 16, color: Colors.DARK_BLUE }, optionTextSelectedWeight: { fontWeight: '700' }, checkmark: { marginLeft: 12 }, checkmarkText: { fontSize: 18, color: Colors.DARK_BLUE, fontWeight: '700' }, chevron: { marginLeft: 2 }, titleRow: { flexDirection: 'row', alignItems: 'center', borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: Colors.DARK_LIGHT }, sheetTitle: { flex: 1, fontSize: 16, fontWeight: '700', color: Colors.DARK_BLUE, paddingVertical: 12, paddingHorizontal: 24, textAlign: 'center' }, closeBtn: { paddingHorizontal: 16, paddingVertical: 12 }, closeBtnAlone: { alignSelf: 'flex-end', paddingHorizontal: 16, paddingTop: 16 } });