import React, { useCallback, useEffect, useRef, useState } from "react"; import { View, Text, TouchableOpacity, ActivityIndicator, LayoutAnimation, useColorScheme, } from "react-native"; import { Ionicons } from "@expo/vector-icons"; import { Entry, entriesApi } from "@/services/api"; import ExpandableItem from "./ExpandableItem"; export interface CollapsibleCategoryProps { id: string; label: string; icon: keyof typeof Ionicons.glyphMap; color: string; darkColor: string; groupName: string; refreshKey?: number; } export default function CollapsibleCategory({ label, icon, color, darkColor, groupName, refreshKey = 0, }: CollapsibleCategoryProps) { const dark = useColorScheme() === "dark"; const accentColor = dark ? darkColor : color; const [open, setOpen] = useState(); const [items, setItems] = useState([]); const [page, setPage] = useState(0); const [hasMore, setHasMore] = useState(true); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); // Stable fetch — won't re-create when loading changes const loadingRef = useRef(false); const fetchPage = useCallback(async (pageNum: number) => { if (loadingRef.current) return; loadingRef.current = true; setLoading(true); setError(""); try { const data = await entriesApi.getEntries({ groupName, page: pageNum }); setItems((prev) => pageNum === 0 ? data.content : [...prev, ...data.content] ); setHasMore(!data.last); setPage(pageNum); } catch { setError("Couldn't load entries. Tap to retry."); } finally { loadingRef.current = false; setLoading(false); } }, [groupName]); // Fetch page 0 on mount AND whenever refreshKey changes useEffect(() => { setItems([]); setPage(0); setHasMore(true); setError(""); fetchPage(0); }, [refreshKey]); // refreshKey bump = full reset const toggle = () => { LayoutAnimation.configureNext({ duration: 260, create: { type: "easeInEaseOut", property: "opacity" }, update: { type: "spring", springDamping: 0.85 }, }); // @ts-ignore bla bla bla setOpen((v) => !v); }; return ( {/* ── Header ── */} {label} {/* Count badge — spinner while loading first page */} {loading && items.length === 0 ? ( ) : ( {items.length} )} {/* Body */} {open && ( {/* Error with retry */} {error !== "" && ( fetchPage(page)} className="mx-4 py-4 items-center" > {error} )} {items.map((item) => ( ))} {/* Load more */} {hasMore && items.length > 0 && ( fetchPage(page + 1)} disabled={loading} className={`mx-4 mt-1 mb-1 py-3 rounded-2xl border items-center ${dark ? "bg-obsidian-50 border-border-dark" : "bg-parchment-100 border-border-light" }`} activeOpacity={0.7} > {loading ? ( ) : ( Load more )} )} {!hasMore && items.length > 0 && ( All {items.length} entries loaded )} )} ); }