modifyQueryUsing(function ($query) { $query->withSum('couponUsages as total_coupon_discount', 'discount_amount'); }) ->columns([ TextColumn::make('user.name') ->label('User') ->searchable() ->sortable() ->limit(30), TextColumn::make('plan.name') ->label('Plan') ->searchable() ->sortable(), TextColumn::make('type') ->badge() ->label('Type') ->colors([ 'gray' => 'default', 'blue' => 'premium', 'purple' => 'enterprise', 'warning' => 'trial', ]), TextColumn::make('status') ->badge() ->label('Status') ->colors([ 'success' => 'active', 'warning' => 'trialing', 'danger' => 'cancelled', 'secondary' => 'paused', 'gray' => 'incomplete', ]), TextColumn::make('provider') ->badge() ->label('Provider') ->colors([ 'blue' => 'stripe', 'green' => 'lemon_squeezy', 'purple' => 'polar', 'orange' => 'oxapay', 'gray' => 'crypto', 'pink' => 'activation_key', ]), TextColumn::make('provider_subscription_id') ->label('Provider ID') ->searchable() ->limit(20), TextColumn::make('trial_ends_at') ->label('Trial Ends') ->dateTime('M j, Y') ->sortable() ->color('warning') ->description(fn ($record): string => $record->isOnTrial() ? $record->trial_ends_at->diffForHumans() : '' ), TextColumn::make('ends_at') ->label('Ends At') ->dateTime('M j, Y') ->sortable() ->color(fn ($record): string => $record->ends_at && $record->ends_at->isPast() ? 'danger' : 'default' ), TextColumn::make('quantity') ->label('Qty') ->numeric() ->sortable() ->toggleable(), IconColumn::make('hasExtendedTrial') ->label('Trial Extended') ->boolean() ->getStateUsing(fn ($record) => $record->hasExtendedTrial()) ->toggleable(), TextColumn::make('total_coupon_discount') ->label('Total Discount') ->money('USD') ->sortable() ->toggleable(), TextColumn::make('created_at') ->label('Created') ->dateTime('M j, Y') ->sortable() ->toggleable(isToggledHiddenByDefault: true), TextColumn::make('last_provider_sync') ->label('Last Sync') ->dateTime('M j, Y') ->sortable() ->toggleable(), ]) ->filters([ SelectFilter::make('status') ->options([ 'active' => 'Active', 'trialing' => 'Trial', 'cancelled' => 'Cancelled', 'paused' => 'Paused', 'incomplete' => 'Incomplete', ]), SelectFilter::make('type') ->label('Subscription Type') ->options([ 'default' => 'Default', 'premium' => 'Premium', 'enterprise' => 'Enterprise', 'trial' => 'Trial', ]), SelectFilter::make('provider') ->options([ 'stripe' => 'Stripe', 'lemon_squeezy' => 'Lemon Squeezy', 'polar' => 'Polar.sh', 'oxapay' => 'OxaPay', 'crypto' => 'Crypto', 'activation_key' => 'Activation Key', ]), SelectFilter::make('has_trial_extension') ->label('Has Trial Extension') ->options([ 'yes' => 'Yes', 'no' => 'No', ]) ->query(fn ($query, $data) => match ($data['value']) { 'yes' => $query->whereHas('trialExtensions'), 'no' => $query->whereDoesntHave('trialExtensions'), default => $query, }), ]) ->recordActions([ EditAction::make(), Action::make('extend_trial') ->label('Extend Trial') ->icon('heroicon-o-clock') ->color('warning') ->schema([ \Filament\Forms\Components\TextInput::make('days') ->label('Days to Extend') ->numeric() ->required() ->default(7), \Filament\Forms\Components\TextInput::make('reason') ->label('Reason') ->required(), \Filament\Forms\Components\Select::make('extension_type') ->label('Extension Type') ->options([ 'manual' => 'Manual Grant', 'automatic' => 'Automatic Extension', 'compensation' => 'Compensation', ]) ->default('manual'), ]) ->action(function (array $data, $record) { $record->extendTrial( (int) $data['days'], $data['reason'], $data['extension_type'], auth()->user() ); }) ->visible(fn ($record) => $record->isOnTrial()), ]) ->toolbarActions([ BulkAction::make('bulk_extend_trial') ->label('Bulk Extend Trial') ->icon('heroicon-o-clock') ->color('warning') ->schema([ \Filament\Forms\Components\TextInput::make('days') ->label('Days to Extend') ->numeric() ->required() ->default(7), \Filament\Forms\Components\TextInput::make('reason') ->label('Reason') ->required(), ]) ->action(function (array $data, \Illuminate\Support\Collection $records) { foreach ($records as $record) { if ($record->isOnTrial()) { $record->extendTrial( (int) $data['days'], $data['reason'], 'manual', auth()->user() ); } } }) ->deselectRecordsAfterCompletion(), BulkActionGroup::make([ DeleteBulkAction::make(), ]), ]) ->emptyStateActions([ CreateAction::make(), ]); } }