Hide finance and admin KPIs from roles that lack them.
Deploy Ladill Care / deploy (push) Successful in 33s
Deploy Ladill Care / deploy (push) Successful in 33s
Doctors no longer see revenue, open bills, or org admin cards on the Care dashboard. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
||||
use App\Http\Controllers\Care\Concerns\ScopesToAccount;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Member;
|
||||
use App\Services\Care\CarePermissions;
|
||||
use App\Services\Care\OrganizationResolver;
|
||||
use App\Services\Care\ReportService;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -17,6 +18,7 @@ class DashboardController extends Controller
|
||||
|
||||
public function __construct(
|
||||
protected ReportService $reports,
|
||||
protected CarePermissions $permissions,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): View
|
||||
@@ -24,27 +26,57 @@ class DashboardController extends Controller
|
||||
$this->authorizeAbility($request, 'dashboard.view');
|
||||
$organization = $this->organization($request);
|
||||
$owner = $this->ownerRef($request);
|
||||
$member = $this->member($request);
|
||||
|
||||
$canBranches = $this->permissions->can($member, 'admin.branches.view');
|
||||
$canMembers = $this->permissions->can($member, 'admin.members.view');
|
||||
$canDepartments = $this->permissions->can($member, 'admin.departments.view');
|
||||
$canBills = $this->permissions->can($member, 'bills.view');
|
||||
$canFinance = $this->permissions->can($member, 'reports.finance.view');
|
||||
|
||||
$branchQuery = Branch::owned($owner)->where('organization_id', $organization->id);
|
||||
$this->scopeToBranch($request, $branchQuery);
|
||||
|
||||
$stats = [
|
||||
'branches' => (clone $branchQuery)->where('is_active', true)->count(),
|
||||
'team_members' => Member::owned($owner)->where('organization_id', $organization->id)->count(),
|
||||
'departments' => $organization->branches()
|
||||
->when(app(OrganizationResolver::class)->branchScope($this->member($request)), function ($q, $branchId) {
|
||||
$q->where('id', $branchId);
|
||||
})
|
||||
->withCount('departments')
|
||||
->get()
|
||||
->sum('departments_count'),
|
||||
'branches' => $canBranches ? (clone $branchQuery)->where('is_active', true)->count() : 0,
|
||||
'team_members' => $canMembers
|
||||
? Member::owned($owner)->where('organization_id', $organization->id)->count()
|
||||
: 0,
|
||||
'departments' => $canDepartments
|
||||
? $organization->branches()
|
||||
->when(app(OrganizationResolver::class)->branchScope($member), function ($q, $branchId) {
|
||||
$q->where('id', $branchId);
|
||||
})
|
||||
->withCount('departments')
|
||||
->get()
|
||||
->sum('departments_count')
|
||||
: 0,
|
||||
];
|
||||
|
||||
$branches = (clone $branchQuery)->withCount('departments')->orderBy('name')->get();
|
||||
$branches = $canBranches
|
||||
? (clone $branchQuery)->withCount('departments')->orderBy('name')->get()
|
||||
: collect();
|
||||
|
||||
$branchScope = app(OrganizationResolver::class)->branchScope($this->member($request));
|
||||
$operational = $this->reports->dashboardStats($owner, $organization->id, $branchScope);
|
||||
$branchScope = app(OrganizationResolver::class)->branchScope($member);
|
||||
$operational = $this->reports->dashboardStats(
|
||||
$owner,
|
||||
$organization->id,
|
||||
$branchScope,
|
||||
includeBilling: $canBills || $canFinance,
|
||||
);
|
||||
|
||||
return view('care.dashboard', compact('organization', 'stats', 'branches', 'operational'));
|
||||
return view('care.dashboard', [
|
||||
'organization' => $organization,
|
||||
'member' => $member,
|
||||
'permissions' => $this->permissions,
|
||||
'stats' => $stats,
|
||||
'branches' => $branches,
|
||||
'operational' => $operational,
|
||||
'canBranches' => $canBranches,
|
||||
'canMembers' => $canMembers,
|
||||
'canDepartments' => $canDepartments,
|
||||
'canBills' => $canBills,
|
||||
'canFinance' => $canFinance,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,12 @@ class ReportService
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function dashboardStats(string $ownerRef, int $organizationId, ?int $branchId = null): array
|
||||
{
|
||||
public function dashboardStats(
|
||||
string $ownerRef,
|
||||
int $organizationId,
|
||||
?int $branchId = null,
|
||||
bool $includeBilling = true,
|
||||
): array {
|
||||
$today = now()->startOfDay();
|
||||
|
||||
$patientsToday = Patient::owned($ownerRef)
|
||||
@@ -35,21 +39,25 @@ class ReportService
|
||||
->whereDate('scheduled_at', $today)
|
||||
->count();
|
||||
|
||||
$openBills = Bill::owned($ownerRef)
|
||||
->where('organization_id', $organizationId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->whereIn('status', [Bill::STATUS_OPEN, Bill::STATUS_PARTIAL])
|
||||
->count();
|
||||
$openBills = 0;
|
||||
$revenueToday = 0;
|
||||
if ($includeBilling) {
|
||||
$openBills = Bill::owned($ownerRef)
|
||||
->where('organization_id', $organizationId)
|
||||
->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
|
||||
->whereIn('status', [Bill::STATUS_OPEN, Bill::STATUS_PARTIAL])
|
||||
->count();
|
||||
|
||||
$revenueToday = Payment::owned($ownerRef)
|
||||
->whereHas('bill', function (Builder $q) use ($organizationId, $branchId) {
|
||||
$q->where('organization_id', $organizationId);
|
||||
if ($branchId) {
|
||||
$q->where('branch_id', $branchId);
|
||||
}
|
||||
})
|
||||
->whereDate('paid_at', $today)
|
||||
->sum('amount_minor');
|
||||
$revenueToday = Payment::owned($ownerRef)
|
||||
->whereHas('bill', function (Builder $q) use ($organizationId, $branchId) {
|
||||
$q->where('organization_id', $organizationId);
|
||||
if ($branchId) {
|
||||
$q->where('branch_id', $branchId);
|
||||
}
|
||||
})
|
||||
->whereDate('paid_at', $today)
|
||||
->sum('amount_minor');
|
||||
}
|
||||
|
||||
$pendingLab = InvestigationRequest::owned($ownerRef)
|
||||
->where('organization_id', $organizationId)
|
||||
|
||||
@@ -1,60 +1,79 @@
|
||||
<x-app-layout title="Dashboard">
|
||||
@php
|
||||
$currency = config('care.billing.currency');
|
||||
$operationalCards = [
|
||||
[
|
||||
$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 = [
|
||||
[
|
||||
$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">
|
||||
@@ -63,73 +82,99 @@
|
||||
<p class="hidden text-sm text-slate-500 lg:block">Healthcare management dashboard</p>
|
||||
</div>
|
||||
<div class="flex shrink-0 items-center gap-2">
|
||||
@include('partials.mobile-header-btn', [
|
||||
'href' => route('care.patients.create'),
|
||||
'label' => 'Register patient',
|
||||
'desktopLabel' => 'Register patient',
|
||||
'variant' => 'outline',
|
||||
'showDesktopIcon' => false,
|
||||
])
|
||||
@include('partials.mobile-header-btn', [
|
||||
'href' => route('care.appointments.create'),
|
||||
'label' => 'Book appointment',
|
||||
'desktopLabel' => 'Book appointment',
|
||||
'variant' => 'primary',
|
||||
])
|
||||
@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')
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 lg:grid-cols-5">
|
||||
@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>
|
||||
@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="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>
|
||||
|
||||
<div class="mt-4 grid grid-cols-2 gap-4 lg:grid-cols-3">
|
||||
@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>
|
||||
|
||||
<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',
|
||||
])
|
||||
<p class="mt-3 text-2xl font-semibold {{ $card['valueClass'] ?? 'text-slate-900' }}">{{ $card['value'] }}</p>
|
||||
</a>
|
||||
@endforeach
|
||||
</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
|
||||
@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>
|
||||
@empty
|
||||
<p class="px-5 py-8 text-center text-sm text-slate-400">No branches configured yet.</p>
|
||||
@endforelse
|
||||
</section>
|
||||
@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>
|
||||
|
||||
@@ -81,7 +81,24 @@ class CareWebTest extends TestCase
|
||||
$this->actingAs($this->user)
|
||||
->get(route('care.dashboard'))
|
||||
->assertOk()
|
||||
->assertSee('Test Clinic');
|
||||
->assertSee('Test Clinic')
|
||||
->assertSee('Revenue today')
|
||||
->assertSee('Open bills');
|
||||
}
|
||||
|
||||
public function test_doctor_dashboard_hides_finance_metrics(): void
|
||||
{
|
||||
Member::where('user_ref', $this->user->public_id)->update(['role' => 'doctor']);
|
||||
|
||||
$this->actingAs($this->user)
|
||||
->get(route('care.dashboard'))
|
||||
->assertOk()
|
||||
->assertSee('Patients today')
|
||||
->assertSee('Appointments today')
|
||||
->assertDontSee('Revenue today')
|
||||
->assertDontSee('Open bills')
|
||||
->assertDontSee('Team members')
|
||||
->assertDontSee('Active branches');
|
||||
}
|
||||
|
||||
public function test_onboarding_creates_organization(): void
|
||||
|
||||
Reference in New Issue
Block a user