'use client' import { useQuery } from '@tanstack/react-query' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Progress } from '@/components/ui/progress' import { Users, Calendar, DollarSign, TrendingUp, Clock, CheckCircle, XCircle, AlertCircle, Image, Upload } from 'lucide-react' import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, LineChart, Line, PieChart, Pie, Cell } from 'recharts' interface DashboardStats { artists: { total: number active: number inactive: number } appointments: { total: number pending: number confirmed: number inProgress: number completed: number cancelled: number thisMonth: number lastMonth: number revenue: number } portfolio: { totalImages: number recentUploads: number } files: { totalUploads: number totalSize: number recentUploads: number } monthlyData: Array<{ month: string appointments: number revenue: number }> statusData: Array<{ name: string value: number color: string }> } const COLORS = { pending: '#f59e0b', confirmed: '#3b82f6', inProgress: '#10b981', completed: '#6b7280', cancelled: '#ef4444', } export function StatsDashboard() { const { data: stats, isLoading } = useQuery({ queryKey: ['dashboard-stats'], queryFn: async () => { const response = await fetch('/api/admin/stats') if (!response.ok) throw new Error('Failed to fetch stats') return response.json() as Promise }, refetchInterval: 30000, // Refresh every 30 seconds }) if (isLoading) { return (
{Array.from({ length: 8 }).map((_, i) => (
))}
) } if (!stats) { return (

Failed to load dashboard statistics

) } const appointmentGrowth = stats.appointments.thisMonth > 0 ? ((stats.appointments.thisMonth - stats.appointments.lastMonth) / stats.appointments.lastMonth) * 100 : 0 const activeArtistPercentage = stats.artists.total > 0 ? (stats.artists.active / stats.artists.total) * 100 : 0 return (
{/* Key Metrics */}
Total Artists
{stats.artists.total}
{stats.artists.active} active
Total Appointments
{stats.appointments.total}
= 0 ? 'text-green-500' : 'text-red-500'}`} /> = 0 ? 'text-green-500' : 'text-red-500'}> {appointmentGrowth >= 0 ? '+' : ''}{appointmentGrowth.toFixed(1)}% from last month
Monthly Revenue
${stats.appointments.revenue.toLocaleString()}

From {stats.appointments.thisMonth} appointments this month

Portfolio Images
{stats.portfolio.totalImages}

{stats.portfolio.recentUploads} uploaded this week

{/* Appointment Status Overview */}
Pending
{stats.appointments.pending}
Confirmed
{stats.appointments.confirmed}
In Progress
{stats.appointments.inProgress}
Completed
{stats.appointments.completed}
Cancelled
{stats.appointments.cancelled}
{/* Charts */}
{/* Monthly Appointments Trend */} Monthly Appointments {/* Appointment Status Distribution */} Appointment Status Distribution `${name} ${(percent * 100).toFixed(0)}%`} outerRadius={80} fill="#8884d8" dataKey="value" > {stats.statusData.map((entry, index) => ( ))}
{/* Monthly Revenue Trend */} Monthly Revenue Trend [`$${value}`, 'Revenue']} /> {/* File Storage Stats */}
Total Files
{stats.files.totalUploads}

{stats.files.recentUploads} uploaded this week

Storage Used
{(stats.files.totalSize / (1024 * 1024)).toFixed(1)} MB

Across all uploads

Active Artists
{stats.artists.active}
of {stats.artists.total} total {activeArtistPercentage.toFixed(0)}%
) }