Deploy Ladill Care / deploy (push) Successful in 39s
Register walk-up kiosks and waiting-room display devices under Devices, with public kiosk ticket issue and linked TV boards surfaced in sidebar and Queue shortcuts. Co-authored-by: Cursor <cursoragent@cursor.com>
163 lines
4.5 KiB
JavaScript
163 lines
4.5 KiB
JavaScript
export function registerCareKiosk(Alpine) {
|
|
Alpine.data('careKioskFlow', (config = {}) => ({
|
|
step: 'welcome',
|
|
queueId: null,
|
|
customerName: '',
|
|
customerPhone: '',
|
|
ticket: null,
|
|
error: null,
|
|
loading: false,
|
|
idleTimer: null,
|
|
countdownInterval: null,
|
|
resetCountdown: 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 ?? 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;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
this.step = 'details';
|
|
},
|
|
|
|
async issue() {
|
|
if (! this.queueId || this.loading) {
|
|
return;
|
|
}
|
|
|
|
this.loading = true;
|
|
this.error = null;
|
|
this.resetIdleTimer();
|
|
|
|
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';
|
|
this.resetIdleTimer();
|
|
} catch (e) {
|
|
this.error = e.message || 'Something went wrong';
|
|
} finally {
|
|
this.loading = false;
|
|
}
|
|
},
|
|
|
|
reset() {
|
|
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) {
|
|
if (! seconds) {
|
|
return null;
|
|
}
|
|
|
|
const minutes = Math.ceil(seconds / 60);
|
|
|
|
return minutes <= 1 ? 'About 1 minute' : `About ${minutes} minutes`;
|
|
},
|
|
}));
|
|
}
|