feat(frontend): workday summary modal, print analytics UI, staff zone-PIN management, report upgrades

manager_dashboard:
- DashboardPage: WorkdaySummaryModal integration (view / close-day flows); revenue chart upgrades
- WorkdaySummaryModal: new component — shows full shift/revenue summary before closing the day
- StaffTab: full rewrite — zone-assignment modal, reset-PIN modal, actions dropdown, richer staff card
- ProductsTab: digital-menu fields surfaced in product form
- PrintFontsTab: expanded font-size/weight controls per printer channel
- TablesConfigTab / TablesPage / tableColourStore: color picker and zone fields for tables
- FilterBar: unified filter component with date-range, printer, and category selectors
- CategoryPerformance / ProductPerformance / TableAnalytics: donut/bar charts,
  thermal+browser print modals, richer breakdown tables
- PrinterHistory: redesigned with per-printer drill-down and summary blocks
- TrafficAnalytics / WorkDaySummary / RevenueTrends / ShiftsOverview / StaffLeaderboard: polish pass
- tokens.js: design token updates

waiter_pwa:
- TableCard: show table color indicator from zone/colour config

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 20:28:23 +03:00
parent 79bd3b0f41
commit ac7ec45279
21 changed files with 3353 additions and 645 deletions

View File

@@ -1,71 +1,72 @@
import { create } from 'zustand'
import { persist } from 'zustand/middleware'
// Mirrors waiter_pwa/src/store/tableColourStore.js — same localStorage key so both apps share state.
// Must stay in sync with waiter_pwa/src/store/tableColourStore.js DEFAULT_COLOURS.
// The PWA uses these as its hardcoded fallback; the manager uses them for "reset to defaults".
export const DEFAULT_COLOURS = {
light: {
free: {
cardBg: '#d6d6d6',
badgeBg: '#e3e3e3',
nameText: '#3b485e',
badgeText: '#adadad',
cardBg: '#dde5ef',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#3d5270',
badgeText: '#3d5270',
},
mine: {
cardBg: '#e83030',
badgeBg: 'rgba(255,255,255,0.40)',
cardBg: '#e8610a',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#e8610a',
},
open: {
cardBg: '#ffbb29',
badgeBg: 'rgba(255,255,255,0.25)',
cardBg: '#FF8F60',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#FF8F60',
},
partially_paid: {
cardBg: '#e89230',
badgeBg: 'rgba(255,255,255,0.25)',
cardBg: '#FFDC67',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#d4a800',
},
paid: {
cardBg: '#79ad38',
badgeBg: 'rgba(255,255,255,0.25)',
cardBg: '#81D264',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#81D264',
},
},
dark: {
free: {
cardBg: '#243044',
badgeBg: 'rgba(26,35,50,0.50)',
nameText: '#ffffff',
badgeText: '#adadad',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#94b8d4',
badgeText: '#94b8d4',
},
mine: {
cardBg: '#e83030',
badgeBg: 'rgba(255,255,255,0.40)',
cardBg: '#e8610a',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#e8610a',
},
open: {
cardBg: '#ffbb29',
badgeBg: 'rgba(255,255,255,0.25)',
cardBg: '#FF8F60',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#FF8F60',
},
partially_paid: {
cardBg: '#e89230',
badgeBg: 'rgba(255,255,255,0.25)',
cardBg: '#FFDC67',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#d4a800',
},
paid: {
cardBg: '#79ad38',
badgeBg: 'rgba(255,255,255,0.25)',
cardBg: '#81D264',
badgeBg: 'rgba(255,255,255,0.92)',
nameText: '#ffffff',
badgeText: '#ffffff',
badgeText: '#81D264',
},
},
}