name; } public static function getGlobalSearchResultDetails(Model $record): array { $donationCount = $record->donations()->count(); $totalDonated = $record->donations() ->whereHas('donationConfirmation', fn ($q) => $q->whereNotNull('confirmed_at')) ->sum('amount') / 100; $activeSG = $record->scheduledGivingDonations()->where('is_active', true)->count(); $details = [ 'Email' => $record->email, ]; if ($record->phone) { $details['Phone'] = $record->phone; } if ($donationCount > 0) { $details['Donations'] = $donationCount . ' (£' . number_format($totalDonated, 0) . ' total)'; } if ($activeSG > 0) { $details['Monthly Giving'] = $activeSG . ' active'; } return $details; } public static function getGlobalSearchResultActions(Model $record): array { return [ GlobalSearchAction::make('edit') ->label('Open Donor Profile') ->url(static::getUrl('edit', ['record' => $record])), ]; } public static function getGlobalSearchEloquentQuery(): Builder { return parent::getGlobalSearchEloquentQuery()->latest('created_at'); } public static function getGlobalSearchResultsLimit(): int { return 10; } // ─── Form (Edit screen) ────────────────────────────────────── public static function form(Form $form): Form { return $form ->schema([ Select::make('user_id') ->relationship('user', 'email') ->searchable() ->live() ->helperText('The website login account linked to this donor (if any).') ->disabled(), Grid::make()->schema([ Section::make('Personal Details')->schema([ Select::make('title') ->required() ->options(config('donate.titles')) ->columnSpan(1), TextInput::make('first_name') ->required() ->maxLength(255) ->columnSpan(2), TextInput::make('last_name') ->required() ->maxLength(255) ->columnSpan(2), ]) ->columns(5) ->columnSpan(1), Section::make('Contact Information')->schema([ TextInput::make('email') ->email() ->required() ->disabled(fn (\Filament\Forms\Get $get) => (bool) $get('user_id')) ->live() ->maxLength(255) ->copyable(), TextInput::make('phone') ->tel() ->maxLength(32) ->copyable(), ]) ->columns() ->columnSpan(1), ]), ]); } // ─── Table (List screen) ───────────────────────────────────── // This is the "Donor Lookup" — staff search by any field and // immediately see key context: are they a monthly giver? how many // donations? This helps them triage before even clicking in. public static function table(Table $table): Table { return $table ->columns([ TextColumn::make('name') ->label('Donor') ->searchable(['first_name', 'last_name']) ->sortable(['first_name']) ->weight('bold') ->description(fn (Customer $record): ?string => $record->email), TextColumn::make('phone') ->label('Phone') ->searchable() ->copyable() ->placeholder('—'), TextColumn::make('donations_count') ->label('Donations') ->counts('donations') ->sortable() ->badge() ->color(fn ($state) => match(true) { $state >= 50 => 'success', $state >= 10 => 'info', $state > 0 => 'gray', default => 'danger', }), TextColumn::make('scheduled_giving_donations_count') ->label('Monthly') ->counts([ 'scheduledGivingDonations' => fn (Builder $q) => $q->where('is_active', true), ]) ->formatStateUsing(fn ($state) => $state > 0 ? 'Active' : null) ->badge() ->color('success') ->placeholder('—'), TextColumn::make('created_at') ->label('Joined') ->since() ->sortable(), ]) ->filters([]) ->actions([ EditAction::make() ->label('Open') ->icon('heroicon-o-arrow-right'), ]) ->defaultSort('created_at', 'desc') ->searchPlaceholder('Search by name, email, or phone...'); } public static function getRelations(): array { return [ DonationsRelationManager::class, ScheduledGivingDonationsRelationManager::class, AddressesRelationManager::class, InternalNotesRelationManager::class, ]; } public static function getPages(): array { return [ 'index' => ListCustomers::route('/'), 'edit' => EditCustomer::route('/{record}/edit'), ]; } }