Deploy Ladill POS / deploy (push) Successful in 30s
Gated by a per-location service_style (retail | restaurant). Restaurant mode adds: - Floor screen with tables (areas, seats, status) — tap a free table to open a dine-in tab; takeaway/counter orders open from the same screen. - Open tickets (tabs): a sale stays pending while items are added; lines persist as you go (posTicket Alpine component posts each change to the server). - Send-to-kitchen fires un-sent lines; a polling Kitchen Display (KDS) shows active tickets and bumps items queued → preparing → ready → served. - Settlement reuses the existing cash / Ladill Pay flow; paying closes the tab and frees the table (PosSaleService::closeTicket, wired into both pay paths). - Settings gains the mode toggle and a tables manager. Schema is additive (new pos_tables; service_style on locations; order/kitchen columns on sales + lines). Retail flow is untouched. Sidebar surfaces Floor + Kitchen only in restaurant mode. New PosRestaurantTest covers the dine-in lifecycle end to end; suite green (10 passed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
54 lines
3.3 KiB
PHP
54 lines
3.3 KiB
PHP
<x-app-layout title="Kitchen">
|
||
<div x-data="posKitchen(@js([
|
||
'feedUrl' => route('pos.kitchen.feed'),
|
||
'bumpUrl' => route('pos.kitchen.bump', ['line' => '__ID__']),
|
||
]))" class="space-y-4">
|
||
|
||
<div class="flex items-center justify-between">
|
||
<div>
|
||
<h1 class="text-lg font-semibold text-slate-900">Kitchen</h1>
|
||
<p class="mt-1 text-sm text-slate-500">Live tickets — tap an item to advance it. Refreshes automatically.</p>
|
||
</div>
|
||
<button type="button" @click="load()" class="rounded-xl border border-slate-200 bg-white px-3 py-2 text-sm font-medium text-slate-600 hover:bg-slate-50">Refresh</button>
|
||
</div>
|
||
|
||
<template x-if="loaded && tickets.length === 0">
|
||
<div class="rounded-2xl border border-dashed border-slate-200 bg-white px-6 py-16 text-center">
|
||
<p class="text-sm text-slate-500">No active tickets. Fired orders will appear here.</p>
|
||
</div>
|
||
</template>
|
||
|
||
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
|
||
<template x-for="t in tickets" :key="t.id">
|
||
<div class="flex flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white">
|
||
<div class="flex items-center justify-between border-b border-slate-100 bg-slate-50 px-4 py-2.5">
|
||
<div>
|
||
<p class="text-sm font-semibold text-slate-900" x-text="t.table ? t.table : t.order_type.replace('_',' ')"></p>
|
||
<p class="text-[11px] text-slate-400" x-text="t.reference"></p>
|
||
</div>
|
||
<span class="rounded-full bg-slate-900/5 px-2 py-0.5 text-xs font-medium text-slate-600" x-text="elapsed(t.sent_at)"></span>
|
||
</div>
|
||
<div class="flex-1 divide-y divide-slate-100">
|
||
<template x-for="line in t.lines" :key="line.id">
|
||
<div class="flex items-center justify-between gap-2 px-4 py-2.5"
|
||
:class="line.state === 'ready' ? 'bg-emerald-50' : (line.state === 'preparing' ? 'bg-amber-50/60' : '')">
|
||
<div class="min-w-0">
|
||
<p class="text-sm font-medium text-slate-900">
|
||
<span x-text="line.quantity + '×'"></span>
|
||
<span x-text="line.name"></span>
|
||
</p>
|
||
<p x-show="line.notes" x-cloak class="text-xs text-rose-600" x-text="line.notes"></p>
|
||
<p class="text-[11px] uppercase tracking-wide text-slate-400" x-text="line.state"></p>
|
||
</div>
|
||
<button type="button" @click="bump(line)"
|
||
class="shrink-0 rounded-lg border border-slate-200 bg-white px-2.5 py-1.5 text-xs font-semibold text-slate-700 hover:bg-slate-50"
|
||
x-text="nextLabel(line.state)"></button>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
</div>
|
||
</div>
|
||
</x-app-layout>
|