'use client' import { useEffect, useState, useCallback } from 'react' import Link from 'next/link' import { Header } from '@/components/layout/Header' interface ProductStats { active: number draft: number total: number withoutImages: number } interface LastSync { createdAt: string userName: string status: string created: number updated: number deactivated: number errors: number } interface DashboardStats { products: ProductStats lastSync: LastSync | null } function StatCard({ icon, label, value, sub, href, loading, error, accent, }: { icon: string label: string value: string | number | null sub?: string href?: string loading?: boolean error?: boolean accent?: 'indigo' | 'amber' | 'green' | 'red' }) { const accentClass = { indigo: 'border-indigo-500/30 bg-indigo-500/5', amber: 'border-amber-500/30 bg-amber-500/5', green: 'border-green-500/30 bg-green-500/5', red: 'border-red-500/30 bg-red-500/5', }[accent ?? 'indigo'] const content = (
{icon}

{label}

{loading ? (

β€”

) : error ? (

Erreur

) : (

{value ?? 'β€”'}

)} {sub &&

{sub}

}
) return href ? {content} : content } function ActionCard({ href, icon, label, description }: { href: string; icon: string; label: string; description: string }) { return ( {icon}

{label}

{description}

) } function formatDate(iso: string) { return new Intl.DateTimeFormat('fr-FR', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit', }).format(new Date(iso)) } export default function DashboardPage() { const [stats, setStats] = useState(null) const [statsError, setStatsError] = useState(false) const [statsLoading, setStatsLoading] = useState(true) const [pendingCount, setPendingCount] = useState(null) const [pendingLoading, setPendingLoading] = useState(false) const [pendingError, setPendingError] = useState(false) useEffect(() => { fetch('/api/dashboard/stats') .then((r) => r.json()) .then((data) => { if (data.error) throw new Error(data.error) setStats(data) }) .catch(() => setStatsError(true)) .finally(() => setStatsLoading(false)) }, []) const loadPending = useCallback(async () => { setPendingLoading(true) setPendingError(false) try { const r = await fetch('/api/dashboard/pending') const data = await r.json() if (data.error) throw new Error(data.error) setPendingCount(data.count) } catch { setPendingError(true) } finally { setPendingLoading(false) } }, []) const lastSync = stats?.lastSync return ( <>
{/* ── KPIs ─────────────────────────────────────────────── */}

Vue d'ensemble

0 ? 'amber' : 'green'} href="/images" /> {/* Pending β€” chargement lazy */}
✨

En attente de crΓ©ation

{pendingLoading ? (

β€”

) : pendingError ? (

Erreur β€” rΓ©essayer

) : pendingCount !== null ? (

{pendingCount}

) : ( )} {pendingCount !== null && (

depuis Google Sheets

)}
{/* ── DerniΓ¨re sync dΓ©tail ──────────────────────────────── */} {!statsLoading && lastSync && (

Dernière synchronisation

{formatDate(lastSync.createdAt)}

par {lastSync.userName}

{lastSync.status === 'success' ? 'βœ… SuccΓ¨s' : '❌ Erreur'}
{[ { label: 'CrΓ©ations', value: lastSync.created, color: 'text-green-400' }, { label: 'Mises Γ  jour', value: lastSync.updated, color: 'text-blue-400' }, { label: 'DΓ©sactivΓ©s', value: lastSync.deactivated, color: 'text-amber-400' }, { label: 'Erreurs', value: lastSync.errors, color: 'text-red-400' }, ].map(({ label, value, color }) => (

{value}

{label}

))}
Nouvelle sync β†’
)} {/* ── Actions rapides ───────────────────────────────────── */}

Actions rapides

) }