← back to Handbag Auth Nextjs
src/app/admin/page.tsx
423 lines
'use client'
import { useState, useEffect } from 'react'
import { LineChart, Line, BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, PieChart, Pie, Cell } from 'recharts'
export default function AdminDashboard() {
const [stats, setStats] = useState<any>(null)
const [gmvData, setGmvData] = useState<any[]>([])
const [activeTab, setActiveTab] = useState('overview')
useEffect(() => {
fetchDashboardData()
// Real-time updates every 0.9 seconds
const interval = setInterval(fetchDashboardData, 900)
return () => clearInterval(interval)
}, [])
const fetchDashboardData = async () => {
try {
const res = await fetch('/api/admin/dashboard')
const data = await res.json()
if (data.success) {
setStats(data.stats)
setGmvData(data.gmvHistory)
}
} catch (error) {
console.error('Failed to fetch dashboard data:', error)
}
}
// Mock data for demonstration
const mockStats = {
totalGMV: 247500,
monthlyGMV: 45000,
totalUsers: 5234,
activeInvestors: 523,
premiumSubscribers: 78,
totalRevenue: 12750,
affiliateRevenue: 5250,
fractionalRevenue: 4500,
subscriptionRevenue: 3000,
avgLTV: 485,
avgCAC: 127,
ltvcac: 3.82
}
const gmvHistory = [
{ month: 'Jan', gmv: 12500, revenue: 875 },
{ month: 'Feb', gmv: 18700, revenue: 1309 },
{ month: 'Mar', gmv: 25300, revenue: 1771 },
{ month: 'Apr', gmv: 32100, revenue: 2247 },
{ month: 'May', gmv: 45000, revenue: 3150 },
{ month: 'Jun (Proj)', gmv: 62000, revenue: 4340 }
]
const assetsByBrand = [
{ name: 'Hermès', value: 35, color: '#DC2626' },
{ name: 'Chanel', value: 28, color: '#000000' },
{ name: 'Louis Vuitton', value: 22, color: '#92400E' },
{ name: 'Dior', value: 10, color: '#1E40AF' },
{ name: 'Others', value: 5, color: '#6B7280' }
]
const recentInvestments = [
{ id: 1, user: 'Emma S.', asset: 'Hermès Birkin 30 Togo', amount: 2500, shares: 100, time: '2 min ago' },
{ id: 2, user: 'Michael R.', asset: 'Chanel Classic Flap Medium', amount: 1200, shares: 80, time: '8 min ago' },
{ id: 3, user: 'Sarah T.', asset: 'Louis Vuitton Neverfull MM', amount: 450, shares: 45, time: '15 min ago' },
{ id: 4, user: 'James K.', asset: 'Dior Lady Dior Medium', amount: 3200, shares: 160, time: '23 min ago' }
]
const activeFractionalAssets = [
{ id: 1, name: 'Hermès Birkin 30 Togo Gold', totalValue: 42000, fractionsSold: 650, fractionsTotal: 1000, performance: '+12.4%' },
{ id: 2, name: 'Chanel Classic Flap Medium Caviar', totalValue: 12500, fractionsSold: 420, fractionsTotal: 500, performance: '+8.7%' },
{ id: 3, name: 'Louis Vuitton Neverfull MM Monogram', totalValue: 2800, fractionsSold: 180, fractionsTotal: 280, performance: '+3.2%' },
{ id: 4, name: 'Hermès Kelly 28 Epsom Black', totalValue: 38000, fractionsSold: 890, fractionsTotal: 1000, performance: '+15.1%' }
]
return (
<div className="min-h-screen bg-gradient-to-br from-gray-900 via-black to-gray-900 text-white">
{/* Header */}
<header className="border-b border-gray-800 bg-black/50 backdrop-blur-xl">
<div className="max-w-7xl mx-auto px-6 py-4">
<div className="flex items-center justify-between">
<div>
<h1 className="text-2xl font-bold bg-gradient-to-r from-amber-400 to-orange-500 bg-clip-text text-transparent">
LUXVAULT Admin
</h1>
<p className="text-sm text-gray-400 mt-1">Fractional Luxury Investment Platform</p>
</div>
<div className="flex items-center space-x-4">
<div className="px-4 py-2 bg-green-500/20 rounded-lg border border-green-500/30">
<div className="flex items-center space-x-2">
<div className="w-2 h-2 bg-green-400 rounded-full animate-pulse"></div>
<span className="text-sm font-semibold text-green-400">Live (0.9s refresh)</span>
</div>
</div>
<button className="px-4 py-2 bg-white/10 hover:bg-white/20 rounded-lg transition-all">
<span className="text-sm font-semibold">Steve</span>
</button>
</div>
</div>
</div>
</header>
{/* Tab Navigation */}
<div className="border-b border-gray-800">
<div className="max-w-7xl mx-auto px-6">
<div className="flex space-x-8">
{['overview', 'assets', 'investors', 'automation', 'analytics'].map((tab) => (
<button
key={tab}
onClick={() => setActiveTab(tab)}
className={`px-4 py-4 text-sm font-semibold border-b-2 transition-all capitalize ${
activeTab === tab
? 'border-amber-500 text-amber-400'
: 'border-transparent text-gray-400 hover:text-white'
}`}
>
{tab}
</button>
))}
</div>
</div>
</div>
{/* Main Content */}
<main className="max-w-7xl mx-auto px-6 py-8">
{activeTab === 'overview' && (
<div className="space-y-8">
{/* Key Metrics Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{/* Total GMV */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<div className="flex items-center justify-between mb-4">
<span className="text-gray-400 text-sm font-medium">Total GMV</span>
<div className="w-10 h-10 bg-green-500/20 rounded-lg flex items-center justify-center">
<span className="text-xl">💰</span>
</div>
</div>
<div className="text-3xl font-bold text-white mb-2">
${mockStats.totalGMV.toLocaleString()}
</div>
<div className="text-sm text-green-400 font-semibold">
+${mockStats.monthlyGMV.toLocaleString()} this month
</div>
</div>
{/* Total Users */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<div className="flex items-center justify-between mb-4">
<span className="text-gray-400 text-sm font-medium">Total Users</span>
<div className="w-10 h-10 bg-blue-500/20 rounded-lg flex items-center justify-center">
<span className="text-xl">👥</span>
</div>
</div>
<div className="text-3xl font-bold text-white mb-2">
{mockStats.totalUsers.toLocaleString()}
</div>
<div className="text-sm text-blue-400 font-semibold">
{mockStats.activeInvestors} active investors (10%)
</div>
</div>
{/* Total Revenue */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<div className="flex items-center justify-between mb-4">
<span className="text-gray-400 text-sm font-medium">Total Revenue</span>
<div className="w-10 h-10 bg-amber-500/20 rounded-lg flex items-center justify-center">
<span className="text-xl">📈</span>
</div>
</div>
<div className="text-3xl font-bold text-white mb-2">
${mockStats.totalRevenue.toLocaleString()}
</div>
<div className="text-sm text-amber-400 font-semibold">
7.2% effective take rate
</div>
</div>
{/* LTV/CAC Ratio */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<div className="flex items-center justify-between mb-4">
<span className="text-gray-400 text-sm font-medium">LTV / CAC</span>
<div className="w-10 h-10 bg-purple-500/20 rounded-lg flex items-center justify-center">
<span className="text-xl">🎯</span>
</div>
</div>
<div className="text-3xl font-bold text-white mb-2">
{mockStats.ltvcac.toFixed(2)}x
</div>
<div className="text-sm text-purple-400 font-semibold">
${mockStats.avgLTV} LTV / ${mockStats.avgCAC} CAC
</div>
</div>
</div>
{/* GMV Growth Chart */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<h2 className="text-xl font-bold mb-6">GMV & Revenue Growth</h2>
<ResponsiveContainer width="100%" height={300}>
<LineChart data={gmvHistory}>
<CartesianGrid strokeDasharray="3 3" stroke="#374151" />
<XAxis dataKey="month" stroke="#9CA3AF" />
<YAxis stroke="#9CA3AF" />
<Tooltip
contentStyle={{
backgroundColor: '#1F2937',
border: '1px solid #374151',
borderRadius: '8px'
}}
/>
<Line type="monotone" dataKey="gmv" stroke="#F59E0B" strokeWidth={3} name="GMV ($)" />
<Line type="monotone" dataKey="revenue" stroke="#10B981" strokeWidth={3} name="Revenue ($)" />
</LineChart>
</ResponsiveContainer>
</div>
{/* Revenue Breakdown & Assets by Brand */}
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Revenue Breakdown */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<h2 className="text-xl font-bold mb-6">Revenue Breakdown</h2>
<div className="space-y-4">
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-gray-400">Affiliate Commissions</span>
<span className="font-bold text-white">${mockStats.affiliateRevenue.toLocaleString()}</span>
</div>
<div className="w-full h-3 bg-gray-700 rounded-full overflow-hidden">
<div className="h-full bg-gradient-to-r from-blue-500 to-cyan-400" style={{ width: '41%' }}></div>
</div>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-gray-400">Fractional Trading Fees</span>
<span className="font-bold text-white">${mockStats.fractionalRevenue.toLocaleString()}</span>
</div>
<div className="w-full h-3 bg-gray-700 rounded-full overflow-hidden">
<div className="h-full bg-gradient-to-r from-purple-500 to-pink-400" style={{ width: '35%' }}></div>
</div>
</div>
<div>
<div className="flex items-center justify-between mb-2">
<span className="text-gray-400">Premium Subscriptions</span>
<span className="font-bold text-white">${mockStats.subscriptionRevenue.toLocaleString()}</span>
</div>
<div className="w-full h-3 bg-gray-700 rounded-full overflow-hidden">
<div className="h-full bg-gradient-to-r from-amber-500 to-orange-400" style={{ width: '24%' }}></div>
</div>
</div>
</div>
</div>
{/* Assets by Brand */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<h2 className="text-xl font-bold mb-6">Fractionalized Assets by Brand</h2>
<ResponsiveContainer width="100%" height={200}>
<PieChart>
<Pie
data={assetsByBrand}
cx="50%"
cy="50%"
labelLine={false}
label={(entry) => entry.name}
outerRadius={80}
fill="#8884d8"
dataKey="value"
>
{assetsByBrand.map((entry, index) => (
<Cell key={`cell-${index}`} fill={entry.color} />
))}
</Pie>
<Tooltip />
</PieChart>
</ResponsiveContainer>
</div>
</div>
{/* Recent Investments */}
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<h2 className="text-xl font-bold mb-6">Recent Investments (Live Feed)</h2>
<div className="space-y-3">
{recentInvestments.map((investment) => (
<div
key={investment.id}
className="flex items-center justify-between p-4 bg-gray-900/50 rounded-lg border border-gray-700 hover:border-amber-500/50 transition-all"
>
<div className="flex-1">
<div className="font-semibold text-white mb-1">{investment.user}</div>
<div className="text-sm text-gray-400">{investment.asset}</div>
</div>
<div className="text-right">
<div className="font-bold text-green-400">${investment.amount.toLocaleString()}</div>
<div className="text-sm text-gray-500">{investment.shares} shares · {investment.time}</div>
</div>
</div>
))}
</div>
</div>
</div>
)}
{activeTab === 'assets' && (
<div className="space-y-6">
<div className="flex items-center justify-between">
<h2 className="text-2xl font-bold">Active Fractional Assets</h2>
<button className="px-6 py-3 bg-gradient-to-r from-amber-500 to-orange-600 rounded-xl font-bold hover:shadow-2xl hover:shadow-amber-500/50 transition-all">
+ Add New Asset
</button>
</div>
<div className="grid grid-cols-1 gap-4">
{activeFractionalAssets.map((asset) => (
<div
key={asset.id}
className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700 hover:border-amber-500/50 transition-all"
>
<div className="flex items-center justify-between mb-4">
<div className="flex-1">
<h3 className="text-lg font-bold text-white mb-2">{asset.name}</h3>
<div className="text-sm text-gray-400">
Total Value: <span className="font-semibold text-white">${asset.totalValue.toLocaleString()}</span>
</div>
</div>
<div className="text-right">
<div className={`text-2xl font-bold ${asset.performance.startsWith('+') ? 'text-green-400' : 'text-red-400'}`}>
{asset.performance}
</div>
<div className="text-sm text-gray-500">Performance</div>
</div>
</div>
<div className="mb-4">
<div className="flex items-center justify-between mb-2">
<span className="text-sm text-gray-400">
Fractions Sold: {asset.fractionsSold} / {asset.fractionsTotal}
</span>
<span className="text-sm font-bold text-white">
{((asset.fractionsSold / asset.fractionsTotal) * 100).toFixed(1)}%
</span>
</div>
<div className="w-full h-3 bg-gray-700 rounded-full overflow-hidden">
<div
className="h-full bg-gradient-to-r from-amber-500 to-orange-500"
style={{ width: `${(asset.fractionsSold / asset.fractionsTotal) * 100}%` }}
></div>
</div>
</div>
<div className="flex items-center space-x-3">
<button className="flex-1 px-4 py-2 bg-blue-500/20 hover:bg-blue-500/30 rounded-lg text-blue-400 font-semibold transition-all">
View Details
</button>
<button className="flex-1 px-4 py-2 bg-green-500/20 hover:bg-green-500/30 rounded-lg text-green-400 font-semibold transition-all">
Manage Fractions
</button>
<button className="flex-1 px-4 py-2 bg-purple-500/20 hover:bg-purple-500/30 rounded-lg text-purple-400 font-semibold transition-all">
Analytics
</button>
</div>
</div>
))}
</div>
</div>
)}
{activeTab === 'automation' && (
<div className="space-y-6">
<h2 className="text-2xl font-bold">Claude Code Automation Status</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{[
{ name: 'Handbag Ingestion', status: 'running', lastRun: '0.2s ago', success: '99.97%' },
{ name: 'Deal Detection', status: 'running', lastRun: '0.5s ago', success: '100%' },
{ name: 'UX Feedback Parser', status: 'running', lastRun: '0.8s ago', success: '98.5%' },
{ name: 'Affiliate Link Checker', status: 'running', lastRun: '0.3s ago', success: '99.2%' },
{ name: 'Slack Notifications', status: 'running', lastRun: 'real-time', success: '100%' },
{ name: 'Smart Contract Generator', status: 'ready', lastRun: 'on-demand', success: '100%' },
{ name: 'AR Try-On Processor', status: 'running', lastRun: '0.6s ago', success: '96.8%' },
{ name: 'System Health Monitor', status: 'running', lastRun: '0.1s ago', success: '100%' }
].map((automation, index) => (
<div
key={index}
className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700"
>
<div className="flex items-center justify-between mb-4">
<h3 className="font-bold text-white">{automation.name}</h3>
<div className={`px-3 py-1 rounded-full text-xs font-bold ${
automation.status === 'running' ? 'bg-green-500/20 text-green-400' : 'bg-blue-500/20 text-blue-400'
}`}>
{automation.status.toUpperCase()}
</div>
</div>
<div className="space-y-2">
<div className="text-sm text-gray-400">
Last Run: <span className="font-semibold text-white">{automation.lastRun}</span>
</div>
<div className="text-sm text-gray-400">
Success Rate: <span className="font-semibold text-green-400">{automation.success}</span>
</div>
</div>
</div>
))}
</div>
<div className="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6 border border-gray-700">
<h3 className="text-xl font-bold mb-4">Recent Automation Logs</h3>
<div className="space-y-2 font-mono text-sm">
<div className="text-green-400">[0.2s ago] ✓ Ingested 400 SKUs from 5 sources</div>
<div className="text-green-400">[0.5s ago] ✓ Detected 3 new deals ({'>'}20% discount)</div>
<div className="text-blue-400">[0.8s ago] ℹ Processed 12 user feedback items</div>
<div className="text-green-400">[1.1s ago] ✓ All 200 affiliate links verified</div>
<div className="text-amber-400">[2.3s ago] ⚠ Flagged Hermès listing for legal review</div>
<div className="text-green-400">[3.5s ago] ✓ Database backup completed (320ms)</div>
</div>
</div>
</div>
)}
</main>
</div>
)
}