import React, { useCallback, useState } from "react"; import { CommandPalette } from "@/components/CommandPalette"; import { View, ScrollView, Pressable, ActivityIndicator, RefreshControl, Image, } from "react-native"; import { useFocusEffect } from "expo-router"; import { api, newsApi } from "@/lib/api"; import { Text } from "@/components/ui/text"; import { Card } from "@/components/ui/card"; import { useSirouRouter } from "@sirou/react-native"; import { AppRoutes } from "@/lib/routes"; import { Clock, DollarSign, FileText, ShieldCheck, Receipt, Wallet, ChevronRight, AlertTriangle, Banknote, FileCheck, } from "@/lib/icons"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { StandardHeader } from "@/components/StandardHeader"; import { EmptyState } from "@/components/EmptyState"; import { useAuthStore } from "@/lib/auth-store"; import { getProviderLogo, isCash } from "@/lib/payment-providers"; interface NewsItem { id: string; title: string; content: string; category: "ANNOUNCEMENT" | "UPDATE" | "MAINTENANCE" | "NEWS"; priority: "LOW" | "MEDIUM" | "HIGH"; publishedAt: string; viewCount: number; } interface Payment { id: string; transactionId: string; amount: number; currency: string; paymentDate: string; paymentMethod: string; isFlagged: boolean; senderName?: string; receiverName?: string; userId: string; invoiceId?: string; createdAt: string; updatedAt: string; } export default function HomeScreen() { const [stats, setStats] = useState({ total: 0, paid: 0, pending: 0, overdue: 0, totalRevenue: 0, }); const [recentPayments, setRecentPayments] = useState([]); const [newsItems, setNewsItems] = useState([]); const [loadingPayments, setLoadingPayments] = useState(false); const [loadingNews, setLoadingNews] = useState(false); const [refreshing, setRefreshing] = useState(false); const [searchOpen, setSearchOpen] = useState(false); const nav = useSirouRouter(); useFocusEffect( useCallback(() => { fetchStats(); fetchRecentPayments(); fetchNews(); }, []), ); const fetchStats = async () => { const { isAuthenticated } = useAuthStore.getState(); if (!isAuthenticated) return; try { const data = await api.invoices.stats(); setStats(data); } catch (e) { console.error("[HomeScreen] Failed to fetch stats:", e); } }; const fetchRecentPayments = async () => { const { isAuthenticated } = useAuthStore.getState(); if (!isAuthenticated) return; setLoadingPayments(true); try { const response = await api.payments.getAll({ query: { page: 1, limit: 5 }, }); setRecentPayments(response.data || []); } catch (e) { console.error("[HomeScreen] Failed to fetch payments:", e); } finally { setLoadingPayments(false); } }; const fetchNews = async () => { const { isAuthenticated } = useAuthStore.getState(); if (!isAuthenticated) return; setLoadingNews(true); try { const service = newsApi || api.news; const data = await service.getLatest({ query: { limit: 5 } }); setNewsItems(data || []); } catch (e) { console.error("[HomeScreen] Failed to fetch news:", e); } finally { setLoadingNews(false); } }; const onRefresh = async () => { setRefreshing(true); await Promise.all([fetchStats(), fetchRecentPayments(), fetchNews()]); }; const getCategoryColor = (category: string) => { switch (category) { case "ANNOUNCEMENT": return "bg-amber-500"; case "UPDATE": return "bg-blue-500"; case "MAINTENANCE": return "bg-red-500"; default: return "bg-emerald-500"; } }; const formatAmount = (pay: Payment) => { const val = typeof pay.amount === "object" ? (pay.amount as any).value : pay.amount; return `${pay.currency || "ETB"} ${(val || 0).toLocaleString()}`; }; return ( } contentContainerStyle={{ paddingTop: 10, paddingBottom: 150 }} > setSearchOpen(true)} /> {/* ── Balance Card + Quick Actions ── */} Available Balance ETB {stats.total.toLocaleString()} Pending ETB {stats.pending.toLocaleString()} Income ETB {stats.totalRevenue.toLocaleString()} {/* Quick Actions integrated into card */} } label="Proforma" onPress={() => nav.go("proforma")} /> } label="Receipt" onPress={() => nav.go("add-receipt")} /> } label="Verify" onPress={() => nav.go("verify-payment")} /> } label="Declaration" onPress={() => nav.go("declarations/index")} /> {/* ── Recent Payments ── */} Recent Payments {recentPayments.length > 0 && ( nav.go("(tabs)/payments")} className="flex-row items-center" > View More )} {loadingPayments ? ( ) : recentPayments.length > 0 ? ( {recentPayments.map((pay) => { const dateStr = new Date( pay.paymentDate, ).toLocaleDateString(); const logo = getProviderLogo(pay.paymentMethod); const cash = isCash(pay.paymentMethod); const hasFlag = pay.isFlagged; return ( nav.go("payments/[id]", { id: pay.id })} > {logo ? ( ) : ( {hasFlag ? ( ) : cash ? ( ) : ( )} )} {formatAmount(pay)} {hasFlag && ( Flagged )} {pay.paymentMethod} · {pay.senderName} · {dateStr} {!hasFlag && ( )} ); })} ) : ( )} {/* ── News Section ── */} News & Updates {newsItems.length > 0 && ( nav.go("news/index")} className="flex-row items-center" > View More )} {loadingNews ? ( ) : newsItems.length > 0 ? ( {newsItems.map((item) => ( nav.go("news/[id]", { id: item.id })} > {item.category} {new Date(item.publishedAt).toLocaleDateString()} {item.title} {item.content} ))} ) : ( )} setSearchOpen(false)} /> ); } function QuickActionInline({ icon, label, onPress, }: { icon: React.ReactNode; label: string; onPress?: () => void; }) { return ( {icon} {label} ); }