import React, { useState, useCallback, useMemo } from "react"; import { View, ScrollView, ActivityIndicator, Pressable, TextInput, Modal, Dimensions, } from "react-native"; import { useSirouRouter } from "@sirou/react-native"; import { AppRoutes } from "@/lib/routes"; import { Stack, useLocalSearchParams, useFocusEffect } from "expo-router"; import { Text } from "@/components/ui/text"; import { User, Building2, Mail, Phone, MapPin, Hash, Tag, ShieldCheck, BookOpen, FileText, Wallet, Plus, Search, X, } from "@/lib/icons"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { StandardHeader } from "@/components/StandardHeader"; import { api } from "@/lib/api"; import { toast } from "@/lib/toast-store"; import { useColorScheme } from "nativewind"; const { height: SCREEN_HEIGHT } = Dimensions.get("window"); export default function CustomerDetailScreen() { const nav = useSirouRouter(); const { id } = useLocalSearchParams(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [proformaItems, setProformaItems] = useState([]); const [paymentRequestItems, setPaymentRequestItems] = useState([]); const [showProformaSheet, setShowProformaSheet] = useState(false); const [showPaymentRequestSheet, setShowPaymentRequestSheet] = useState(false); const [sheetLoading, setSheetLoading] = useState(false); const [proformaSearch, setProformaSearch] = useState(""); const [paymentReqSearch, setPaymentReqSearch] = useState(""); const fetch = useCallback(async () => { try { setLoading(true); const cId = Array.isArray(id) ? id[0] : id; if (!cId) return; const response = await api.customers.getById({ params: { id: cId } }); setData(response || null); } catch { toast.error("Error", "Failed to load customer"); setData(null); } finally { setLoading(false); } }, [id]); useFocusEffect(useCallback(() => { fetch(); }, [fetch])); const openProformaSheet = async () => { setSheetLoading(true); setShowProformaSheet(true); setProformaSearch(""); try { const res = await api.proforma.getAll({ query: { page: 1, limit: 50 } }); setProformaItems(res?.data || []); } catch { setProformaItems([]); } finally { setSheetLoading(false); } }; const openPaymentRequestSheet = async () => { setSheetLoading(true); setShowPaymentRequestSheet(true); setPaymentReqSearch(""); try { const res = await api.paymentRequests.getAll({ query: { page: 1, limit: 50 } }); setPaymentRequestItems(res?.data || []); } catch { setPaymentRequestItems([]); } finally { setSheetLoading(false); } }; const filteredProformas = useMemo(() => { if (!proformaSearch.trim()) return proformaItems; const q = proformaSearch.toLowerCase(); return proformaItems.filter( (p: any) => (p.proformaNumber || "")?.toLowerCase().includes(q) || (p.customerName || "")?.toLowerCase().includes(q) || (String(p.amount || "")).includes(q), ); }, [proformaItems, proformaSearch]); const filteredPaymentRequests = useMemo(() => { if (!paymentReqSearch.trim()) return paymentRequestItems; const q = paymentReqSearch.toLowerCase(); return paymentRequestItems.filter( (r: any) => (r.paymentRequestNumber || "")?.toLowerCase().includes(q) || (r.customerName || "")?.toLowerCase().includes(q) || (String(r.amount || "")).includes(q), ); }, [paymentRequestItems, paymentReqSearch]); if (loading) { return ( ); } if (!data) { return ( Failed to load customer details. Retry ); } const isCompany = data?.type === "COMPANY"; const d = data || {}; const goProformaCreate = () => nav.go("proforma/create"); const goPaymentRequestCreate = () => nav.go("payment-requests/create"); return ( {/* Identity Header */} {isCompany ? ( ) : ( )} {d.displayName || "—"} {isCompany ? "Company" : "Individual"} Created {d.createdAt ? new Date(d.createdAt).toLocaleDateString() : "—"} {/* Contact */} {(d.email || d.phone) && ( Contact } label="Email" value={d.email} /> {d.email && d.phone ? : null} } label="Phone" value={d.phone} /> )} {/* Identity Details */} {(d.firstName || d.lastName || d.companyName) && ( Identity Details {isCompany ? ( } label="Company Name" value={d.companyName} /> ) : ( <> } label="First Name" value={d.firstName} /> {d.firstName && d.lastName ? : null} } label="Last Name" value={d.lastName} /> )} )} {/* Documents */} {(d.tin || d.vatRegistrationNumber || d.businessLicenseNumber) && ( Documents } label="TIN Number" value={d.tin} /> {d.tin && d.vatRegistrationNumber ? : null} } label="VAT Registration" value={d.vatRegistrationNumber} /> {(d.tin || d.vatRegistrationNumber) && d.businessLicenseNumber ? : null} } label="Business License" value={d.businessLicenseNumber} /> )} {/* Address */} {d.address && ( Address {d.address} )} {/* Notes */} {d.notes && ( Notes {d.notes} )} {/* Divider */} {/* Action Buttons */} Proformas Payment Requests {/* Proforma Bottom Sheet */} setShowProformaSheet(false)} loading={sheetLoading} items={filteredProformas} search={proformaSearch} onSearchChange={setProformaSearch} onCreateNew={goProformaCreate} onSelectItem={(id: string) => { setShowProformaSheet(false); nav.go("proforma/[id]", { id }); }} /> {/* Payment Request Bottom Sheet */} setShowPaymentRequestSheet(false)} loading={sheetLoading} items={filteredPaymentRequests} search={paymentReqSearch} onSearchChange={setPaymentReqSearch} onCreateNew={goPaymentRequestCreate} onSelectItem={(id: string) => { setShowPaymentRequestSheet(false); nav.go("payment-requests/[id]", { id }); }} type="payment" /> ); } function ProformaSheet({ visible, onClose, loading, items, search, onSearchChange, onCreateNew, onSelectItem, type = "proforma", }: { visible: boolean; onClose: () => void; loading: boolean; items: any[]; search: string; onSearchChange: (v: string) => void; onCreateNew: () => void; onSelectItem: (id: string) => void; type?: "proforma" | "payment"; }) { const { colorScheme } = useColorScheme(); const isDark = colorScheme === "dark"; const label = type === "proforma" ? "Proforma" : "Payment Request"; return ( e.stopPropagation()} > {/* Header */} {label}s {/* Search */} {search.length > 0 && ( onSearchChange("")}> )} {/* Create New */} Create New {label} {/* List */} {loading ? ( ) : items.length === 0 ? ( {search ? `No ${label}s match your search` : `No ${label}s found`} ) : ( items.map((item: any) => { const num = type === "proforma" ? item.proformaNumber : item.paymentRequestNumber; const status = (item.status || "DRAFT").toUpperCase(); const st: Record = { PAID: { label: "Paid", bg: "bg-emerald-500/10", text: "text-emerald-600" }, PENDING: { label: "Pending", bg: "bg-amber-500/10", text: "text-amber-600" }, DRAFT: { label: "Draft", bg: "bg-blue-500/10", text: "text-blue-600" }, CANCELLED: { label: "Cancelled", bg: "bg-slate-500/10", text: "text-slate-600" }, }; const s = st[status] || st.DRAFT; return ( onSelectItem(item.id)} className="bg-card rounded-[6px] border border-border p-4 mb-3" > {num || item.id?.slice(0, 8) || "—"} {item.customerName || "—"} {item.amount != null ? Number(item.amount).toLocaleString("en-US", { minimumFractionDigits: 2 }) : "—"} {s.label} {item.issueDate && ( {new Date(item.issueDate).toLocaleDateString()} )} ); }) )} ); } function InfoRow({ icon, label, value }: { icon: React.ReactNode; label: string; value: string }) { if (!value) return null; return ( {icon} {label} {value} ); }