Data display
Billing History code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/billing-history.blade.php
@props([
'title' => 'Billing history',
'description' => null,
'invoices' => [],
'currency' => '$',
'emptyMessage' => 'No invoices yet. Your billing history will appear here.',
])
@php
/*
| Billing history table — a list of past invoices with a number, date, amount,
| status badge and a download link. Reuses the same status palette as
| <x-ui.invoice>. Numeric amounts are formatted with the `currency` symbol;
| pre-formatted strings pass through. Use the `actions` slot for a header
| action (e.g. "Download all").
|
| Each invoice: [
| 'number' => ?, 'date' => ?, 'description' => ?, 'amount' => ?,
| 'status' => 'paid'|'due'|'overdue'|'refunded'|'draft'|'void',
| 'href' => ?(download/view link),
| ]
|
| Usage:
| <x-ui.billing-history :invoices="[
| ['number' => 'INV-0142', 'date' => 'Jun 1, 2026', 'amount' => 55.08, 'status' => 'paid', 'href' => '#'],
| ['number' => 'INV-0141', 'date' => 'May 1, 2026', 'amount' => 55.08, 'status' => 'paid', 'href' => '#'],
| ]" />
*/
$money = function ($value) use ($currency): ?string {
if ($value === null || $value === '') {
return null;
}
return is_numeric($value) ? $currency.number_format((float) $value, 2) : (string) $value;
};
$statuses = [
'paid' => ['variant' => 'green', 'icon' => 'check-circle', 'label' => 'Paid'],
'due' => ['variant' => 'amber', 'icon' => 'clock', 'label' => 'Due'],
'overdue' => ['variant' => 'red', 'icon' => 'warning-circle', 'label' => 'Overdue'],
'draft' => ['variant' => 'gray', 'icon' => 'pencil-simple', 'label' => 'Draft'],
'refunded' => ['variant' => 'blue', 'icon' => 'arrow-counter-clockwise', 'label' => 'Refunded'],
'void' => ['variant' => 'gray', 'icon' => 'prohibit', 'label' => 'Void'],
];
$rows = collect($invoices)->map(fn (array $invoice): array => [
'number' => $invoice['number'] ?? '—',
'date' => $invoice['date'] ?? null,
'description' => $invoice['description'] ?? null,
'amount' => $invoice['amount'] ?? null,
'status' => $invoice['status'] ?? 'paid',
'href' => $invoice['href'] ?? null,
])->values();
@endphp
<div {{ $attributes->merge(['class' => 'overflow-hidden rounded-2xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-900']) }}>
{{-- Header --}}
<div class="flex flex-col gap-4 border-b border-gray-200 p-5 dark:border-gray-800 sm:flex-row sm:items-center sm:justify-between">
<div class="min-w-0">
<h3 class="text-base font-semibold text-gray-900 dark:text-white">{{ $title }}</h3>
@if ($description)
<p class="mt-0.5 text-sm text-gray-500 dark:text-gray-400">{{ $description }}</p>
@endif
</div>
@isset($actions)
<div class="shrink-0">{{ $actions }}</div>
@endisset
</div>
@if ($rows->isNotEmpty())
<table class="w-full text-sm">
<thead>
<tr class="border-b border-gray-200 text-left text-xs font-semibold uppercase tracking-wide text-gray-400 dark:border-gray-800 dark:text-gray-500">
<th class="px-5 py-3 font-semibold">Invoice</th>
<th class="hidden px-5 py-3 font-semibold sm:table-cell">Date</th>
<th class="px-5 py-3 text-right font-semibold">Amount</th>
<th class="hidden px-5 py-3 text-center font-semibold sm:table-cell">Status</th>
<th class="px-5 py-3 text-right font-semibold"><span class="sr-only">Download</span></th>
</tr>
</thead>
<tbody class="divide-y divide-gray-100 dark:divide-gray-800">
@foreach ($rows as $row)
@php $meta = $statuses[$row['status']] ?? $statuses['paid']; @endphp
<tr class="transition hover:bg-gray-50/70 dark:hover:bg-gray-800/40">
<td class="px-5 py-3.5">
<p class="font-medium text-gray-900 dark:text-white">{{ $row['number'] }}</p>
<p class="mt-0.5 text-xs text-gray-500 dark:text-gray-400 sm:hidden">
@if ($row['date']){{ $row['date'] }}@endif
</p>
@if ($row['description'])
<p class="mt-0.5 hidden text-xs text-gray-500 dark:text-gray-400 sm:block">{{ $row['description'] }}</p>
@endif
</td>
<td class="hidden px-5 py-3.5 text-gray-600 dark:text-gray-300 sm:table-cell">{{ $row['date'] ?? '—' }}</td>
<td class="px-5 py-3.5 text-right font-medium tabular-nums text-gray-900 dark:text-white">{{ $money($row['amount']) ?? '—' }}</td>
<td class="hidden px-5 py-3.5 text-center sm:table-cell">
<x-ui.badge :variant="$meta['variant']" size="sm" :icon="$meta['icon']">{{ $meta['label'] }}</x-ui.badge>
</td>
<td class="px-5 py-3.5 text-right">
@if ($row['href'])
<x-ui.icon-button :href="$row['href']" icon="download-simple" size="sm" variant="ghost" label="Download invoice {{ $row['number'] }}" />
@else
<span class="text-gray-300 dark:text-gray-600">—</span>
@endif
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div class="flex flex-col items-center justify-center gap-3 px-6 py-12 text-center">
<span class="flex h-11 w-11 items-center justify-center rounded-full bg-gray-100 text-gray-400 dark:bg-gray-800 dark:text-gray-500">
<x-ui.icon name="receipt" weight="duotone" size="lg" />
</span>
<p class="max-w-xs text-sm text-gray-500 dark:text-gray-400">{{ $emptyMessage }}</p>
</div>
@endif
</div>