Files
ladill-queue/resources/js/kiosk-flow.js
T
isaaccladandCursor cca98eefd2
Deploy Ladill Queue / deploy (push) Successful in 56s
Initial Ladill Queue release — enterprise QMS standalone app.
Phases 1–6: tickets, counters, displays, appointments, workflows, rules, analytics, reports, feedback, admin, device API, and Gitea deploy workflow for queue.ladill.com.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 20:19:52 +00:00

99 lines
3.1 KiB
JavaScript

export function registerKioskFlow(Alpine) {
Alpine.data('kioskFlow', (config = {}) => ({
step: 'select',
queueId: null,
customerName: '',
customerPhone: '',
ticket: null,
error: null,
loading: false,
issueUrl: config.issueUrl,
csrf: config.csrf,
selectQueue(id) {
this.queueId = id;
this.step = 'details';
},
async issue() {
if (! this.queueId) return;
this.loading = true;
this.error = null;
try {
const res = await fetch(this.issueUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': this.csrf,
},
body: JSON.stringify({
queue_id: this.queueId,
customer_name: this.customerName || null,
customer_phone: this.customerPhone || null,
}),
});
const data = await res.json();
if (! res.ok) throw new Error(data.message || 'Could not issue ticket');
this.ticket = data.data;
this.step = 'ticket';
} catch (e) {
this.error = e.message || 'Something went wrong';
} finally {
this.loading = false;
}
},
reset() {
this.step = 'select';
this.queueId = null;
this.customerName = '';
this.customerPhone = '';
this.ticket = null;
this.error = null;
},
}));
Alpine.data('displayBoard', (dataUrl) => ({
payload: null,
async poll() {
try {
const res = await fetch(dataUrl, { headers: { Accept: 'application/json' } });
this.payload = await res.json();
if (this.payload?.announcements?.length && window.speechSynthesis) {
const msg = this.payload.announcements[0]?.message;
if (msg) {
const utter = new SpeechSynthesisUtterance(msg);
window.speechSynthesis.speak(utter);
}
}
} catch (e) {
console.error('Display poll failed', e);
}
},
init() {
this.poll();
setInterval(() => this.poll(), 5000);
},
}));
Alpine.data('mobileTracker', (pollUrl) => ({
data: null,
ahead: 0,
async poll() {
try {
const res = await fetch(pollUrl, { headers: { Accept: 'application/json' } });
const json = await res.json();
this.data = json.data;
this.ahead = json.customers_ahead ?? 0;
} catch (e) {
console.error('Tracker poll failed', e);
}
},
init() {
this.poll();
setInterval(() => this.poll(), 10000);
},
}));
}