Files
ladill-pos/resources/views/pos/kitchen/public.blade.php
T
isaacclad ede4aaa10c
Deploy Ladill POS / deploy (push) Successful in 46s
Add public token-gated kitchen display for POS devices.
Kitchen display devices open a full-screen KDS without staff login,
with feed/stream/bump over the device token. Shared kitchen board
logic is extracted so the signed-in Kitchen page stays in sync.
2026-07-15 22:52:28 +00:00

102 lines
6.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="en" class="h-full">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>Kitchen · {{ $locationName }}</title>
@include('partials.favicon')
<link rel="preconnect" href="https://fonts.bunny.net">
<link href="https://fonts.bunny.net/css?family=figtree:400,500,600,700&display=swap" rel="stylesheet" />
@vite(['resources/css/app.css', 'resources/js/app.js'])
<style>
[x-cloak] { display: none !important; }
</style>
</head>
<body class="min-h-full bg-slate-100 font-sans text-slate-900 antialiased">
<div class="fixed inset-x-0 top-0 z-20 h-1.5 bg-gradient-to-r from-amber-500 to-orange-600"></div>
<div x-data="posKitchen(@js([
'feedUrl' => $feedUrl,
'streamUrl' => $streamUrl,
'bumpUrl' => $bumpUrl,
'csrf' => csrf_token(),
]))"
class="mx-auto min-h-dvh max-w-[1600px] space-y-4 px-4 py-5 sm:px-6 lg:px-8">
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
<p class="text-xs font-semibold uppercase tracking-wider text-amber-700">Kitchen display</p>
<h1 class="mt-0.5 text-xl font-semibold tracking-tight text-slate-900 sm:text-2xl">{{ $locationName }}</h1>
<p class="mt-1 text-sm text-slate-500">Live tickets tap an item to advance it. No sign-in required on this screen.</p>
</div>
<div class="flex items-center gap-2">
<span class="rounded-full bg-white px-3 py-1 text-xs font-medium text-slate-500 ring-1 ring-slate-200"
x-text="loaded ? 'Live' : 'Connecting…'"></span>
<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>
</div>
@if($stations->isNotEmpty())
<div class="flex flex-wrap gap-1.5">
<button type="button" @click="activeStation = ''" :class="activeStation === '' ? 'bg-amber-600 text-white' : 'bg-white text-slate-600 ring-1 ring-slate-200'"
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-amber-600 text-white' : 'bg-white text-slate-600 ring-1 ring-slate-200'"
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 shadow-sm">
<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 x-show="line.source === 'online'" x-cloak class="rounded bg-blue-50 px-1.5 text-[10px] font-medium text-blue-700">online</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>
</body>
</html>