Files
ladill-care/resources/views/care/dashboard.blade.php
T
isaaccladandCursor 50f515cf6a
Deploy Ladill Care / deploy (push) Successful in 33s
Hide finance and admin KPIs from roles that lack them.
Doctors no longer see revenue, open bills, or org admin cards on the Care dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 22:32:41 +00:00

181 lines
11 KiB
PHP

<x-app-layout title="Dashboard">
@php
$currency = config('care.billing.currency');
$operationalCards = [];
if ($permissions->can($member, 'patients.view')) {
$operationalCards[] = [
'label' => 'Patients today',
'value' => number_format($operational['patients_today']),
'href' => route('care.patients.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />',
];
}
if ($permissions->can($member, 'appointments.view')) {
$operationalCards[] = [
'label' => 'Appointments today',
'value' => number_format($operational['appointments_today']),
'href' => route('care.appointments.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5" />',
];
}
if ($canBills) {
$operationalCards[] = [
'label' => 'Open bills',
'value' => number_format($operational['open_bills']),
'href' => route('care.bills.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 18.75a60.07 60.07 0 0 1 15.797 2.101c.727.198 1.453-.342 1.453-1.096V18.75M3.75 4.5v.75A.75.75 0 0 1 3 6h-.75m0 0v-.375c0-.621.504-1.125 1.125-1.125H20.25M2.25 6v9m18-10.5v.75c0 .414.336.75.75.75h.75m-1.5-1.5h.375c.621 0 1.125.504 1.125 1.125v9.75c0 .621-.504 1.125-1.125 1.125h-.375m1.5-1.5H21a.75.75 0 0 0-.75.75v.75m0 0H3.75m0 0h-.375a1.125 1.125 0 0 1-1.125-1.125V15m1.5 1.5v-.75A.75.75 0 0 0 3 15h-.375M15 10.5a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />',
];
}
if ($canFinance) {
$operationalCards[] = [
'label' => 'Revenue today',
'value' => $currency.' '.number_format($operational['revenue_today_minor'] / 100, 2),
'href' => route('care.bills.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M12 6v12m-3-2.818.879.659c1.171.879 3.07.879 4.242 0 1.172-.879 1.172-2.303 0-3.182C13.536 12.219 12.768 12 12 12c-.725 0-1.45-.22-2.003-.659-1.106-.879-1.106-2.303 0-3.182s2.9-.878 4.006 0l.415.33M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />',
'valueClass' => 'text-emerald-700',
];
}
if ($permissions->can($member, 'lab.view')) {
$operationalCards[] = [
'label' => 'Pending lab',
'value' => number_format($operational['pending_lab']),
'href' => route('care.lab.queue.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M9.75 3.104v5.714a2.25 2.25 0 0 1-.659 1.591L5 14.5M9.75 3.104c-.251.023-.501.05-.75.082m.75-.082a24.301 24.301 0 0 1 4.5 0m0 0v5.714a2.25 2.25 0 0 0 .659 1.591L19 14.5M14.25 3.104c.251.023.501.05.75.082M19 14.5l-2.47 2.47a2.25 2.25 0 0 1-1.59.659H9.06a2.25 2.25 0 0 1-1.591-.659L5 14.5m14 0V17a2.25 2.25 0 0 1-2.25 2.25H7.25A2.25 2.25 0 0 1 5 17v-2.5" />',
];
}
$organizationCards = [];
if ($canBranches) {
$organizationCards[] = [
'label' => 'Active branches',
'value' => number_format($stats['branches']),
'href' => route('care.branches.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 21h16.5M4.5 3h15M5.25 3v18m13.5-18v18M9 6.75h1.5m-1.5 3h1.5m-1.5 3h1.5m-1.5 3h1.5m3-9H15m-1.5 3H15m-1.5 3H15m-1.5 3H15M9 21v-3.375c0-.621.504-1.125 1.125-1.125h3.75c.621 0 1.125.504 1.125 1.125V21" />',
];
}
if ($canMembers) {
$organizationCards[] = [
'label' => 'Team members',
'value' => number_format($stats['team_members']),
'href' => route('care.members.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M18 18.72a9.094 9.094 0 0 0 3.741-.479 3 3 0 0 0-4.682-2.72m.94 3.198.001.031c0 .225-.012.447-.037.666A11.944 11.944 0 0 1 12 21c-2.17 0-4.207-.576-5.963-1.584A6.062 6.062 0 0 1 6 18.719m12 0a5.971 5.971 0 0 0-.941-3.197m0 0A5.995 5.995 0 0 0 12 12.75a5.995 5.995 0 0 0-5.058 2.772m0 0a3 3 0 0 0-4.681 2.72 8.986 8.986 0 0 0 3.74.477m.94-3.197a5.971 5.971 0 0 0-.94 3.197M15 6.75a3 3 0 1 1-6 0 3 3 0 0 1 6 0Zm6 3a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Zm-13.5 0a2.25 2.25 0 1 1-4.5 0 2.25 2.25 0 0 1 4.5 0Z" />',
];
}
if ($canDepartments) {
$organizationCards[] = [
'label' => 'Departments',
'value' => number_format($stats['departments']),
'href' => route('care.departments.index'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6A2.25 2.25 0 0 1 6 3.75h2.25A2.25 2.25 0 0 1 10.5 6v2.25a2.25 2.25 0 0 1-2.25 2.25H6a2.25 2.25 0 0 1-2.25-2.25V6ZM3.75 15.75A2.25 2.25 0 0 1 6 13.5h2.25a2.25 2.25 0 0 1 2.25 2.25V18a2.25 2.25 0 0 1-2.25 2.25H6A2.25 2.25 0 0 1 3.75 18v-2.25ZM13.5 6a2.25 2.25 0 0 1 2.25-2.25H18A2.25 2.25 0 0 1 20.25 6v2.25A2.25 2.25 0 0 1 18 10.5h-2.25a2.25 2.25 0 0 1-2.25-2.25V6ZM13.5 15.75a2.25 2.25 0 0 1 2.25-2.25H18a2.25 2.25 0 0 1 2.25 2.25V18A2.25 2.25 0 0 1 18 20.25h-2.25A2.25 2.25 0 0 1 13.5 18v-2.25Z" />',
];
}
@endphp
<div class="mb-6 flex items-center justify-between gap-3">
<div class="min-w-0 flex-1">
<h1 class="truncate text-lg font-semibold tracking-tight text-slate-900 lg:text-xl">{{ $organization->name }}</h1>
<p class="hidden text-sm text-slate-500 lg:block">Healthcare management dashboard</p>
</div>
<div class="flex shrink-0 items-center gap-2">
@if ($permissions->can($member, 'patients.manage'))
@include('partials.mobile-header-btn', [
'href' => route('care.patients.create'),
'label' => 'Register patient',
'desktopLabel' => 'Register patient',
'variant' => 'outline',
'showDesktopIcon' => false,
])
@endif
@if ($permissions->can($member, 'appointments.manage'))
@include('partials.mobile-header-btn', [
'href' => route('care.appointments.create'),
'label' => 'Book appointment',
'desktopLabel' => 'Book appointment',
'variant' => 'primary',
])
@endif
</div>
</div>
@include('partials.upgrade-banner')
@if (count($operationalCards) > 0)
@php
$opCols = match (count($operationalCards)) {
1 => 'lg:grid-cols-1',
2 => 'lg:grid-cols-2',
3 => 'lg:grid-cols-3',
4 => 'lg:grid-cols-4',
default => 'lg:grid-cols-5',
};
@endphp
<div class="grid grid-cols-2 gap-4 {{ $opCols }}">
@foreach ($operationalCards as $card)
<a href="{{ $card['href'] }}" class="rounded-2xl border border-slate-200 bg-white p-5 transition hover:border-indigo-300 hover:shadow-sm">
<div class="flex items-center gap-2.5">
<div class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-indigo-50">
<svg class="h-4 w-4 text-indigo-600" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">{!! $card['icon'] !!}</svg>
</div>
<p class="text-xs font-medium uppercase tracking-wide text-slate-500">{{ $card['label'] }}</p>
</div>
<p class="mt-3 text-2xl font-semibold {{ $card['valueClass'] ?? 'text-slate-900' }}">{{ $card['value'] }}</p>
</a>
@endforeach
</div>
@endif
@if (count($organizationCards) > 0)
@php
$orgCols = match (count($organizationCards)) {
1 => 'lg:grid-cols-1',
2 => 'lg:grid-cols-2',
default => 'lg:grid-cols-3',
};
@endphp
<div class="mt-4 grid grid-cols-2 gap-4 {{ $orgCols }}">
@foreach ($organizationCards as $card)
<a href="{{ $card['href'] }}" class="rounded-2xl border border-slate-200 bg-white p-5 transition hover:border-indigo-300 hover:shadow-sm">
<div class="flex items-center gap-2.5">
<div class="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-indigo-50">
<svg class="h-4 w-4 text-indigo-600" fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">{!! $card['icon'] !!}</svg>
</div>
<p class="text-xs font-medium uppercase tracking-wide text-slate-500">{{ $card['label'] }}</p>
</div>
<p class="mt-3 text-2xl font-semibold text-slate-900">{{ $card['value'] }}</p>
</a>
@endforeach
</div>
@endif
@if ($canBranches)
<section class="mt-6 rounded-2xl border border-slate-200 bg-white">
<div class="flex items-center justify-between border-b border-slate-100 px-5 py-4">
<h2 class="text-sm font-semibold text-slate-900">Branches</h2>
@include('partials.mobile-icon-link', [
'href' => route('care.branches.index'),
'label' => 'Manage branches',
'icon' => 'arrow',
])
</div>
@forelse ($branches as $branch)
<div class="flex items-center justify-between border-b border-slate-50 px-5 py-3 last:border-0">
<div class="min-w-0">
<p class="font-medium text-slate-900">{{ $branch->name }}</p>
<p class="text-sm text-slate-500">{{ $branch->departments_count }} department(s) · {{ $branch->address ?? 'No address' }}</p>
</div>
@unless ($branch->is_active)
<span class="shrink-0 rounded-full bg-slate-100 px-2 py-1 text-xs text-slate-600">Inactive</span>
@endunless
</div>
@empty
<p class="px-5 py-8 text-center text-sm text-slate-400">No branches configured yet.</p>
@endforelse
</section>
@endif
</x-app-layout>