Add clinical device registry, browser wedge scan, and local agent API.
Deploy Ladill Care / deploy (push) Successful in 1m39s
Deploy Ladill Care / deploy (push) Successful in 1m39s
Branch-scoped Care devices with hashed agent tokens, patient barcode lookup/labels, and provenance-aware vitals from a minimal device agent (Pro for agent hardware; wedge free). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
<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">Inventory is branch-scoped. Agent devices get a token shown once after create.</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="Nurse station scanner"
|
||||
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);
|
||||
@endphp
|
||||
<option value="{{ $value }}"
|
||||
data-mode="{{ $defaultModes[$value] ?? 'manual' }}"
|
||||
data-pro="{{ $needsPro ? '1' : '0' }}"
|
||||
@selected(old('type', 'barcode_scanner') === $value)
|
||||
@disabled($needsPro && ! $hasAgentDevices)>
|
||||
{{ $label }}@if ($needsPro && ! $hasAgentDevices) (Pro)@endif
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@if (! $hasAgentDevices)
|
||||
<p class="mt-1 text-xs text-amber-700">Clinical agent devices need Care Pro. USB barcode/QR scanners work on Free.</p>
|
||||
@endif
|
||||
</div>
|
||||
<div>
|
||||
<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. Serial/BLE needs the local agent.</p>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-slate-700">Branch</label>
|
||||
<select name="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>
|
||||
</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 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 only — no automated capture path.',
|
||||
};
|
||||
function sync() {
|
||||
const opt = typeEl.selectedOptions[0];
|
||||
if (!opt) return;
|
||||
const mode = opt.dataset.mode || 'manual';
|
||||
modeEl.value = mode;
|
||||
hintEl.textContent = hints[mode] || hints.manual;
|
||||
}
|
||||
typeEl.addEventListener('change', sync);
|
||||
modeEl.addEventListener('change', () => {
|
||||
hintEl.textContent = hints[modeEl.value] || hints.manual;
|
||||
});
|
||||
sync();
|
||||
})();
|
||||
</script>
|
||||
</x-app-layout>
|
||||
Reference in New Issue
Block a user