Gate specialty modules by staff role with view and refer levels.
Deploy Ladill Care / deploy (push) Successful in 37s

Give nurses, lab techs, pharmacists, and GPs broad access to day-to-day modules, keep restricted specialties for specialists (with support nurses), and let GPs view results or refer without full clinical edit.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-18 18:03:47 +00:00
co-authored by Cursor
parent 7989ab9184
commit 2cff8fdd6c
13 changed files with 762 additions and 89 deletions
+20 -2
View File
@@ -76,12 +76,25 @@
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M3 13.125C3 12.504 3.504 12 4.125 12h2.25c.621 0 1.125.504 1.125 1.125v6.75C7.5 20.496 6.996 21 6.375 21h-2.25A1.125 1.125 0 0 1 3 19.875v-6.75ZM9.75 8.625c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125v11.25c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V8.625ZM16.5 4.125c0-.621.504-1.125 1.125-1.125h2.25C20.496 3 21 3.504 21 4.125v15.75c0 .621-.504 1.125-1.125 1.125h-2.25a1.125 1.125 0 0 1-1.125-1.125V4.125Z" />'];
}
// Specialty modules stay enabled for clinical depth, but patient flow lives on Queue only.
// Specialty modules — role-gated clinical surfaces for floor staff.
if ($permissions->handlesFloorCare($member) && $organization) {
app(\App\Services\Care\SpecialtyModuleService::class)->ensureDefaultModulesProvisioned(
$specialtyService = app(\App\Services\Care\SpecialtyModuleService::class);
$specialtyService->ensureDefaultModulesProvisioned(
$organization,
(string) $organization->owner_ref,
);
$specialtyIcon = '<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.714c0 .846.344 1.657.955 2.247L19 14.5M14.25 3.104c.251.023.501.05.75.082M19 14.5l-1.659 1.659a2.25 2.25 0 0 1-1.591.659H8.25" />';
foreach ($specialtyService->enabledModulesForMember($organization, $member) as $item) {
$key = $item['key'];
$label = $item['definition']['nav_label'] ?? $item['definition']['label'] ?? $key;
$nav[] = [
'name' => $label,
'route' => route('care.specialty.workspace', $key),
'active' => request()->routeIs('care.specialty.*') && request()->route('module') === $key,
'icon' => $specialtyIcon,
'group' => 'specialty',
];
}
}
}
@@ -108,7 +121,12 @@
@endphp
<nav class="flex-1 space-y-0.5 overflow-y-auto px-3 py-4">
@php $specialtyHeadingShown = false; @endphp
@foreach ($nav as $item)
@if (($item['group'] ?? null) === 'specialty' && ! $specialtyHeadingShown)
<p class="mb-1 mt-4 px-3 text-[10px] font-semibold uppercase tracking-wider text-slate-400">Specialty</p>
@php $specialtyHeadingShown = true; @endphp
@endif
<a href="{{ $item['route'] }}" class="group flex items-center gap-3 rounded-lg px-3 py-2 text-[13px] transition {{ $item['active'] ? 'bg-indigo-50 text-indigo-700 font-semibold' : 'text-slate-600 hover:bg-slate-50 hover:text-slate-900' }}">
<svg class="{{ $item['iconSizeClass'] ?? 'h-[18px] w-[18px]' }} shrink-0 {{ $item['active'] ? 'text-indigo-600' : 'text-slate-400' }}" viewBox="{{ $item['iconViewBox'] ?? '0 0 24 24' }}" fill="none" stroke="currentColor" stroke-width="{{ $item['iconStrokeWidth'] ?? 1.5 }}">{!! $item['icon'] !!}</svg>
<span>{{ $item['name'] }}</span>