Redesign the Payment view page infolist

Groups fields into Payment/Timeline sections with icons, copyable IDs, and
a money-formatted amount. Drops the permission-gated Gateway Response
section (raw gateway_payload) and its two visibility tests along with it.
This commit is contained in:
Nyan Lin Paing
2026-08-30 15:46:19 +07:00
parent bebcab88fa
commit 95b369174d
2 changed files with 33 additions and 43 deletions
@@ -6,6 +6,7 @@ use Filament\Infolists\Components\TextEntry;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Components\Section;
use Filament\Schemas\Schema;
use Filament\Support\Icons\Heroicon;
use Modules\Payment\Enums\PaymentStatus;
class PaymentInfolist
@@ -15,40 +16,51 @@ class PaymentInfolist
return $schema
->components([
Section::make('Payment')
->icon(Heroicon::OutlinedBanknotes)
->schema([
Grid::make(4)
->schema([
TextEntry::make('booking.booking_ref')->label('Booking'),
TextEntry::make('gateway')->badge(),
TextEntry::make('booking.booking_ref')
->label('Booking')
->icon(Heroicon::OutlinedTicket)
->copyable(),
TextEntry::make('gateway')
->icon(Heroicon::OutlinedCreditCard)
->badge(),
TextEntry::make('status')
->icon(Heroicon::OutlinedCheckCircle)
->badge()
->color(fn (PaymentStatus $state) => match ($state) {
PaymentStatus::Pending => 'warning',
PaymentStatus::Completed => 'success',
PaymentStatus::Failed => 'danger',
}),
TextEntry::make('gateway_transaction_id')->label('Gateway Txn ID'),
TextEntry::make('amount')->numeric(2),
TextEntry::make('currency'),
TextEntry::make('initiated_at')->dateTime(),
TextEntry::make('completed_at')->dateTime()->placeholder('—'),
TextEntry::make('amount')
->label('Amount')
->icon(Heroicon::OutlinedCurrencyDollar)
->money(fn ($record) => $record->currency)
->weight('bold'),
]),
]),
// Raw gateway response — may include data not meant for the
// support role, so it's gated the same as refund initiation
// (process_refunds: admin/super_admin only, domain.md §6).
Section::make('Gateway Response')
->visible(fn () => auth()->user()?->can('process_refunds') ?? false)
Section::make('Timeline')
->icon(Heroicon::OutlinedClock)
->schema([
TextEntry::make('gateway_payload')
->label('')
->formatStateUsing(fn (mixed $state) => match (true) {
is_array($state) => json_encode($state, JSON_PRETTY_PRINT),
is_string($state) && $state !== '' => $state,
default => null,
})
->placeholder('—')
->columnSpanFull(),
Grid::make(3)
->schema([
TextEntry::make('gateway_transaction_id')
->label('Gateway Txn ID')
->icon(Heroicon::OutlinedHashtag)
->copyable()
->placeholder('—'),
TextEntry::make('initiated_at')
->icon(Heroicon::OutlinedPlayCircle)
->dateTime()
->placeholder('—'),
TextEntry::make('completed_at')
->icon(Heroicon::OutlinedFlag)
->dateTime()
->placeholder('—'),
]),
]),
]);
}
@@ -56,25 +56,3 @@ test('can view a payment\'s detail page', function () {
->assertSee($booking->booking_ref)
->assertSee('EVB-VIEWTEST-1');
});
test('the gateway response is visible to a user with process_refunds', function () {
$admin = User::factory()->create()->givePermissionTo(['view_payments', 'process_refunds']);
$this->actingAs($admin);
$payment = Payment::factory()->create(['gateway_payload' => ['prepay_id' => 'PREPAY-SECRET-123']]);
Livewire::test(ViewPayment::class, ['record' => $payment->getRouteKey()])
->assertOk()
->assertSee('PREPAY-SECRET-123');
});
test('the gateway response is hidden from a user without process_refunds', function () {
$support = User::factory()->create()->givePermissionTo('view_payments');
$this->actingAs($support);
$payment = Payment::factory()->create(['gateway_payload' => ['prepay_id' => 'PREPAY-SECRET-123']]);
Livewire::test(ViewPayment::class, ['record' => $payment->getRouteKey()])
->assertOk()
->assertDontSee('PREPAY-SECRET-123');
});