import { BottomSheetBackdrop, BottomSheetBackdropProps, BottomSheetFlatList, BottomSheetModal, BottomSheetScrollView, BottomSheetView, } from "@gorhom/bottom-sheet"; import React, { useCallback, useEffect, useMemo, useRef, useState, } from "react"; import { Text } from "@/components/common/Text"; import { StyleSheet, TouchableOpacity, View, ViewProps } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { Button } from "../Button"; import { Input } from "../common/Input"; interface Props extends ViewProps { open: boolean; setOpen: (open: boolean) => void; data?: T[] | null; values: T[]; set: (value: T[]) => void; title: string; searchFilter: (item: T, query: string) => boolean; renderItemLabel: (item: T) => React.ReactNode; showSearch?: boolean; } const LIMIT = 100; export const FilterSheet = ({ values, data: _data, open, set, setOpen, title, searchFilter, renderItemLabel, showSearch = true, ...props }: Props) => { const bottomSheetModalRef = useRef(null); const snapPoints = useMemo(() => ["80%"], []); const [data, setData] = useState([]); const [offset, setOffset] = useState(0); const [search, setSearch] = useState(""); const filteredData = useMemo(() => { if (!search) return _data; const results = []; for (let i = 0; i < (_data?.length || 0); i++) { if (_data && searchFilter(_data[i], search)) { results.push(_data[i]); } } return results.slice(0, 100); }, [search, _data, searchFilter]); useEffect(() => { if (!_data || _data.length === 0) return; const tmp = new Set(data); for (let i = offset; i < Math.min(_data.length, offset + LIMIT); i++) { tmp.add(_data[i]); } setData(Array.from(tmp)); }, [offset, _data]); useEffect(() => { if (open) bottomSheetModalRef.current?.present(); else bottomSheetModalRef.current?.dismiss(); }, [open]); const handleSheetChanges = useCallback((index: number) => { if (index === -1) { setOpen(false); } }, []); const renderData = useMemo(() => { if (search.length > 0 && showSearch) return filteredData; return data; }, [search, filteredData, data]); const renderBackdrop = useCallback( (props: BottomSheetBackdropProps) => ( ), [] ); return ( {title} {_data?.length} items {showSearch && ( { setSearch(text); }} returnKeyType="done" /> )} {renderData?.map((item, index) => ( <> { set( values.includes(item) ? values.filter((i) => i !== item) : [item] ); setTimeout(() => { setOpen(false); }, 250); }} key={index} className=" bg-neutral-800 px-4 py-3 flex flex-row items-center justify-between" > {renderItemLabel(item)} {values.includes(item) ? ( ) : ( )} ))} {data.length < (_data?.length || 0) && ( )} ); };