import { useState } from 'react' import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query' import { Trash2 } from 'lucide-react' import toast from 'react-hot-toast' import { LineChart, Line, 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, StatusBadge, WaiterAvatar, ChartTooltip } from '../shared/TablePrimitives' import DrillDownModal from '../shared/DrillDownModal' import OrderDetailModal from '../shared/OrderDetailModal' import ShiftDetailModal from '../shared/ShiftDetailModal' import DeleteConfirmModal from '../../../ui/DeleteConfirmModal' import EmptyState from '../shared/EmptyState' import SkeletonTable from '../shared/SkeletonTable' import ExportButton from '../shared/ExportButton' import { fmtEUR, fmtNum, fmtDate, fmtTime, fmtDuration, fmtDateTime, fmtDateStr } 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) } // ── Workday drill-down modal ──────────────────────────────────────────────── function WorkDayModal({ day, onClose, onDeleteShift }) { const [tab, setTab] = useState('orders') const [drillOrder, setDrillOrder] = useState(null) const [detailShift, setDetailShift] = useState(null) const { data: ordersData } = useQuery({ queryKey: ['business-day-orders', day.id], queryFn: () => client.get('/api/reports/orders/history', { params: { business_day_id: day.id, page_size: 200 } }).then(r => r.data), staleTime: 0, }) const { data: shiftsData } = useQuery({ queryKey: ['shifts-for-day', day.id], queryFn: () => client.get('/api/reports/shifts', { params: { business_day_id: day.id } }).then(r => r.data), staleTime: 0, }) const orders = Array.isArray(ordersData) ? ordersData : [] const shifts = shiftsData?.shifts || [] const TABS = [ { key: 'orders', label: `Παραγγελίες (${orders.length})` }, { key: 'shifts', label: `Βάρδιες (${shifts.length})` }, ] return ( <> {/* Tabs */}
{TABS.map(t => ( ))}
{/* Orders tab */} {tab === 'orders' && ( orders.length === 0 ?
Δεν βρέθηκαν παραγγελίες
: #ΤραπέζιΆνοιξεΈκλεισε ΕίδηΣύνολοΚατάσταση {orders.map(o => { const total = (o.items || []).filter(i => i.status !== 'cancelled').reduce((s, i) => s + i.unit_price * i.quantity, 0) return ( setDrillOrder(o)} className="cursor-pointer"> #{o.id} {o.table_name ?? o.table_id} {fmtDateTime(o.opened_at)} {o.closed_at ? fmtDateTime(o.closed_at) : '—'} {(o.items || []).length} {fmtEUR(total)} ) })} )} {/* Shifts tab */} {tab === 'shifts' && ( shifts.length === 0 ?
Δεν βρέθηκαν βάρδιες
: Σερβιτόρος Έναρξη Λήξη Διάρκεια Εισπράχθηκαν Κατάσταση {shifts.map(s => ( setDetailShift(s)} className="cursor-pointer"> {fmtDateTime(s.started_at)} {s.ended_at ? fmtDateTime(s.ended_at) : — ενεργή —} {fmtDuration(s.started_at, s.ended_at)} {fmtEUR(s.total_collected)}
{!s.is_active && ( )}
))}
)}
{drillOrder && ( setDrillOrder(null)} /> )} {detailShift && ( setDetailShift(null)} /> )} ) } // ── Main page ─────────────────────────────────────────────────────────────── export default function WorkDaySummary() { const [from, setFrom] = useState(monthAgo()) const [to, setTo] = useState(today()) const [drillDay, setDrillDay] = useState(null) const [deleteDay, setDeleteDay] = useState(null) const [deleteShift, setDeleteShift] = useState(null) const qc = useQueryClient() const { data, isLoading, isError, refetch } = useQuery({ queryKey: ['business-days', from, to], queryFn: () => client.get('/api/reports/business-days', { params: { from: from + 'T00:00:00', to: to + 'T23:59:59' } }).then(r => r.data), staleTime: 0, }) const deleteDayMutation = useMutation({ mutationFn: (id) => client.delete(`/api/business-day/${id}`), onSuccess: () => { toast.success('Η εργάσιμη μέρα διαγράφηκε') qc.invalidateQueries({ queryKey: ['business-days'] }) qc.invalidateQueries({ queryKey: ['business-days-list'] }) setDeleteDay(null) }, onError: (err) => { toast.error(err?.response?.data?.detail || 'Σφάλμα διαγραφής εργάσιμης μέρας') setDeleteDay(null) }, }) const deleteShiftMutation = useMutation({ mutationFn: (id) => client.delete(`/api/shifts/${id}`), onSuccess: () => { toast.success('Η βάρδια και οι παραγγελίες της διαγράφηκαν') qc.invalidateQueries({ queryKey: ['shifts'] }) qc.invalidateQueries({ queryKey: ['shifts-for-day'] }) qc.invalidateQueries({ queryKey: ['business-days'] }) qc.invalidateQueries({ queryKey: ['business-days-list'] }) setDeleteShift(null) }, onError: (err) => { toast.error(err?.response?.data?.detail || 'Σφάλμα διαγραφής βάρδιας') setDeleteShift(null) }, }) const days = data?.business_days || [] const chartData = [...days].reverse().map(d => ({ date: fmtDate(d.opened_at), revenue: d.revenue, })) if (isLoading) return
if (isError) return (
Αδυναμία φόρτωσης δεδομένων
) return (
}>
{chartData.length > 0 && (
'€' + v} /> fmtEUR(v)} />} />
)}
{days.length === 0 ? ( ) : ( Εργάσιμη Μέρα Άνοιξε Έκλεισε Διάρκεια Παραγγελίες Έσοδα Ακυρώσεις Σερβιτόροι Κατάσταση {days.map(d => ( setDrillDay(d)} striped> {fmtDate(d.opened_at)} {fmtTime(d.opened_at)} {d.closed_at ? fmtTime(d.closed_at) : '—'} {fmtDuration(d.opened_at, d.closed_at)} {fmtNum(d.order_count)} {fmtEUR(d.revenue)} {fmtNum(d.cancellation_count)} {fmtNum(d.waiter_count)} {d.status === 'closed' && ( )} ))} )}
{drillDay && ( setDrillDay(null)} onDeleteShift={s => setDeleteShift(s)} /> )} {deleteDay && ( deleteDayMutation.mutate(deleteDay.id)} onCancel={() => setDeleteDay(null)} /> )} {deleteShift && ( deleteShiftMutation.mutate(deleteShift.id)} onCancel={() => setDeleteShift(null)} /> )}
) }