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>
141 lines
8.5 KiB
PHP
141 lines
8.5 KiB
PHP
<x-app-layout title="Add device">
|
|
<div class="mx-auto max-w-lg space-y-4">
|
|
<div>
|
|
<a href="{{ route('care.devices.index') }}" class="text-sm text-slate-500 hover:text-slate-800">← Devices</a>
|
|
<h1 class="mt-2 text-xl font-semibold text-slate-900">Register device</h1>
|
|
<p class="mt-1 text-sm text-slate-500">Queue kiosks/displays and clinical scanners/agents. Queue devices need Care Pro.</p>
|
|
</div>
|
|
|
|
<form method="POST" action="{{ route('care.devices.store') }}" class="space-y-4 rounded-2xl border border-slate-200 bg-white p-6">
|
|
@csrf
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700">Name</label>
|
|
<input type="text" name="name" value="{{ old('name') }}" required placeholder="Lobby kiosk"
|
|
class="mt-1 w-full rounded-lg border-slate-300 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700">Type</label>
|
|
<select name="type" id="device-type" required class="mt-1 w-full rounded-lg border-slate-300 text-sm">
|
|
@foreach ($deviceTypes as $value => $label)
|
|
@php
|
|
$needsPro = in_array($value, $agentTypes, true) || in_array($value, $queueDeviceTypes, true);
|
|
$allowed = ! $needsPro || ($value === 'kiosk' || $value === 'display' ? $hasQueueDevices : $hasAgentDevices);
|
|
@endphp
|
|
<option value="{{ $value }}"
|
|
data-mode="{{ $defaultModes[$value] ?? 'manual' }}"
|
|
data-queue="{{ in_array($value, $queueDeviceTypes, true) ? '1' : '0' }}"
|
|
data-display="{{ $value === 'display' ? '1' : '0' }}"
|
|
@selected(old('type', $prefillType ?? 'barcode_scanner') === $value)
|
|
@disabled(! $allowed)>
|
|
{{ $label }}@if ($needsPro && ! $allowed) (Pro)@endif
|
|
</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div id="connection-wrap">
|
|
<label class="block text-sm font-medium text-slate-700">Connection mode</label>
|
|
<select name="connection_mode" id="connection-mode" class="mt-1 w-full rounded-lg border-slate-300 text-sm">
|
|
@foreach ($connectionModes as $value => $label)
|
|
<option value="{{ $value }}" @selected(old('connection_mode', 'browser_wedge') === $value)>{{ $label }}</option>
|
|
@endforeach
|
|
</select>
|
|
<p class="mt-1 text-xs text-slate-500" id="connection-hint">USB scanners act as a keyboard in the browser.</p>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700">Branch</label>
|
|
<select name="branch_id" id="branch-id" class="mt-1 w-full rounded-lg border-slate-300 text-sm">
|
|
<option value="">All branches</option>
|
|
@foreach ($branches as $branch)
|
|
<option value="{{ $branch->id }}" @selected(old('branch_id') == $branch->id)>{{ $branch->name }}</option>
|
|
@endforeach
|
|
</select>
|
|
<p class="mt-1 text-xs text-slate-500" id="branch-hint" hidden>Queue displays require a branch.</p>
|
|
</div>
|
|
|
|
<div id="queue-config" class="space-y-3 border-t border-slate-100 pt-4" hidden>
|
|
<p class="text-sm font-medium text-slate-800">Service queues</p>
|
|
<p class="text-xs text-slate-500">Leave unchecked to allow all active queues for the branch.</p>
|
|
<div class="max-h-40 space-y-2 overflow-y-auto rounded-lg border border-slate-100 p-3">
|
|
@forelse ($queues as $queue)
|
|
<label class="flex items-center gap-2 text-sm text-slate-700">
|
|
<input type="checkbox" name="queue_ids[]" value="{{ $queue->id }}"
|
|
@checked(collect(old('queue_ids', []))->contains($queue->id))
|
|
class="rounded border-slate-300">
|
|
{{ $queue->name }} <span class="text-xs text-slate-400">({{ $queue->prefix }})</span>
|
|
</label>
|
|
@empty
|
|
<p class="text-xs text-amber-700">No service queues yet — enable service queues in Settings and check patients in.</p>
|
|
@endforelse
|
|
</div>
|
|
|
|
<div id="kiosk-options" class="space-y-3">
|
|
<label class="flex items-center gap-2 text-sm text-slate-700">
|
|
<input type="checkbox" name="collect_name" value="1" @checked(old('collect_name')) class="rounded border-slate-300">
|
|
Collect visitor name
|
|
</label>
|
|
<label class="flex items-center gap-2 text-sm text-slate-700">
|
|
<input type="checkbox" name="collect_phone" value="1" @checked(old('collect_phone')) class="rounded border-slate-300">
|
|
Collect phone
|
|
</label>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700">Reset after (seconds)</label>
|
|
<input type="number" name="reset_seconds" min="5" max="120" value="{{ old('reset_seconds', 15) }}" class="mt-1 w-full rounded-lg border-slate-300 text-sm">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-slate-700">Welcome message</label>
|
|
<input type="text" name="welcome_message" value="{{ old('welcome_message') }}" class="mt-1 w-full rounded-lg border-slate-300 text-sm" placeholder="Optional">
|
|
</div>
|
|
</div>
|
|
|
|
<div id="display-options" hidden>
|
|
<label class="block text-sm font-medium text-slate-700">Display layout</label>
|
|
<select name="layout" class="mt-1 w-full rounded-lg border-slate-300 text-sm">
|
|
@foreach ($layouts as $value => $label)
|
|
<option value="{{ $value }}" @selected(old('layout', 'standard') === $value)>{{ $label }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="submit" class="btn-primary w-full">Register device</button>
|
|
</form>
|
|
</div>
|
|
<script>
|
|
(() => {
|
|
const typeEl = document.getElementById('device-type');
|
|
const modeEl = document.getElementById('connection-mode');
|
|
const hintEl = document.getElementById('connection-hint');
|
|
const connWrap = document.getElementById('connection-wrap');
|
|
const queueConfig = document.getElementById('queue-config');
|
|
const kioskOpts = document.getElementById('kiosk-options');
|
|
const displayOpts = document.getElementById('display-options');
|
|
const branchHint = document.getElementById('branch-hint');
|
|
const hints = {
|
|
browser_wedge: 'Works in the browser today as a USB keyboard wedge. No local agent required.',
|
|
agent: 'Needs the Care Device Agent on a local machine (serial / BLE / vendor SDK).',
|
|
web_bluetooth: 'Experimental Web Bluetooth — prefer the local agent for clinical devices.',
|
|
manual: 'Manual / inventory — or open the public URL for kiosk / display devices.',
|
|
};
|
|
function sync() {
|
|
const opt = typeEl.selectedOptions[0];
|
|
if (!opt) return;
|
|
const mode = opt.dataset.mode || 'manual';
|
|
const isQueue = opt.dataset.queue === '1';
|
|
const isDisplay = opt.dataset.display === '1';
|
|
modeEl.value = mode;
|
|
hintEl.textContent = hints[mode] || hints.manual;
|
|
connWrap.hidden = isQueue;
|
|
queueConfig.hidden = !isQueue;
|
|
kioskOpts.hidden = isDisplay;
|
|
displayOpts.hidden = !isDisplay;
|
|
branchHint.hidden = !isDisplay;
|
|
}
|
|
typeEl.addEventListener('change', sync);
|
|
modeEl.addEventListener('change', () => {
|
|
hintEl.textContent = hints[modeEl.value] || hints.manual;
|
|
});
|
|
sync();
|
|
})();
|
|
</script>
|
|
</x-app-layout>
|