Files
calvana/temp_files/fix2/ListDonations.php
Omair Saleh 50d449e2b7 feat: conditional & match funding pledges — deeply integrated across entire product
- Schema: isConditional, conditionType, conditionText, conditionThreshold, conditionMet, conditionMetAt on Pledge
- Pledge form: 'This is a match pledge' toggle after amount selection
  - Two modes: threshold (if target is reached) and match (match funding)
  - Goal amount passed through from event
- Auto-trigger: when total raised hits threshold, conditional pledges unlock automatically
  - WhatsApp notification sent to donor when unlocked
  - Threshold check runs after every pledge creation AND every status change
- Cron: skips conditional pledges until conditionMet=true (no premature reminders)
- Dashboard Home: progress bar shows conditional segment (amber), stats grid adds Conditional column
- Dashboard Money: conditional/unlocked badge on pledge rows
- Dashboard Collect: hero shows conditional total in amber
- Dashboard Reports: financial summary shows conditional breakdown
- Donor 'My Pledges': conditional card with condition text + activation status
- Confirmation step: specialized messaging for match pledges
- CRM export: includes is_conditional, condition_type, condition_text, condition_met columns
- Status guide: conditional status explained in human language
2026-03-05 04:19:23 +08:00

111 lines
4.1 KiB
PHP

<?php
namespace App\Filament\Resources\DonationResource\Pages;
use App\Filament\Resources\DonationResource;
use App\Models\Donation;
use Filament\Resources\Components\Tab;
use Filament\Resources\Pages\ListRecords;
use Illuminate\Database\Eloquent\Builder;
class ListDonations extends ListRecords
{
protected static string $resource = DonationResource::class;
public function getHeading(): string
{
return 'Donations';
}
public function getSubheading(): string
{
$todayCount = Donation::whereHas('donationConfirmation', fn ($q) => $q->whereNotNull('confirmed_at'))
->whereDate('created_at', today())
->count();
$todayAmount = Donation::whereHas('donationConfirmation', fn ($q) => $q->whereNotNull('confirmed_at'))
->whereDate('created_at', today())
->sum('amount') / 100;
return "Today: {$todayCount} confirmed (£" . number_format($todayAmount, 0) . ")";
}
public function getTabs(): array
{
$incompleteCount = Donation::whereDoesntHave('donationConfirmation', fn ($q) => $q->whereNotNull('confirmed_at'))
->where('created_at', '>=', now()->subDays(7))
->count();
$recurring = Donation::where('reoccurrence', '!=', -1)
->whereHas('donationConfirmation', fn ($q) => $q->whereNotNull('confirmed_at'))
->count();
// Use whereIn with subquery instead of whereHas to avoid null model crash
// during Filament tab initialization (modifyQueryUsing gets a builder with no model)
$confirmedSubquery = fn (Builder $q) => $q->whereIn(
'donations.id',
fn ($sub) => $sub->select('donation_id')
->from('donation_confirmations')
->whereNotNull('confirmed_at')
);
$unconfirmedSubquery = fn (Builder $q) => $q->whereNotIn(
'donations.id',
fn ($sub) => $sub->select('donation_id')
->from('donation_confirmations')
->whereNotNull('confirmed_at')
);
return [
'today' => Tab::make('Today')
->icon('heroicon-o-clock')
->modifyQueryUsing(fn (Builder $q) => $confirmedSubquery($q)
->whereDate('created_at', today())
),
'all_confirmed' => Tab::make('All Confirmed')
->icon('heroicon-o-check-circle')
->modifyQueryUsing(fn (Builder $q) => $confirmedSubquery($q)),
'incomplete' => Tab::make('Incomplete')
->icon('heroicon-o-exclamation-triangle')
->badge($incompleteCount > 0 ? $incompleteCount : null)
->badgeColor('danger')
->modifyQueryUsing(fn (Builder $q) => $unconfirmedSubquery($q)
->where('created_at', '>=', now()->subDays(7))
),
'zakat' => Tab::make('Zakat')
->icon('heroicon-o-star')
->modifyQueryUsing(fn (Builder $q) => $confirmedSubquery($q)
->whereIn('donations.id', fn ($sub) => $sub->select('donation_id')
->from('donation_preferences')
->where('is_zakat', true))
),
'gift_aid' => Tab::make('Gift Aid')
->icon('heroicon-o-gift')
->modifyQueryUsing(fn (Builder $q) => $confirmedSubquery($q)
->whereIn('donations.id', fn ($sub) => $sub->select('donation_id')
->from('donation_preferences')
->where('is_gift_aid', true))
),
'recurring' => Tab::make('Recurring')
->icon('heroicon-o-arrow-path')
->badge($recurring > 0 ? $recurring : null)
->badgeColor('info')
->modifyQueryUsing(fn (Builder $q) => $confirmedSubquery($q)
->where('reoccurrence', '!=', -1)
),
'everything' => Tab::make('Everything')
->icon('heroicon-o-squares-2x2'),
];
}
public function getDefaultActiveTab(): string | int | null
{
return 'today';
}
}