import { useQuery } from '@tanstack/react-query'
import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell } from 'recharts'
import { TrendingUp, ReceiptText, Clock, Users, Trophy, XCircle, Package, Sunset, PiggyBank, ShoppingBag } from 'lucide-react'
import client from '../../../api/client'
import { FilterBar } from '../shared/FilterBar'
import { Panel, DataTable, THead, TH, TR, TD, StatusBadge, WaiterAvatar, ChartTooltip } from '../shared/TablePrimitives'
import StatCard from '../shared/StatCard'
import EmptyState from '../shared/EmptyState'
import SkeletonTable from '../shared/SkeletonTable'
import ExportButton from '../shared/ExportButton'
import { fmtEUR, fmtNum, fmtTime, fmtDateTime } from '../shared/reportDesignTokens'
export default function Today() {
const { data: bdData, isLoading: bdLoading } = useQuery({
queryKey: ['business-day-current'],
queryFn: () => client.get('/api/reports/business-days/current').then(r => r.data),
staleTime: 30 * 1000,
refetchInterval: 30 * 1000,
})
const bd = bdData?.business_day
const { data: ordersData, isLoading: ordersLoading } = useQuery({
queryKey: ['today-orders', bd?.id],
queryFn: () => client.get('/api/reports/orders/history', { params: { business_day_id: bd.id, page_size: 200 } }).then(r => r.data),
enabled: !!bd?.id,
staleTime: 30 * 1000,
refetchInterval: 30 * 1000,
})
const { data: trafficData } = useQuery({
queryKey: ['today-traffic', bd?.id],
queryFn: () => client.get('/api/reports/traffic', { params: { business_day_id: bd.id } }).then(r => r.data),
enabled: !!bd?.id,
staleTime: 30 * 1000,
})
if (bdLoading || ordersLoading) {
return
}
if (!bd) {
return (
)
}
const orders = Array.isArray(ordersData) ? ordersData : []
const hourlyMap = {}
;(trafficData?.by_hour || []).forEach(h => { hourlyMap[h.hour] = h })
const hours = Array.from({ length: 14 }, (_, i) => 10 + i)
const hourlyChart = hours.map(h => ({
hour: `${String(h).padStart(2, '0')}:00`,
revenue: hourlyMap[h]?.revenue || 0,
}))
const nowH = new Date().getHours()
return (
Εργάσιμη μέρα ανοιχτή · άνοιξε {fmtTime(bd.opened_at)}
}>
Ζωντανή Εικόνα
{fmtEUR(bd.revenue)}
{bd.orders_closed} κλειστές παραγγελίες
·
{fmtEUR(bd.orders_closed ? bd.revenue / bd.orders_closed : 0)} μέσος όρος
{bd.trackable_profit > 0 && (
Μεικτό Κέρδος
{fmtEUR(bd.trackable_profit)}
{bd.revenue > 0 && (
{((bd.trackable_profit / bd.revenue) * 100).toFixed(0)}% margin
{bd.has_gap && ⚠ μερικό}
)}
)}
{bd.top_product && (
)}
{bd.total_cost > 0 && (
)}
{bd.trackable_profit > 0 && (
)}
Σήμερα}>
'€' + v} />
fmtEUR(v)} />} cursor={{ fill: '#f1f5f9' }} />
{hourlyChart.map((entry, i) => (
| nowH ? '#e2e8f0' : '#60a5fa'} />
))}
|
}>
# | Τραπέζι | Άνοιξε | Έκλεισε |
Είδη | Σύνολο | Κέρδος | Κατάσταση |
{orders.slice(0, 30).map(o => {
const activeItems = (o.items || []).filter(i => ['active', 'paid'].includes(i.status))
const total = activeItems.reduce((s, i) => s + i.unit_price * i.quantity, 0)
const costedItems = activeItems.filter(i => i.unit_cost != null)
const orderProfit = costedItems.length > 0
? costedItems.reduce((s, i) => s + (i.unit_price - i.unit_cost) * i.quantity, 0)
: null
const isCancelled = o.status === 'cancelled'
return (
| #{o.id} |
{o.table_id} |
{fmtDateTime(o.opened_at)} |
{fmtDateTime(o.closed_at)} |
{(o.items || []).length} |
{fmtEUR(total)} |
{orderProfit != null
? = 0 ? 'text-green-700' : 'text-red-600'}>{fmtEUR(orderProfit)}
: —
}
|
|
)
})}
)
}