Overhaul of the frontend on waiters, orders, and payment events

Manager Dashboard: product reorder/bulk actions, preference sub-choices
UI, expanded reports with DateInput component, waiter management updates,
order detail improvements, Docker config and backend dockerignore added.

Backend: table groups, auto-numbering, has_active_order flag, expanded
reporting endpoints, waiter zone management, user schema updates, system
router additions, table router fixes.

Waiter PWA: TableDetailPage order/payment event improvements.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-24 17:37:34 +03:00
parent ee51e52acf
commit 603fd45eaa
18 changed files with 2243 additions and 256 deletions

View File

@@ -0,0 +1,79 @@
/**
* DateInput / DateTimeInput
*
* Native date pickers display in the OS/browser locale (MM/DD/YYYY on en-US).
* These wrappers overlay the native input with a visible DD/MM/YYYY display
* while keeping the full native picker UX (click, keyboard, mobile wheel).
*
* Props mirror a plain <input>: value (YYYY-MM-DD or YYYY-MM-DDTHH:MM),
* onChange (receives the same synthetic event), className.
*/
import { useRef } from 'react'
function formatDateGR(value) {
// value is "YYYY-MM-DD"
if (!value) return ''
const [y, m, d] = value.split('-')
if (!y || !m || !d) return value
return `${d}/${m}/${y}`
}
function formatDateTimeGR(value) {
// value is "YYYY-MM-DDTHH:MM"
if (!value) return ''
const [datePart, timePart] = value.split('T')
if (!datePart) return value
const [y, m, d] = datePart.split('-')
if (!y || !m || !d) return value
return `${d}/${m}/${y}${timePart ? ' ' + timePart : ''}`
}
export function DateInput({ value, onChange, className = '', ...rest }) {
const ref = useRef(null)
return (
<div
className={`relative cursor-pointer ${className}`}
onClick={() => ref.current?.showPicker?.()}
>
{/* Visible display */}
<div className="absolute inset-0 flex items-center px-3 pointer-events-none z-10 bg-white rounded-lg text-sm text-gray-800">
{value ? formatDateGR(value) : <span className="text-gray-400">ΗΗ/ΜΜ/ΕΕΕΕ</span>}
</div>
{/* Native input — invisible but functional (provides the picker) */}
<input
ref={ref}
type="date"
value={value}
onChange={onChange}
className="opacity-0 w-full h-full absolute inset-0 cursor-pointer"
tabIndex={0}
{...rest}
/>
</div>
)
}
export function DateTimeInput({ value, onChange, className = '', ...rest }) {
const ref = useRef(null)
return (
<div
className={`relative cursor-pointer ${className}`}
onClick={() => ref.current?.showPicker?.()}
>
<div className="absolute inset-0 flex items-center px-3 pointer-events-none z-10 bg-white rounded-lg text-sm text-gray-800">
{value ? formatDateTimeGR(value) : <span className="text-gray-400">ΗΗ/ΜΜ/ΕΕΕΕ ΩΩ:ΛΛ</span>}
</div>
<input
ref={ref}
type="datetime-local"
value={value}
onChange={onChange}
className="opacity-0 w-full h-full absolute inset-0 cursor-pointer"
tabIndex={0}
{...rest}
/>
</div>
)
}