import { useState, useEffect } from 'react'; import { Link } from 'react-router-dom'; import { Users, Scissors, Calendar, FileText, DollarSign, TrendingUp, AlertCircle, } from 'lucide-react'; import { API_URL } from '../config'; interface Stat { label: string; value: number; sublabel: string; icon: any; color: string; path: string } export default function Dashboard() { const stats: Stat[] = [ { label: 'Active Clients', value: 0, sublabel: '+12 this month', icon: Users, color: 'from-blue-500 to-blue-600', path: '/clients' }, { label: 'Scheduled', value: 0, sublabel: '3 today', icon: Calendar, color: 'from-amber-500 to-amber-600', path: '/bookings' }, { label: 'Unpaid', value: 0, sublabel: '4 invoices', icon: FileText, color: 'from-red-500 to-red-600', path: '/invoices' }, { label: 'Revenue', value: 0, sublabel: 'This month', icon: DollarSign, color: 'from-emerald-500 to-emerald-600', path: '/invoices' }, ]; // Fetch stats const [statsData, setStatsData] = useState([]); const [recentBookings, setRecentBookings] = useState([]); useEffect(() => { Promise.all([ fetch(`${API_URL}/clients?limit=1`).then(r => r.json().catch(() => ({ total: 0 }))), fetch(`${API_URL}/bookings?status=scheduled`).then(r => r.json().catch(() => ({ items: [] }))), fetch(`${API_URL}/invoices`).then(r => r.json().catch(() => ({ items: [] }))), fetch(`${API_URL}/services`).then(r => r.json().catch(() => ({ items: [] }))), fetch(`${API_URL}/bookings?limit=5`).then(r => r.json().catch(() => ({ items: [] }))), ]).then(([clients, bookings, invoices, services, recent]) => { const paidCount = (invoices.items || []).filter((x: any) => x.status !== 'paid').length; const unpaidTotal = (invoices.items || []).reduce((sum: number, x: any) => sum + (x.total || 0), 0); setStatsData([ { ...stats[0], value: clients.total || 0 }, { ...stats[1], value: bookings.items?.filter((x: any) => x.status === 'scheduled').length || 0 }, { ...stats[2], value: paidCount, sublabel: `${paidCount} invoices` }, { ...stats[3], value: unpaidTotal / 100 || 0, sublabel: 'This month' }, ]); setRecentBookings(recent.items || []); }).catch(() => {}); }, []); const statusColors: Record = { scheduled: { bg: 'bg-amber-100', text: 'text-amber-700' }, confirmed: { bg: 'bg-blue-100', text: 'text-blue-700' }, in_progress: { bg: 'bg-purple-100', text: 'text-purple-700' }, completed: { bg: 'bg-green-100', text: 'text-green-700' }, cancelled: { bg: 'bg-red-100', text: 'text-red-700' }, }; return (
{/* Top Bar */}

Dashboard

{new Date().toLocaleDateString('en-US', { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' })}

New Booking
{/* Stats Row */}
{statsData.map((s, i) => (
{s.label}
{s.label === 'Revenue' ? `$${s.value}` : s.value}
{s.sublabel}
))}
{/* Two Column: Schedule + Alerts */}
{/* Left: Today's Schedule (2 cols) */}

Today's Schedule

View Full Calendar โ†’
{recentBookings.length === 0 ? (
๐Ÿ“…

No bookings today

Create your first booking โ†’
) : (
{recentBookings.map((booking) => { const sc = statusColors[booking.status] || statusColors.scheduled; return (
{booking.startAt ? new Date(booking.startAt).toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true }) : 'โ€”'}
๐Ÿพ
{booking.client?.firstName} {booking.client?.lastName}
{booking.service?.name} ยท {booking.assignedStaff || 'Unassigned'}
{booking.status} ); })}
)}
{/* Right: Quick Actions + Alerts */}

Quick Actions

Add Client
Create Booking
Generate Invoice
Send Message

Alerts

2 invoices overdue

1 pet vaccination expiring

); }