components([ Grid::make(3)->schema([ TextInput::make('name') ->label('Plan Name') ->required() ->maxLength(255), TextInput::make('price') ->label('Price') ->numeric() ->prefix('$') ->required(), Select::make('billing_cycle_days') ->label('Billing Cycle') ->options([ 30 => 'Monthly', 90 => 'Quarterly', 365 => 'Yearly', 60 => 'Bi-Monthly', 180 => 'Semi-Annual', ]) ->default(30) ->required(), ]), Grid::make(2)->schema([ TextInput::make('product_id') ->label('Product ID') ->required() ->helperText('External product identifier'), TextInput::make('pricing_id') ->label('Pricing ID') ->required() ->helperText('External pricing identifier'), ]), Textarea::make('description') ->label('Description') ->rows(3) ->maxLength(500), Grid::make(3)->schema([ Select::make('plan_tier_id') ->label('Plan Tier') ->options(PlanTier::pluck('name', 'id')) ->nullable() ->searchable() ->helperText('Optional tier classification'), Toggle::make('is_active') ->label('Active') ->default(true) ->helperText('Plan is available for new subscriptions'), TextInput::make('sort_order') ->label('Sort Order') ->numeric() ->default(0) ->helperText('Display order in pricing tables'), ]), Section::make('Legacy Settings') ->description('Legacy payment provider settings (will be migrated to new system)') ->collapsible() ->schema([ Grid::make(3)->schema([ Toggle::make('monthly_billing') ->label('Monthly Billing (Legacy)') ->helperText('Legacy monthly billing flag'), TextInput::make('mailbox_limit') ->label('Mailbox Limit') ->numeric() ->default(10) ->helperText('Maximum number of mailboxes'), TextInput::make('shoppy_product_id') ->label('Shoppy Product ID') ->nullable(), ]), ]), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('name') ->label('Plan Name') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('planTier.name') ->label('Tier') ->badge() ->sortable() ->placeholder('No Tier'), Tables\Columns\TextColumn::make('price') ->label('Price') ->money('USD') ->sortable(), Tables\Columns\TextColumn::make('billing_cycle_display') ->label('Billing Cycle') ->badge() ->color('primary'), Tables\Columns\IconColumn::make('is_active') ->label('Active') ->boolean() ->trueColor('success') ->falseColor('danger'), Tables\Columns\TextColumn::make('planProviders_count') ->label('Providers') ->counts('planProviders') ->badge() ->color('info') ->sortable(false), Tables\Columns\TextColumn::make('planFeatureLimits_count') ->label('Features') ->counts('planFeatureLimits') ->badge() ->color('warning') ->sortable(false), Tables\Columns\TextColumn::make('sort_order') ->label('Order') ->sortable() ->alignCenter(), ]) ->filters([ Tables\Filters\SelectFilter::make('plan_tier_id') ->label('Tier') ->options(PlanTier::pluck('name', 'id')) ->searchable(), Tables\Filters\TernaryFilter::make('is_active') ->label('Active Status') ->placeholder('All plans') ->trueLabel('Active only') ->falseLabel('Inactive only'), Tables\Filters\SelectFilter::make('billing_cycle_days') ->label('Billing Cycle') ->options([ 30 => 'Monthly', 90 => 'Quarterly', 365 => 'Yearly', ]), Tables\Filters\Filter::make('has_providers') ->label('Has Payment Providers') ->query(fn (Builder $query): Builder => $query->whereHas('planProviders')) ->toggle(), ]) ->recordActions([ ViewAction::make(), EditAction::make(), DeleteAction::make() ->before(function (Plan $record) { // Prevent deletion if plan has active subscriptions if ($record->subscriptions()->where('status', 'active')->exists()) { Log::error('Cannot delete plan with active subscriptions'); } }), ]) ->toolbarActions([ BulkActionGroup::make([ DeleteBulkAction::make() ->before(function ($records) { foreach ($records as $record) { if ($record->subscriptions()->where('status', 'active')->exists()) { Log::error('Cannot delete plan(s) with active subscriptions'); } } }), ]), ]) ->emptyStateActions([ CreateAction::make(), ]) ->defaultSort('sort_order', 'asc') ->groups([ Tables\Grouping\Group::make('planTier.name') ->label('Tier') ->collapsible(), ]); } public static function getRelations(): array { return [ // ]; } public static function getPages(): array { return [ 'index' => ListPlans::route('/'), 'create' => CreatePlan::route('/create'), 'edit' => EditPlan::route('/{record}/edit'), ]; } public static function getNavigationBadge(): ?string { return static::getModel()::active()->count(); } public static function getNavigationBadgeColor(): ?string { return 'success'; } }