- Delete duplicate page-new.tsx in verification folder - Create reusable StatCard component in components/ui - Enhance StatusBadge component with icons and REJECTED status - Refactor 7 files to use StatusBadge instead of local getStatusBadge - Refactor Statistics.tsx to use shared StatCard component - Reduces overall code duplication from 9.85% to lower 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
132 lines
3.4 KiB
TypeScript
132 lines
3.4 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { adminService } from '@/services/admin.service';
|
|
import { AdminStatistics } from '@/types';
|
|
import { StatCard } from '@/components/ui';
|
|
|
|
export default function Statistics() {
|
|
const [stats, setStats] = useState<AdminStatistics | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
loadStatistics();
|
|
}, []);
|
|
|
|
const loadStatistics = async () => {
|
|
try {
|
|
setLoading(true);
|
|
setError(null);
|
|
const data = await adminService.getStatistics();
|
|
setStats(data);
|
|
} catch (err: any) {
|
|
setError(err.message || 'Erreur lors du chargement des statistiques');
|
|
setStats(null);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
if (loading) {
|
|
return <div className="text-center py-8">Chargement des statistiques...</div>;
|
|
}
|
|
|
|
if (error || !stats) {
|
|
return (
|
|
<div className="p-6">
|
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
|
|
{error || 'Erreur lors du chargement des statistiques'}
|
|
</div>
|
|
<button
|
|
onClick={loadStatistics}
|
|
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700"
|
|
>
|
|
Réessayer
|
|
</button>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="p-6">
|
|
<h1 className="text-2xl font-bold mb-6">Statistiques</h1>
|
|
|
|
{/* Utilisateurs */}
|
|
<div className="mb-8">
|
|
<h2 className="text-xl font-semibold mb-4">Utilisateurs</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-5 gap-4">
|
|
<StatCard
|
|
title="Total"
|
|
value={stats.users.total}
|
|
color="blue"
|
|
/>
|
|
<StatCard
|
|
title="Clients"
|
|
value={stats.users.clients}
|
|
color="green"
|
|
/>
|
|
<StatCard
|
|
title="Employés"
|
|
value={stats.users.employees}
|
|
color="purple"
|
|
/>
|
|
<StatCard
|
|
title="Admins"
|
|
value={stats.users.admins}
|
|
color="red"
|
|
/>
|
|
<StatCard
|
|
title="Emails vérifiés"
|
|
value={stats.users.verifiedEmails}
|
|
color="yellow"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Tickets */}
|
|
<div className="mb-8">
|
|
<h2 className="text-xl font-semibold mb-4">Tickets</h2>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-5 gap-4">
|
|
<StatCard
|
|
title="Total"
|
|
value={stats.tickets.total}
|
|
color="blue"
|
|
/>
|
|
<StatCard
|
|
title="En attente"
|
|
value={stats.tickets.pending}
|
|
color="yellow"
|
|
/>
|
|
<StatCard
|
|
title="Réclamés"
|
|
value={stats.tickets.claimed}
|
|
color="green"
|
|
/>
|
|
<StatCard
|
|
title="Rejetés"
|
|
value={stats.tickets.rejected}
|
|
color="red"
|
|
/>
|
|
<StatCard
|
|
title="Récupérés"
|
|
value={stats.tickets.claimed}
|
|
color="purple"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Bouton rafraîchir */}
|
|
<div className="mt-8 text-center">
|
|
<button
|
|
onClick={loadStatistics}
|
|
className="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700"
|
|
>
|
|
Rafraîchir
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|