import React, { useState } from "react"; import { base44 } from "@/api/base44Client"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { Link } from "react-router-dom"; import { createPageUrl } from "@/utils"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { FileText, Plus, DollarSign, Search, Eye, Download } from "lucide-react"; import { format, parseISO, isPast } from "date-fns"; import PageHeader from "../components/common/PageHeader"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; const statusColors = { 'Open': 'bg-orange-500 text-white', 'Confirmed': 'bg-purple-500 text-white', 'Overdue': 'bg-red-500 text-white', 'Resolved': 'bg-blue-500 text-white', 'Paid': 'bg-green-500 text-white', 'Reconciled': 'bg-yellow-600 text-white', 'Disputed': 'bg-gray-500 text-white', 'Verified': 'bg-teal-500 text-white', 'Pending': 'bg-amber-500 text-white', }; export default function Invoices() { const [activeTab, setActiveTab] = useState("all"); const [searchTerm, setSearchTerm] = useState(""); const [selectedInvoice, setSelectedInvoice] = useState(null); const [showPaymentDialog, setShowPaymentDialog] = useState(false); const [showCreateDialog, setShowCreateDialog] = useState(false); const [paymentMethod, setPaymentMethod] = useState(""); const queryClient = useQueryClient(); const { data: user } = useQuery({ queryKey: ['current-user-invoices'], queryFn: () => base44.auth.me(), }); const { data: invoices = [], isLoading } = useQuery({ queryKey: ['invoices'], queryFn: () => base44.entities.Invoice.list('-issue_date'), initialData: [], }); const userRole = user?.user_role || user?.role; // Filter invoices based on user role const visibleInvoices = React.useMemo(() => { if (userRole === "client") { return invoices.filter(inv => inv.business_name === user?.company_name || inv.manager_name === user?.full_name || inv.created_by === user?.email ); } if (userRole === "vendor") { return invoices.filter(inv => inv.vendor_name === user?.company_name); } // Admin, procurement, operator can see all return invoices; }, [invoices, userRole, user]); const updateInvoiceMutation = useMutation({ mutationFn: ({ id, data }) => base44.entities.Invoice.update(id, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['invoices'] }); setShowPaymentDialog(false); setSelectedInvoice(null); }, }); const getFilteredInvoices = () => { let filtered = visibleInvoices; // Status filter if (activeTab !== "all") { const statusMap = { open: "Open", disputed: "Disputed", resolved: "Resolved", verified: "Verified", overdue: "Overdue", reconciled: "Reconciled", paid: "Paid" }; filtered = filtered.filter(inv => inv.status === statusMap[activeTab]); } // Search filter if (searchTerm) { filtered = filtered.filter(inv => inv.invoice_number?.toLowerCase().includes(searchTerm.toLowerCase()) || inv.business_name?.toLowerCase().includes(searchTerm.toLowerCase()) || inv.manager_name?.toLowerCase().includes(searchTerm.toLowerCase()) || inv.event_name?.toLowerCase().includes(searchTerm.toLowerCase()) ); } return filtered; }; const filteredInvoices = getFilteredInvoices(); // Calculate metrics const getStatusCount = (status) => { if (status === "all") return visibleInvoices.length; return visibleInvoices.filter(inv => inv.status === status).length; }; const getTotalAmount = (status) => { const filtered = status === "all" ? visibleInvoices : visibleInvoices.filter(inv => inv.status === status); return filtered.reduce((sum, inv) => sum + (inv.amount || 0), 0); }; const allTotal = getTotalAmount("all"); const openTotal = getTotalAmount("Open"); const overdueTotal = getTotalAmount("Overdue"); const paidTotal = getTotalAmount("Paid"); const openPercentage = allTotal > 0 ? ((openTotal / allTotal) * 100).toFixed(1) : 0; const overduePercentage = allTotal > 0 ? ((overdueTotal / allTotal) * 100).toFixed(1) : 0; const paidPercentage = allTotal > 0 ? ((paidTotal / allTotal) * 100).toFixed(1) : 0; const handleRecordPayment = () => { if (selectedInvoice && paymentMethod) { updateInvoiceMutation.mutate({ id: selectedInvoice.id, data: { ...selectedInvoice, status: "Paid", paid_date: new Date().toISOString().split('T')[0], payment_method: paymentMethod } }); } }; return (
} /> {/* Status Tabs */} All Invoices {getStatusCount("all")} Open {getStatusCount("Open")} Disputed {getStatusCount("Disputed")} Resolved {getStatusCount("Resolved")} Verified {getStatusCount("Verified")} Overdue {getStatusCount("Overdue")} Reconciled {getStatusCount("Reconciled")} Paid {getStatusCount("Paid")} {/* Summary Cards */}

All

${allTotal.toLocaleString()}

{getStatusCount("all")} invoices

100%

Open

${openTotal.toLocaleString()}

{getStatusCount("Open")} invoices

{openPercentage}%

Overdue

${overdueTotal.toLocaleString()}

{getStatusCount("Overdue")} invoices

{overduePercentage}%

Paid

${paidTotal.toLocaleString()}

{getStatusCount("Paid")} invoices

{paidPercentage}%

{/* Search */}
setSearchTerm(e.target.value)} className="pl-10 border-slate-300" />
{/* Invoices Table */} S # Manager Name Hub Invoice ID Cost Center Event Value $ Count Payment Status Actions {filteredInvoices.length === 0 ? (

No invoices found

) : ( filteredInvoices.map((invoice, idx) => ( {idx + 1} {invoice.manager_name || invoice.business_name} {invoice.hub || "Hub Name"}

{invoice.invoice_number}

{format(parseISO(invoice.issue_date), 'M.d.yyyy')}

{invoice.cost_center || "Cost Center"} {invoice.event_name || "Events Name"} ${invoice.amount?.toLocaleString()} {invoice.item_count || 2} {invoice.status}
)) )}
{/* Record Payment Dialog */} Record Payment
{/* Create Invoice Dialog */} Create Invoice

Invoice creation form coming soon...

); }