124 lines
4.8 KiB
PHP
124 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace App\Filament\Resources\Coupons\RelationManagers;
|
|
|
|
use Filament\Resources\RelationManagers\RelationManager;
|
|
use Filament\Schemas\Schema;
|
|
use Filament\Tables\Columns\TextColumn;
|
|
use Filament\Tables\Filters\SelectFilter;
|
|
use Filament\Tables\Table;
|
|
use Illuminate\Support\Str;
|
|
|
|
class RedemptionsRelationManager extends RelationManager
|
|
{
|
|
protected static string $relationship = 'redemptions';
|
|
|
|
public function form(Schema $schema): Schema
|
|
{
|
|
return $schema;
|
|
}
|
|
|
|
public function table(Table $table): Table
|
|
{
|
|
return $table
|
|
->recordTitleAttribute('paddle_transaction_id')
|
|
->columns([
|
|
TextColumn::make('tenant.name')
|
|
->label(__('Tenant'))
|
|
->searchable(),
|
|
TextColumn::make('ip_address')
|
|
->label(__('IP'))
|
|
->copyable()
|
|
->toggleable(isToggledHiddenByDefault: true),
|
|
TextColumn::make('device_id')
|
|
->label(__('Device'))
|
|
->copyable()
|
|
->toggleable(isToggledHiddenByDefault: true),
|
|
TextColumn::make('user_agent')
|
|
->label(__('User agent'))
|
|
->toggleable(isToggledHiddenByDefault: true)
|
|
->wrap(),
|
|
TextColumn::make('fraud_ip')
|
|
->label(__('IP reputation'))
|
|
->badge()
|
|
->formatStateUsing(fn ($state, $record) => self::formatReputation(data_get($record->metadata, 'fraud.ip')))
|
|
->color(fn ($state, $record) => self::riskColor(data_get($record->metadata, 'fraud.ip.risk')))
|
|
->toggleable(isToggledHiddenByDefault: true),
|
|
TextColumn::make('fraud_device')
|
|
->label(__('Device reputation'))
|
|
->badge()
|
|
->formatStateUsing(fn ($state, $record) => self::formatReputation(data_get($record->metadata, 'fraud.device')))
|
|
->color(fn ($state, $record) => self::riskColor(data_get($record->metadata, 'fraud.device.risk')))
|
|
->toggleable(isToggledHiddenByDefault: true),
|
|
TextColumn::make('user.name')
|
|
->label(__('User'))
|
|
->toggleable(isToggledHiddenByDefault: true),
|
|
TextColumn::make('amount_discounted')
|
|
->label(__('Discount'))
|
|
->formatStateUsing(fn ($state, $record) => sprintf('%s %s', number_format($record->amount_discounted, 2), $record->currency))
|
|
->sortable(),
|
|
TextColumn::make('status')
|
|
->label(__('Status'))
|
|
->badge()
|
|
->color(fn ($state) => match ($state) {
|
|
'success' => 'success',
|
|
'failed' => 'danger',
|
|
default => 'warning',
|
|
}),
|
|
TextColumn::make('paddle_transaction_id')
|
|
->label(__('Transaction'))
|
|
->copyable()
|
|
->toggleable(isToggledHiddenByDefault: true),
|
|
TextColumn::make('redeemed_at')
|
|
->label(__('Redeemed at'))
|
|
->dateTime()
|
|
->sortable(),
|
|
TextColumn::make('metadata')
|
|
->label(__('Metadata'))
|
|
->formatStateUsing(fn ($state) => $state ? json_encode($state, JSON_PRETTY_PRINT) : '—')
|
|
->toggleable(isToggledHiddenByDefault: true)
|
|
->copyable(),
|
|
])
|
|
->filters([
|
|
SelectFilter::make('status')
|
|
->label(__('Status'))
|
|
->options([
|
|
'pending' => __('Pending'),
|
|
'success' => __('Success'),
|
|
'failed' => __('Failed'),
|
|
]),
|
|
])
|
|
->headerActions([
|
|
// read-only
|
|
])
|
|
->recordActions([])
|
|
->toolbarActions([]);
|
|
}
|
|
|
|
/**
|
|
* @param array{risk?: string, recent_failed?: int, recent_total?: int}|null $snapshot
|
|
*/
|
|
private static function formatReputation(?array $snapshot): string
|
|
{
|
|
if (! $snapshot) {
|
|
return '—';
|
|
}
|
|
|
|
$risk = Str::headline($snapshot['risk'] ?? 'unknown');
|
|
$failed = (int) ($snapshot['recent_failed'] ?? 0);
|
|
$total = (int) ($snapshot['recent_total'] ?? 0);
|
|
|
|
return sprintf('%s (%d/%d)', $risk, $failed, $total);
|
|
}
|
|
|
|
private static function riskColor(?string $risk): string
|
|
{
|
|
return match ($risk) {
|
|
'high' => 'danger',
|
|
'medium' => 'warning',
|
|
'low' => 'success',
|
|
default => 'gray',
|
|
};
|
|
}
|
|
}
|