import React, { useCallback, useState } from "react"; import { View, ScrollView, Pressable, TextInput, ActivityIndicator, RefreshControl, } from "react-native"; import { useFocusEffect } from "expo-router"; import { useSirouRouter } from "@sirou/react-native"; import { AppRoutes } from "@/lib/routes"; import { api } from "@/lib/api"; import { Text } from "@/components/ui/text"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { FileText, Plus, Search } from "@/lib/icons"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { StandardHeader } from "@/components/StandardHeader"; import { EmptyState } from "@/components/EmptyState"; import { useColorScheme } from "nativewind"; import { getPlaceholderColor } from "@/lib/colors"; const STATUSES = ["All", "Draft", "Pending", "Paid", "Overdue", "Cancelled"]; export default function InvoicesTabScreen() { const nav = useSirouRouter(); const { colorScheme } = useColorScheme(); const isDark = colorScheme === "dark"; const [activeFilter, setActiveFilter] = useState("All"); const [allInvoices, setAllInvoices] = useState([]); const [loading, setLoading] = useState(false); const [refreshing, setRefreshing] = useState(false); const [page, setPage] = useState(1); const [hasMore, setHasMore] = useState(true); const [loadingMore, setLoadingMore] = useState(false); const [search, setSearch] = useState(""); const fetchPage = useCallback(async (pageNum: number, replace = false) => { try { pageNum === 1 && !replace ? setLoading(true) : setLoadingMore(true); const response = await api.invoices.getAll({ query: { page: pageNum, limit: 10 }, }); const newInvoices = response.data || []; setAllInvoices((prev) => replace || pageNum === 1 ? newInvoices : [...prev, ...newInvoices], ); setHasMore(response.meta?.hasNextPage ?? false); setPage(pageNum); } catch (err) { console.error("[Invoices] Fetch error:", err); } finally { setLoading(false); setRefreshing(false); setLoadingMore(false); } }, []); useFocusEffect( useCallback(() => { fetchPage(1, true); }, [fetchPage]), ); const onRefresh = () => { setRefreshing(true); fetchPage(1, true); }; const loadMore = () => { if (hasMore && !loadingMore && !loading) { fetchPage(page + 1); } }; const filteredInvoices = useCallback(() => { let list = allInvoices; if (activeFilter !== "All") { list = list.filter( (inv) => inv.status?.toUpperCase() === activeFilter.toUpperCase(), ); } if (search.trim()) { const q = search.toLowerCase(); const searchNum = parseFloat(q); list = list.filter((inv) => { if (inv.customerName?.toLowerCase().includes(q)) return true; if (inv.invoiceNumber?.toLowerCase().includes(q)) return true; const invAmount = typeof inv.amount === "object" ? parseFloat(inv.amount.value) : parseFloat(inv.amount); if (!isNaN(searchNum) && !isNaN(invAmount)) { if (invAmount === searchNum) return true; if (String(invAmount).includes(q)) return true; } return false; }); } return list; }, [allInvoices, activeFilter, search]); const getStatusStyle = (status: string) => { switch (status?.toUpperCase()) { case "PAID": return "bg-emerald-500/15 text-emerald-700 border-emerald-200"; case "PENDING": return "bg-amber-500/15 text-amber-700 border-amber-200"; case "DRAFT": return "bg-muted text-muted-foreground border-border"; case "OVERDUE": return "bg-red-500/15 text-red-700 border-red-200"; case "CANCELLED": return "bg-muted text-muted-foreground border-border"; default: return "bg-muted text-muted-foreground border-border"; } }; if (loading && allInvoices.length === 0) { return ( ); } return ( } contentContainerStyle={{ paddingBottom: 150 }} onScroll={({ nativeEvent }) => { const isCloseToBottom = nativeEvent.layoutMeasurement.height + nativeEvent.contentOffset.y >= nativeEvent.contentSize.height - 20; if (isCloseToBottom) loadMore(); }} scrollEventThrottle={400} > {/* Search */} {/* Create button */} {/* Filters */} {allInvoices.length > 0 && ( {STATUSES.map((s) => ( setActiveFilter(s)} className={`rounded-[4px] px-4 py-1.5 ${ activeFilter === s ? "bg-primary" : "bg-card border border-border" }`} > {s} ))} )} {filteredInvoices().length > 0 ? ( {filteredInvoices().map((inv: any) => ( nav.go("invoices/[id]", { id: inv.id })} > {inv.customerName || "Unknown"} {inv.issueDate ? new Date(inv.issueDate).toLocaleDateString() : ""} {inv.invoiceNumber ? ` ยท ${inv.invoiceNumber}` : ""} {inv.currency || ""} {Number(inv.amount || 0).toLocaleString()} {inv.status || "DRAFT"} ))} {hasMore && ( {loadingMore ? ( ) : ( Load More )} )} ) : ( )} ); }