Deploy Ladill POS / deploy (push) Successful in 1m22s
Replace the kitchen display's 4s polling with a pushed feed. GET /kitchen/stream holds an SSE connection and emits the board the moment it changes (~1s tick, heartbeat between changes), so fired/bumped/guest orders land on screen near instantly. Bounded to ~25s per connection so PHP-FPM workers recycle — the browser's EventSource reconnects automatically; if EventSource is unavailable it falls back to polling /kitchen/feed. Sends X-Accel-Buffering: no so nginx streams it, and releases the session early (DB sessions don't lock, but be safe). feed()/stream() now share buildTickets(); behaviour of the JSON feed (initial load + fallback) is unchanged. Suite green (12). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
4.9 KiB
PHP
73 lines
4.9 KiB
PHP
<x-app-layout title="Kitchen">
|
||
<div x-data="posKitchen(@js([
|
||
'feedUrl' => route('pos.kitchen.feed'),
|
||
'streamUrl' => route('pos.kitchen.stream'),
|
||
'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>
|
||
|
||
@if($stations->isNotEmpty())
|
||
<div class="flex flex-wrap gap-1.5">
|
||
<button type="button" @click="activeStation = ''" :class="activeStation === '' ? 'bg-indigo-600 text-white' : 'bg-slate-100 text-slate-600'"
|
||
class="rounded-full px-3 py-1 text-xs font-medium">All stations</button>
|
||
@foreach($stations as $station)
|
||
<button type="button" @click="activeStation = '{{ $station->id }}'"
|
||
:class="activeStation === '{{ $station->id }}' ? 'bg-indigo-600 text-white' : 'bg-slate-100 text-slate-600'"
|
||
class="rounded-full px-3 py-1 text-xs font-medium">{{ $station->name }}</button>
|
||
@endforeach
|
||
</div>
|
||
@endif
|
||
|
||
<template x-if="loaded && visibleTickets.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 visibleTickets" :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.modifiers.length" x-cloak class="text-xs text-slate-500" x-text="line.modifiers.join(', ')"></p>
|
||
<p x-show="line.notes" x-cloak class="text-xs text-rose-600" x-text="line.notes"></p>
|
||
<div class="mt-0.5 flex items-center gap-1.5">
|
||
<span x-show="line.course" x-cloak class="rounded bg-slate-100 px-1.5 text-[10px] font-medium text-slate-500" x-text="line.course"></span>
|
||
<span x-show="line.station" x-cloak class="rounded bg-indigo-50 px-1.5 text-[10px] font-medium text-indigo-600" x-text="line.station"></span>
|
||
<span x-show="line.source === 'guest'" x-cloak class="rounded bg-violet-50 px-1.5 text-[10px] font-medium text-violet-700">guest</span>
|
||
<span class="text-[11px] uppercase tracking-wide text-slate-400" x-text="line.state"></span>
|
||
</div>
|
||
</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>
|