Spaces:
Sleeping
Sleeping
| import { useAnalyticsStats } from '../features/analytics/useAnalyticsStats'; | |
| import { | |
| BarChart3, | |
| TrendingUp, | |
| Crown, | |
| Pizza, | |
| Car, | |
| Coffee, | |
| ShoppingBag, | |
| MoreHorizontal, | |
| Plane, | |
| Wallet, | |
| ShoppingBasket, | |
| Activity, | |
| Zap, | |
| ArrowUpRight, | |
| ArrowDownRight, | |
| Scale, | |
| PiggyBank, | |
| HandCoins, | |
| Banknote, | |
| BrainCircuit, | |
| Target, | |
| ZapOff, | |
| Lightbulb | |
| } from 'lucide-react'; | |
| import { | |
| ResponsiveContainer, | |
| Tooltip, | |
| AreaChart, | |
| Area, | |
| XAxis, | |
| YAxis, | |
| CartesianGrid | |
| } from 'recharts'; | |
| import { cn } from '../lib/utils'; | |
| import { useMemo } from 'react'; | |
| // Icon mapping for categories | |
| const CATEGORY_ICONS: Record<string, any> = { | |
| 'food': Pizza, | |
| 'market': ShoppingBag, | |
| 'transport': Car, | |
| 'cafe': Coffee, | |
| 'other': MoreHorizontal, | |
| 'salary': Crown, | |
| 'transfer': Wallet, | |
| 'travel': Plane, | |
| 'shopping': ShoppingBasket, | |
| 'health': Activity, | |
| 'bills': Zap, | |
| }; | |
| const MONTHS = [ | |
| { id: 1, label: 'JAN' }, { id: 2, label: 'FEB' }, { id: 3, label: 'MAR' }, | |
| { id: 4, label: 'APR' }, { id: 5, label: 'MAY' }, { id: 6, label: 'JUN' }, | |
| { id: 7, label: 'JUL' }, { id: 8, label: 'AUG' }, { id: 9, label: 'SEP' }, | |
| { id: 10, label: 'OCT' }, { id: 11, label: 'NOV' }, { id: 12, label: 'DEC' } | |
| ]; | |
| const COLORS = ['#6366f1', '#10b981', '#f59e0b', '#ef4444', '#8b5cf6', '#ec4899', '#06b6d4', '#14b8a6']; | |
| export default function Analytics() { | |
| const stats = useAnalyticsStats(); | |
| const { | |
| isLoaded, | |
| mainCurrency, | |
| selectedYear, | |
| setSelectedYear, | |
| selectedMonth, | |
| setSelectedMonth, | |
| spendingByCategory, | |
| avgDailySpend, | |
| netWorth, | |
| liquidAssets, | |
| totalLent, | |
| totalBorrowed, | |
| savingsRate, | |
| debtRatio, | |
| expenseRatio, | |
| todaySpend, | |
| dailySpendChange, | |
| totalDeposits, | |
| totalWithdrawals, | |
| availableYears, | |
| sharpeRatio, | |
| maxDrawdown, | |
| velocity, | |
| ruleAnalysis, | |
| projectedBalance, | |
| heatmap, | |
| cumulativeHistory, | |
| largestTransaction | |
| } = stats; | |
| const financialInsight = useMemo(() => { | |
| if (!spendingByCategory.length) return null; | |
| const topCat = spendingByCategory[0]; | |
| const leakMsg = topCat.pct > 30 ? `Spend concentration in ${topCat.name} (${topCat.pct.toFixed(0)}%) exceeds risk parameters.` : null; | |
| const velocityMsg = velocity < 1 ? "Capital circulation is low. Consider redeploying stagnant assets." : "Capital velocity is healthy."; | |
| const todayMsg = todaySpend > avgDailySpend ? `Today's spend (${todaySpend.toLocaleString()}) is ${(todaySpend / (avgDailySpend || 1)).toFixed(1)}x your daily average.` : "Spending is within historical daily norms."; | |
| return { leakMsg, velocityMsg, todayMsg, topCat }; | |
| }, [spendingByCategory, velocity, todaySpend, avgDailySpend]); | |
| if (!isLoaded) { | |
| return ( | |
| <div className="flex items-center justify-center h-screen bg-[#0a0a0a]"> | |
| <div className="flex flex-col items-center gap-4"> | |
| <div className="relative"> | |
| <div className="animate-spin rounded-full h-16 w-16 border-b-2 border-indigo-500"></div> | |
| <div className="absolute inset-0 flex items-center justify-center"> | |
| <BrainCircuit className="w-6 h-6 text-indigo-400 animate-pulse" /> | |
| </div> | |
| </div> | |
| <span className="text-gray-500 text-[10px] font-black uppercase tracking-[0.5em] animate-pulse">Processing Intelligence...</span> | |
| </div> | |
| </div> | |
| ); | |
| } | |
| return ( | |
| <div className="min-h-screen bg-[#0a0a0a] text-white p-4 font-sans pb-24 overflow-y-auto no-scrollbar selection:bg-indigo-500/30"> | |
| {/* Header / Date Control Section */} | |
| <header className="mb-8 pt-2"> | |
| <div className="flex items-center justify-between mb-8"> | |
| <div> | |
| <div className="flex items-center gap-2 mb-2"> | |
| <BrainCircuit className="w-4 h-4 text-indigo-500" /> | |
| <span className="text-gray-500 text-[10px] font-black uppercase tracking-[0.3em]">Quantitative Intelligence</span> | |
| </div> | |
| <h1 className="text-3xl font-black text-gray-100 flex items-baseline gap-2"> | |
| Analytics | |
| <span className="text-indigo-600/50 text-base font-bold italic">v2.0</span> | |
| </h1> | |
| </div> | |
| <div className="flex flex-col items-end"> | |
| <p className="text-[10px] font-black text-gray-600 uppercase tracking-widest leading-none mb-1">Status</p> | |
| <div className="flex items-center gap-2 px-3 py-1 bg-emerald-500/10 border border-emerald-500/20 rounded-full"> | |
| <div className="w-1.5 h-1.5 bg-emerald-500 rounded-full animate-pulse" /> | |
| <span className="text-[8px] font-black text-emerald-500 uppercase">Live Engine</span> | |
| </div> | |
| </div> | |
| </div> | |
| {/* Filters Row */} | |
| <div className="flex items-center gap-4 mb-6"> | |
| <div className="flex items-center gap-2 overflow-x-auto no-scrollbar flex-1"> | |
| {availableYears.map((year: number) => ( | |
| <button | |
| key={year} | |
| onClick={() => setSelectedYear(year)} | |
| className={cn( | |
| "px-6 py-2.5 rounded-2xl text-[10px] font-black transition-all border shrink-0 uppercase tracking-widest", | |
| selectedYear === year | |
| ? "bg-indigo-600 text-white border-indigo-500 shadow-[0_0_25px_rgba(99,102,241,0.4)]" | |
| : "bg-[#111] text-gray-500 border-white/5 hover:text-white" | |
| )} | |
| > | |
| {year} | |
| </button> | |
| ))} | |
| </div> | |
| </div> | |
| {/* Month Selection Grid */} | |
| <div className="grid grid-cols-6 gap-1.5 p-1.5 bg-[#111] rounded-[24px] border border-white/5 shadow-inner"> | |
| <button | |
| onClick={() => setSelectedMonth(null)} | |
| className={cn( | |
| "py-3 rounded-[18px] text-[9px] font-black transition-all col-span-2 uppercase tracking-widest", | |
| selectedMonth === null | |
| ? "bg-white text-black shadow-xl" | |
| : "text-gray-500 hover:text-gray-300" | |
| )} | |
| > | |
| ANNUAL | |
| </button> | |
| {MONTHS.map((m: any) => ( | |
| <button | |
| key={m.id} | |
| onClick={() => setSelectedMonth(m.id)} | |
| className={cn( | |
| "py-3 rounded-[18px] text-[9px] font-black transition-all uppercase tracking-tight", | |
| selectedMonth === m.id | |
| ? "bg-white text-black shadow-xl" | |
| : "text-gray-500 hover:text-gray-300" | |
| )} | |
| > | |
| {m.label} | |
| </button> | |
| ))} | |
| </div> | |
| </header> | |
| {/* Intelligence Insights - Leak/Anomaly Detection */} | |
| {financialInsight && ( | |
| <section className="mb-10 px-2"> | |
| <div className="bg-indigo-600/10 border border-indigo-500/20 rounded-[32px] p-6 relative overflow-hidden group"> | |
| <div className="absolute top-0 right-0 p-6 opacity-10 group-hover:opacity-20 transition-all"> | |
| <Lightbulb className="w-16 h-16 text-indigo-400" /> | |
| </div> | |
| <div className="flex items-center gap-3 mb-3"> | |
| <div className="w-8 h-8 rounded-full bg-indigo-500/20 flex items-center justify-center"> | |
| <Zap className="w-4 h-4 text-indigo-400" /> | |
| </div> | |
| <span className="text-[10px] font-black text-indigo-400 uppercase tracking-[0.2em]">Strategy Insight</span> | |
| </div> | |
| <h4 className="text-sm font-black text-gray-100 mb-2">{financialInsight.leakMsg || "Spending Efficiency is Optimal"}</h4> | |
| <div className="flex flex-col gap-1"> | |
| <p className="text-[10px] font-bold text-gray-500 uppercase tracking-widest">{financialInsight.velocityMsg}</p> | |
| <p className="text-[10px] font-bold text-gray-500 uppercase tracking-widest">{financialInsight.todayMsg}</p> | |
| </div> | |
| </div> | |
| </section> | |
| )} | |
| {/* Hero KPI Cards - Net Worth Focus */} | |
| <section className="mb-10"> | |
| <div className="bg-gradient-to-br from-[#1a1a1a] to-[#111] p-8 rounded-[40px] border border-white/5 shadow-2xl relative overflow-hidden group"> | |
| <div className="absolute top-0 right-0 p-8 opacity-5 group-hover:opacity-10 transition-opacity"> | |
| <TrendingUp className="w-48 h-48 text-indigo-500 -rotate-12" /> | |
| </div> | |
| <div className="flex justify-between items-start mb-10"> | |
| <div> | |
| <p className="text-[10px] font-black text-indigo-400 uppercase tracking-[0.4em] mb-4">NAV (Net Asset Value)</p> | |
| <div className="flex items-baseline gap-3"> | |
| <h2 className="text-5xl font-black text-white tracking-tighter"> | |
| {netWorth.toLocaleString(undefined, { maximumFractionDigits: 0 })} | |
| </h2> | |
| <span className="text-gray-600 font-black text-lg">{mainCurrency}</span> | |
| </div> | |
| </div> | |
| <div className="text-right"> | |
| <p className="text-[10px] font-black text-gray-600 uppercase tracking-widest mb-2">Projected EOM</p> | |
| <p className={cn( | |
| "text-xl font-black tracking-tight", | |
| projectedBalance > netWorth ? "text-emerald-400" : "text-rose-400" | |
| )}> | |
| {projectedBalance.toLocaleString(undefined, { maximumFractionDigits: 0 })} | |
| </p> | |
| </div> | |
| </div> | |
| <div className="grid grid-cols-4 gap-4"> | |
| <div className="bg-white/5 p-4 rounded-2xl border border-white/5 backdrop-blur-md"> | |
| <p className="text-[8px] font-bold text-gray-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5"> | |
| <Target className="w-2.5 h-2.5 text-emerald-400" /> Savings | |
| </p> | |
| <p className={cn("text-xs font-black", savingsRate >= 20 ? "text-emerald-400" : "text-amber-400")}> | |
| {savingsRate.toFixed(1)}% | |
| </p> | |
| </div> | |
| <div className="bg-white/5 p-4 rounded-2xl border border-white/5 backdrop-blur-md"> | |
| <p className="text-[8px] font-bold text-gray-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5"> | |
| <ZapOff className="w-2.5 h-2.5 text-rose-400" /> Debt | |
| </p> | |
| <p className="text-xs font-black text-rose-400"> | |
| {debtRatio.toFixed(1)}% | |
| </p> | |
| </div> | |
| <div className="bg-white/5 p-4 rounded-2xl border border-white/5 backdrop-blur-md"> | |
| <p className="text-[8px] font-bold text-gray-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5"> | |
| <Scale className="w-2.5 h-2.5 text-amber-400" /> Expense | |
| </p> | |
| <p className="text-xs font-black text-amber-400"> | |
| {expenseRatio.toFixed(1)}% | |
| </p> | |
| </div> | |
| <div className="bg-white/5 p-4 rounded-2xl border border-white/5 backdrop-blur-md"> | |
| <p className="text-[8px] font-bold text-gray-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5"> | |
| <Activity className="w-2.5 h-2.5 text-indigo-400" /> Velocity | |
| </p> | |
| <p className="text-xs font-black text-indigo-400"> | |
| {velocity.toFixed(2)}x | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Risk Metrics Section - Quant Finance Essentials */} | |
| <section className="grid grid-cols-2 gap-4 mb-10"> | |
| <div className="bg-[#111] p-6 rounded-[32px] border border-white/5 shadow-xl relative overflow-hidden group hover:border-indigo-500/30 transition-all"> | |
| <div className="flex items-center justify-between mb-4"> | |
| <div className="w-10 h-10 rounded-2xl bg-indigo-500/10 flex items-center justify-center"> | |
| <BarChart3 className="w-5 h-5 text-indigo-400" /> | |
| </div> | |
| <div className="text-right"> | |
| <p className="text-[8px] font-black text-gray-600 uppercase tracking-widest mb-0.5">Risk Adjusted</p> | |
| <span className="text-[10px] font-black text-indigo-400 uppercase tracking-tighter self-end bg-indigo-500/10 px-2 py-0.5 rounded-full border border-indigo-500/20"> | |
| Sharpe: {sharpeRatio.toFixed(2)} | |
| </span> | |
| </div> | |
| </div> | |
| <p className="text-[10px] font-black text-gray-500 uppercase tracking-widest mb-1">Daily Volatility</p> | |
| <p className="text-2xl font-black tracking-tighter"> | |
| {dailySpendChange > 0 ? '+' : ''}{dailySpendChange.toFixed(1)}% | |
| </p> | |
| </div> | |
| <div className="bg-[#111] p-6 rounded-[32px] border border-white/5 shadow-xl relative overflow-hidden group hover:border-rose-500/30 transition-all"> | |
| <div className="flex items-center justify-between mb-4"> | |
| <div className="w-10 h-10 rounded-2xl bg-rose-500/10 flex items-center justify-center"> | |
| <ZapOff className="w-5 h-5 text-rose-400" /> | |
| </div> | |
| <div className="text-right"> | |
| <p className="text-[8px] font-black text-gray-600 uppercase tracking-widest mb-0.5">Tolerance</p> | |
| <span className="text-[10px] font-black text-rose-400 uppercase tracking-tighter self-end bg-rose-500/10 px-2 py-0.5 rounded-full border border-rose-500/20"> | |
| Drawdown | |
| </span> | |
| </div> | |
| </div> | |
| <p className="text-[10px] font-black text-gray-500 uppercase tracking-widest mb-1">Max Exposure</p> | |
| <p className="text-2xl font-black tracking-tighter text-rose-400"> | |
| -{(maxDrawdown * 100).toFixed(1)}% | |
| </p> | |
| </div> | |
| </section> | |
| {/* Cash Flow Dynamics - Advanced Area + Line Projection */} | |
| <section className="mb-16"> | |
| <h3 className="text-xs font-black text-gray-500 uppercase tracking-[0.3em] mb-8 flex items-center gap-3"> | |
| <TrendingUp className="w-4 h-4 text-indigo-500" /> Capital Flow Trend | |
| </h3> | |
| <div className="bg-[#111] p-8 rounded-[40px] border border-white/5 shadow-2xl relative overflow-hidden group"> | |
| <div className="h-[320px] w-full relative"> | |
| <ResponsiveContainer width="100%" height="100%"> | |
| <AreaChart data={cumulativeHistory}> | |
| <defs> | |
| <linearGradient id="colorBalance" x1="0" y1="0" x2="0" y2="1"> | |
| <stop offset="5%" stopColor="#6366f1" stopOpacity={0.2}/> | |
| <stop offset="95%" stopColor="#6366f1" stopOpacity={0}/> | |
| </linearGradient> | |
| </defs> | |
| <CartesianGrid strokeDasharray="3 3" vertical={false} stroke="#ffffff" strokeOpacity={0.03} /> | |
| <XAxis | |
| dataKey="date" | |
| tick={{ fontSize: 8, fill: '#444', fontWeight: 'bold' }} | |
| axisLine={false} | |
| tickLine={false} | |
| tickFormatter={(val) => val.split('-').slice(1).join('/')} | |
| /> | |
| <YAxis hide /> | |
| <Tooltip | |
| contentStyle={{ backgroundColor: '#111', border: '1px solid rgba(255,255,255,0.1)', borderRadius: '16px', color: '#fff', fontSize: '10px' }} | |
| itemStyle={{ fontWeight: 'black' }} | |
| /> | |
| <Area | |
| type="monotone" | |
| dataKey="balance" | |
| stroke="#6366f1" | |
| strokeWidth={3} | |
| fill="url(#colorBalance)" | |
| animationDuration={2500} | |
| /> | |
| </AreaChart> | |
| </ResponsiveContainer> | |
| </div> | |
| <div className="grid grid-cols-2 gap-8 mt-8 pt-8 border-t border-white/5"> | |
| <div> | |
| <p className="text-[10px] font-black text-emerald-500 uppercase tracking-widest mb-2 flex items-center gap-2"> | |
| <ArrowUpRight className="w-3 h-3" /> Inflow | |
| </p> | |
| <p className="text-2xl font-black text-white">{totalDeposits.toLocaleString()}</p> | |
| </div> | |
| <div> | |
| <p className="text-[10px] font-black text-rose-500 uppercase tracking-widest mb-2 flex items-center gap-2"> | |
| <ArrowDownRight className="w-3 h-3" /> Outflow | |
| </p> | |
| <p className="text-2xl font-black text-white">{totalWithdrawals.toLocaleString()}</p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| {/* 50/30/20 Rule Analysis Section */} | |
| <section className="mb-16"> | |
| <div className="flex items-center justify-between mb-8"> | |
| <h3 className="text-xs font-black text-gray-500 uppercase tracking-[0.3em] flex items-center gap-3"> | |
| <Target className="w-4 h-4 text-amber-500" /> Allocation Strategy | |
| </h3> | |
| <div className="px-3 py-1 bg-white/5 rounded-full border border-white/10 text-[8px] font-black text-amber-500 uppercase tracking-widest"> | |
| 50/30/20 Framework | |
| </div> | |
| </div> | |
| <div className="bg-[#111] p-8 rounded-[40px] border border-white/5 shadow-xl relative overflow-hidden mb-6"> | |
| <div className="flex h-12 w-full gap-1 mb-8 rounded-2xl overflow-hidden shadow-inner bg-white/5 p-1"> | |
| <div | |
| className="h-full bg-indigo-500 transition-all duration-1000 shadow-[0_0_15px_rgba(99,102,241,0.3)] rounded-l-xl" | |
| style={{ width: `${ruleAnalysis.needs}%` }} | |
| /> | |
| <div | |
| className="h-full bg-amber-500 transition-all duration-1000 shadow-[0_0_15px_rgba(245,158,11,0.3)]" | |
| style={{ width: `${ruleAnalysis.wants}%` }} | |
| /> | |
| <div | |
| className="h-full bg-emerald-500 transition-all duration-1000 shadow-[0_0_15px_rgba(16,185,129,0.3)] rounded-r-xl" | |
| style={{ width: `${ruleAnalysis.savings}%` }} | |
| /> | |
| </div> | |
| <div className="grid grid-cols-3 gap-4"> | |
| <div className="space-y-1"> | |
| <p className="text-[8px] font-black text-gray-500 uppercase tracking-[0.1em]">Needs (Target 50%)</p> | |
| <p className="text-xl font-black text-indigo-400">{ruleAnalysis.needs.toFixed(0)}%</p> | |
| </div> | |
| <div className="space-y-1"> | |
| <p className="text-[8px] font-black text-gray-500 uppercase tracking-[0.1em]">Wants (Target 30%)</p> | |
| <p className="text-xl font-black text-amber-400">{ruleAnalysis.wants.toFixed(0)}%</p> | |
| </div> | |
| <div className="space-y-1"> | |
| <p className="text-[8px] font-black text-gray-500 uppercase tracking-[0.1em]">Savings (Target 20%)</p> | |
| <p className="text-xl font-black text-emerald-400">{ruleAnalysis.savings.toFixed(0)}%</p> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Spending Density Heatmap */} | |
| <section className="mb-16"> | |
| <h3 className="text-xs font-black text-gray-500 uppercase tracking-[0.3em] mb-8 flex items-center gap-3"> | |
| <Activity className="w-4 h-4 text-emerald-500" /> Behavioral Heatmap | |
| </h3> | |
| <div className="bg-[#111] p-8 rounded-[40px] border border-white/5 shadow-2xl overflow-hidden"> | |
| <p className="text-[10px] font-black text-gray-600 uppercase tracking-widest mb-6">Spending Concentration (Day vs Hour)</p> | |
| <div className="flex flex-col gap-2"> | |
| {['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT'].map((day, dIdx) => ( | |
| <div key={day} className="flex items-center gap-2"> | |
| <span className="text-[8px] font-black text-gray-600 w-8">{day}</span> | |
| <div className="flex gap-1 flex-1"> | |
| {Array.from({ length: 24 }).map((_, hIdx) => { | |
| const value = heatmap[`${dIdx}-${hIdx}`] || 0; | |
| const opacity = Math.min(1, value / (avgDailySpend || 1)); | |
| return ( | |
| <div | |
| key={hIdx} | |
| className="flex-1 aspect-square rounded-[2px] transition-all hover:scale-110 active:scale-95 cursor-pointer" | |
| style={{ | |
| backgroundColor: value > 0 ? '#6366f1' : 'rgba(255,255,255,0.02)', | |
| opacity: value > 0 ? 0.2 + (opacity * 0.8) : 1 | |
| }} | |
| title={`Time: ${hIdx}:00, Spend: ${value.toLocaleString()}`} | |
| /> | |
| ); | |
| })} | |
| </div> | |
| </div> | |
| ))} | |
| </div> | |
| <div className="flex justify-between mt-6 text-[8px] font-black text-gray-600 uppercase tracking-[0.2em] px-10"> | |
| <span>00:00</span> | |
| <span>12:00</span> | |
| <span>23:00</span> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Spending Analysis Section */} | |
| <section className="mb-16"> | |
| <div className="flex items-center justify-between mb-8"> | |
| <h3 className="text-xs font-black text-gray-500 uppercase tracking-[0.3em] flex items-center gap-3"> | |
| <Pizza className="w-4 h-4 text-orange-500" /> Expenditure DNA | |
| </h3> | |
| <div className="flex gap-2"> | |
| {largestTransaction && ( | |
| <div className="px-3 py-1 bg-rose-500/10 rounded-full border border-rose-500/20 text-[8px] font-black text-rose-500 uppercase tracking-widest flex items-center gap-1.5"> | |
| <Zap className="w-2 h-2" /> Outlier: {largestTransaction.mainAmount.toLocaleString()} | |
| </div> | |
| )} | |
| <div className="px-3 py-1 bg-white/5 rounded-full border border-white/10 uppercase font-black text-[8px] tracking-widest text-orange-400"> | |
| {spendingByCategory.length} ACTIVE CLUSTERS | |
| </div> | |
| </div> | |
| </div> | |
| <div className="grid grid-cols-1 gap-4"> | |
| {spendingByCategory.map((cat: any, index: number) => { | |
| const Icon = CATEGORY_ICONS[cat.name.toLowerCase()] || MoreHorizontal; | |
| const color = COLORS[index % COLORS.length]; | |
| return ( | |
| <div key={cat.name} className="bg-[#111] p-6 rounded-[32px] border border-white/5 group hover:border-white/10 transition-all relative overflow-hidden"> | |
| <div className="absolute top-0 left-0 w-1 h-full opacity-50 transition-all group-hover:w-2" style={{ backgroundColor: color }}></div> | |
| <div className="flex items-center gap-6 mb-5"> | |
| <div className="w-14 h-14 rounded-2xl flex items-center justify-center relative overflow-hidden shrink-0 shadow-lg group-hover:scale-105 transition-transform"> | |
| <div className="absolute inset-0 opacity-10" style={{ backgroundColor: color }}></div> | |
| <Icon className="w-7 h-7 relative z-10" style={{ color: color }} /> | |
| </div> | |
| <div className="flex-1 min-w-0"> | |
| <div className="flex justify-between items-center mb-1.5"> | |
| <h4 className="text-base font-black text-gray-100 capitalize tracking-tight">{cat.name}</h4> | |
| <span className="text-base font-black tracking-tight">{cat.value.toLocaleString(undefined, { maximumFractionDigits: 0 })} <span className="text-[10px] text-gray-600 ml-1">{mainCurrency}</span></span> | |
| </div> | |
| <div className="flex justify-between text-[10px] font-bold text-gray-500 uppercase tracking-tighter"> | |
| <span>{cat.count} Transactions Logged</span> | |
| <span className="text-indigo-400 font-black">{cat.pct.toFixed(1)}% Global Share</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div className="w-full h-1.5 bg-white/5 rounded-full overflow-hidden shadow-inner"> | |
| <div className="h-full transition-all duration-1000 ease-out" style={{ width: `${cat.pct}%`, backgroundColor: color }} /> | |
| </div> | |
| </div> | |
| ); | |
| })} | |
| {spendingByCategory.length === 0 && ( | |
| <div className="bg-[#111] p-12 rounded-[32px] border border-white/5 text-center"> | |
| <Activity className="w-12 h-12 text-gray-800 mx-auto mb-4" /> | |
| <p className="text-[10px] font-black text-gray-600 uppercase tracking-widest leading-relaxed">System analysis indicates<br/>no expenditure recorded for this period.</p> | |
| </div> | |
| )} | |
| </div> | |
| </section> | |
| {/* Loans & Liabilities Section */} | |
| <section className="pb-12 text-center"> | |
| <h3 className="text-xs font-black text-gray-500 uppercase tracking-[0.3em] mb-8 flex items-center justify-center gap-3"> | |
| <HandCoins className="w-4 h-4 text-amber-500" /> Debt & Equity Summary | |
| </h3> | |
| <div className="grid grid-cols-2 gap-4 mb-8"> | |
| <div className="bg-[#111] p-6 rounded-[32px] border border-white/5 relative overflow-hidden group hover:border-emerald-500/20 transition-all"> | |
| <div className="absolute -top-4 -right-4 p-4 opacity-5 group-hover:opacity-10 transition-opacity"> | |
| <PiggyBank className="w-16 h-16" /> | |
| </div> | |
| <p className="text-[9px] font-black text-emerald-500 uppercase tracking-widest mb-3">Portfolio Credit</p> | |
| <p className="text-2xl font-black text-gray-100 tracking-tighter">{totalLent.toLocaleString()}</p> | |
| <p className="text-[8px] text-gray-600 mt-2 font-bold uppercase tracking-tight">Owed to you</p> | |
| </div> | |
| <div className="bg-[#111] p-6 rounded-[32px] border border-white/5 relative overflow-hidden group hover:border-rose-500/20 transition-all"> | |
| <div className="absolute -top-4 -right-4 p-4 opacity-5 group-hover:opacity-10 transition-opacity"> | |
| <Banknote className="w-16 h-16" /> | |
| </div> | |
| <p className="text-[9px] font-black text-rose-500 uppercase tracking-widest mb-3">Liabilities</p> | |
| <p className="text-2xl font-black text-gray-100 tracking-tighter">{totalBorrowed.toLocaleString()}</p> | |
| <p className="text-[8px] text-gray-600 mt-2 font-bold uppercase tracking-tight">System Debt</p> | |
| </div> | |
| </div> | |
| <div className="bg-[#111] p-8 rounded-[40px] border border-white/5 shadow-2xl relative overflow-hidden"> | |
| <div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-emerald-500 to-rose-500"></div> | |
| <div className="flex items-center justify-between mb-8"> | |
| <p className="text-[10px] font-black text-gray-500 uppercase tracking-[0.3em]">Account Solvency</p> | |
| <div className={cn( | |
| "text-[10px] font-black px-4 py-1.5 rounded-full shadow-lg", | |
| netWorth > 0 ? "bg-emerald-500 text-black border-none" : "bg-rose-500 text-white border-none" | |
| )}> | |
| {netWorth > 0 ? 'CRITICAL SOLVENCY ACHIEVED' : 'LEVERAGED EXPOSURE'} | |
| </div> | |
| </div> | |
| {/* Simple visual indicator bar */} | |
| <div className="w-full h-4 bg-white/5 rounded-full overflow-hidden flex shadow-inner mb-4"> | |
| <div | |
| className="h-full bg-emerald-500 transition-all duration-1000 shadow-[0_0_15px_rgba(16,185,129,0.3)]" | |
| style={{ width: `${(liquidAssets / (liquidAssets + totalBorrowed || 1)) * 100}%` }} | |
| /> | |
| <div | |
| className="h-full bg-rose-500 transition-all duration-1000 shadow-[0_0_15px_rgba(239,68,68,0.3)]" | |
| style={{ width: `${(totalBorrowed / (liquidAssets + totalBorrowed || 1)) * 100}%` }} | |
| /> | |
| </div> | |
| <div className="flex justify-between text-[10px] font-black uppercase tracking-widest text-gray-600"> | |
| <span className="flex items-center gap-2"><div className="w-2 h-2 bg-emerald-500 rounded-full"></div> Assets</span> | |
| <span className="flex items-center gap-2">Liabilities <div className="w-2 h-2 bg-rose-500 rounded-full"></div></span> | |
| </div> | |
| </div> | |
| </section> | |
| {/* Sticky Bottom Nav / Quick Jump */} | |
| <div className="sticky bottom-8 left-0 right-0 flex justify-center z-50 pointer-events-none"> | |
| <div className="bg-white/10 backdrop-blur-2xl px-1.5 py-1.5 rounded-[24px] border border-white/10 shadow-[0_20px_50px_rgba(0,0,0,0.5)] flex items-center gap-1.5 pointer-events-auto"> | |
| <button | |
| onClick={() => { | |
| const container = document.getElementById('main-content-area'); | |
| if (container) container.scrollTo({ top: 0, behavior: 'smooth' }); | |
| }} | |
| className="px-6 py-3 rounded-[18px] bg-white text-black text-[10px] font-black transition-all shadow-xl hover:scale-105 active:scale-95 uppercase tracking-widest" | |
| > | |
| TOP | |
| </button> | |
| </div> | |
| </div> | |
| <style dangerouslySetInnerHTML={{ __html: ` | |
| .no-scrollbar::-webkit-scrollbar { display: none; } | |
| .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; } | |
| `}} /> | |
| </div> | |
| ); | |
| } | |