import BottomSheet, { BottomSheetBackdrop, BottomSheetBackdropProps, BottomSheetFlashList, } from "@gorhom/bottom-sheet"; import React, { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useRef, useState, } from "react"; import { Pressable, Text, View } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import Ionicon from "@expo/vector-icons/Ionicons"; import { IoniconsType } from "../../lib/types"; import { ListRenderItemInfo } from "@shopify/flash-list"; import { Input } from "./Input"; import { useDebounce } from "../../hooks/useDebounce"; import { StatusBar } from "expo-status-bar"; export interface CustomBottomSheetHandle { showSheet: () => void; hideSheet: () => void; isVisible: () => boolean; } export type CustomBottomSheetProps = { defaultOpen?: boolean; children: React.ReactNode; snapPoints?: (number | string)[]; handleSheetClose?: (index: number) => void; topInset?: number; bottomInset?: number; }; export const CustomBottomSheet = forwardRef< CustomBottomSheetHandle, CustomBottomSheetProps >( ( { children, snapPoints = ["50%"], handleSheetClose, defaultOpen = false, topInset, bottomInset, }, ref ) => { const sheetRef = useRef(null); const [isVisible, setIsVisible] = useState(defaultOpen); useImperativeHandle( ref, () => ({ showSheet() { setIsVisible(true); sheetRef.current?.snapToIndex(0); }, hideSheet() { setIsVisible(false); sheetRef.current?.close(); }, isVisible() { return isVisible; }, }), [setIsVisible] ); const renderBackdrop = useCallback( (props: BottomSheetBackdropProps) => ( sheetRef.current?.close()} /> ), [] ); const handleSheetChange = useCallback( (index: number) => { if ((index !== -1) !== isVisible) { setIsVisible(index !== -1); } if (index === -1 && handleSheetClose) { handleSheetClose(index); } }, [handleSheetClose] ); const insets = useSafeAreaInsets(); if (!isVisible) return null; return ( {children} ); } ); export function CustomBottomSheetTitle({ title, subTitle, }: { title: string; subTitle: string; }) { return ( <> {title} {subTitle} ); } export type CustomBottomSheetSelectItemType = { icon?: IoniconsType; iconContent?: React.ReactNode; name: string; descriptionContent?: React.ReactNode; description?: string; id: string; }; export const CustomBottomSheetSelectItem = memo( ({ isActive, item, handleOnPress, }: { isActive: boolean; item: CustomBottomSheetSelectItemType; handleOnPress: (id: string) => void; }) => { return ( handleOnPress(item.id)} className="h-16 flex-row items-center" > {item.iconContent || (item.icon && ( ))} {item.name} {item.descriptionContent || (item.description && ( {item.description} ))} {isActive && ( )} ); } ); export function CustomBottomSheetSelect({ activeItem, items, handleOnPress, searchable, }: { activeItem?: string; items: CustomBottomSheetSelectItemType[]; handleOnPress: (id: string) => void; searchable?: boolean; }) { const [searchInput, setSearchInput] = useState(""); const searchInputDelay = useDebounce(searchInput, 500); const filteredItems = useMemo( () => items.filter((i) => i.name.includes(searchInput)), [searchInputDelay] ); const keyExtractor = useCallback((item: { id: string }) => item.id, []); const renderItem = useCallback( ({ item }: ListRenderItemInfo) => ( ), [activeItem, handleOnPress] ); return ( <> {searchable && ( )} ); }