Add full Blood Bank specialty suite on shared shell.
Deploy Ladill Care / deploy (push) Successful in 37s
Deploy Ladill Care / deploy (push) Successful in 37s
Mirror Emergency: stage workflow, issue/transfusion records, analytics, print, and action-menu stage flow without a parallel EHR. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Blood Bank summary · {{ $patient->fullName() }}</title>
|
||||
<style>
|
||||
body { font-family: system-ui, sans-serif; color: #0f172a; margin: 2rem; }
|
||||
h1 { font-size: 1.25rem; margin: 0 0 .25rem; }
|
||||
h2 { font-size: .95rem; margin: 1.25rem 0 .5rem; border-bottom: 1px solid #e2e8f0; padding-bottom: .25rem; }
|
||||
.meta { color: #64748b; font-size: .875rem; }
|
||||
dl { display: grid; grid-template-columns: 10rem 1fr; gap: .35rem .75rem; font-size: .875rem; }
|
||||
dt { color: #64748b; }
|
||||
dd { margin: 0; font-weight: 500; }
|
||||
@media print { .no-print { display: none; } }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="no-print"><a href="{{ route('care.specialty.workspace', ['module' => 'blood_bank', 'visit' => $visit]) }}">Back</a></p>
|
||||
|
||||
<h1>{{ $patient->fullName() }}</h1>
|
||||
<p class="meta">
|
||||
{{ $patient->patient_number }}
|
||||
· Visit #{{ $visit->id }}
|
||||
· Stage {{ $visit->specialty_stage ?? '—' }}
|
||||
· {{ $visit->checked_in_at?->format('d M Y H:i') ?? '—' }}
|
||||
</p>
|
||||
|
||||
<h2>Blood request</h2>
|
||||
@if ($bloodRequest)
|
||||
<dl>
|
||||
<dt>Product</dt><dd>{{ $bloodRequest->payload['product'] ?? '—' }}</dd>
|
||||
<dt>Units requested</dt><dd>{{ $bloodRequest->payload['units'] ?? '—' }}</dd>
|
||||
<dt>Urgency</dt><dd>{{ $bloodRequest->payload['urgency'] ?? '—' }}</dd>
|
||||
<dt>Blood group</dt><dd>{{ $bloodRequest->payload['patient_blood_group'] ?? '—' }}</dd>
|
||||
<dt>Indication</dt><dd>{{ $bloodRequest->payload['indication'] ?? '—' }}</dd>
|
||||
<dt>Cross-match</dt><dd>{{ $bloodRequest->payload['crossmatch_status'] ?? '—' }}</dd>
|
||||
<dt>Issued units</dt><dd>{{ $bloodRequest->payload['issued_units'] ?? '—' }}</dd>
|
||||
<dt>Notes</dt><dd>{{ $bloodRequest->payload['notes'] ?? '—' }}</dd>
|
||||
</dl>
|
||||
@else
|
||||
<p class="meta">No blood request recorded.</p>
|
||||
@endif
|
||||
|
||||
<h2>Issue</h2>
|
||||
@if ($issueNote)
|
||||
<dl>
|
||||
<dt>Product</dt><dd>{{ $issueNote->payload['product'] ?? '—' }}</dd>
|
||||
<dt>Units issued</dt><dd>{{ $issueNote->payload['units_issued'] ?? '—' }}</dd>
|
||||
<dt>Bag numbers</dt><dd>{{ $issueNote->payload['bag_numbers'] ?? '—' }}</dd>
|
||||
<dt>Issued to</dt><dd>{{ $issueNote->payload['issued_to'] ?? '—' }}</dd>
|
||||
<dt>Issued at</dt><dd>{{ $issueNote->payload['issued_at'] ?? '—' }}</dd>
|
||||
<dt>Notes</dt><dd>{{ $issueNote->payload['notes'] ?? '—' }}</dd>
|
||||
</dl>
|
||||
@else
|
||||
<p class="meta">No issue recorded.</p>
|
||||
@endif
|
||||
|
||||
<h2>Transfusion</h2>
|
||||
@if ($transfusionNote)
|
||||
<dl>
|
||||
<dt>Started</dt><dd>{{ $transfusionNote->payload['started_at'] ?? '—' }}</dd>
|
||||
<dt>Units transfused</dt><dd>{{ $transfusionNote->payload['units_transfused'] ?? '—' }}</dd>
|
||||
<dt>Reaction</dt><dd>{{ $transfusionNote->payload['reaction'] ?? '—' }}</dd>
|
||||
<dt>Outcome</dt><dd>{{ $transfusionNote->payload['outcome'] ?? '—' }}</dd>
|
||||
<dt>Notes</dt><dd>{{ $transfusionNote->payload['notes'] ?? '—' }}</dd>
|
||||
</dl>
|
||||
@else
|
||||
<p class="meta">No transfusion record.</p>
|
||||
@endif
|
||||
|
||||
@if ($visit->bill)
|
||||
<h2>Billing ({{ $visit->bill->invoice_number }})</h2>
|
||||
<dl>
|
||||
@foreach ($visit->bill->lineItems as $line)
|
||||
<dt>{{ $line->description }}</dt>
|
||||
<dd>{{ number_format($line->total_minor / 100, 2) }}</dd>
|
||||
@endforeach
|
||||
</dl>
|
||||
@endif
|
||||
|
||||
<script>window.print();</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,86 @@
|
||||
<x-app-layout title="Blood Bank reports">
|
||||
<div class="space-y-6">
|
||||
<div class="flex flex-wrap items-center justify-between gap-3">
|
||||
<div>
|
||||
<h1 class="text-xl font-semibold text-slate-900">Blood Bank reports</h1>
|
||||
<p class="mt-1 text-sm text-slate-500">Requests, urgency mix, products issued, low stock, and bb.* revenue.</p>
|
||||
</div>
|
||||
<a href="{{ route('care.specialty.workspace', 'blood_bank') }}" class="text-sm font-medium text-indigo-600">← Specialty home</a>
|
||||
</div>
|
||||
|
||||
<form method="GET" class="flex flex-wrap items-end gap-3 rounded-2xl border border-slate-200 bg-white p-4">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">From</label>
|
||||
<input type="date" name="from" value="{{ $report['from'] ?? '' }}" class="mt-1 rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">To</label>
|
||||
<input type="date" name="to" value="{{ $report['to'] ?? '' }}" class="mt-1 rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
<button type="submit" class="rounded-xl bg-indigo-600 px-4 py-2 text-sm font-semibold text-white">Apply</button>
|
||||
</form>
|
||||
|
||||
<div class="grid gap-4 sm:grid-cols-4">
|
||||
<div class="rounded-2xl border border-slate-200 bg-white p-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Requests today</p>
|
||||
<p class="mt-2 text-2xl font-semibold tabular-nums text-slate-900">{{ number_format($report['requests_today']) }}</p>
|
||||
</div>
|
||||
<div class="rounded-2xl border border-slate-200 bg-white p-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Completed today</p>
|
||||
<p class="mt-2 text-2xl font-semibold tabular-nums text-slate-900">{{ number_format($report['completed_today']) }}</p>
|
||||
</div>
|
||||
<div class="rounded-2xl border border-slate-200 bg-white p-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">High-urgency open</p>
|
||||
<p class="mt-2 text-2xl font-semibold tabular-nums text-rose-700">{{ number_format($report['high_urgency_open']) }}</p>
|
||||
</div>
|
||||
<div class="rounded-2xl border border-slate-200 bg-white p-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Low stock flags</p>
|
||||
<p class="mt-2 text-2xl font-semibold tabular-nums text-amber-800">{{ number_format($report['low_stock_flags']) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-4 lg:grid-cols-2">
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-5">
|
||||
<h2 class="text-sm font-semibold text-slate-900">Urgency mix</h2>
|
||||
<ul class="mt-3 space-y-2 text-sm">
|
||||
@forelse ($report['urgency_mix'] as $row)
|
||||
<li class="flex justify-between gap-3">
|
||||
<span>{{ $row['urgency'] }}</span>
|
||||
<span class="tabular-nums text-slate-600">{{ $row['total'] }}</span>
|
||||
</li>
|
||||
@empty
|
||||
<li class="text-slate-500">No requests in range.</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-5">
|
||||
<h2 class="text-sm font-semibold text-slate-900">Products issued</h2>
|
||||
<ul class="mt-3 space-y-2 text-sm">
|
||||
@forelse ($report['products_issued'] as $row)
|
||||
<li class="flex justify-between gap-3">
|
||||
<span>{{ $row['product'] }} <span class="text-slate-400">×{{ $row['issues'] }}</span></span>
|
||||
<span class="tabular-nums text-slate-600">{{ $row['total'] }} units</span>
|
||||
</li>
|
||||
@empty
|
||||
<li class="text-slate-500">No issues in range.</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-5">
|
||||
<h2 class="text-sm font-semibold text-slate-900">Blood Bank service revenue</h2>
|
||||
<ul class="mt-3 space-y-2 text-sm">
|
||||
@forelse ($report['revenue_by_service'] as $row)
|
||||
<li class="flex justify-between gap-3">
|
||||
<span>{{ $row->description }} <span class="text-slate-400">×{{ $row->total }}</span></span>
|
||||
<span class="tabular-nums">{{ $currency }} {{ number_format($row->amount_minor / 100, 2) }}</span>
|
||||
</li>
|
||||
@empty
|
||||
<li class="text-slate-500">No Blood Bank bill lines in range.</li>
|
||||
@endforelse
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@@ -0,0 +1,100 @@
|
||||
@php
|
||||
$issue = $bloodBankIssue;
|
||||
$payload = $issue?->payload ?? [];
|
||||
$requestPayload = $bloodBankRequest?->payload ?? [];
|
||||
$canManage = $canManageClinical ?? $canConsult ?? false;
|
||||
$defaults = [
|
||||
'product' => $payload['product'] ?? ($requestPayload['product'] ?? ''),
|
||||
'units_issued' => $payload['units_issued'] ?? ($requestPayload['units'] ?? ''),
|
||||
'bag_numbers' => $payload['bag_numbers'] ?? '',
|
||||
'issued_to' => $payload['issued_to'] ?? '',
|
||||
'issued_at' => $payload['issued_at'] ?? now()->format('Y-m-d H:i'),
|
||||
'notes' => $payload['notes'] ?? '',
|
||||
];
|
||||
@endphp
|
||||
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-5">
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-slate-900">Product issue</h3>
|
||||
<p class="mt-0.5 text-xs text-slate-500">Confirm units issued and optionally bill Blood Bank catalog services.</p>
|
||||
</div>
|
||||
@if ($issue)
|
||||
<span class="rounded-lg bg-emerald-50 px-2.5 py-1 text-xs font-semibold text-emerald-800">Issued recorded</span>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if ($canManage)
|
||||
<form method="POST" action="{{ route('care.specialty.blood-bank.issue', $workspaceVisit) }}" class="mt-4 space-y-4">
|
||||
@csrf
|
||||
<input type="hidden" name="tab" value="issue">
|
||||
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Product</label>
|
||||
<select name="payload[product]" required class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
<option value="">Select…</option>
|
||||
@foreach (['Whole blood', 'Packed RBC', 'Platelets', 'FFP', 'Cryoprecipitate'] as $option)
|
||||
<option value="{{ $option }}" @selected(old('payload.product', $defaults['product']) === $option)>{{ $option }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Units issued</label>
|
||||
<input type="number" name="payload[units_issued]" min="1" required value="{{ old('payload.units_issued', $defaults['units_issued']) }}" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Bag / unit numbers</label>
|
||||
<input type="text" name="payload[bag_numbers]" value="{{ old('payload.bag_numbers', $defaults['bag_numbers']) }}" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Issued to (ward / clinician)</label>
|
||||
<input type="text" name="payload[issued_to]" value="{{ old('payload.issued_to', $defaults['issued_to']) }}" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Issued at</label>
|
||||
<input type="text" name="payload[issued_at]" value="{{ old('payload.issued_at', $defaults['issued_at']) }}" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Notes</label>
|
||||
<textarea name="payload[notes]" rows="2" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">{{ old('payload.notes', $defaults['notes']) }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-wrap gap-4 text-sm">
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input type="checkbox" name="bill_product" value="1" checked class="rounded border-slate-300">
|
||||
Bill product units (bb.*)
|
||||
</label>
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input type="checkbox" name="bill_crossmatch" value="1" class="rounded border-slate-300">
|
||||
Bill cross-match
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary">Confirm issue</button>
|
||||
</form>
|
||||
@elseif ($issue)
|
||||
<dl class="mt-4 grid gap-3 text-sm sm:grid-cols-2">
|
||||
<div>
|
||||
<dt class="text-slate-500">Product</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['product'] ?? '—' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Units issued</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['units_issued'] ?? '—' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Bag numbers</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['bag_numbers'] ?? '—' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Issued to</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['issued_to'] ?? '—' }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@else
|
||||
<p class="mt-3 text-sm text-slate-500">No issue recorded yet.</p>
|
||||
@endif
|
||||
</section>
|
||||
@@ -0,0 +1,143 @@
|
||||
@php
|
||||
$requestRecord = $bloodBankRequest;
|
||||
$payload = $requestRecord?->payload ?? [];
|
||||
$issuePayload = $bloodBankIssue?->payload ?? [];
|
||||
$inventoryPayload = $bloodBankInventory?->payload ?? [];
|
||||
$currentStage = $workspaceVisit->specialty_stage;
|
||||
$stageFlow = $bloodBankStageFlow ?? [];
|
||||
$canManage = $canConsult ?? false;
|
||||
$urgency = (string) ($payload['urgency'] ?? '');
|
||||
$isHighUrgency = str_contains(strtolower($urgency), 'urgent')
|
||||
|| str_contains(strtolower($urgency), 'emergency')
|
||||
|| str_contains(strtolower($urgency), 'massive');
|
||||
@endphp
|
||||
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-5">
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-slate-900">Blood Bank overview</h3>
|
||||
<p class="mt-0.5 text-xs text-slate-500">Open request, urgency, cross-match status, and visit stage.</p>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-3 text-sm">
|
||||
<a href="{{ route('care.specialty.blood-bank.print', $workspaceVisit) }}" target="_blank" class="font-medium text-indigo-600">Print summary</a>
|
||||
<a href="{{ route('care.specialty.blood-bank.reports') }}" class="font-medium text-indigo-600">BB reports</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 grid gap-3 sm:grid-cols-3">
|
||||
<div class="rounded-xl border border-slate-100 bg-slate-50 px-3 py-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Request</p>
|
||||
<p class="mt-1 text-sm font-semibold text-slate-900">{{ $payload['product'] ?? 'No request' }}</p>
|
||||
<p class="mt-1 text-xs text-slate-500">
|
||||
{{ isset($payload['units']) ? $payload['units'].' unit(s)' : '—' }}
|
||||
· {{ $payload['patient_blood_group'] ?? 'Group —' }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="rounded-xl border border-slate-100 bg-slate-50 px-3 py-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Urgency / cross-match</p>
|
||||
<p @class([
|
||||
'mt-1 text-sm font-semibold',
|
||||
'text-rose-700' => $isHighUrgency,
|
||||
'text-slate-900' => ! $isHighUrgency,
|
||||
])>
|
||||
{{ $urgency !== '' ? $urgency : 'Not set' }}
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-slate-500">{{ $payload['crossmatch_status'] ?? 'Cross-match not started' }}</p>
|
||||
</div>
|
||||
<div class="rounded-xl border border-slate-100 bg-slate-50 px-3 py-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Issued</p>
|
||||
<p class="mt-1 text-sm font-semibold text-slate-900">
|
||||
{{ $issuePayload['units_issued'] ?? $payload['issued_units'] ?? '0' }} unit(s)
|
||||
</p>
|
||||
<p class="mt-1 text-xs text-slate-500">
|
||||
{{ $issuePayload['product'] ?? ($payload['product'] ?? '—') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 rounded-xl border border-slate-100 bg-slate-50 px-3 py-3">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Visit stage</p>
|
||||
<p class="mt-1 text-sm font-medium text-slate-900">
|
||||
{{ $currentStage ? ucfirst(str_replace('_', ' ', $currentStage)) : 'Not set' }}
|
||||
</p>
|
||||
<div class="mt-3 flex flex-wrap gap-2">
|
||||
@foreach (($bloodBankStageCodes ?: ['request', 'crossmatch', 'issue', 'transfusion', 'completed']) as $stageCode)
|
||||
@if ($canManage)
|
||||
<form method="POST" action="{{ route('care.specialty.blood-bank.stage', $workspaceVisit) }}">
|
||||
@csrf
|
||||
<input type="hidden" name="stage" value="{{ $stageCode }}">
|
||||
<button type="submit"
|
||||
@class([
|
||||
'rounded-lg px-2.5 py-1 text-xs font-semibold',
|
||||
'bg-indigo-600 text-white' => $currentStage === $stageCode,
|
||||
'border border-slate-200 bg-white text-slate-700 hover:bg-slate-50' => $currentStage !== $stageCode,
|
||||
])>
|
||||
{{ ucfirst(str_replace('_', ' ', $stageCode)) }}
|
||||
</button>
|
||||
</form>
|
||||
@else
|
||||
<span
|
||||
@class([
|
||||
'rounded-lg px-2.5 py-1 text-xs font-semibold',
|
||||
'bg-indigo-600 text-white' => $currentStage === $stageCode,
|
||||
'border border-slate-200 bg-white text-slate-400' => $currentStage !== $stageCode,
|
||||
])
|
||||
@if ($currentStage !== $stageCode) aria-disabled="true" title="View-only access" @endif
|
||||
>
|
||||
{{ ucfirst(str_replace('_', ' ', $stageCode)) }}
|
||||
</span>
|
||||
@endif
|
||||
@endforeach
|
||||
@if ($canManage && $currentStage && isset($stageFlow[$currentStage]) && $stageFlow[$currentStage]['next'] !== $currentStage)
|
||||
<form method="POST" action="{{ route('care.specialty.blood-bank.stage', $workspaceVisit) }}">
|
||||
@csrf
|
||||
<input type="hidden" name="stage" value="{{ $stageFlow[$currentStage]['next'] }}">
|
||||
<button type="submit" class="rounded-lg bg-emerald-600 px-2.5 py-1 text-xs font-semibold text-white hover:bg-emerald-700">
|
||||
{{ $stageFlow[$currentStage]['label'] }} →
|
||||
</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<dl class="mt-4 grid gap-3 text-sm sm:grid-cols-2">
|
||||
<div>
|
||||
<dt class="text-slate-500">Indication</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['indication'] ?? '—' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Inventory flag</dt>
|
||||
<dd class="font-medium text-slate-900">
|
||||
@if (! empty($inventoryPayload['low_stock_alert']))
|
||||
<span class="text-amber-800">Low stock flagged</span>
|
||||
@else
|
||||
{{ isset($inventoryPayload['packed_rbc_units']) ? 'Stock noted' : '—' }}
|
||||
@endif
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Queue</dt>
|
||||
<dd class="font-medium text-slate-900">
|
||||
{{ $workspaceVisit->appointment?->queue_ticket_number ?? '—' }}
|
||||
@if ($workspaceVisit->appointment?->queue_ticket_status)
|
||||
<span class="text-slate-500">({{ $workspaceVisit->appointment->queue_ticket_status }})</span>
|
||||
@endif
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Checked in</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $workspaceVisit->checked_in_at?->format('d M Y H:i') ?? '—' }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
@if (! empty($clinicalAlerts))
|
||||
<div class="mt-4 space-y-1.5 border-t border-slate-100 pt-4">
|
||||
<p class="text-xs font-semibold uppercase tracking-wide text-slate-500">Alerts</p>
|
||||
@foreach ($clinicalAlerts as $alert)
|
||||
<p class="text-sm {{ ($alert['severity'] ?? '') === 'critical' ? 'text-rose-700' : 'text-amber-800' }}">
|
||||
{{ $alert['message'] ?? '' }}
|
||||
</p>
|
||||
@endforeach
|
||||
</div>
|
||||
@endif
|
||||
</section>
|
||||
@@ -0,0 +1,90 @@
|
||||
@php
|
||||
$transfusion = $bloodBankTransfusion;
|
||||
$payload = $transfusion?->payload ?? [];
|
||||
$canManage = $canManageClinical ?? $canConsult ?? false;
|
||||
$defaults = [
|
||||
'started_at' => $payload['started_at'] ?? now()->format('Y-m-d H:i'),
|
||||
'units_transfused' => $payload['units_transfused'] ?? '',
|
||||
'vitals_ok' => old('payload.vitals_ok', $payload['vitals_ok'] ?? true),
|
||||
'reaction' => $payload['reaction'] ?? 'None',
|
||||
'outcome' => $payload['outcome'] ?? '',
|
||||
'notes' => $payload['notes'] ?? '',
|
||||
];
|
||||
@endphp
|
||||
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-5">
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-slate-900">Transfusion</h3>
|
||||
<p class="mt-0.5 text-xs text-slate-500">Document transfusion progress, reactions, and outcome.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($canManage)
|
||||
<form method="POST" action="{{ route('care.specialty.blood-bank.transfusion', $workspaceVisit) }}" class="mt-4 space-y-4">
|
||||
@csrf
|
||||
<input type="hidden" name="tab" value="transfusion">
|
||||
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Started at</label>
|
||||
<input type="text" name="payload[started_at]" value="{{ old('payload.started_at', $defaults['started_at']) }}" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Units transfused</label>
|
||||
<input type="number" name="payload[units_transfused]" min="0" value="{{ old('payload.units_transfused', $defaults['units_transfused']) }}" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Reaction</label>
|
||||
<select name="payload[reaction]" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
@foreach (['None', 'Mild (fever / itch)', 'Moderate', 'Severe / stop transfusion'] as $option)
|
||||
<option value="{{ $option }}" @selected(old('payload.reaction', $defaults['reaction']) === $option)>{{ $option }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Outcome</label>
|
||||
<select name="payload[outcome]" required class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">
|
||||
<option value="">Select…</option>
|
||||
@foreach (['In progress', 'Completed uneventfully', 'Stopped — reaction', 'Stopped — other'] as $option)
|
||||
<option value="{{ $option }}" @selected(old('payload.outcome', $defaults['outcome']) === $option)>{{ $option }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<label class="inline-flex items-center gap-2 text-sm">
|
||||
<input type="checkbox" name="payload[vitals_ok]" value="1" @checked(old('payload.vitals_ok', $defaults['vitals_ok'])) class="rounded border-slate-300">
|
||||
Pre-/intra-transfusion vitals acceptable
|
||||
</label>
|
||||
|
||||
<div>
|
||||
<label class="block text-xs font-medium text-slate-600">Notes</label>
|
||||
<textarea name="payload[notes]" rows="3" class="mt-1 w-full rounded-xl border border-slate-200 px-3 py-2 text-sm">{{ old('payload.notes', $defaults['notes']) }}</textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary">Save transfusion</button>
|
||||
</form>
|
||||
@elseif ($transfusion)
|
||||
<dl class="mt-4 grid gap-3 text-sm sm:grid-cols-2">
|
||||
<div>
|
||||
<dt class="text-slate-500">Outcome</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['outcome'] ?? '—' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Reaction</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['reaction'] ?? '—' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Units transfused</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['units_transfused'] ?? '—' }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-slate-500">Notes</dt>
|
||||
<dd class="font-medium text-slate-900">{{ $payload['notes'] ?? '—' }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
@else
|
||||
<p class="mt-3 text-sm text-slate-500">No transfusion record yet.</p>
|
||||
@endif
|
||||
</section>
|
||||
@@ -30,21 +30,51 @@
|
||||
&& $openConsultation->status !== \App\Models\Consultation::STATUS_COMPLETED;
|
||||
$chartTab = collect($workspaceTabs ?? [])
|
||||
->keys()
|
||||
->first(fn ($key) => ! in_array($key, ['overview', 'timeline', 'plan', 'treat', 'notes', 'imaging', 'orders', 'billing', 'documents', 'perio', 'lab', 'recalls', 'vitals', 'disposition', 'observation'], true))
|
||||
?: ($moduleKey === 'emergency' ? 'triage' : 'odontogram');
|
||||
$stageFlow = $moduleKey === 'emergency'
|
||||
? ($emergencyStageFlow ?? [
|
||||
->first(fn ($key) => ! in_array($key, ['overview', 'timeline', 'plan', 'treat', 'notes', 'imaging', 'orders', 'billing', 'documents', 'perio', 'lab', 'recalls', 'vitals', 'disposition', 'observation', 'issue', 'transfusion', 'inventory'], true))
|
||||
?: match ($moduleKey) {
|
||||
'emergency' => 'triage',
|
||||
'blood_bank' => 'requests',
|
||||
default => 'odontogram',
|
||||
};
|
||||
$stageRoute = match ($moduleKey) {
|
||||
'dentistry' => 'care.specialty.dentistry.stage',
|
||||
'emergency' => 'care.specialty.emergency.stage',
|
||||
'blood_bank' => 'care.specialty.blood-bank.stage',
|
||||
default => null,
|
||||
};
|
||||
$stageFlow = match ($moduleKey) {
|
||||
'emergency' => ($emergencyStageFlow ?? [
|
||||
'arrival' => ['next' => 'treatment', 'label' => 'Move to treatment'],
|
||||
'resus' => ['next' => 'treatment', 'label' => 'Move to treatment bay'],
|
||||
'treatment' => ['next' => 'observation', 'label' => 'Move to observation'],
|
||||
'observation' => ['next' => 'disposition', 'label' => 'Ready for disposition'],
|
||||
])
|
||||
: [
|
||||
]),
|
||||
'blood_bank' => ($bloodBankStageFlow ?? [
|
||||
'request' => ['next' => 'crossmatch', 'label' => 'Start cross-match'],
|
||||
'crossmatch' => ['next' => 'issue', 'label' => 'Ready to issue'],
|
||||
'issue' => ['next' => 'transfusion', 'label' => 'Start transfusion'],
|
||||
'transfusion' => ['next' => 'completed', 'label' => 'Complete visit'],
|
||||
]),
|
||||
'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 => [],
|
||||
};
|
||||
$defaultStartStage = match ($moduleKey) {
|
||||
'emergency' => 'arrival',
|
||||
'blood_bank' => 'request',
|
||||
'dentistry' => 'chair',
|
||||
default => null,
|
||||
};
|
||||
$defaultStartLabel = match ($moduleKey) {
|
||||
'emergency' => 'Start triage',
|
||||
'blood_bank' => 'Start request',
|
||||
'dentistry' => 'Seat at chair',
|
||||
default => 'Start',
|
||||
};
|
||||
$currentStage = $workspaceVisit?->specialty_stage;
|
||||
@endphp
|
||||
|
||||
@@ -67,29 +97,17 @@
|
||||
@endif
|
||||
|
||||
@if ($workspaceVisit)
|
||||
@if ($canAdvanceStage && $moduleKey === 'dentistry' && $currentStage && isset($stageFlow[$currentStage]))
|
||||
<form method="POST" action="{{ route('care.specialty.dentistry.stage', $workspaceVisit) }}" class="w-full" @click.stop>
|
||||
@if ($canAdvanceStage && $stageRoute && $currentStage && isset($stageFlow[$currentStage]) && ($stageFlow[$currentStage]['next'] ?? null) !== $currentStage)
|
||||
<form method="POST" action="{{ route($stageRoute, $workspaceVisit) }}" class="w-full" @click.stop>
|
||||
@csrf
|
||||
<input type="hidden" name="stage" value="{{ $stageFlow[$currentStage]['next'] }}">
|
||||
<button type="submit" class="{{ $btnAccent }}">{{ $stageFlow[$currentStage]['label'] }}</button>
|
||||
</form>
|
||||
@elseif ($canAdvanceStage && $moduleKey === 'dentistry' && ! $currentStage)
|
||||
<form method="POST" action="{{ route('care.specialty.dentistry.stage', $workspaceVisit) }}" class="w-full" @click.stop>
|
||||
@elseif ($canAdvanceStage && $stageRoute && ! $currentStage && $defaultStartStage)
|
||||
<form method="POST" action="{{ route($stageRoute, $workspaceVisit) }}" class="w-full" @click.stop>
|
||||
@csrf
|
||||
<input type="hidden" name="stage" value="chair">
|
||||
<button type="submit" class="{{ $btnAccent }}">Seat at chair</button>
|
||||
</form>
|
||||
@elseif ($canAdvanceStage && $moduleKey === 'emergency' && $currentStage && isset($stageFlow[$currentStage]) && ($stageFlow[$currentStage]['next'] ?? null) !== $currentStage)
|
||||
<form method="POST" action="{{ route('care.specialty.emergency.stage', $workspaceVisit) }}" class="w-full" @click.stop>
|
||||
@csrf
|
||||
<input type="hidden" name="stage" value="{{ $stageFlow[$currentStage]['next'] }}">
|
||||
<button type="submit" class="{{ $btnAccent }}">{{ $stageFlow[$currentStage]['label'] }}</button>
|
||||
</form>
|
||||
@elseif ($canAdvanceStage && $moduleKey === 'emergency' && ! $currentStage)
|
||||
<form method="POST" action="{{ route('care.specialty.emergency.stage', $workspaceVisit) }}" class="w-full" @click.stop>
|
||||
@csrf
|
||||
<input type="hidden" name="stage" value="arrival">
|
||||
<button type="submit" class="{{ $btnAccent }}">Start triage</button>
|
||||
<input type="hidden" name="stage" value="{{ $defaultStartStage }}">
|
||||
<button type="submit" class="{{ $btnAccent }}">{{ $defaultStartLabel }}</button>
|
||||
</form>
|
||||
@endif
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
@include('care.specialty.dentistry.workspace-'.$activeTab)
|
||||
@elseif ($moduleKey === 'emergency' && in_array($activeTab, ['overview', 'vitals', 'disposition'], true))
|
||||
@include('care.specialty.emergency.workspace-'.$activeTab)
|
||||
@elseif ($moduleKey === 'blood_bank' && in_array($activeTab, ['overview', 'issue', 'transfusion'], true))
|
||||
@include('care.specialty.blood-bank.workspace-'.$activeTab)
|
||||
@elseif ($activeTab === 'billing')
|
||||
<section class="rounded-2xl border border-slate-200 bg-white p-5">
|
||||
<h3 class="text-sm font-semibold text-slate-900">
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
@if ($moduleKey === 'emergency')
|
||||
<a href="{{ route('care.specialty.emergency.reports') }}" class="text-slate-600 hover:text-slate-900">Reports</a>
|
||||
@endif
|
||||
@if ($moduleKey === 'blood_bank')
|
||||
<a href="{{ route('care.specialty.blood-bank.reports') }}" class="text-slate-600 hover:text-slate-900">Reports</a>
|
||||
@endif
|
||||
<a href="{{ route('care.specialty.history', $moduleKey) }}" class="text-slate-600 hover:text-slate-900">History</a>
|
||||
@if ($canManageClinical ?? $canManageSpecialty ?? true)
|
||||
<a href="{{ route('care.specialty.billing', $moduleKey) }}" class="text-slate-600 hover:text-slate-900">Billing</a>
|
||||
|
||||
Reference in New Issue
Block a user