import React, { useState, useEffect, useCallback } from 'react'; import { LineChart, Line, PieChart, Pie, Cell, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend, AreaChart, Area } from 'recharts'; import { TrendingUp, TrendingDown, DollarSign, Clock, AlertCircle, CheckCircle, Search, RefreshCw, Link, Calendar, FileText, CreditCard, Activity } from 'lucide-react'; // Mock data for disconnected state preview const MOCK_KPIs = { total_revenue: { value: 124500, trend: 'up', trendValue: 12.5 }, outstanding_amount: { value: 18750, count: 23 }, overdue_amount: { value: 4200, count: 5 }, paid_this_month: { value: 45300, trend: 'up', trendValue: 8.3 } }; const MOCK_REVENUE_DATA = [ { date: 'Dec 15', amount: 3200 }, { date: 'Dec 16', amount: 4100 }, { date: 'Dec 17', amount: 2800 }, { date: 'Dec 18', amount: 5600 }, { date: 'Dec 19', amount: 4900 }, { date: 'Dec 20', amount: 3700 }, { date: 'Dec 21', amount: 6200 }, ]; const MOCK_STATUS_DATA = [ { name: 'Paid', value: 145, color: '#34d399' }, { name: 'Outstanding', value: 23, color: '#fbbf24' }, { name: 'Overdue', value: 5, color: '#f87171' }, { name: 'Void', value: 8, color: '#64748b' }, ]; const MOCK_INVOICES = [ { id: 'in_1MqJ2K', customer: 'Acme Corp', amount: 1999, currency: 'USD', status: 'paid', due_date: '2024-01-15', paid_at: '2024-01-14' }, { id: 'in_2NpL3M', customer: 'TechStart Inc', amount: 4500, currency: 'USD', status: 'outstanding', due_date: '2024-01-20', paid_at: null }, { id: 'in_3OqM4N', customer: 'Global Ltd', amount: 2750, currency: 'USD', status: 'overdue', due_date: '2024-01-05', paid_at: null }, { id: 'in_4PrN5O', customer: 'StartupXYZ', amount: 999, currency: 'USD', status: 'paid', due_date: '2024-01-18', paid_at: '2024-01-17' }, { id: 'in_5QsO6P', customer: 'Enterprise Co', amount: 12000, currency: 'USD', status: 'outstanding', due_date: '2024-01-25', paid_at: null }, ]; const COLORS = ['#34d399', '#fbbf24', '#f87171', '#64748b']; const formatCurrency = (amount: number, currency: string = 'USD') => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: currency, minimumFractionDigits: 2 }).format(amount / 100); }; const formatDate = (timestamp: number | string) => { if (!timestamp) return '—'; const date = typeof timestamp === 'string' ? new Date(timestamp) : new Date(timestamp * 1000); return date.toLocaleDateString('en-US', { day: 'numeric', month: 'short', year: 'numeric' }); }; const getStatusBadgeClass = (status: string) => { const classes: Record = { paid: 'status-paid', outstanding: 'status-outstanding', overdue: 'status-overdue', void: 'status-void', draft: 'status-void' }; return classes[status] || 'status-void'; }; const KPICard = ({ label, value, trend, trendValue, count, icon: Icon }: any) => (
{label} {Icon && }
{value}
{count !== undefined && (
{count} invoices
)} {trend && (
{trend === 'up' ? : } {trendValue > 0 ? '+' : ''}{trendValue}%
)}
); const ConnectPrompt = ({ onConnect }: { onConnect: () => void }) => (

Connect Stripe Account

Link your Stripe account to view invoice analytics, payment insights, and revenue metrics in real-time.

Preview of what you'll see:

); export default function App() { const [connected, setConnected] = useState(false); const [loading, setLoading] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const [sortColumn, setSortColumn] = useState('due_date'); const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc'); const [currentPage, setCurrentPage] = useState(1); const [lastSynced, setLastSynced] = useState(null); // Simulate connection check on mount useEffect(() => { // In production, this would check /api/framework/connections/app/fintech-invoice-dashboard/data // For now, show disconnected state (credentials not yet added) setConnected(false); }, []); const handleConnect = useCallback(() => { // In production, this triggers OAuth flow via dispatch('oauth', { service: 'stripe' }) // or navigates to the connection endpoint alert('In production, this would open Stripe OAuth flow. For now, credentials must be added via: agentsmon-cli vault set stripe:sandbox "sk_test_..."'); }, []); const handleRefresh = useCallback(() => { setLoading(true); setTimeout(() => { setLastSynced(new Date()); setLoading(false); }, 1000); }, []); const filteredInvoices = MOCK_INVOICES.filter(inv => inv.customer.toLowerCase().includes(searchTerm.toLowerCase()) || inv.id.toLowerCase().includes(searchTerm.toLowerCase()) ); const sortedInvoices = [...filteredInvoices].sort((a, b) => { const aVal = a[sortColumn as keyof typeof a]; const bVal = b[sortColumn as keyof typeof b]; if (aVal === null) return 1; if (bVal === null) return -1; const cmp = aVal < bVal ? -1 : aVal > bVal ? 1 : 0; return sortDirection === 'asc' ? cmp : -cmp; }); const handleSort = (column: string) => { if (sortColumn === column) { setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc'); } else { setSortColumn(column); setSortDirection('asc'); } }; if (!connected) { return (

Invoice Analytics

Stripe Dashboard

Data from Stripe API © 2024 Invoice Analytics
); } return (
{/* Header */}

Invoice Analytics

Stripe Dashboard

{/* KPI Row */}
{/* Charts Grid */}
Revenue Over Time
`$${v}`} /> [`$${v}`, 'Revenue']} />
Payment Status Distribution
{MOCK_STATUS_DATA.map((entry, index) => ( ))}
{MOCK_STATUS_DATA.map((item) => (
{item.name}: {item.value}
))}
{/* Invoice Table */}
setSearchTerm(e.target.value)} className="search-input pl-10" />
{sortedInvoices.map((invoice) => ( ))}
handleSort('id')} className="cursor-pointer"> Invoice ID {sortColumn === 'id' && (sortDirection === 'asc' ? '↑' : '↓')} handleSort('customer')} className="cursor-pointer"> Customer {sortColumn === 'customer' && (sortDirection === 'asc' ? '↑' : '↓')} handleSort('amount')} className="cursor-pointer text-right"> Amount {sortColumn === 'amount' && (sortDirection === 'asc' ? '↑' : '↓')} handleSort('status')} className="cursor-pointer"> Status {sortColumn === 'status' && (sortDirection === 'asc' ? '↑' : '↓')} handleSort('due_date')} className="cursor-pointer"> Due Date {sortColumn === 'due_date' && (sortDirection === 'asc' ? '↑' : '↓')} Paid Date
{invoice.id} {invoice.customer} {formatCurrency(invoice.amount, invoice.currency)} {invoice.status === 'paid' && } {invoice.status === 'outstanding' && } {invoice.status === 'overdue' && } {invoice.status} {formatDate(invoice.due_date)} {formatDate(invoice.paid_at)}
Showing {sortedInvoices.length} of {MOCK_INVOICES.length} invoices
{/* Footer */}
); }