import { useEffect, useState, useCallback, useMemo } from "react"; import { View, Text, FlatList } from "react-native"; import { useLocalSearchParams, router } from "expo-router"; import { ActivityIndicator } from "react-native-paper"; import { useAppSelector } from "@/store/hooks"; import { selectIsMobile } from "@/store/screen/screenSizeSlice"; import { SearchResult, useGlobalSearchQuery } from "@/store/api/searchApi"; import { SearchBar } from "@/components/ui/SearchBar"; import { SizeEnum } from "@/constants/sizeEnum"; import { ResultRow } from "@/components/features/search/ResultRow"; import { normalizeEnumLike } from "@/utils/formattingUtils"; import { useDebounce } from "@/hooks/useDebounce"; import { Button } from "@/components/ui/Button"; const SearchPage = () => { const params = useLocalSearchParams<{ q?: string }>(); const [q, setQ] = useState(params.q ?? ""); const isMobile = useAppSelector(selectIsMobile); useEffect(() => { setQ(params.q ?? ""); }, [params.q]); const debouncedQ = useDebounce(q, 300); const [limit] = useState(100); const { data, isFetching, isLoading, isError } = useGlobalSearchQuery( { q: debouncedQ, page: 1, limit }, { skip: !debouncedQ || debouncedQ.trim().length < 2, refetchOnMountOrArgChange: true, refetchOnFocus: true, } ); const results = useMemo(() => data?.results ?? [], [data?.results]); const [expandedIds, setExpandedIds] = useState>({}); const toggleExpanded = useCallback((id: string) => { setExpandedIds((prev) => ({ ...prev, [id]: !prev[id] })); }, []); const isExpanded = useCallback( (id: string) => !!expandedIds[id], [expandedIds] ); // Reset expansions when new query results arrive useEffect(() => { if (data?.results) setExpandedIds({}); }, [debouncedQ, data?.results]); // Update route param only after debounce useEffect(() => { router.setParams({ q: debouncedQ || "" }); }, [debouncedQ]); // Preprocess heavy formatting outside render const formattedResults = useMemo( () => results.map((item) => ({ ...item, subtitle: item.subtitle ? normalizeEnumLike(item.subtitle) : null, description: item.description ? normalizeEnumLike(item.description) : null, createdAtFormatted: item.createdAt ? new Date(item.createdAt).toLocaleString() : null, })), [results] ); const renderResult = useCallback( ({ item }: { item: SearchResult }) => ( ), [isExpanded, toggleExpanded] ); return ( {isMobile && ( )} {!q || q.trim().length < 2 ? ( Start typing to search. ) : isLoading && results.length === 0 ? ( ) : isError && results.length === 0 ? ( Search failed. Please try again. ) : ( Results: {results.length} `${item.type}-${item.id}`} renderItem={renderResult} contentContainerStyle={{ paddingBottom: 16 }} ItemSeparatorComponent={() => } /> {isFetching && ( )} )} ); }; export default SearchPage;