import React, { useState, useCallback } from "react"; import { View, ScrollView, ActivityIndicator, Linking, Pressable, Modal, Dimensions, StyleSheet, Image, } 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 { EmptyState } from "@/components/EmptyState"; import { FileText, Calendar, Clock, User, Hash, AlertCircle, Edit, Mail, MessageSquare, MoreVertical, X, Package, Share2, Download, TrendingUp, TrendingDown, Check, Trash2, } from "@/lib/icons"; import { ScreenWrapper } from "@/components/ScreenWrapper"; import { StandardHeader } from "@/components/StandardHeader"; import { api, BASE_URL } from "@/lib/api"; import { toast } from "@/lib/toast-store"; import { useAuthStore } from "@/lib/auth-store"; import { useColorScheme } from "nativewind"; import { ActionModal } from "@/components/ActionModal"; import { SendHorizonal } from "lucide-react-native"; import ticketImage from "@/assets/ticket.png"; const { height: SCREEN_HEIGHT } = Dimensions.get("window"); function safeVal(v: any): number { if (v == null) return 0; if (typeof v === "object") return Number(v.value) || 0; return Number(v) || 0; } function fmt(v: number, currency = "ETB") { return `${currency} ${v.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`; } const STATUS_THEME: Record< string, { label: string; bg: string; text: string; dot: string } > = { PAID: { label: "Paid", bg: "bg-emerald-500/10", text: "text-emerald-600", dot: "bg-emerald-500", }, PENDING: { label: "Pending", bg: "bg-amber-500/10", text: "text-amber-600", dot: "bg-amber-500", }, DRAFT: { label: "Draft", bg: "bg-blue-500/10", text: "text-blue-600", dot: "bg-blue-500", }, CANCELLED: { label: "Cancelled", bg: "bg-slate-500/10", text: "text-slate-600", dot: "bg-slate-500", }, DEFAULT: { label: "Unknown", bg: "bg-slate-500/10", text: "text-slate-500", dot: "bg-slate-500", }, }; export default function ProformaDetailScreen() { const nav = useSirouRouter(); const { id } = useLocalSearchParams(); const { colorScheme } = useColorScheme(); const isDark = colorScheme === "dark"; const [loading, setLoading] = useState(true); const [proforma, setProforma] = useState(null); const [activeTab, setActiveTab] = useState<"details" | "items">("details"); const [showMoreSheet, setShowMoreSheet] = useState(false); const [showSendSheet, setShowSendSheet] = useState(false); const [sharing, setSharing] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); const [deleting, setDeleting] = useState(false); useFocusEffect( useCallback(() => { fetchProforma(); }, [id]), ); const fetchProforma = async () => { try { setLoading(true); const pid = Array.isArray(id) ? id[0] : id; if (!pid) return; const data = await api.proforma.getById({ params: { id: pid } }); setProforma(data); } catch { toast.error("Error", "Failed to load proforma details"); } finally { setLoading(false); } }; const handleGetPdf = async () => { try { const { token } = useAuthStore.getState(); const pid = Array.isArray(id) ? id[0] : id; await Linking.openURL(`${BASE_URL}proforma/${pid}/pdf?token=${token}`); } catch { toast.error("Error", "Failed to open PDF"); } }; const handleShare = async (channel: "email" | "sms") => { try { setSharing(true); const pid = Array.isArray(id) ? id[0] : id; await api.proforma.shareLink({ body: { proformaId: pid, channel } }); toast.success( "Sent", `Proforma shared via ${channel === "email" ? "email" : "SMS"}`, ); setShowSendSheet(false); } catch (err: any) { toast.error("Error", err?.message || "Failed to share proforma"); } finally { setSharing(false); } }; const handleDelete = () => setShowDeleteModal(true); const confirmDelete = async () => { try { setDeleting(true); const pid = Array.isArray(id) ? id[0] : id; await api.proforma.delete({ params: { id: pid } }); toast.success("Deleted", "Proforma has been removed."); setShowDeleteModal(false); nav.back(); } catch (err: any) { toast.error("Error", err?.message || "Failed to delete proforma"); } finally { setDeleting(false); } }; if (loading) { return ( ); } if (!proforma) { return ( Proforma not found. ); } const currency = proforma.currency || "ETB"; const amount = safeVal(proforma.amount); const tax = safeVal(proforma.taxAmount); const discount = safeVal(proforma.discountAmount); const subtotal = amount + discount - tax; const items: any[] = proforma.items || []; const statusKey = (proforma.status || "DRAFT").toUpperCase(); const theme = STATUS_THEME[statusKey] || STATUS_THEME.DEFAULT; const issueDate = proforma.issueDate ? new Date(proforma.issueDate) : null; const dueDate = proforma.dueDate ? new Date(proforma.dueDate) : null; const formatLongDate = (d: Date) => d.toLocaleDateString("en-US", { day: "numeric", month: "short", year: "numeric", }); const customerName = ( proforma.customerName?.replace("Customer Name: ", "") || "Walking Client" ).trim(); const ActionOption = ({ icon, label, description, onPress, destructive, }: { icon: React.ReactNode; label: string; description: string; onPress?: () => void; destructive?: boolean; }) => ( {icon} {label} {description} ); return ( setShowMoreSheet(true)} className="h-10 w-10 rounded-[10px] bg-card items-center justify-center border border-border" > } /> {/* Hero Card — illustration overflows the top */} {amount.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2, })}{" "} {currency} {proforma.proformaNumber ? `Proforma ${proforma.proformaNumber}` : `Proforma #${(proforma.id || "").slice(0, 8).toUpperCase()}`} {/* Status badge */} {theme.label} Issued {issueDate ? formatLongDate(issueDate) : "—"} Due {dueDate ? formatLongDate(dueDate) : "—"} {/* Tabs */} setActiveTab("details")} className="pb-2.5" > Details {activeTab === "details" && ( )} setActiveTab("items")} className="pb-2.5"> Items {activeTab === "items" && ( )} {/* Tab content */} {activeTab === "details" ? ( {/* Customer */} {proforma.customerName && ( Customer {customerName} {(proforma.customerEmail || proforma.customerPhone) && ( {proforma.customerEmail || proforma.customerPhone} )} )} {/* Proforma Details */} Proforma Details Proforma Number {proforma.proformaNumber || `PRF${(proforma.id || "").slice(0, 8).toUpperCase()}`} Issue Date {issueDate ? issueDate.toLocaleString() : "—"} Due Date {dueDate ? dueDate.toLocaleString() : "—"} {proforma.description && ( Description {proforma.description} )} {/* Note (border only, no bg) */} {proforma.notes && ( Note {proforma.notes} )} ) : ( {items.length > 0 ? ( Items {items.map((item: any, idx: number) => { const qty = safeVal(item.quantity || 1); const unitPrice = safeVal(item.unitPrice); const lineTotal = safeVal(item.total || qty * unitPrice); return ( {item.description || "No item"} {qty} ×{" "} {unitPrice.toLocaleString("en-US", { minimumFractionDigits: 2, })}{" "} {currency} {lineTotal.toLocaleString("en-US", { minimumFractionDigits: 2, })}{" "} {currency} ); })} {/* Summary */} Subtotal {fmt(subtotal, currency)} {tax > 0 && ( Tax +{fmt(tax, currency)} )} {discount > 0 && ( Discount -{fmt(discount, currency)} )} Total {fmt(amount, currency)} ) : ( )} )} {/* Sticky bottom bar — Send + Download PDF (like invoice detail) */} setShowSendSheet(true)} className="flex-1 h-12 rounded-[8px] border border-border items-center justify-center flex-row gap-2 bg-card" > Send Download PDF {/* More bottom sheet */} setShowMoreSheet(false)} > setShowMoreSheet(false)} > e.stopPropagation()} > Proforma setShowMoreSheet(false)} className="h-8 w-8 bg-secondary/80 rounded-full items-center justify-center border border-border/10" > } label="Edit Proforma" description="Update details, items, or dates" onPress={() => { setShowMoreSheet(false); nav.go("proforma/edit", { id: proforma.id }); }} /> } label="Delete Proforma" description="Permanently remove this record" onPress={() => { setShowMoreSheet(false); handleDelete(); }} destructive /> {/* Send bottom sheet (Email / SMS) */} setShowSendSheet(false)} > setShowSendSheet(false)} > e.stopPropagation()} > Send Proforma setShowSendSheet(false)} className="h-8 w-8 bg-secondary/80 rounded-full items-center justify-center border border-border/10" > Send a public, shortened link via yaltopia.com to your customer's email or phone. } label="Send as Email" description="Public accessible shortened link via yaltopia.com" onPress={() => handleShare("email")} /> } label="Send as SMS" description="Public accessible shortened link via yaltopia.com" onPress={() => handleShare("sms")} /> setShowDeleteModal(false)} onConfirm={confirmDelete} title="Delete Proforma" description="Are you sure you want to permanently delete this proforma? This action cannot be reversed." confirmText="Delete" confirmVariant="destructive" icon={Trash2} iconColor="#ef4444" loading={deleting} /> ); }