Files
ladill-care/resources/views/care/patients/show.blade.php
T
isaaccladandCursor 5c394cec2e
Deploy Ladill Care / deploy (push) Successful in 55s
Clarify patient vs nurse unit placement on nursing charts.
The empty state referred to the patient but read like the nurse was unassigned; show duty units and patient-specific copy instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-20 16:36:35 +00:00

420 lines
28 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<x-app-layout :title="$patient->fullName()">
@include('care.partials.patient-header', [
'patient' => $patient,
'outstandingMinor' => $patientHeaderMeta['outstanding_minor'] ?? 0,
'allergies' => $patientHeaderMeta['allergies'] ?? [],
'insuranceSummary' => $patientHeaderMeta['insurance_summary'] ?? null,
'emergency' => $patientHeaderMeta['emergency'] ?? false,
'currency' => $currency ?? 'GHS',
])
<div class="mt-4 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div>
<p class="text-sm text-slate-500">
@if ($patient->phone) {{ $patient->phone }} @endif
</p>
</div>
@if ($canManage)
<div class="flex gap-2">
<a href="{{ route('care.patients.label', $patient) }}" target="_blank" class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Print ID label</a>
<a href="{{ route('care.patients.edit', $patient) }}" class="btn-primary">Edit</a>
<x-confirm-dialog
:name="'archive-patient-'.$patient->id"
title="Archive this patient?"
message="The patient record will be archived and hidden from active lists."
:action="route('care.patients.destroy', $patient)"
method="DELETE"
confirm-label="Archive patient"
>
<x-slot:trigger>
<x-btn type="button" variant="danger">Archive</x-btn>
</x-slot:trigger>
</x-confirm-dialog>
</div>
@else
<div class="flex gap-2">
<a href="{{ route('care.patients.label', $patient) }}" target="_blank" class="rounded-lg border border-slate-200 bg-white px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Print ID label</a>
</div>
@endif
</div>
<div class="mt-6 grid gap-6 lg:grid-cols-3">
<div class="space-y-6 lg:col-span-2">
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">Personal information</h2>
<dl class="mt-4 grid gap-3 sm:grid-cols-2 text-sm">
<div><dt class="text-slate-500">National ID</dt><dd class="font-medium">{{ $patient->national_id ?? '—' }}</dd></div>
<div><dt class="text-slate-500">Email</dt><dd class="font-medium">{{ $patient->email ?? '—' }}</dd></div>
<div class="sm:col-span-2"><dt class="text-slate-500">Address</dt><dd class="font-medium">{{ collect([$patient->address, $patient->city, $patient->region])->filter()->implode(', ') ?: '—' }}</dd></div>
<div><dt class="text-slate-500">Branch</dt><dd class="font-medium">{{ $patient->branch?->name ?? '—' }}</dd></div>
</dl>
@if ($patient->notes)
<p class="mt-4 text-sm text-slate-600">{{ $patient->notes }}</p>
@endif
</section>
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">Medical history</h2>
<div class="mt-4 space-y-4 text-sm">
<div>
<h3 class="font-medium text-slate-800">Allergies</h3>
@forelse ($patient->allergies as $allergy)
<p class="mt-1 text-slate-600">{{ $allergy->allergen }} <span class="text-slate-400">({{ $allergySeverities[$allergy->severity] ?? $allergy->severity }})</span></p>
@empty
<p class="mt-1 text-slate-400">None recorded</p>
@endforelse
</div>
<div>
<h3 class="font-medium text-slate-800">Conditions</h3>
@forelse ($patient->conditions as $condition)
<p class="mt-1 text-slate-600">{{ $condition->condition }}@if ($condition->is_chronic) <span class="text-amber-600">(chronic)</span>@endif</p>
@empty
<p class="mt-1 text-slate-400">None recorded</p>
@endforelse
</div>
<div>
<h3 class="font-medium text-slate-800">Family history</h3>
@forelse ($patient->familyHistory as $entry)
<p class="mt-1 text-slate-600">{{ $entry->relation }}: {{ $entry->condition }}</p>
@empty
<p class="mt-1 text-slate-400">None recorded</p>
@endforelse
</div>
</div>
</section>
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">
{{ ($isNurseStation ?? false) && ! ($canConsult ?? false) ? 'Visit & nursing care' : 'Visit & clinical history' }}
</h2>
<div class="mt-4 space-y-4 text-sm">
<div>
<h3 class="font-medium text-slate-800">Recent visits</h3>
@forelse ($visits as $visit)
<p class="mt-1 text-slate-600">
{{ $visit->checked_in_at?->format('d M Y H:i') ?? '—' }}
· {{ config('care.visit_statuses')[$visit->status] ?? $visit->status }}
@if ($visit->branch) · {{ $visit->branch->name }} @endif
@if ($visit->careUnit)
· {{ $visit->careUnit->name }}@if ($visit->bed) / {{ $visit->bed->label }}@endif
@endif
</p>
@empty
<p class="mt-1 text-slate-400">No visits yet</p>
@endforelse
</div>
@if (($isNurseStation ?? false) && ! ($canConsult ?? false))
@if ($activePlacedVisit ?? null)
<div class="rounded-xl border border-teal-100 bg-teal-50/60 px-3 py-3">
<p class="text-xs font-semibold uppercase tracking-wide text-teal-800">Patient on unit</p>
<p class="mt-1 font-medium text-slate-900">
{{ $activePlacedVisit->careUnit?->name ?? 'Care unit' }}
@if ($activePlacedVisit->careUnit?->department?->branch)
· {{ $activePlacedVisit->careUnit->department->branch->name }}
@endif
@if ($activePlacedVisit->bed)
· Bed {{ $activePlacedVisit->bed->label }}
@endif
</p>
@if ($latestVitals ?? null)
<p class="mt-1 text-xs text-slate-600">
Latest vitals
{{ $latestVitals->recorded_at?->format('d M H:i') }}:
BP {{ $latestVitals->bp_systolic }}/{{ $latestVitals->bp_diastolic }}
· P {{ $latestVitals->pulse }}
· SpO₂ {{ $latestVitals->spo2 }}
</p>
@else
<p class="mt-1 text-xs text-slate-500">No vitals recorded on this placement yet.</p>
@endif
<p class="mt-3 flex flex-wrap gap-3">
<a href="{{ route('care.nursing.station', ['unit' => $activePlacedVisit->care_unit_id]) }}" class="text-sm font-medium text-teal-700 hover:text-teal-900">Open care unit</a>
@if ($canViewMar ?? false)
<a href="{{ route('care.visits.mar', $activePlacedVisit) }}" class="text-sm font-medium text-teal-700 hover:text-teal-900">MAR chart</a>
@endif
@if ($activePlacedVisit->careUnit)
<a href="{{ route('care.care-units.assessments', $activePlacedVisit->careUnit) }}" class="text-sm font-medium text-teal-700 hover:text-teal-900">Vitals &amp; assess</a>
<a href="{{ route('care.care-units.notes', $activePlacedVisit->careUnit) }}" class="text-sm font-medium text-teal-700 hover:text-teal-900">Nursing notes</a>
@endif
</p>
</div>
@else
<div class="rounded-xl border border-dashed border-slate-200 px-3 py-3 text-slate-600">
<p class="font-medium text-slate-800">This patient is not on a care unit right now.</p>
@if (($nurseDutyUnits ?? collect())->isNotEmpty())
<p class="mt-1 text-sm text-slate-500">
You are on duty at
{{ $nurseDutyUnits->pluck('name')->join(', ') }}
this chart is about the patients placement, not yours.
</p>
<p class="mt-2 flex flex-wrap gap-3">
@foreach ($nurseDutyUnits as $dutyUnit)
<a href="{{ route('care.nursing.station', ['unit' => $dutyUnit->id]) }}" class="text-sm font-medium text-indigo-600 hover:text-indigo-800">
Open {{ $dutyUnit->name }}
</a>
@endforeach
</p>
@else
<p class="mt-1 text-sm text-slate-500">
Ask a charge nurse to place them, or open
<a href="{{ route('care.nursing.station') }}" class="font-medium text-indigo-600 hover:text-indigo-800">My care unit</a>.
</p>
@endif
</div>
@endif
<div>
<div class="flex items-center justify-between gap-2">
<h3 class="font-medium text-slate-800">Nursing assessments</h3>
@if ($canViewAssessments ?? false)
<a href="{{ route('care.assessments.index', $patient) }}" class="text-xs text-sky-600 hover:text-sky-700">View all</a>
@endif
</div>
@forelse ($nursingAssessments ?? [] as $assessment)
<p class="mt-1">
<a href="{{ route('care.assessments.show', $assessment) }}" class="text-sky-600 hover:text-sky-700">
{{ $assessment->template->name }}
</a>
· {{ ($assessmentStatuses[$assessment->status] ?? $assessment->status) }}
· {{ $assessment->created_at?->format('d M Y') ?? '—' }}
</p>
@empty
<p class="mt-1 text-slate-400">No nursing assessments yet start NEWS2, Braden, Morse, or pain from the unit board.</p>
@endforelse
</div>
<div>
<h3 class="font-medium text-slate-800">Medications</h3>
@forelse ($prescriptions as $rx)
<p class="mt-1 text-slate-600">
{{ $rx->created_at->format('d M Y') }}
· {{ config('care.prescription_statuses')[$rx->status] ?? $rx->status }}
· {{ $rx->items->pluck('name')->take(2)->join(', ') }}
</p>
@empty
<p class="mt-1 text-slate-400">No prescriptions on record</p>
@endforelse
</div>
<div>
<h3 class="font-medium text-slate-800">Laboratory</h3>
@forelse ($laboratory as $lab)
<p class="mt-1 text-slate-600">
{{ $lab->investigationType->name }}
· {{ $lab->completed_at?->format('d M Y') ?? '—' }}
@if ($lab->result?->is_abnormal)
<span class="text-red-600">abnormal</span>
@endif
</p>
@empty
<p class="mt-1 text-slate-400">No lab results yet</p>
@endforelse
</div>
@else
<div>
<h3 class="font-medium text-slate-800">Consultations</h3>
@forelse ($consultations as $consultation)
<p class="mt-1">
<a href="{{ route('care.consultations.show', $consultation) }}" class="text-sky-600 hover:text-sky-700">
{{ $consultation->started_at?->format('d M Y') ?? '—' }}
@if ($consultation->practitioner) · {{ $consultation->practitioner->name }} @endif
</a>
@if ($consultation->diagnoses->isNotEmpty())
<span class="text-slate-400"> {{ $consultation->diagnoses->first()->description }}</span>
@endif
</p>
@empty
<p class="mt-1 text-slate-400">No consultations yet</p>
@endforelse
</div>
@if ($canViewLab ?? true)
<div>
<h3 class="font-medium text-slate-800">Laboratory</h3>
@forelse ($laboratory as $lab)
<p class="mt-1">
<a href="{{ route('care.lab.requests.show', $lab) }}" class="text-sky-600 hover:text-sky-700">
{{ $lab->investigationType->name }}
</a>
· {{ $lab->completed_at?->format('d M Y') ?? '—' }}
@if ($lab->result?->is_abnormal)
<span class="text-red-600">abnormal</span>
@endif
</p>
@empty
<p class="mt-1 text-slate-400">No lab results yet</p>
@endforelse
</div>
@endif
@if ($canViewRx ?? true)
<div>
<h3 class="font-medium text-slate-800">Prescriptions</h3>
@forelse ($prescriptions as $rx)
<p class="mt-1">
<a href="{{ route('care.prescriptions.show', $rx) }}" class="text-sky-600 hover:text-sky-700">
{{ $rx->created_at->format('d M Y') }}
</a>
· {{ config('care.prescription_statuses')[$rx->status] ?? $rx->status }}
· {{ $rx->items->pluck('name')->take(2)->join(', ') }}
</p>
@empty
<p class="mt-1 text-slate-400">No prescriptions yet</p>
@endforelse
</div>
@endif
@if ($canViewAssessments ?? false)
<div>
<div class="flex items-center justify-between gap-2">
<h3 class="font-medium text-slate-800">Assessments</h3>
<a href="{{ route('care.assessments.index', $patient) }}" class="text-xs text-sky-600 hover:text-sky-700">View all</a>
</div>
@if ($latestUniversalIntake ?? null)
@php
$ccAnswer = $latestUniversalIntake->answers->first(fn ($a) => $a->question?->code === 'chief_complaint');
@endphp
<div class="mt-2 rounded-lg border border-sky-100 bg-sky-50/50 px-3 py-2">
<p class="text-xs font-medium uppercase tracking-wide text-sky-800">Patient history form</p>
<p class="mt-1">
<a href="{{ route('care.assessments.show', $latestUniversalIntake) }}" class="text-sky-600 hover:text-sky-700">
{{ $assessmentStatuses[$latestUniversalIntake->status] ?? $latestUniversalIntake->status }}
</a>
· {{ $latestUniversalIntake->created_at?->format('d M Y') ?? '—' }}
</p>
@if ($ccAnswer)
<p class="mt-1 text-slate-600">{{ \Illuminate\Support\Str::limit((string) $ccAnswer->authoritativeValue(), 120) }}</p>
@endif
</div>
@endif
@forelse ($recentAssessments as $assessment)
<p class="mt-1">
<a href="{{ route('care.assessments.show', $assessment) }}" class="text-sky-600 hover:text-sky-700">
{{ $assessment->template->name }}
</a>
· {{ ($assessmentStatuses[$assessment->status] ?? $assessment->status) }}
· {{ $assessment->created_at?->format('d M Y') ?? '—' }}
</p>
@empty
<p class="mt-1 text-slate-400">No assessments yet</p>
@endforelse
<p class="mt-2 flex flex-wrap gap-3">
@if ($canCaptureAssessment ?? false)
<a href="{{ route('care.assessments.create', $patient) }}" class="text-sm font-medium text-sky-600 hover:text-sky-700">Start assessment</a>
@endif
@if ($canViewPathways ?? false)
<a href="{{ route('care.pathways.index', $patient) }}" class="text-sm font-medium text-sky-600 hover:text-sky-700">Condition pathways</a>
<a href="{{ route('care.outcomes.index', $patient) }}" class="text-sm font-medium text-sky-600 hover:text-sky-700">Follow-up scores</a>
@endif
</p>
</div>
@endif
@endif
</div>
</section>
</div>
<div class="space-y-6">
@include('care.partials.patient-timeline', ['events' => $patientTimeline ?? []])
@if ($canManage)
<section class="rounded-2xl border border-slate-200 bg-white p-6" x-data="{ tab: 'sms' }">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">Message patient</h2>
<p class="mt-1 text-xs text-slate-500">
Uses suite messaging by default (no API keys).
<a href="{{ $messagingSettingsUrl ?? '#' }}" class="text-teal-700 underline" target="_blank" rel="noopener">Account messaging settings</a>
·
<a href="{{ route('care.integrations') }}" class="text-slate-500 underline">Advanced keys</a>
</p>
@if (! ($messagingSmsReady ?? false) || ! ($messagingEmailReady ?? false))
<p class="mt-3 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800">
@if (! ($messagingSmsReady ?? false) && ! ($messagingEmailReady ?? false))
Messaging is not available yet. Bind a mailbox under Account Messaging once platform keys are configured, or connect product keys under Integrations.
@elseif (! ($messagingSmsReady ?? false))
SMS is not available (platform SMS key missing and no product SMS credentials).
@else
Email is not available (platform email key missing and no Bird credentials). Set a mailbox under Account Messaging when suite email is live.
@endif
</p>
@endif
<div class="mt-4 flex gap-1 rounded-xl bg-slate-100 p-1 text-sm">
<button type="button" @click="tab = 'sms'" :class="tab === 'sms' ? 'bg-white shadow-sm text-slate-900' : 'text-slate-500'" class="flex-1 rounded-lg px-3 py-1.5 font-medium">SMS</button>
<button type="button" @click="tab = 'email'" :class="tab === 'email' ? 'bg-white shadow-sm text-slate-900' : 'text-slate-500'" class="flex-1 rounded-lg px-3 py-1.5 font-medium">Email</button>
</div>
<form x-show="tab === 'sms'" x-cloak method="POST" action="{{ route('care.patients.sms', $patient) }}" class="mt-4 space-y-3">
@csrf
<p class="text-xs text-slate-500">To: {{ $patient->phone ?: 'no phone on file' }}</p>
<textarea name="message" rows="3" maxlength="480" placeholder="Text message" required class="block w-full rounded-xl border-slate-300 text-sm focus:border-sky-500 focus:ring-sky-500">{{ old('message') }}</textarea>
<div class="text-right">
<button type="submit" class="btn-primary" @if(! $patient->phone || ! ($messagingSmsReady ?? false)) disabled @endif>Send SMS</button>
</div>
</form>
<form x-show="tab === 'email'" x-cloak method="POST" action="{{ route('care.patients.email', $patient) }}" class="mt-4 space-y-3">
@csrf
<p class="text-xs text-slate-500">To: {{ $patient->email ?: 'no email on file' }}</p>
<input type="text" name="subject" value="{{ old('subject') }}" placeholder="Subject" required class="block w-full rounded-xl border-slate-300 text-sm focus:border-sky-500 focus:ring-sky-500">
<textarea name="body" rows="4" placeholder="Message" required class="block w-full rounded-xl border-slate-300 text-sm focus:border-sky-500 focus:ring-sky-500">{{ old('body') }}</textarea>
<div class="text-right">
<button type="submit" class="btn-primary" @if(! $patient->email || ! ($messagingEmailReady ?? false)) disabled @endif>Send email</button>
</div>
</form>
</section>
@endif
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">Emergency contacts</h2>
@forelse ($patient->emergencyContacts as $contact)
<div class="mt-3 text-sm">
<p class="font-medium">{{ $contact->name }}@if ($contact->is_primary) <span class="text-sky-600">(primary)</span>@endif</p>
<p class="text-slate-600">{{ $contact->phone }} · {{ $contact->relationship ?? '—' }}</p>
</div>
@empty
<p class="mt-3 text-sm text-slate-400">None recorded</p>
@endforelse
</section>
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">Insurance</h2>
@forelse ($patient->insurancePolicies as $policy)
<div class="mt-3 text-sm">
<p class="font-medium">{{ $policy->provider_name }}</p>
<p class="text-slate-600">{{ $policy->policy_number ?? '—' }} · {{ $policy->coverage_type ?? '—' }}</p>
</div>
@empty
<p class="mt-3 text-sm text-slate-400">None recorded</p>
@endforelse
</section>
@if (($canViewBills ?? false) || ($canConsult ?? false) || ($canManage ?? false))
@php $money = fn ($minor) => config('care.billing.currency').' '.number_format($minor / 100, 2); @endphp
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">Billing</h2>
<div class="mt-3 space-y-2 text-sm">
@forelse ($invoices as $invoice)
<div>
<a href="{{ route('care.bills.show', $invoice) }}" class="font-medium text-sky-600 hover:text-sky-700">{{ $invoice->invoice_number }}</a>
<p class="text-slate-600">{{ $invoice->created_at->format('d M Y') }} · {{ $money($invoice->total_minor) }} · {{ config('care.bill_statuses')[$invoice->status] ?? $invoice->status }}</p>
</div>
@empty
<p class="text-slate-400">No invoices yet</p>
@endforelse
</div>
</section>
@endif
<section class="rounded-2xl border border-slate-200 bg-white p-6">
<h2 class="text-sm font-semibold uppercase tracking-wide text-slate-500">Documents</h2>
<ul class="mt-3 space-y-2 text-sm">
@forelse ($patient->attachments as $attachment)
<li>
<a href="{{ $attachment->url() }}" target="_blank" class="text-sky-600 hover:underline">{{ $attachment->original_name }}</a>
</li>
@empty
<li class="text-slate-400">No documents uploaded</li>
@endforelse
</ul>
</section>
</div>
</div>
</x-app-layout>