Deploy Ladill Care / deploy (push) Successful in 1m7s
Drop wallet/brand marketing language so credential setup reads as neutral configuration. Co-authored-by: Cursor <cursoragent@cursor.com>
240 lines
15 KiB
PHP
240 lines
15 KiB
PHP
<x-app-layout :title="$patient->fullName()">
|
|
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
|
<div>
|
|
<p class="font-mono text-xs text-sky-600">{{ $patient->patient_number }}</p>
|
|
<h1 class="text-2xl font-semibold text-slate-900">{{ $patient->fullName() }}</h1>
|
|
<p class="mt-1 text-sm text-slate-500">
|
|
{{ $genders[$patient->gender] ?? '—' }}
|
|
@if ($patient->date_of_birth)
|
|
· {{ $patient->date_of_birth->format('d M Y') }}
|
|
({{ $patient->date_of_birth->age }} yrs)
|
|
@endif
|
|
@if ($patient->phone) · {{ $patient->phone }} @endif
|
|
</p>
|
|
</div>
|
|
@if ($canManage)
|
|
<div class="flex gap-2">
|
|
<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>
|
|
@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">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
|
|
</p>
|
|
@empty
|
|
<p class="mt-1 text-slate-400">No visits yet</p>
|
|
@endforelse
|
|
</div>
|
|
<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>
|
|
<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>
|
|
<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>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
|
|
<div class="space-y-6">
|
|
@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">Requires SMS and email credentials. <a href="{{ route('care.integrations') }}" class="text-teal-700 underline">Manage integrations</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))
|
|
Connect SMS and Bird in Integrations before messaging patients.
|
|
@elseif (! ($messagingSmsReady ?? false))
|
|
Connect Ladill SMS in Integrations to enable SMS.
|
|
@else
|
|
Connect Ladill Bird in Integrations to enable email.
|
|
@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>
|
|
|
|
@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>
|
|
|
|
<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>
|