count() ?: null; } public static function getNavigationBadgeColor(): ?string { return 'warning'; } protected static ?string $cluster = Services::class; public static function form(Form $form): Form { return $form ->schema([ Forms\Components\Select::make('product_id') ->label('Product') ->required() ->options(Product::all()->pluck('name', 'id')->toArray()) ->searchable() ->live() ->preload() ->placeholder('Select the product'), Forms\Components\Select::make('plan_id') ->label('Plan') ->required() ->relationship('plan', 'name', fn (Builder $query, Get $get) => $query->where('priceable_id', $get('product_id'))->where('priceable_type', Product::class)) ->searchable() ->preload() ->disabled(fn (Get $get) => !$get('product_id')) ->placeholder('Select the plan'), UserComponent::make('user_id'), Forms\Components\Select::make('status') ->label('Status') ->required() ->options([ // active, pending, suspended, cancelled 'active' => 'Active', 'pending' => 'Pending', 'suspended' => 'Suspended', 'cancelled' => 'Cancelled', ]) ->default('pending'), Forms\Components\TextInput::make('quantity') ->label('Quantity') ->required() ->placeholder('Enter the quantity'), Forms\Components\DatePicker::make('expires_at') ->label('Expires At') ->required() ->placeholder('Select the expiration date'), Forms\Components\Select::make('coupon_id') ->label('Coupon') ->relationship('coupon', 'code') ->searchable() ->placeholder('Select the coupon'), Forms\Components\Select::make('currency_code') ->options(function (Get $get, ?string $state) { $pricing = collect($get('../../pricing'))->pluck('currency_code'); if ($state !== null) { $pricing = $pricing->filter(function ($code) use ($state) { return $code !== $state; }); } $pricing = $pricing->filter(function ($code) { return $code !== null; }); return Currency::whereNotIn('code', $pricing)->pluck('code', 'code'); }) ->live() ->default(config('settings.default_currency')) ->required(), Forms\Components\TextInput::make('price') ->required() ->label('Price') // Suffix based on chosen currency ->prefix(fn (Get $get) => Currency::where('code', $get('currency_code'))->first()?->prefix) ->suffix(fn (Get $get) => Currency::where('code', $get('currency_code'))->first()?->suffix) ->live(onBlur: true) ->mask(RawJs::make( <<<'JS' $money($input, '.', '', 2) JS )) ->numeric() ->minValue(0), Forms\Components\TextInput::make('subscription_id') ->label('Subscription ID') ->nullable() ->placeholder('Enter the subscription ID') ->hintAction( Action::make('Cancel Subscription ID') ->action(function (Component $component) { if (ExtensionHelper::cancelSubscription($component->getRecord())) { Notification::make('Subscription Cancelled') ->title('The subscription has been successfully cancelled') ->success() ->send(); } else { Notification::make('Subscription Not Cancelled') ->title('The subscription could not be cancelled') ->error() ->send(); } // Update the record to remove the subscription ID $component->getRecord()->update(['subscription_id' => null]); }) ->requiresConfirmation() ->label('Cancel Subscription') ->hidden(fn (Component $component) => !$component->getRecord()?->subscription_id), ), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('id') ->label('ID') ->sortable() ->searchable(), Tables\Columns\TextColumn::make('user.name') ->label('User') ->searchable(true, fn (Builder $query, string $search) => $query->whereHas('user', fn (Builder $query) => $query->where('first_name', 'like', "%$search%")->orWhere('last_name', 'like', "%$search%"))), Tables\Columns\TextColumn::make('product.name') ->label('Product') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('proxmoxServer.hostname') ->label('Hostname') ->searchable() ->sortable() ->placeholder('—'), Tables\Columns\TextColumn::make('status') ->badge() ->color(fn (Service $record) => match ($record->status) { 'pending' => 'gray', 'active' => 'success', 'cancelled' => 'danger', 'suspended' => 'warning', default => 'gray', }) ->formatStateUsing(fn (string $state) => ucfirst($state)) ->label('Status') ->searchable() ->sortable(), Tables\Columns\TextColumn::make('expires_at') ->label('Expires At') ->date() ->searchable() ->sortable(), ]) ->filters([ Tables\Filters\SelectFilter::make('status') ->label('Status') ->options([ 'active' => 'Active', 'pending' => 'Pending', 'suspended' => 'Suspended', 'cancelled' => 'Cancelled', ]), ]) ->defaultSort(function (Builder $query): Builder { return $query ->orderBy('id', 'desc'); }) ->actions([ Tables\Actions\EditAction::make(), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\DeleteBulkAction::make(), ]), ]); } public static function getRelations(): array { return [ RelationManagers\InvoicesRelationManager::class, PropertiesRelationManager::class, RelationManagers\ConfigOptionsRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => Pages\ListService::route('/'), 'create' => Pages\CreateService::route('/create'), 'edit' => Pages\EditService::route('/{record}/edit'), ]; } }