diff --git a/apps/web/src/pages/DashboardPage.tsx b/apps/web/src/pages/DashboardPage.tsx index 9de5539..aa1b022 100644 --- a/apps/web/src/pages/DashboardPage.tsx +++ b/apps/web/src/pages/DashboardPage.tsx @@ -1,11 +1,333 @@ import React, { useMemo } from 'react'; +import { useTransactionStore } from '../stores/transactionStore'; +import { BarChart, LineChart, PieChart } from '../components/Charts'; +import { getDefaultConverter } from '@brazil-swift-ops/utils'; +import type { Transaction } from '@brazil-swift-ops/types'; export default function DashboardPage() { + const { transactions, results } = useTransactionStore(); + const converter = getDefaultConverter(); + + // Calculate statistics + const stats = useMemo(() => { + const now = new Date(); + const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); + const weekAgo = new Date(today); + weekAgo.setDate(weekAgo.getDate() - 7); + const monthAgo = new Date(today); + monthAgo.setDate(monthAgo.getDate() - 30); + + const todayTransactions = transactions.filter((txn) => txn.createdAt >= today); + const weekTransactions = transactions.filter((txn) => txn.createdAt >= weekAgo); + const monthTransactions = transactions.filter((txn) => txn.createdAt >= monthAgo); + + const totalUsdEquivalent = transactions.reduce((sum, txn) => { + const usd = txn.usdEquivalent || converter.convert(txn.amount, txn.currency, 'USD'); + return sum + usd; + }, 0); + + const reportingRequired = transactions.filter((txn) => { + const usd = txn.usdEquivalent || converter.convert(txn.amount, txn.currency, 'USD'); + return usd >= 10000; + }).length; + + const pendingCount = transactions.filter((txn) => txn.status === 'pending').length; + const approvedCount = transactions.filter((txn) => txn.status === 'approved').length; + const heldCount = transactions.filter((txn) => txn.status === 'held').length; + const escalatedCount = transactions.filter((txn) => txn.status === 'escalated').length; + + // Currency breakdown + const currencyMap = new Map(); + transactions.forEach((txn) => { + const usd = txn.usdEquivalent || converter.convert(txn.amount, txn.currency, 'USD'); + currencyMap.set(txn.currency, (currencyMap.get(txn.currency) || 0) + usd); + }); + + // Transaction volume over time (last 7 days) + const volumeData = []; + for (let i = 6; i >= 0; i--) { + const date = new Date(today); + date.setDate(date.getDate() - i); + const dayTransactions = transactions.filter((txn) => { + const txnDate = new Date(txn.createdAt); + return ( + txnDate.getFullYear() === date.getFullYear() && + txnDate.getMonth() === date.getMonth() && + txnDate.getDate() === date.getDate() + ); + }); + const dayVolume = dayTransactions.reduce((sum, txn) => { + const usd = txn.usdEquivalent || converter.convert(txn.amount, txn.currency, 'USD'); + return sum + usd; + }, 0); + volumeData.push({ + date: date.toISOString().split('T')[0], + value: dayVolume, + }); + } + + return { + total: transactions.length, + today: todayTransactions.length, + week: weekTransactions.length, + month: monthTransactions.length, + totalUsdEquivalent, + reportingRequired, + pendingCount, + approvedCount, + heldCount, + escalatedCount, + currencyBreakdown: Array.from(currencyMap.entries()).map(([currency, amount]) => ({ + label: currency, + value: amount, + })), + statusDistribution: [ + { label: 'Approved', value: approvedCount, color: '#10b981' }, + { label: 'Pending', value: pendingCount, color: '#f59e0b' }, + { label: 'Held', value: heldCount, color: '#ef4444' }, + { label: 'Escalated', value: escalatedCount, color: '#8b5cf6' }, + ].filter((item) => item.value > 0), + volumeData, + }; + }, [transactions, converter]); + + // Recent activity (last 10 transactions) + const recentActivity = useMemo(() => { + return [...transactions] + .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime()) + .slice(0, 10) + .map((txn) => { + const result = results.get(txn.id); + const usd = txn.usdEquivalent || converter.convert(txn.amount, txn.currency, 'USD'); + return { + ...txn, + usd, + decision: result?.overallDecision || 'Pending', + severity: result?.overallSeverity || 'Info', + }; + }); + }, [transactions, results, converter]); + + // Compliance status + const complianceStatus = useMemo(() => { + const totalWithResults = transactions.filter((txn) => results.has(txn.id)).length; + const compliant = transactions.filter((txn) => { + const result = results.get(txn.id); + return result?.overallDecision === 'Allow'; + }).length; + + return { + totalEvaluated: totalWithResults, + compliant, + complianceRate: totalWithResults > 0 ? (compliant / totalWithResults) * 100 : 0, + }; + }, [transactions, results]); + return (
-
-

Dashboard

-

Brazil SWIFT Operations Platform

+
+

Dashboard

+

Brazil SWIFT Operations Platform Overview

+
+ + {/* Statistics Cards */} +
+
+
+
+

Total Transactions

+

{stats.total}

+

+ {stats.today} today, {stats.week} this week +

+
+
+ + + +
+
+
+ +
+
+
+

Total Volume (USD)

+

+ ${(stats.totalUsdEquivalent / 1000000).toFixed(2)}M +

+

+ {stats.month} transactions this month +

+
+
+ + + +
+
+
+ +
+
+
+

Reporting Required

+

{stats.reportingRequired}

+

≥ USD 10,000

+
+
+ + + +
+
+
+ +
+
+
+

Pending Approvals

+

{stats.pendingCount}

+

+ {stats.escalatedCount} escalated +

+
+
+ + + +
+
+
+
+ + {/* Charts Row */} +
+ {stats.volumeData.length > 0 && ( + + )} + {stats.statusDistribution.length > 0 && ( + + )} +
+ + {stats.currencyBreakdown.length > 0 && ( +
+ +
+ )} + + {/* Recent Activity and Compliance Status */} +
+ {/* Recent Activity */} +
+
+

Recent Activity

+
+
+ {recentActivity.length > 0 ? ( +
+ {recentActivity.map((txn) => ( +
+
+
+ {txn.id} + + {txn.decision} + +
+

+ {txn.direction} • {txn.currency} {txn.amount.toLocaleString()} • ${txn.usd.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} +

+

+ {new Date(txn.createdAt).toLocaleString()} +

+
+
+ ))} +
+ ) : ( +
+

No recent transactions

+
+ )} +
+
+ + {/* Compliance Status */} +
+
+

Compliance Status

+
+
+
+
+
+ Compliance Rate + + {complianceStatus.complianceRate.toFixed(1)}% + +
+
+
+
+
+ +
+
+

Total Evaluated

+

+ {complianceStatus.totalEvaluated} +

+
+
+

Compliant

+

+ {complianceStatus.compliant} +

+
+
+ +
+
+
+ BCB Reporting: Compliant +
+
+
+ AML Checks: Active +
+
+
+ FX Contracts: Monitoring +
+
+
+
+
);