Initial Ladill Queue release — enterprise QMS standalone app.
Deploy Ladill Queue / deploy (push) Successful in 56s
Deploy Ladill Queue / deploy (push) Successful in 56s
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>
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
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);
|
||||
},
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user