Files
ladill-care/resources/views/care/partials/queue-board-card.blade.php
T
isaaccladandCursor 1bc0f84d9f
Deploy Ladill Care / deploy (push) Successful in 1m21s
Restack queue and dispatch cards so actions never crowd the text.
Board cards previously put Open/Start/advance buttons in a right-hand
column, which overlapped patient names in narrow board columns. Cards
now stack: badges on top, patient info in the middle, and a bordered
action footer. Also align two patient-queue tests with the clinical-
staff-only board access (receptionists are 403'd by design).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-20 12:42:22 +00:00

107 lines
5.7 KiB
PHP

{{--
Single patient-flow card for queue-board stages.
Expected: $appointment, $stage (waiting|called|in_care|done),
$canConsult, $queueIntegration, $startRouteName, $openInCareUrl (callable)
Open (view workspace / form) is available whenever a destination URL exists
not gated by canConsult. Start / Call again remain consult-manage only.
Layout: stacked badges on top, patient info in the middle, actions in a
footer row so narrow board columns never squeeze text under buttons.
--}}
@php
$stage = $stage ?? 'waiting';
$ticketStatus = $appointment->queue_ticket_status ?? null;
$isCalled = in_array($ticketStatus, ['called', 'serving'], true);
$openUrl = isset($openInCareUrl) ? $openInCareUrl($appointment) : null;
$canConsult = $canConsult ?? false;
$canRecall = ! empty($queueIntegration['enabled']) && $appointment->queue_ticket_uuid && $isCalled && $canConsult;
$showStart = $canConsult && ($stage === 'waiting' || $stage === 'called');
$hasActions = $openUrl || $canRecall || $showStart;
@endphp
<article
@if ($openUrl)
role="link"
tabindex="0"
data-href="{{ $openUrl }}"
onclick="if (! event.target.closest('a, button, form, input, select, textarea, label')) { window.location.href = this.dataset.href }"
onkeydown="if ((event.key === 'Enter' || event.key === ' ') && ! event.target.closest('a, button, form, input, select, textarea, label')) { event.preventDefault(); window.location.href = this.dataset.href }"
@endif
@class([
'group relative flex flex-col rounded-xl border transition',
'cursor-pointer hover:shadow-sm' => (bool) $openUrl,
'border-indigo-200 bg-indigo-50/70 ring-1 ring-indigo-100' => $stage === 'called' || ($stage === 'waiting' && $isCalled),
'border-emerald-200 bg-emerald-50/60' => $stage === 'in_care',
'border-slate-200 bg-white' => $stage === 'waiting' && ! $isCalled,
'border-slate-100 bg-white opacity-80' => $stage === 'done',
])
>
<div class="min-w-0 space-y-2 px-3 pt-3 {{ $hasActions ? 'pb-2.5' : 'pb-3' }}">
@if (! empty($queueIntegration['enabled']) && $appointment->queue_ticket_number)
@include('care.partials.queue-ticket', [
'ticketNumber' => $appointment->queue_ticket_number,
'ticketStatus' => $ticketStatus,
'destination' => $appointment->queue_destination,
'staffDisplayName' => $appointment->queue_staff_display_name,
'showAssignment' => $stage !== 'in_care' && $stage !== 'done',
'prominent' => false,
])
@elseif (! empty($queueIntegration['enabled']) && ($appointment->queue_routing_status ?? '') === 'unresolved')
<span class="inline-flex rounded-md bg-amber-100 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-amber-800">Unassigned</span>
@elseif ($appointment->queue_position)
<span class="inline-flex h-6 min-w-[1.75rem] items-center justify-center rounded-md bg-slate-100 px-1.5 font-mono text-xs font-bold text-slate-600">{{ $appointment->queue_position }}</span>
@endif
<div class="min-w-0">
<p class="truncate text-sm font-semibold text-slate-900">{{ $appointment->patient?->fullName() ?? 'Patient' }}</p>
<p class="mt-0.5 truncate text-xs text-slate-500">
@if ($stage === 'in_care' || $stage === 'done')
{{ $appointment->practitioner?->name ?? 'Unassigned' }}
@if ($appointment->patient?->patient_number)
<span class="text-slate-300"> · </span>{{ $appointment->patient->patient_number }}
@endif
@else
{{ $appointment->patient?->patient_number ?? '—' }}
@if ($appointment->reason)
<span class="text-slate-300"> · </span>{{ $appointment->reason }}
@endif
@endif
</p>
</div>
</div>
@if ($hasActions)
<div class="relative z-10 flex items-center justify-end gap-1.5 border-t border-slate-900/5 px-3 py-2" @click.stop>
@if ($canRecall)
<form method="POST" action="{{ route('care.queue.recall', $appointment) }}">
@csrf
<button type="submit" class="rounded-lg px-2 py-1 text-xs font-medium text-indigo-700 hover:bg-indigo-100/60">Call again</button>
</form>
@endif
@if ($openUrl)
<a href="{{ $openUrl }}" @class([
'rounded-lg px-2.5 py-1 text-xs font-semibold',
// Primary when it is the only meaningful action on the card.
'bg-emerald-600 text-white hover:bg-emerald-700' => $stage === 'in_care',
'bg-indigo-600 text-white hover:bg-indigo-700' => ! $showStart && $stage !== 'in_care' && $stage !== 'done',
'text-slate-600 hover:bg-slate-100' => $stage === 'done' || ($showStart && $stage !== 'in_care'),
])>Open</a>
@endif
@if ($showStart)
<form method="POST" action="{{ route($startRouteName, $appointment) }}">
@csrf
<button type="submit" @class([
'rounded-lg px-2.5 py-1 text-xs font-semibold text-white',
'bg-indigo-600 hover:bg-indigo-700' => $isCalled,
'bg-slate-900 hover:bg-slate-800' => ! $isCalled,
])>
{{ ! empty($queueIntegration['enabled']) && $ticketStatus === 'called' ? 'Serve & start' : 'Start' }}
</button>
</form>
@endif
</div>
@endif
</article>