@extends('layouts.app') @section('title', 'Queue Board') @php if (!function_exists('queueOpenUrl')) { function queueOpenUrl($visit) { if ($visit->visit_type === 'anc' && $visit->patient_id) { $ancReg = \App\Models\AncRegistration::where('patient_id', $visit->patient_id)->where('status', 'active')->first(); if ($ancReg) return route('maternity.anc.show', $ancReg); } return route('visits.show', $visit); } } $queueReadOnly = auth()->user()->hasAnyRole('Lab User', 'Imaging User') && !auth()->user()->hasAnyRole('Super Admin', 'Hospital Admin'); // Merge all active visits into one collection with stage labels for // the row-based table view. Done visits are NOT merged in — the // queue board is for active patients only; completed encounters // belong in OPD Visits → Completed, not on the live floor view. // (May 24 2026 cleanup: the Done tab was removed from this page.) $allQueue = collect(); foreach ($waiting as $v) { $v->_stage = 'waiting'; $allQueue->push($v); } foreach ($inTriage as $v) { $v->_stage = 'triage'; $allQueue->push($v); } foreach ($inConsultation as $v) { $v->_stage = 'consulting'; $allQueue->push($v); } foreach ($atLab as $v) { $v->_stage = 'lab'; $allQueue->push($v); } foreach ($atRadiology as $v) { $v->_stage = 'imaging'; $allQueue->push($v); } @endphp @section('styles') @endsection @section('content') {{-- Page header and action row removed per UI cleanup. Department filtering and refresh are out; the queue auto-shows all departments, and a manual refresh isn't needed (the page is mostly real-time-ish). If you need the completed-visits view back, it's still at route('visits.opd.completed'). --}} {{-- Carryover banner removed May 14 2026: the per-card wait-time display and the >30-min hot-card highlighting already surface stuck visits more usefully than a banner could. The banner was also confusing to staff who read it as an error message. --}} {{-- Quick Action Button — May 24 2026: Consolidated to ONE "Start New Visit" button. The receptionist picks the department inside the modal and the system decides which encounter to open from that choice: Laboratory → direct_lab encounter, Radiology → direct_radiology encounter, everything else (Outpatient, Inpatient, Maternity, Dental, MCH/FP, Specialized Clinics + sub-clinics) opens a standard OPD encounter. Replaces the four separate buttons we had before (OPD / Dental / Direct Lab / Direct Radiology), which forced the receptionist to know the visit_type before knowing the department — backwards from how reception actually works. --}} @if(!$queueReadOnly)
@endif {{-- Main Queue Card with Tabs --}}
{{-- May 24 2026: Done tab was removed. Completed visits live in OPD Visits → Completed; the queue page is for active patients only. Tab colour cues were also realigned to match the new row palette below (waiting red, triage pink, lab/imaging yellow, consulting green). --}}
{{-- ── Queue Table ───────────────────────────────────────────── Single row-based table. Rows are shaded by stage so the receptionist can scan and tell at a glance who's where: Waiting → red (not yet seen, urgency) Triage → pink (intake / early engagement) Lab + Imaging → yellow (diagnostic step, away) Consulting → green (with the clinician) The All tab shows every active row at once with its stage colour. Each stage-specific tab is a client-side filter on the same table — no separate Kanban board view. The Done tab and the kanban "snapshot pipeline" were both removed on 24 May 2026 per a UX simplification pass. --}}
{{-- Actions column removed 25 May 2026 — per-stage advance buttons (Triage / Consult / Send Lab / Send Imaging) now live only inside the encounter page. Clicking a row opens the encounter; the receptionist advances the patient from there. --}} @php $rowNum = 0; @endphp @forelse($allQueue as $v) @php $rowNum++; @endphp {{-- Row is clickable, opens the encounter. Stage colour comes from CSS on the [data-stage] attribute, so the same row template handles every stage without inline colour logic. --}} @empty @endforelse
# Patient Type Stage Check-In Wait Time Department Clinician
{{ $rowNum }}
@if($v->status === 'urgent')URG@endif
{{-- Name + phone two-line layout (25 May 2026): name is the primary scan-target at the row's base font size; phone sits underneath one step smaller as metadata. MRN was removed from this cell — it stays visible inside the encounter and on invoices for staff who need it. --}}

{{ $v->patient->full_name ?? '' }}

{{ $v->patient->phone ?? '' }}

@if($v->visit_type === 'anc')ANC @elseif($v->visit_type === 'direct_lab')Direct Lab @elseif($v->visit_type === 'direct_radiology')Direct Radiology @else{{ str_replace('_', ' ', $v->visit_type ?? 'OPD') }} @endif @switch($v->_stage) @case('waiting')Waiting@break @case('triage'){{ $v->status === 'triaged' ? 'Triaged' : 'In Triage' }}@break @case('consulting')Consulting@break @case('lab')At Lab@break @case('imaging')At Imaging@break @endswitch {{ $v->check_in_at ? $v->check_in_at->format('H:i') : '-' }} {{ $v->check_in_at ? $v->check_in_at->diffForHumans(null, true, false, 2) : '-' }} {{ $v->department->name ?? '-' }} {{ $v->clinician->name ?? '-' }}
No active visits.
@if(!$queueReadOnly) {{-- Quick Visit Modal — May 24 2026 unified version. Single modal for every new visit. The receptionist picks the department from the dropdown and the system infers what kind of encounter to open from that choice: Laboratory (LAB) → direct_lab encounter Radiology (RAD) → direct_radiology encounter Anything else → standard OPD encounter The mapping happens client-side (to update the modal title / submit-button text / hint) AND server-side via the hidden visit_type input that JS keeps in sync with the selected department. The server already accepts visit_type values of outpatient / direct_lab / direct_radiology in VisitController@store, so no controller change is required. --}} @endif @endsection @push('scripts') @include('partials._tab-state-helper', ['defaultTab' => 'all']) @endpush