import { useState, useMemo } from 'react' import { useQuery } from '@tanstack/react-query' import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts' import client from '../../../api/client' import { FilterBar, FilterDateInput } from '../shared/FilterBar' import { Panel, DataTable, THead, TH, TR, TD, WaiterAvatar, ChartTooltip } from '../shared/TablePrimitives' import EmptyState from '../shared/EmptyState' import SkeletonTable from '../shared/SkeletonTable' import { fmtEUR, fmtNum, avatarColor } from '../shared/reportDesignTokens' function today() { return new Date().toISOString().slice(0, 10) } function monthAgo() { const d = new Date(); d.setDate(d.getDate() - 30); return d.toISOString().slice(0, 10) } const PODIUM_HEIGHTS = ['h-44', 'h-32', 'h-24'] const PODIUM_COLORS = [ 'bg-gradient-to-b from-amber-200 to-amber-100 ring-amber-300', 'bg-gradient-to-b from-slate-200 to-slate-100 ring-slate-300', 'bg-gradient-to-b from-orange-200 to-orange-100 ring-orange-300', ] const MEDAL_LABEL = ['1ος', '2ος', '3ος'] const PODIUM_ORDER = [1, 0, 2] export default function StaffLeaderboard() { const [from, setFrom] = useState(monthAgo()) const [to, setTo] = useState(today()) const { data, isLoading, isError, refetch } = useQuery({ queryKey: ['shifts-leaderboard', from, to], queryFn: () => client.get('/api/reports/shifts', { params: { from: from + 'T00:00:00', to: to + 'T23:59:59' } }).then(r => r.data), staleTime: 60 * 1000, }) const ranked = useMemo(() => { const shifts = data?.shifts || [] const map = new Map() shifts.forEach(s => { const cur = map.get(s.waiter_id) || { waiter_id: s.waiter_id, waiter_name: s.waiter_name, shifts: 0, orders: 0, value: 0 } cur.shifts += 1 cur.value += s.total_collected || 0 map.set(s.waiter_id, cur) }) return [...map.values()] .map(r => ({ ...r, avg_per_shift: r.shifts ? r.value / r.shifts : 0 })) .sort((a, b) => b.value - a.value) }, [data]) const top3 = ranked.slice(0, 3) const chartData = ranked.map(r => ({ name: (r.waiter_name || '').split(' ')[0], value: Math.round(r.value), })) if (isLoading) return
if (isError) return (
Αδυναμία φόρτωσης δεδομένων
) return (
{ranked.length} σερβιτόροι · άθροισμα περιόδου
{top3.length === 0 ? ( ) : (
{PODIUM_ORDER.map(rank => { const r = top3[rank] if (!r) return
const initials = (r.waiter_name || '').split(' ').map(p => p[0]).slice(0, 2).join('').toUpperCase() const cls = avatarColor(r.waiter_id) return (
{initials}
{r.waiter_name}
{r.shifts} βάρδιες
{MEDAL_LABEL[rank]}
{fmtEUR(r.value)}
) })}
)}
Θέση Σερβιτόρος Βάρδιες Συνολικά Έσοδα Μέσος / Βάρδια {ranked.map((r, i) => ( {i + 1} {r.shifts} {fmtEUR(r.value)} {fmtEUR(r.avg_per_shift)} ))}
fmtEUR(v)} />} cursor={{ fill: '#f1f5f9' }} />
) }