|null $practitionerScope * @return array{ * columns: list, * empty: string, * accent: string, * dot: string, * next_stage: ?string, * next_label: ?string * }>, * active_count: int, * completed_today: int * } */ public function board( Organization $organization, string $ownerRef, ?int $branchScope = null, ?array $practitionerScope = null, ): array { $flow = app(AmbulanceWorkflowService::class)->stageFlow(); $open = $this->shell->openVisits($organization, 'ambulance', $ownerRef, $branchScope, $practitionerScope, 80); $completed = $this->completedToday($organization, $ownerRef, $branchScope, $practitionerScope); $byStage = [ AmbulanceWorkflowService::STAGE_CHECK_IN => collect(), AmbulanceWorkflowService::STAGE_DISPATCH => collect(), AmbulanceWorkflowService::STAGE_ON_SCENE => collect(), AmbulanceWorkflowService::STAGE_TRANSPORT => collect(), AmbulanceWorkflowService::STAGE_HANDOVER => collect(), AmbulanceWorkflowService::STAGE_COMPLETED => $completed, ]; foreach ($open as $visit) { $stage = $visit->specialty_stage; if ($stage === null || $stage === '' || $stage === AmbulanceWorkflowService::STAGE_CHECK_IN) { $byStage[AmbulanceWorkflowService::STAGE_CHECK_IN]->push($visit); } elseif (isset($byStage[$stage]) && $stage !== AmbulanceWorkflowService::STAGE_COMPLETED) { $byStage[$stage]->push($visit); } else { // Unknown / unexpected stage — keep visible under New call. $byStage[AmbulanceWorkflowService::STAGE_CHECK_IN]->push($visit); } } $meta = [ AmbulanceWorkflowService::STAGE_CHECK_IN => [ 'label' => 'New call', 'empty' => 'No new calls.', 'accent' => 'text-amber-700', 'dot' => 'bg-amber-500', ], AmbulanceWorkflowService::STAGE_DISPATCH => [ 'label' => 'Dispatched', 'empty' => 'Nothing dispatched.', 'accent' => 'text-indigo-700', 'dot' => 'bg-indigo-500', ], AmbulanceWorkflowService::STAGE_ON_SCENE => [ 'label' => 'On scene', 'empty' => 'No crews on scene.', 'accent' => 'text-sky-700', 'dot' => 'bg-sky-500', ], AmbulanceWorkflowService::STAGE_TRANSPORT => [ 'label' => 'Transport', 'empty' => 'No patients in transport.', 'accent' => 'text-violet-700', 'dot' => 'bg-violet-500', ], AmbulanceWorkflowService::STAGE_HANDOVER => [ 'label' => 'Handover', 'empty' => 'No handovers in progress.', 'accent' => 'text-emerald-700', 'dot' => 'bg-emerald-500', ], AmbulanceWorkflowService::STAGE_COMPLETED => [ 'label' => 'Completed today', 'empty' => 'None completed today.', 'accent' => 'text-slate-500', 'dot' => 'bg-slate-300', ], ]; $columns = []; foreach ($meta as $key => $column) { $items = $byStage[$key] ?? collect(); $next = $flow[$key]['next'] ?? null; $nextLabel = $flow[$key]['label'] ?? null; if ($key === AmbulanceWorkflowService::STAGE_COMPLETED) { $next = null; $nextLabel = null; } $columns[] = [ 'key' => $key, 'label' => $column['label'], 'count' => $items->count(), 'items' => $items, 'empty' => $column['empty'], 'accent' => $column['accent'], 'dot' => $column['dot'], 'next_stage' => $next !== $key ? $next : null, 'next_label' => $next !== $key ? $nextLabel : null, ]; } $activeCount = collect($columns) ->reject(fn (array $col) => $col['key'] === AmbulanceWorkflowService::STAGE_COMPLETED) ->sum('count'); return [ 'columns' => $columns, 'active_count' => $activeCount, 'completed_today' => $completed->count(), ]; } /** * @param list|null $practitionerScope * @return Collection */ protected function completedToday( Organization $organization, string $ownerRef, ?int $branchScope = null, ?array $practitionerScope = null, int $limit = 40, ): Collection { $departmentIds = $this->shell->departmentIds($organization, 'ambulance', $ownerRef, $branchScope); return Visit::owned($ownerRef) ->where('organization_id', $organization->id) ->where(function ($q) { $q->where('specialty_stage', AmbulanceWorkflowService::STAGE_COMPLETED) ->orWhere(function ($qq) { $qq->where('status', Visit::STATUS_COMPLETED) ->whereDate('completed_at', today()); }); }) ->where(function ($q) { $q->whereDate('completed_at', today()) ->orWhere(function ($qq) { $qq->whereNull('completed_at') ->whereDate('updated_at', today()); }); }) ->when($branchScope, fn ($q) => $q->where('branch_id', $branchScope)) ->whereHas('appointment', function ($q) use ($departmentIds, $practitionerScope) { $q->when($departmentIds !== [], fn ($qq) => $qq->whereIn('department_id', $departmentIds)) ->when($departmentIds === [], fn ($qq) => $qq->whereRaw('1 = 0')) ->when( $practitionerScope !== null, fn ($qq) => $qq->whereIn('practitioner_id', $practitionerScope ?: [0]), ); }) ->with(['patient', 'appointment.practitioner', 'appointment.department']) ->orderByDesc('completed_at') ->orderByDesc('id') ->limit($limit) ->get(); } }