Reserve floor queues for clinical staff and deepen specialty forms.
Deploy Ladill Care / deploy (push) Successful in 41s
Deploy Ladill Care / deploy (push) Successful in 41s
Hospital admins no longer see specialty/queue floor nav; Call next is a full-width button; specialty encounters open module-specific clinical forms instead of the general consultation page. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,34 +1,20 @@
|
||||
{{-- Inline Queue ops when Care↔Queue integration is enabled (not a bolted-on Service counter). --}}
|
||||
{{-- Inline Queue ops when Care Queue Engine is enabled. --}}
|
||||
@php
|
||||
$qi = $queueIntegration ?? null;
|
||||
$callNextRoute = $queueCallNextRoute ?? null;
|
||||
$callNextParams = $queueCallNextParams ?? [];
|
||||
@endphp
|
||||
@if (! empty($qi['enabled']) && $callNextRoute)
|
||||
<div class="flex flex-wrap items-center justify-between gap-3 rounded-xl border border-sky-100 bg-sky-50/70 px-4 py-3">
|
||||
<div>
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-sky-700">Queue</p>
|
||||
<p class="text-sm text-slate-600">
|
||||
@if (($qi['routing_mode'] ?? null) === 'shared_pool')
|
||||
Call next takes the next waiting patient in line for this queue (shared pool).
|
||||
@elseif (! empty($queueCallNextScansAllPoints))
|
||||
Call next picks the next waiting patient across service desks for this specialty at this branch.
|
||||
@else
|
||||
Call next operates on your assigned service point only — tickets routed to other rooms or desks stay there.
|
||||
@endif
|
||||
</p>
|
||||
</div>
|
||||
<form method="POST" action="{{ route($callNextRoute, $callNextParams) }}">
|
||||
@csrf
|
||||
@foreach ($callNextParams as $key => $value)
|
||||
@if (is_scalar($value))
|
||||
<input type="hidden" name="{{ $key }}" value="{{ $value }}">
|
||||
@endif
|
||||
@endforeach
|
||||
@if (! empty($branchId))
|
||||
<input type="hidden" name="branch_id" value="{{ $branchId }}">
|
||||
<form method="POST" action="{{ route($callNextRoute, $callNextParams) }}" class="w-full">
|
||||
@csrf
|
||||
@foreach ($callNextParams as $key => $value)
|
||||
@if (is_scalar($value))
|
||||
<input type="hidden" name="{{ $key }}" value="{{ $value }}">
|
||||
@endif
|
||||
<button type="submit" class="btn-primary text-sm">Call next</button>
|
||||
</form>
|
||||
</div>
|
||||
@endforeach
|
||||
@if (! empty($branchId))
|
||||
<input type="hidden" name="branch_id" value="{{ $branchId }}">
|
||||
@endif
|
||||
<button type="submit" class="btn-primary flex w-full items-center justify-center text-sm">Call next</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
@@ -72,7 +72,6 @@
|
||||
'queueCallNextRoute' => 'care.specialty.call-next',
|
||||
'queueCallNextParams' => ['module' => $moduleKey],
|
||||
'branchId' => $branchId ?? null,
|
||||
'queueCallNextScansAllPoints' => ($practitionerScope ?? null) === null,
|
||||
])
|
||||
|
||||
@if ($workspaceVisit)
|
||||
@@ -88,17 +87,21 @@
|
||||
$appointment->status === \App\Models\Appointment::STATUS_IN_CONSULTATION
|
||||
|| ($openConsultation && $openConsultation->status !== \App\Models\Consultation::STATUS_COMPLETED)
|
||||
);
|
||||
$chartTab = collect($workspaceTabs ?? [])
|
||||
->keys()
|
||||
->first(fn ($key) => ! in_array($key, ['overview', 'orders', 'billing', 'documents'], true))
|
||||
?: 'clinical_notes';
|
||||
@endphp
|
||||
@if ($consultationInProgress && $openConsultation)
|
||||
<a href="{{ route('care.consultations.show', $openConsultation) }}"
|
||||
@if ($consultationInProgress)
|
||||
<a href="{{ route('care.specialty.workspace', ['module' => $moduleKey, 'visit' => $workspaceVisit, 'tab' => $chartTab]) }}"
|
||||
class="flex w-full items-center justify-center rounded-xl bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-700">
|
||||
Open consultation
|
||||
Open specialty chart
|
||||
</a>
|
||||
@elseif ($canStartConsultation)
|
||||
<form method="POST" action="{{ route('care.specialty.consultation.start', ['module' => $moduleKey, 'visit' => $workspaceVisit]) }}">
|
||||
@csrf
|
||||
<button type="submit" class="flex w-full items-center justify-center rounded-xl bg-indigo-600 px-3 py-2 text-sm font-semibold text-white hover:bg-indigo-700">
|
||||
{{ $actions['start'] ?? 'Start consultation' }}
|
||||
{{ $actions['start'] ?? 'Start specialty encounter' }}
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
@@ -26,8 +26,10 @@
|
||||
if ($permissions->can($member, 'appointments.view')) {
|
||||
$nav[] = ['name' => 'Appointments', 'route' => route('care.appointments.index'), 'active' => request()->routeIs('care.appointments.*'),
|
||||
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5" />'];
|
||||
$nav[] = ['name' => 'Queue', 'route' => route('care.queue.index'), 'active' => request()->routeIs('care.queue.*') || request()->routeIs('care.consultations.*'),
|
||||
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.25 4.5h13.5a.75.75 0 0 1 .75.75v15.75a.75.75 0 0 1-.75.75H5.25a.75.75 0 0 1-.75-.75V5.25a.75.75 0 0 1 .75-.75Z" />'];
|
||||
if ($permissions->handlesFloorCare($member)) {
|
||||
$nav[] = ['name' => 'Queue', 'route' => route('care.queue.index'), 'active' => request()->routeIs('care.queue.*') || request()->routeIs('care.consultations.*'),
|
||||
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 12h16.5m-16.5 3.75h16.5M3.75 19.5h16.5M5.25 4.5h13.5a.75.75 0 0 1 .75.75v15.75a.75.75 0 0 1-.75.75H5.25a.75.75 0 0 1-.75-.75V5.25a.75.75 0 0 1 .75-.75Z" />'];
|
||||
}
|
||||
}
|
||||
|
||||
// Clinical assessments (layered intake / pathways) — on by default; toggle in Settings.
|
||||
@@ -36,7 +38,7 @@
|
||||
$organization,
|
||||
\App\Services\Care\CareFeatures::ASSESSMENTS_ENGINE,
|
||||
);
|
||||
if ($assessmentsEngineOn && $permissions->can($member, 'assessments.view') && $permissions->can($member, 'patients.view')) {
|
||||
if ($assessmentsEngineOn && $permissions->can($member, 'assessments.view') && $permissions->can($member, 'patients.view') && $permissions->handlesFloorCare($member)) {
|
||||
$nav[] = [
|
||||
'name' => 'Clinical forms',
|
||||
'route' => route('care.patients.index', ['focus' => 'assessments']),
|
||||
@@ -49,12 +51,12 @@
|
||||
|
||||
// Lab, pharmacy, billing, and Queue service counters are Pro/Enterprise modules.
|
||||
if (! empty($hasPaidPlan)) {
|
||||
if ($permissions->can($member, 'lab.view')) {
|
||||
if ($permissions->can($member, 'lab.view') && $permissions->handlesFloorCare($member)) {
|
||||
$nav[] = ['name' => 'Laboratory', 'route' => route('care.lab.queue.index'), 'active' => request()->routeIs('care.lab.*'),
|
||||
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714a2.25 2.25 0 0 0 .659 1.591L19 14.5M14.25 3.104c.251.023.501.05.75.082M19 14.5l-2.47 2.47a2.25 2.25 0 0 1-1.59.659H9.06a2.25 2.25 0 0 1-1.591-.659L5 14.5m14 0V17a2.25 2.25 0 0 1-2.25 2.25H7.25A2.25 2.25 0 0 1 5 17v-2.5" />'];
|
||||
}
|
||||
|
||||
if ($permissions->can($member, 'prescriptions.view')) {
|
||||
if ($permissions->can($member, 'prescriptions.view') && $permissions->handlesFloorCare($member)) {
|
||||
$nav[] = ['name' => 'Pharmacy queue', 'route' => route('care.prescriptions.queue'), 'active' => request()->routeIs('care.prescriptions.*') && ! request()->routeIs('care.pharmacy.*'),
|
||||
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714a2.25 2.25 0 0 0 .659 1.591L19 14.5" />'];
|
||||
}
|
||||
@@ -75,40 +77,42 @@
|
||||
}
|
||||
|
||||
// Always-on Pro/Enterprise surfaces first, then other specialty modules.
|
||||
$specialtyService = app(\App\Services\Care\SpecialtyModuleService::class);
|
||||
if ($organization) {
|
||||
$specialtyService->ensureDefaultModulesProvisioned(
|
||||
$organization,
|
||||
(string) $organization->owner_ref,
|
||||
);
|
||||
$organization->refresh();
|
||||
}
|
||||
$specialtyModules = $specialtyService->enabledModulesForMember($organization, $member);
|
||||
$pinnedKeys = $specialtyService->defaultKeysForPaidPlans();
|
||||
usort($specialtyModules, function (array $a, array $b) use ($pinnedKeys): int {
|
||||
$aPin = in_array($a['key'], $pinnedKeys, true) ? 0 : 1;
|
||||
$bPin = in_array($b['key'], $pinnedKeys, true) ? 0 : 1;
|
||||
if ($aPin !== $bPin) {
|
||||
return $aPin <=> $bPin;
|
||||
}
|
||||
$aOrder = array_search($a['key'], $pinnedKeys, true);
|
||||
$bOrder = array_search($b['key'], $pinnedKeys, true);
|
||||
if ($aOrder !== false || $bOrder !== false) {
|
||||
return ($aOrder === false ? 99 : $aOrder) <=> ($bOrder === false ? 99 : $bOrder);
|
||||
if ($permissions->handlesFloorCare($member)) {
|
||||
$specialtyService = app(\App\Services\Care\SpecialtyModuleService::class);
|
||||
if ($organization) {
|
||||
$specialtyService->ensureDefaultModulesProvisioned(
|
||||
$organization,
|
||||
(string) $organization->owner_ref,
|
||||
);
|
||||
$organization->refresh();
|
||||
}
|
||||
$specialtyModules = $specialtyService->enabledModulesForMember($organization, $member);
|
||||
$pinnedKeys = $specialtyService->defaultKeysForPaidPlans();
|
||||
usort($specialtyModules, function (array $a, array $b) use ($pinnedKeys): int {
|
||||
$aPin = in_array($a['key'], $pinnedKeys, true) ? 0 : 1;
|
||||
$bPin = in_array($b['key'], $pinnedKeys, true) ? 0 : 1;
|
||||
if ($aPin !== $bPin) {
|
||||
return $aPin <=> $bPin;
|
||||
}
|
||||
$aOrder = array_search($a['key'], $pinnedKeys, true);
|
||||
$bOrder = array_search($b['key'], $pinnedKeys, true);
|
||||
if ($aOrder !== false || $bOrder !== false) {
|
||||
return ($aOrder === false ? 99 : $aOrder) <=> ($bOrder === false ? 99 : $bOrder);
|
||||
}
|
||||
|
||||
return strcasecmp(
|
||||
(string) ($a['definition']['nav_label'] ?? $a['definition']['label'] ?? $a['key']),
|
||||
(string) ($b['definition']['nav_label'] ?? $b['definition']['label'] ?? $b['key']),
|
||||
);
|
||||
});
|
||||
foreach ($specialtyModules as $item) {
|
||||
$nav[] = [
|
||||
'name' => $item['definition']['nav_label'] ?? $item['definition']['label'],
|
||||
'route' => route('care.specialty.show', $item['key']),
|
||||
'active' => request()->routeIs('care.specialty.show') && request()->route('module') === $item['key'],
|
||||
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v6m3-3H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />',
|
||||
];
|
||||
return strcasecmp(
|
||||
(string) ($a['definition']['nav_label'] ?? $a['definition']['label'] ?? $a['key']),
|
||||
(string) ($b['definition']['nav_label'] ?? $b['definition']['label'] ?? $b['key']),
|
||||
);
|
||||
});
|
||||
foreach ($specialtyModules as $item) {
|
||||
$nav[] = [
|
||||
'name' => $item['definition']['nav_label'] ?? $item['definition']['label'],
|
||||
'route' => route('care.specialty.show', $item['key']),
|
||||
'active' => request()->routeIs('care.specialty.show') && request()->route('module') === $item['key'],
|
||||
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v6m3-3H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />',
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user