diff --git a/app/Http/Controllers/Qms/KioskDeviceController.php b/app/Http/Controllers/Qms/KioskDeviceController.php
index 0449cbd..066377b 100644
--- a/app/Http/Controllers/Qms/KioskDeviceController.php
+++ b/app/Http/Controllers/Qms/KioskDeviceController.php
@@ -33,6 +33,7 @@ class KioskDeviceController extends Controller
return view('qms.kiosk.device', [
'device' => $device,
+ 'organization' => $organization,
'queues' => $queues,
'settings' => $settings,
'logoUrl' => $organization
@@ -41,7 +42,6 @@ class KioskDeviceController extends Controller
'logoAlt' => $organization
? OrganizationBranding::logoAlt($organization)
: 'Ladill Queue',
- 'poweredByLogoUrl' => OrganizationBranding::assetUrl(OrganizationBranding::POWERED_BY_LOGO),
]);
}
diff --git a/resources/css/app.css b/resources/css/app.css
index 98cbbee..76807c0 100644
--- a/resources/css/app.css
+++ b/resources/css/app.css
@@ -428,104 +428,14 @@ html:has(.qms-display) body {
rgb(255 255 255 / 0.97);
}
-/* Self-service kiosk */
-html:has(.qms-kiosk),
-html:has(.qms-kiosk) body,
-html:has(.qms-kiosk) .qms-kiosk {
+/* Self-service kiosk — ticket number sizing (Frontdesk-style shell uses Tailwind) */
+html:has(.qms-kiosk__ticket-number),
+html:has(.qms-kiosk__ticket-number) body {
font-family: 'Figtree', ui-sans-serif, system-ui, sans-serif;
}
-html:has(.qms-kiosk),
-html:has(.qms-kiosk) body {
- height: 100%;
- overflow: hidden;
-}
-
-.qms-kiosk {
- display: flex;
- flex-direction: column;
- height: 100dvh;
- max-height: 100dvh;
- overflow: hidden;
- background:
- radial-gradient(ellipse 90% 60% at 50% -20%, rgb(238 242 255 / 0.9), transparent),
- linear-gradient(180deg, rgb(248 250 252) 0%, rgb(255 255 255) 100%);
- color: rgb(15 23 42);
-}
-
-.qms-kiosk__shell {
- display: flex;
- min-height: 0;
- flex: 1;
- flex-direction: column;
-}
-
-.qms-kiosk__main {
- display: flex;
- min-height: 0;
- flex: 1;
- flex-direction: column;
- align-items: center;
- justify-content: center;
-}
-
-.qms-kiosk__queue-grid {
- display: grid;
- width: 100%;
- gap: 0.75rem;
-}
-
-.qms-kiosk__queue-btn {
- display: flex;
- width: 100%;
- align-items: center;
- gap: 1rem;
- border-radius: 1rem;
- border: 1px solid rgb(226 232 240);
- background: #fff;
- padding: 1rem 1.25rem;
- text-align: left;
- box-shadow: 0 1px 2px rgb(15 23 42 / 0.04);
- transition: border-color 0.15s ease, box-shadow 0.15s ease;
-}
-
-.qms-kiosk__queue-btn:hover {
- border-color: rgb(165 180 252);
- box-shadow: 0 8px 24px -12px rgb(79 70 229 / 0.25);
-}
-
-.qms-kiosk__queue-btn:disabled {
- opacity: 0.6;
- pointer-events: none;
-}
-
-.qms-kiosk__queue-mark {
- display: flex;
- height: 2.75rem;
- width: 2.75rem;
- flex-shrink: 0;
- align-items: center;
- justify-content: center;
- border-radius: 0.75rem;
- font-size: 0.875rem;
- font-weight: 700;
- color: #fff;
-}
-
-.qms-kiosk__ticket-card {
- width: 100%;
- border-radius: 1.5rem;
- border: 1px solid rgb(226 232 240);
- background: #fff;
- padding: clamp(1.5rem, 5vh, 3rem);
- text-align: center;
- box-shadow:
- 0 1px 2px rgb(15 23 42 / 0.04),
- 0 24px 48px -20px rgb(79 70 229 / 0.18);
-}
-
.qms-kiosk__ticket-number {
- font-size: clamp(3.5rem, 16vh, 7rem);
+ font-size: clamp(3.5rem, 16vh, 5.5rem);
font-weight: 700;
line-height: 1;
letter-spacing: -0.04em;
diff --git a/resources/js/kiosk-flow.js b/resources/js/kiosk-flow.js
index 8e6c89e..59e7cc0 100644
--- a/resources/js/kiosk-flow.js
+++ b/resources/js/kiosk-flow.js
@@ -39,36 +39,98 @@ function pickVoice(voices, locale, preference) {
export function registerKioskFlow(Alpine) {
Alpine.data('kioskFlow', (config = {}) => ({
- step: 'select',
+ step: 'welcome',
queueId: null,
customerName: '',
customerPhone: '',
ticket: null,
error: null,
loading: false,
+ idleTimer: null,
+ countdownInterval: null,
resetCountdown: null,
- resetTimer: null,
- countdownTimer: null,
issueUrl: config.issueUrl,
csrf: config.csrf,
queues: config.queues ?? [],
collectName: config.collectName ?? false,
collectPhone: config.collectPhone ?? false,
resetSeconds: config.resetSeconds ?? 15,
- welcomeMessage: config.welcomeMessage ?? 'Tap a service below to get your ticket',
+ welcomeMessage: config.welcomeMessage ?? null,
+
+ startTimer() {
+ this.resetIdleTimer();
+ },
+
+ resetIdleTimer() {
+ clearTimeout(this.idleTimer);
+ clearInterval(this.countdownInterval);
+ this.resetCountdown = this.resetSeconds;
+
+ this.countdownInterval = setInterval(() => {
+ this.resetCountdown -= 1;
+ if (this.resetCountdown <= 0) {
+ clearInterval(this.countdownInterval);
+ this.countdownInterval = null;
+ }
+ }, 1000);
+
+ this.idleTimer = setTimeout(() => this.reset(), this.resetSeconds * 1000);
+ },
+
+ clearIdleTimer() {
+ clearTimeout(this.idleTimer);
+ clearInterval(this.countdownInterval);
+ this.idleTimer = null;
+ this.countdownInterval = null;
+ this.resetCountdown = null;
+ },
+
+ beginKiosk() {
+ this.resetIdleTimer();
+
+ if (this.queues.length === 0) {
+ this.step = 'select';
+
+ return;
+ }
- init() {
if (this.queues.length === 1) {
this.queueId = this.queues[0].id;
+
+ if (! this.collectName && ! this.collectPhone) {
+ this.issue();
+
+ return;
+ }
+ }
+
+ this.step = 'select';
+ },
+
+ goBack() {
+ this.resetIdleTimer();
+ this.error = null;
+
+ if (this.step === 'details') {
+ this.step = 'select';
+
+ return;
+ }
+
+ if (this.step === 'select') {
+ this.step = 'welcome';
+ this.queueId = null;
}
},
selectQueue(id) {
this.queueId = id;
this.error = null;
+ this.resetIdleTimer();
if (! this.collectName && ! this.collectPhone) {
this.issue();
+
return;
}
@@ -82,6 +144,7 @@ export function registerKioskFlow(Alpine) {
this.loading = true;
this.error = null;
+ this.resetIdleTimer();
try {
const res = await fetch(this.issueUrl, {
@@ -105,7 +168,7 @@ export function registerKioskFlow(Alpine) {
this.ticket = data.data;
this.step = 'ticket';
- this.scheduleReset();
+ this.resetIdleTimer();
} catch (e) {
this.error = e.message || 'Something went wrong';
} finally {
@@ -113,41 +176,16 @@ export function registerKioskFlow(Alpine) {
}
},
- scheduleReset() {
- this.clearResetTimers();
- this.resetCountdown = this.resetSeconds;
-
- this.countdownTimer = setInterval(() => {
- this.resetCountdown -= 1;
- if (this.resetCountdown <= 0) {
- this.clearResetTimers();
- }
- }, 1000);
-
- this.resetTimer = setTimeout(() => this.reset(), this.resetSeconds * 1000);
- },
-
- clearResetTimers() {
- if (this.resetTimer) {
- clearTimeout(this.resetTimer);
- this.resetTimer = null;
- }
- if (this.countdownTimer) {
- clearInterval(this.countdownTimer);
- this.countdownTimer = null;
- }
- this.resetCountdown = null;
- },
-
reset() {
- this.clearResetTimers();
- this.step = 'select';
- this.queueId = this.queues.length === 1 ? this.queues[0].id : null;
+ this.clearIdleTimer();
+ this.step = 'welcome';
+ this.queueId = null;
this.customerName = '';
this.customerPhone = '';
this.ticket = null;
this.error = null;
this.loading = false;
+ this.startTimer();
},
formatWait(seconds) {
diff --git a/resources/views/qms/kiosk/device.blade.php b/resources/views/qms/kiosk/device.blade.php
index 453c084..05ff8bd 100644
--- a/resources/views/qms/kiosk/device.blade.php
+++ b/resources/views/qms/kiosk/device.blade.php
@@ -1,17 +1,24 @@
-
+
-
+
-
+
{{ $device->name }} · Queue Kiosk
@vite(['resources/css/app.css', 'resources/js/app.js'])
+
-
-
-
-

+
+
+
+
+
+
+ @include('qms.partials.kiosk-brand', ['logoUrl' => $logoUrl, 'logoAlt' => $logoAlt])
+
+
+ {{-- Welcome --}}
+
+
+
+
Queue
+
+ Welcome to {{ $organization?->name ?? 'Queue' }}
+
+
+
+
+
-
+
-
-
- {{-- Queue selection --}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
No services available
-
Ask a staff member for assistance.
-
-
-
-
+ {{-- Service selection --}}
+
+
+
+ @include('qms.partials.kiosk-back')
- {{-- Optional details --}}
-
-
-
Your details
-
Optional information to help staff assist you.
-
-
-
-
-
-
-
-
-
-
+
+
Choose a service
+
Select an option to get your ticket
- {{-- Ticket issued --}}
-
-
-
Your ticket number
-
-
-
-
-
Please take a seat. Your number will be called on the display.
-
-
+
+
+ {{-- Optional details --}}
+
+
+
+ @include('qms.partials.kiosk-back')
+
+
+
+
+
+ Your details
+ Step 1 of 1
+
+
+
Tell us a little about yourself
+
+
+
+
+
+
+
+ Get ticket
+ Please wait…
+
-
+
-