Add shared specialty stage stepper to all workspace shells.
Deploy Ladill Care / deploy (push) Successful in 35s

Lift Eye Care stage pills into a reusable action-bar component so every
module visit workspace shows config-driven stages with RBAC-gated Move CTAs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-19 16:13:29 +00:00
co-authored by Cursor
parent b44ed50fe7
commit be7bd8f433
13 changed files with 185 additions and 233 deletions
@@ -963,6 +963,8 @@ class SpecialtyModuleController extends Controller
'visitHistory' => $visitHistory,
'kpis' => $kpis,
'stages' => $shell->stages($module),
'specialtyStageFlow' => $shell->stageFlow($module),
'specialtyStageRoute' => $shell->stageAdvanceRoute($module),
'services' => $services,
'workspaceTabs' => $shell->workspaceTabs($module),
'actions' => $shell->actions($module),
@@ -9,6 +9,9 @@ use App\Models\Member;
use App\Models\Organization;
use App\Models\Patient;
use App\Models\Visit;
use App\Services\Care\BloodBank\BloodBankWorkflowService;
use App\Services\Care\Emergency\EmergencyWorkflowService;
use App\Services\Care\Ophthalmology\OphthalmologyWorkflowService;
use Illuminate\Support\Collection;
/**
@@ -43,6 +46,79 @@ class SpecialtyShellService
return is_array($stages) ? array_values($stages) : [];
}
/**
* Named route for advancing/setting specialty visit stage, if the module has one.
*/
public function stageAdvanceRoute(string $moduleKey): ?string
{
return match ($moduleKey) {
'dentistry' => 'care.specialty.dentistry.stage',
'emergency' => 'care.specialty.emergency.stage',
'blood_bank' => 'care.specialty.blood-bank.stage',
'ophthalmology' => 'care.specialty.ophthalmology.stage',
default => null,
};
}
/**
* Default stage progression for Move CTAs and action menus.
*
* @return array<string, array{next: string, label: string}>
*/
public function stageFlow(string $moduleKey): array
{
return match ($moduleKey) {
'emergency' => app(EmergencyWorkflowService::class)->stageFlow(),
'blood_bank' => app(BloodBankWorkflowService::class)->stageFlow(),
'ophthalmology' => app(OphthalmologyWorkflowService::class)->stageFlow(),
'dentistry' => [
'waiting' => ['next' => 'chair', 'label' => 'Seat at chair'],
'chair' => ['next' => 'procedure', 'label' => 'Start procedure'],
'procedure' => ['next' => 'recovery', 'label' => 'Move to recovery'],
'recovery' => ['next' => 'completed', 'label' => 'Complete visit'],
],
default => $this->sequentialStageFlow($moduleKey),
};
}
/**
* Build next-stage map from configured stage order when no suite workflow exists.
*
* @return array<string, array{next: string, label: string}>
*/
protected function sequentialStageFlow(string $moduleKey): array
{
$stages = $this->stages($moduleKey);
$flow = [];
for ($i = 0, $count = count($stages); $i < $count; $i++) {
$code = (string) ($stages[$i]['code'] ?? '');
if ($code === '') {
continue;
}
$next = $stages[$i + 1] ?? null;
if ($next === null) {
$flow[$code] = ['next' => $code, 'label' => 'Completed'];
continue;
}
$nextCode = (string) ($next['code'] ?? '');
if ($nextCode === '') {
continue;
}
$nextLabel = (string) ($next['label'] ?? $nextCode);
$flow[$code] = [
'next' => $nextCode,
'label' => 'Move to '.mb_strtolower($nextLabel),
];
}
return $flow;
}
/**
* Catalog from config (authoritative template).
*