import { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { api } from '@/lib/api'; import type { Client, Event, Email, InsightsData } from '@/types'; import type { Interaction } from '@/types'; import { Users, Calendar, Mail, Plus, ArrowRight, Gift, Heart, Clock, AlertTriangle, Sparkles, UserCheck, PhoneForwarded, Star, Phone, FileText, MoreHorizontal } from 'lucide-react'; import { formatDate, getDaysUntil, getInitials } from '@/lib/utils'; import { EventTypeBadge } from '@/components/Badge'; import { PageLoader } from '@/components/LoadingSpinner'; import { usePinnedClients } from '@/hooks/usePinnedClients'; export default function DashboardPage() { const [clients, setClients] = useState([]); const [events, setEvents] = useState([]); const [emails, setEmails] = useState([]); const [insights, setInsights] = useState(null); const [recentInteractions, setRecentInteractions] = useState([]); const [loading, setLoading] = useState(true); const { pinnedIds, togglePin, isPinned } = usePinnedClients(); useEffect(() => { Promise.all([ api.getClients().catch(() => []), api.getEvents({ upcoming: 7 }).catch(() => []), api.getEmails({ status: 'draft' }).catch(() => []), api.getInsights().catch(() => null), api.getRecentInteractions(5).catch(() => []), ]).then(([c, e, em, ins, ri]) => { setClients(c); setEvents(e); setEmails(em); setInsights(ins as InsightsData | null); setRecentInteractions(ri as Interaction[]); setLoading(false); }); }, []); if (loading) return ; const pinnedClients = clients.filter((c) => pinnedIds.includes(c.id)); const stats = [ { label: 'Total Clients', value: clients.length, icon: Users, color: 'bg-blue-50 dark:bg-blue-900/30 text-blue-600 dark:text-blue-400', link: '/clients' }, { label: 'Upcoming Events', value: events.length, icon: Calendar, color: 'bg-emerald-50 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400', link: '/events' }, { label: 'Pending Drafts', value: emails.length, icon: Mail, color: 'bg-amber-50 dark:bg-amber-900/30 text-amber-600 dark:text-amber-400', link: '/emails' }, ]; const eventIcon = (type: string) => { if (type === 'birthday') return ; if (type === 'anniversary') return ; return ; }; return (

Dashboard

Welcome back. Here's your overview.

Add Client
{/* Stats */}
{stats.map((stat) => (

{stat.value}

{stat.label}

))}
{/* Pinned Clients */} {pinnedClients.length > 0 && (

Pinned Clients

{pinnedClients.map((client) => (
{getInitials(client.firstName, client.lastName)}

{client.firstName} {client.lastName}

{client.company || 'No company'}

))}
)} {/* AI Insights */} {insights && (insights.staleClients.length > 0 || insights.upcomingBirthdays.length > 0 || insights.suggestedFollowups.length > 0) && (

AI Insights

{insights.staleClients.length > 0 && (
Needs Attention

{insights.summary.staleCount} client{insights.summary.staleCount !== 1 ? 's' : ''} not contacted in 30+ days {insights.summary.neverContacted > 0 && `, ${insights.summary.neverContacted} never contacted`}

{insights.staleClients.slice(0, 3).map(c => (
{c.firstName[0]}{c.lastName[0]}

{c.firstName} {c.lastName}

{c.daysSinceContact ? `${c.daysSinceContact}d ago` : 'Never contacted'}

))} {insights.staleClients.length > 3 && ( +{insights.staleClients.length - 3} more )}
)} {insights.upcomingBirthdays.length > 0 && (
Birthdays This Week
{insights.upcomingBirthdays.map(c => (
๐ŸŽ‚

{c.firstName} {c.lastName}

{c.daysUntil === 0 ? 'Today!' : c.daysUntil === 1 ? 'Tomorrow' : `In ${c.daysUntil} days`}

))}
)} {insights.suggestedFollowups.length > 0 && (
Suggested Follow-ups

Contacted 14-30 days ago โ€” good time to reach out

{insights.suggestedFollowups.slice(0, 3).map(c => (
{c.firstName[0]}{c.lastName[0]}

{c.firstName} {c.lastName}

{c.daysSinceContact}d since last contact

))}
)}
)}
{/* Upcoming Events */}

Upcoming Events

View all
{events.length === 0 ? (

No upcoming events

) : ( events.slice(0, 5).map((event) => (
{eventIcon(event.type)}

{event.title}

{formatDate(event.date)}

{getDaysUntil(event.date)}d
)) )}
{/* Recent Interactions */}

Recent Interactions

{recentInteractions.length === 0 ? (

No interactions logged yet

) : ( recentInteractions.map((interaction) => { const typeIcons: Record = { call: Phone, meeting: Users, email: Mail, note: FileText, other: MoreHorizontal, }; const typeColors: Record = { call: 'text-green-600 dark:text-green-400', meeting: 'text-blue-600 dark:text-blue-400', email: 'text-purple-600 dark:text-purple-400', note: 'text-amber-600 dark:text-amber-400', other: 'text-slate-500', }; const Icon = typeIcons[interaction.type] || MoreHorizontal; return (

{interaction.title}

{interaction.client ? `${interaction.client.firstName} ${interaction.client.lastName}` : ''} {interaction.duration ? ` ยท ${interaction.duration}min` : ''}

{formatDate(interaction.contactedAt)} ); }) )}
{/* Recent Clients */}

Recent Clients

View all
{clients.length === 0 ? (

No clients yet

) : ( [...clients] .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()) .slice(0, 5) .map((client) => (
{client.firstName[0]}{client.lastName[0]}

{client.firstName} {client.lastName}

{client.company || client.email || 'No details'}

)) )}
); }