branch backend + ajout du serveur backend, next, et sqlite
This commit is contained in:
104
backendia/dashboard/src/app/contributors/page.tsx
Normal file
104
backendia/dashboard/src/app/contributors/page.tsx
Normal file
@@ -0,0 +1,104 @@
|
||||
import { fetchApi } from "@/lib/api";
|
||||
import { Users, Award, Camera, Clock } from "lucide-react";
|
||||
|
||||
interface Contributor {
|
||||
wallet_hash: string;
|
||||
photo_count: number;
|
||||
last_upload: string;
|
||||
}
|
||||
|
||||
export default async function ContributorsPage() {
|
||||
let contributors: Contributor[] = [];
|
||||
try {
|
||||
const response = await fetchApi('/api/contributors');
|
||||
contributors = response.contributors;
|
||||
} catch (error) {
|
||||
console.error("Error fetching contributors:", error);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="flex flex-col gap-2">
|
||||
<h2 className="text-3xl font-bold tracking-tight">Top Contributeurs</h2>
|
||||
<p className="text-slate-400">Classement des utilisateurs selon leur contribution à l'entraînement de l'IA.</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
|
||||
{/* Stats Summary */}
|
||||
<div className="lg:col-span-1 space-y-6">
|
||||
<StatCard
|
||||
title="Total Contributeurs"
|
||||
value={contributors.length}
|
||||
icon={<Users className="text-indigo-400" />}
|
||||
/>
|
||||
<StatCard
|
||||
title="Total Photos"
|
||||
value={contributors.reduce((acc, c) => acc + c.photo_count, 0)}
|
||||
icon={<Camera className="text-emerald-400" />}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Table */}
|
||||
<div className="lg:col-span-3 bg-slate-900 border border-slate-800 rounded-2xl overflow-hidden">
|
||||
<table className="w-full text-left">
|
||||
<thead className="bg-slate-950/50 border-b border-slate-800">
|
||||
<tr>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-widest">Rang</th>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-widest">Wallet Hash</th>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-widest text-center">Photos</th>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-500 uppercase tracking-widest text-right">Dernier Upload</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-800">
|
||||
{contributors.map((c, index) => (
|
||||
<tr key={c.wallet_hash} className="hover:bg-slate-800/30 transition-colors">
|
||||
<td className="px-6 py-4">
|
||||
<div className="flex items-center gap-3">
|
||||
{index < 3 ? (
|
||||
<Award className={index === 0 ? "text-yellow-500" : index === 1 ? "text-slate-400" : "text-amber-700"} />
|
||||
) : (
|
||||
<span className="text-slate-500 font-mono w-6 text-center">#{index + 1}</span>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-4">
|
||||
<span className="font-mono text-xs text-slate-300">{c.wallet_hash}</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-center">
|
||||
<span className="px-2 py-1 bg-indigo-500/10 text-indigo-400 rounded-md text-xs font-bold border border-indigo-500/20">
|
||||
{c.photo_count}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-4 text-right text-xs text-slate-400 flex items-center justify-end gap-2">
|
||||
<Clock size={14} />
|
||||
{new Date(c.last_upload).toLocaleString()}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
{contributors.length === 0 && (
|
||||
<div className="py-24 text-center text-slate-500">
|
||||
Aucun contributeur enregistré pour le moment.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function StatCard({ title, value, icon }: any) {
|
||||
return (
|
||||
<div className="bg-slate-900 border border-slate-800 p-6 rounded-2xl flex items-center justify-between">
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs text-slate-500 font-bold uppercase tracking-widest">{title}</p>
|
||||
<p className="text-3xl font-bold">{value}</p>
|
||||
</div>
|
||||
<div className="w-12 h-12 bg-slate-800 rounded-xl flex items-center justify-center shadow-inner">
|
||||
{icon}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user