Deploy Ladill Queue / deploy (push) Successful in 27s
Service selection shows the service name only, without the colored letter icon. Co-authored-by: Cursor <cursoragent@cursor.com>
211 lines
11 KiB
PHP
211 lines
11 KiB
PHP
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">
|
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
|
<meta name="theme-color" content="#f1f5f9">
|
|
<title>{{ $device->name }} · Queue Kiosk</title>
|
|
<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>
|
|
@keyframes kiosk-tap-pulse {
|
|
0%, 100% { transform: scale(1); box-shadow: 0 20px 40px -12px rgb(79 70 229 / 0.45); }
|
|
50% { transform: scale(1.02); box-shadow: 0 24px 48px -10px rgb(79 70 229 / 0.55); }
|
|
}
|
|
.kiosk-tap-btn { animation: kiosk-tap-pulse 2.4s ease-in-out infinite; }
|
|
</style>
|
|
</head>
|
|
<body
|
|
class="min-h-screen bg-slate-100 font-sans text-slate-900 antialiased"
|
|
x-data="kioskFlow(@js([
|
|
'issueUrl' => route('qms.kiosk.device.issue', $device->device_token),
|
|
'csrf' => csrf_token(),
|
|
'queues' => $queues->map(fn ($q) => [
|
|
'id' => $q->id,
|
|
'name' => $q->name,
|
|
])->values()->all(),
|
|
'collectName' => $settings['collect_name'],
|
|
'collectPhone' => $settings['collect_phone'],
|
|
'resetSeconds' => $settings['reset_seconds'],
|
|
'welcomeMessage' => $settings['welcome_message'] ?? null,
|
|
]))"
|
|
x-init="startTimer()"
|
|
>
|
|
<div class="pointer-events-none fixed inset-0 overflow-hidden" aria-hidden="true">
|
|
<div class="absolute -left-24 top-0 h-72 w-72 rounded-full bg-indigo-200/40 blur-3xl"></div>
|
|
<div class="absolute -right-16 bottom-0 h-80 w-80 rounded-full bg-violet-200/40 blur-3xl"></div>
|
|
</div>
|
|
|
|
<div class="fixed inset-x-0 top-0 z-10 h-1.5 bg-gradient-to-r from-indigo-600 to-violet-600"></div>
|
|
|
|
@include('qms.partials.kiosk-brand', ['logoUrl' => $logoUrl, 'logoAlt' => $logoAlt])
|
|
|
|
<div class="relative mx-auto flex min-h-screen max-w-3xl flex-col pt-20">
|
|
{{-- Welcome --}}
|
|
<template x-if="step === 'welcome'">
|
|
<div class="flex min-h-[calc(100vh-5rem)] flex-col items-center justify-center px-6 py-12 text-center">
|
|
<div class="max-w-xl">
|
|
<p class="text-sm font-semibold uppercase tracking-wider text-indigo-600">Queue</p>
|
|
<h1 class="mt-3 text-4xl font-bold tracking-tight text-slate-900 sm:text-5xl">
|
|
Welcome to {{ $organization?->name ?? 'Queue' }}
|
|
</h1>
|
|
<p
|
|
class="mt-4 text-lg text-slate-500"
|
|
x-text="welcomeMessage || 'Tap below to get your ticket'"
|
|
></p>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
@click="beginKiosk()"
|
|
class="kiosk-tap-btn btn-primary btn-primary-lg mt-16 w-full max-w-lg py-8 text-xl font-bold"
|
|
:disabled="loading"
|
|
>
|
|
<span x-show="!loading">Tap to begin</span>
|
|
<span x-show="loading">Please wait…</span>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- Service selection --}}
|
|
<template x-if="step === 'select'">
|
|
<div class="relative flex min-h-[calc(100vh-5rem)] flex-col items-center justify-center px-6 py-12">
|
|
<div class="absolute left-6 top-8 z-10">
|
|
@include('qms.partials.kiosk-back')
|
|
</div>
|
|
|
|
<div class="max-w-xl text-center">
|
|
<h2 class="text-2xl font-bold text-slate-900 sm:text-3xl">Choose a service</h2>
|
|
<p class="mt-2 text-slate-500">Select an option to get your ticket</p>
|
|
</div>
|
|
|
|
<template x-if="queues.length === 1">
|
|
<div class="mt-12 w-full max-w-lg">
|
|
<button
|
|
type="button"
|
|
class="group flex w-full flex-col items-center rounded-3xl border-2 border-slate-200 bg-white px-6 py-10 text-center shadow-sm transition hover:border-indigo-300 hover:shadow-md active:scale-[0.98]"
|
|
:disabled="loading"
|
|
@click="selectQueue(queues[0].id)"
|
|
>
|
|
<span class="text-xl font-bold text-slate-900" x-text="queues[0].name"></span>
|
|
<span class="mt-1 text-sm text-slate-500">Tap to get ticket</span>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-if="queues.length > 1">
|
|
<div class="mt-12 grid w-full max-w-2xl gap-4 sm:grid-cols-2">
|
|
<template x-for="queue in queues" :key="queue.id">
|
|
<button
|
|
type="button"
|
|
class="group flex flex-col items-center rounded-3xl border-2 border-slate-200 bg-white px-6 py-10 text-center shadow-sm transition hover:border-indigo-300 hover:shadow-md active:scale-[0.98]"
|
|
:disabled="loading"
|
|
@click="selectQueue(queue.id)"
|
|
>
|
|
<span class="text-xl font-bold text-slate-900" x-text="queue.name"></span>
|
|
<span class="mt-1 text-sm text-slate-500">Tap to get ticket</span>
|
|
</button>
|
|
</template>
|
|
</div>
|
|
</template>
|
|
|
|
<template x-if="queues.length === 0">
|
|
<div class="mt-12 w-full max-w-lg rounded-3xl border border-slate-200 bg-white p-8 text-center shadow-sm">
|
|
<p class="text-lg font-semibold text-slate-900">No services available</p>
|
|
<p class="mt-2 text-sm text-slate-500">Ask a staff member for assistance.</p>
|
|
</div>
|
|
</template>
|
|
|
|
<p x-show="error" x-cloak class="mt-6 max-w-lg rounded-xl bg-red-50 px-4 py-3 text-sm text-red-700" x-text="error"></p>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- Optional details --}}
|
|
<template x-if="step === 'details'">
|
|
<div class="relative flex min-h-[calc(100vh-5rem)] flex-col justify-center px-6 py-8">
|
|
<div class="absolute left-6 top-8 z-10">
|
|
@include('qms.partials.kiosk-back')
|
|
</div>
|
|
|
|
<div class="mx-auto w-full max-w-lg rounded-3xl border border-slate-200 bg-white p-6 shadow-sm">
|
|
<div class="mb-6">
|
|
<div class="flex items-center justify-between text-xs font-medium text-slate-500">
|
|
<span>Your details</span>
|
|
<span>Step 1 of 1</span>
|
|
</div>
|
|
<div class="mt-2 h-1.5 overflow-hidden rounded-full bg-slate-100">
|
|
<div class="h-full w-full rounded-full bg-gradient-to-r from-indigo-600 to-violet-600"></div>
|
|
</div>
|
|
<p class="mt-2 text-sm font-semibold text-slate-900">Tell us a little about yourself</p>
|
|
</div>
|
|
|
|
<p x-show="error" x-cloak class="mb-4 rounded-xl bg-red-50 px-4 py-3 text-sm text-red-700" x-text="error"></p>
|
|
|
|
<div class="space-y-4">
|
|
<div x-show="collectName">
|
|
<label class="block text-sm font-medium text-slate-600">Name</label>
|
|
<input
|
|
type="text"
|
|
x-model="customerName"
|
|
placeholder="Your name"
|
|
autocomplete="name"
|
|
class="mt-1 w-full rounded-xl border-slate-200 px-4 py-4 text-lg"
|
|
>
|
|
</div>
|
|
<div x-show="collectPhone">
|
|
<label class="block text-sm font-medium text-slate-600">Phone</label>
|
|
<input
|
|
type="tel"
|
|
x-model="customerPhone"
|
|
placeholder="Phone number"
|
|
autocomplete="tel"
|
|
class="mt-1 w-full rounded-xl border-slate-200 px-4 py-4 text-lg"
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
class="btn-primary mt-6 w-full py-3"
|
|
@click="issue()"
|
|
:disabled="loading"
|
|
>
|
|
<span x-show="!loading">Get ticket</span>
|
|
<span x-show="loading">Please wait…</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
{{-- Ticket issued --}}
|
|
<template x-if="step === 'ticket' && ticket">
|
|
<div class="flex min-h-[calc(100vh-5rem)] flex-col items-center justify-center px-6 py-8">
|
|
<div class="w-full max-w-lg rounded-3xl border border-slate-200 bg-white p-8 text-center shadow-sm">
|
|
<div class="mx-auto mb-4 flex h-20 w-20 items-center justify-center rounded-full bg-indigo-100 text-4xl text-indigo-600">✓</div>
|
|
<h2 class="text-2xl font-bold text-slate-900">You're in the queue!</h2>
|
|
<p class="mt-4 text-sm font-semibold uppercase tracking-wider text-slate-500">Your ticket number</p>
|
|
<p class="qms-kiosk__ticket-number mt-2" x-text="ticket?.ticket_number"></p>
|
|
|
|
<div class="mt-4 space-y-1 text-sm text-slate-600">
|
|
<p x-show="ticket?.position">
|
|
<span class="font-semibold text-slate-900" x-text="ticket?.position"></span>
|
|
<span> ahead of you</span>
|
|
</p>
|
|
<p x-show="formatWait(ticket?.estimated_wait_seconds)" x-text="formatWait(ticket?.estimated_wait_seconds)"></p>
|
|
</div>
|
|
|
|
<p class="mt-6 text-sm text-slate-500">Please take a seat. Your number will be called on the display.</p>
|
|
|
|
<button type="button" class="btn-primary btn-primary-lg mt-8 w-full" @click="reset()">
|
|
Done
|
|
<span x-show="resetCountdown" x-text="'(' + resetCountdown + 's)'"></span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</div>
|
|
</body>
|
|
</html>
|