Files
ladill-transfer/resources/views/transfer/transfers/index.blade.php
T
isaaccladandCursor 49ff64eda3
Deploy Ladill Transfer / deploy (push) Successful in 31s
Add hero sections to Transfers and Files index pages.
Surface wallet balance and key stats at a glance, matching the layout used across other Ladill apps.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-04 20:47:15 +00:00

134 lines
9.7 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-user-layout>
<x-slot name="title">Transfers</x-slot>
<div class="space-y-6">
<div class="relative overflow-hidden rounded-2xl border border-slate-200 bg-white">
<div class="absolute inset-0 bg-gradient-to-br from-sky-50/80 via-white to-indigo-50/60"></div>
<div class="relative px-6 py-8 sm:px-10">
<div class="flex flex-col gap-6 lg:flex-row lg:items-center lg:justify-between">
<div class="max-w-xl">
<div class="inline-flex items-center gap-1.5 rounded-full bg-sky-100 px-3 py-1 text-xs font-semibold text-sky-700">
File shares · QR downloads
</div>
<h1 class="mt-3 text-2xl font-bold tracking-tight text-slate-900 sm:text-3xl">Your transfers</h1>
<p class="mt-2 text-sm leading-6 text-slate-600">
All your file shares active, grace, and expired. Each transfer gets a QR code and download link for recipients.
</p>
<div class="mt-6">
<x-btn.create :href="route('transfer.transfers.create')">New transfer</x-btn.create>
</div>
</div>
<div class="scrollbar-hide flex snap-x snap-mandatory gap-3 overflow-x-auto pb-2 sm:grid sm:grid-cols-3 sm:overflow-visible sm:pb-0 lg:gap-4" style="-ms-overflow-style:none;scrollbar-width:none;">
<div class="mobile-stats-card shrink-0 snap-start rounded-xl border border-slate-200 bg-white/90 px-4 py-3 text-center backdrop-blur-sm">
<p class="whitespace-nowrap text-xl font-bold text-slate-900 sm:text-2xl">GHS {{ number_format($balanceMinor / 100, 2) }}</p>
<p class="mt-0.5 whitespace-nowrap text-[11px] font-medium text-slate-500">Account balance</p>
</div>
<div class="mobile-stats-card shrink-0 snap-start rounded-xl border border-slate-200 bg-white/90 px-4 py-3 text-center backdrop-blur-sm">
<p class="whitespace-nowrap text-xl font-bold text-slate-900 sm:text-2xl">{{ number_format($transferCount) }}</p>
<p class="mt-0.5 whitespace-nowrap text-[11px] font-medium text-slate-500">Transfers</p>
</div>
<div class="mobile-stats-card shrink-0 snap-start rounded-xl border border-slate-200 bg-white/90 px-4 py-3 text-center backdrop-blur-sm">
<p class="whitespace-nowrap text-xl font-bold text-slate-900 sm:text-2xl">{{ number_format($activeCount) }}</p>
<p class="mt-0.5 whitespace-nowrap text-[11px] font-medium text-slate-500">Active</p>
</div>
</div>
</div>
</div>
</div>
<div class="overflow-hidden rounded-2xl border border-slate-200 bg-white">
<div class="flex flex-wrap items-center gap-2 border-b border-slate-100 px-4 py-3 sm:px-6">
<h2 class="text-sm font-semibold text-slate-900">All transfers</h2>
<form method="get" action="{{ route('transfer.transfers.index') }}" class="ml-auto flex w-full flex-wrap items-center gap-2 sm:w-auto">
<div class="relative min-w-0 flex-1 sm:min-w-[200px]">
<svg class="pointer-events-none absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-slate-400" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z"/></svg>
<input type="search" name="q" value="{{ $search }}" placeholder="Search transfers…"
class="w-full rounded-lg border border-slate-200 py-1.5 pl-8 pr-2.5 text-xs text-slate-700 placeholder-slate-400 focus:border-indigo-300 focus:outline-none focus:ring-2 focus:ring-indigo-100 sm:w-52">
</div>
<select name="status" onchange="this.form.submit()" class="min-w-[9rem] rounded-lg border border-slate-200 py-1.5 pl-3 pr-8 text-xs text-slate-700">
<option value="all" @selected($status === 'all')>All statuses</option>
<option value="active" @selected($status === 'active')>Active</option>
<option value="grace" @selected($status === 'grace')>Payment due</option>
<option value="expired" @selected($status === 'expired')>Expired</option>
</select>
<select name="sort" onchange="this.form.submit()" class="min-w-[7.5rem] rounded-lg border border-slate-200 py-1.5 pl-3 pr-8 text-xs text-slate-700">
<option value="newest" @selected($sort === 'newest')>Newest</option>
<option value="oldest" @selected($sort === 'oldest')>Oldest</option>
<option value="title" @selected($sort === 'title')>Title</option>
<option value="downloads" @selected($sort === 'downloads')>Downloads</option>
</select>
@if($search !== '' || $status !== 'all' || $sort !== 'newest')
<a href="{{ route('transfer.transfers.index') }}" class="text-xs font-medium text-slate-500 hover:text-slate-700">Clear</a>
@endif
</form>
</div>
@if($transfers->isEmpty())
<div class="px-6 py-12 text-center">
<p class="text-sm text-slate-500">
@if($search !== '' || $status !== 'all')
No transfers match your filters.
@else
No transfers yet.
@endif
</p>
<a href="{{ route('transfer.transfers.create') }}" class="mt-3 inline-block text-sm font-semibold text-indigo-600 hover:text-indigo-800">Create your first transfer</a>
</div>
@else
<div class="flex items-center justify-between border-b border-slate-100 px-4 py-3 text-xs text-slate-500 sm:px-6">
<span>{{ $transfers->total() }} transfer{{ $transfers->total() === 1 ? '' : 's' }}</span>
<span>Showing {{ $transfers->firstItem() }}{{ $transfers->lastItem() }}</span>
</div>
<table class="min-w-full divide-y divide-slate-100">
<thead class="bg-slate-50 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">
<tr>
<th class="px-4 py-3 sm:px-6">Title</th>
<th class="px-4 py-3 sm:px-6">Status</th>
<th class="hidden px-4 py-3 sm:table-cell sm:px-6">Files</th>
<th class="hidden px-4 py-3 md:table-cell sm:px-6">Downloads</th>
<th class="hidden px-4 py-3 lg:table-cell sm:px-6">Expires</th>
<th class="px-4 py-3 sm:px-6"></th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 text-sm">
@foreach($transfers as $transfer)
@php
$statusClass = match (true) {
$transfer->isPaid() => 'bg-emerald-50 text-emerald-700',
$transfer->isInGracePeriod() => 'bg-amber-50 text-amber-700',
default => 'bg-slate-100 text-slate-600',
};
@endphp
<tr class="hover:bg-slate-50/80">
<td class="px-4 py-4 sm:px-6">
<p class="font-medium text-slate-900">{{ $transfer->title }}</p>
<p class="text-xs text-slate-500">{{ $transfer->created_at->format('M j, Y') }}</p>
@if($transfer->recipient_email)
<p class="mt-0.5 text-xs text-slate-400">To {{ $transfer->recipient_email }}</p>
@endif
</td>
<td class="px-4 py-4 sm:px-6">
<span class="inline-flex rounded-full px-2.5 py-0.5 text-xs font-medium {{ $statusClass }}">
{{ $transfer->billingStatusLabel() }}
</span>
</td>
<td class="hidden px-4 py-4 text-slate-600 sm:table-cell sm:px-6">{{ $transfer->files->count() }}</td>
<td class="hidden px-4 py-4 text-slate-600 md:table-cell sm:px-6">{{ number_format($transfer->downloads_total) }}</td>
<td class="hidden px-4 py-4 text-slate-600 lg:table-cell sm:px-6">{{ $transfer->expires_at?->format('M j, Y') ?? '—' }}</td>
<td class="px-4 py-4 text-right sm:px-6">
<a href="{{ route('transfer.transfers.show', $transfer) }}" class="font-medium text-indigo-600 hover:text-indigo-800">Open</a>
</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
@if($transfers->hasPages())
<div>{{ $transfers->links() }}</div>
@endif
</div>
</x-user-layout>