Gate Queue to doctors and land specialty modules on list indexes.
Deploy Ladill Care / deploy (push) Successful in 34s

Hide the patient-flow Queue board from nurses, reception, and other
non-doctors; specialty home routes now render the queue board list
instead of auto-opening the first open visit.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-18 22:53:12 +00:00
co-authored by Cursor
parent 244bb8fba6
commit d422797050
22 changed files with 277 additions and 122 deletions
@@ -150,7 +150,12 @@ class AppointmentController extends Controller
->with('success', 'Walk-in checked in. Complete the current patient journey stage before Queue release.');
}
return redirect()->route('care.queue.index')
if (app(CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
return redirect()->route('care.queue.index')
->with('success', 'Walk-in added to queue.');
}
return redirect()->route('care.appointments.show', $appointment)
->with('success', 'Walk-in added to queue.');
}
@@ -217,7 +222,12 @@ class AppointmentController extends Controller
->with('success', 'Patient checked in. Complete the current patient journey stage before Queue release.');
}
return redirect()->route('care.queue.index')
if (app(CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
return redirect()->route('care.queue.index')
->with('success', 'Patient checked in and added to queue.');
}
return redirect()->route('care.appointments.show', $appointment)
->with('success', 'Patient checked in and added to queue.');
}
@@ -278,8 +278,11 @@ class ConsultationController extends Controller
->with('success', 'Consultation completed. Continue the patient journey from the next stage.');
}
return redirect()->route('care.queue.index')
->with('success', 'Consultation completed.');
return redirect()->route(
app(CarePermissions::class)->canAccessPatientQueue($this->member($request))
? 'care.queue.index'
: 'care.appointments.index'
)->with('success', 'Consultation completed.');
}
protected function authorizeConsultation(Request $request, Consultation $consultation): void
@@ -8,7 +8,8 @@ use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
/**
* Legacy Ladill Queue console routes redirect to the Care patient queue.
* Legacy Ladill Queue console routes redirect to the Care patient queue (doctors)
* or appointments list when the actor cannot open the patient-flow board.
*/
class ServiceQueueController extends Controller
{
@@ -18,20 +19,29 @@ class ServiceQueueController extends Controller
{
$this->authorizeAbility($request, 'service_queues.console');
return redirect()->route('care.queue.index');
return $this->redirectAwayFromLegacyConsole($request);
}
public function console(Request $request, string $counterUuid): RedirectResponse
{
$this->authorizeAbility($request, 'service_queues.console');
return redirect()->route('care.queue.index');
return $this->redirectAwayFromLegacyConsole($request);
}
public function action(Request $request, string $counterUuid): RedirectResponse
{
$this->authorizeAbility($request, 'service_queues.console');
return redirect()->route('care.queue.index');
return $this->redirectAwayFromLegacyConsole($request);
}
protected function redirectAwayFromLegacyConsole(Request $request): RedirectResponse
{
if (app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
return redirect()->route('care.queue.index');
}
return redirect()->route('care.appointments.index');
}
}
@@ -31,20 +31,9 @@ class SpecialtyModuleController extends Controller
SpecialtyModuleService $modules,
SpecialtyShellService $shell,
CareQueueBridge $queueBridge,
): RedirectResponse {
$definition = $modules->definition($module);
abort_unless($definition, 404);
abort_unless(
$modules->memberCanAccess($this->organization($request), $this->member($request), $module),
403,
);
// Specialty patient flow lives on Queue; nurses stay on the specialty workspace.
if (app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
return redirect()->route('care.queue.index');
}
return redirect()->route('care.specialty.workspace', $module);
): View {
// Everyone lands on the specialty list/index — never auto-open a patient.
return $this->renderShell($request, $module, 'visits', $modules, $shell, $queueBridge);
}
public function visits(
@@ -53,19 +42,8 @@ class SpecialtyModuleController extends Controller
SpecialtyModuleService $modules,
SpecialtyShellService $shell,
CareQueueBridge $queueBridge,
): RedirectResponse {
$definition = $modules->definition($module);
abort_unless($definition, 404);
abort_unless(
$modules->memberCanAccess($this->organization($request), $this->member($request), $module),
403,
);
if (app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($this->member($request))) {
return redirect()->route('care.queue.index');
}
return redirect()->route('care.specialty.workspace', $module);
): View {
return $this->renderShell($request, $module, 'visits', $modules, $shell, $queueBridge);
}
public function history(
@@ -95,7 +73,12 @@ class SpecialtyModuleController extends Controller
SpecialtyShellService $shell,
CareQueueBridge $queueBridge,
?Visit $visit = null,
): View {
): View|RedirectResponse {
// Bare /workspace (no visit) is the old auto-open entry — send users to the list.
if ($visit === null) {
return redirect()->route('care.specialty.show', $module);
}
return $this->renderShell($request, $module, 'workspace', $modules, $shell, $queueBridge, $visit);
}
@@ -589,14 +572,7 @@ class SpecialtyModuleController extends Controller
);
return redirect()
->route(
app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($member)
? 'care.queue.index'
: 'care.specialty.workspace',
app(\App\Services\Care\CarePermissions::class)->canAccessPatientQueue($member)
? []
: ['module' => $module],
)
->route('care.specialty.show', $module)
->with('success', 'Referred '.$patient->fullName().' to '.($definition['label'] ?? $module).'.');
}
@@ -792,25 +768,6 @@ class SpecialtyModuleController extends Controller
);
$timeline = $shell->patientTimeline($visit->patient);
}
} elseif ($section === 'workspace') {
$first = $openVisits->first();
if ($first?->patient) {
$first->load([
'patient.allergies',
'patient.emergencyContacts',
'patient.attachments',
'appointment.practitioner',
'appointment.consultation.investigationRequests.investigationType',
'bill.lineItems',
'consultations.investigationRequests.investigationType',
]);
$workspaceVisit = $first;
$patientHeader = array_merge(
['patient' => $first->patient, 'visit' => $first, 'appointment' => $first->appointment],
$shell->patientHeaderMeta($first->patient),
);
$timeline = $shell->patientTimeline($first->patient);
}
}
if ($workspaceVisit && $section === 'workspace') {