#!/usr/bin/env python3 """ Navigation overhaul: - Daily: Donors, Donations (with recurring tab) - Seasonal Campaigns: Campaign Dashboard, Subscribers, Giving Campaigns config - Fundraising: Review Queue, All Fundraisers - Setup: unchanged """ import os BASE = '/home/forge/app.charityright.org.uk' # ── 1. ScheduledGivingDonationResource → Seasonal Campaigns group ── path = os.path.join(BASE, 'app/Filament/Resources/ScheduledGivingDonationResource.php') with open(path, 'r') as f: c = f.read() # Change nav group c = c.replace( "protected static ?string $navigationGroup = 'Daily';", "protected static ?string $navigationGroup = 'Seasonal Campaigns';" ) # Change label c = c.replace( "protected static ?string $navigationLabel = 'Regular Giving';", "protected static ?string $navigationLabel = 'Subscribers';" ) # Change sort c = c.replace( "protected static ?int $navigationSort = 3;", "protected static ?int $navigationSort = 1;" ) # Change model label c = c.replace( "protected static ?string $modelLabel = 'Regular Giving';", "protected static ?string $modelLabel = 'Scheduled Giving';" ) c = c.replace( "protected static ?string $pluralModelLabel = 'Regular Giving';", "protected static ?string $pluralModelLabel = 'Scheduled Giving';" ) # Change icon to calendar c = c.replace( "protected static ?string $navigationIcon = 'heroicon-o-arrow-path';", "protected static ?string $navigationIcon = 'heroicon-o-user-group';" ) with open(path, 'w') as f: f.write(c) print('Updated ScheduledGivingDonationResource nav') # ── 2. ScheduledGivingCampaignResource → Seasonal Campaigns group ── path = os.path.join(BASE, 'app/Filament/Resources/ScheduledGivingCampaignResource.php') with open(path, 'r') as f: c = f.read() c = c.replace( "protected static ?string $navigationGroup = 'Fundraising';", "protected static ?string $navigationGroup = 'Seasonal Campaigns';" ) c = c.replace( "protected static ?string $navigationLabel = 'Giving Campaigns';", "protected static ?string $navigationLabel = 'Campaign Config';" ) # Add sort if missing if 'navigationSort' not in c: c = c.replace( "protected static ?string $navigationLabel = 'Campaign Config';", "protected static ?string $navigationLabel = 'Campaign Config';\n\n protected static ?int $navigationSort = 2;" ) with open(path, 'w') as f: f.write(c) print('Updated ScheduledGivingCampaignResource nav') # ── 3. AdminPanelProvider → Add Seasonal Campaigns group ── path = os.path.join(BASE, 'app/Providers/Filament/AdminPanelProvider.php') with open(path, 'r') as f: c = f.read() old_groups = """ ->navigationGroups([ // ── Daily Work (always visible, top of sidebar) ── NavigationGroup::make('Daily') ->collapsible(false), // ── Fundraising (campaigns, review queue) ── NavigationGroup::make('Fundraising') ->icon('heroicon-o-megaphone') ->collapsible(), // ── Setup (rarely touched config) ── NavigationGroup::make('Setup') ->icon('heroicon-o-cog-6-tooth') ->collapsible() ->collapsed(), ])""" new_groups = """ ->navigationGroups([ // ── Daily Work (always visible, top of sidebar) ── NavigationGroup::make('Daily') ->collapsible(false), // ── Seasonal Campaigns (30 Nights, 10 Days, Night of Power) ── NavigationGroup::make('Seasonal Campaigns') ->icon('heroicon-o-calendar-days') ->collapsible(), // ── Fundraising (appeals, review queue) ── NavigationGroup::make('Fundraising') ->icon('heroicon-o-megaphone') ->collapsible(), // ── Setup (rarely touched config) ── NavigationGroup::make('Setup') ->icon('heroicon-o-cog-6-tooth') ->collapsible() ->collapsed(), ])""" c = c.replace(old_groups, new_groups) with open(path, 'w') as f: f.write(c) print('Updated AdminPanelProvider nav groups') # ── 4. Update ListScheduledGivingDonations labels ── path = os.path.join(BASE, 'app/Filament/Resources/ScheduledGivingDonationResource/Pages/ListScheduledGivingDonations.php') with open(path, 'r') as f: c = f.read() c = c.replace( "return 'Regular Giving';", "return 'Scheduled Giving Subscribers';" ) c = c.replace( 'return "{$active} people giving every month.";', 'return "{$active} active subscribers across all campaigns.";' ) with open(path, 'w') as f: f.write(c) print('Updated ListScheduledGivingDonations labels') # ── 5. Add "Recurring" tab to Donations list ── # Monthly/weekly donors should be visible under Donations path = os.path.join(BASE, 'app/Filament/Resources/DonationResource/Pages/ListDonations.php') with open(path, 'r') as f: c = f.read() # Check if 'recurring' tab already exists if "'recurring'" not in c: # Find the 'everything' tab and add 'recurring' before it old_everything = """ 'everything' => Tab::make('Everything')""" new_recurring = """ 'recurring' => Tab::make('Recurring') ->icon('heroicon-o-arrow-path') ->badge($recurring > 0 ? $recurring : null) ->badgeColor('info') ->modifyQueryUsing(fn (Builder $q) => $q->where('reoccurrence', '!=', -1) ->whereHas('donationConfirmation', fn ($sub) => $sub->whereNotNull('confirmed_at'))), 'everything' => Tab::make('Everything')""" c = c.replace(old_everything, new_recurring) # Add $recurring count variable if '$recurring' not in c: c = c.replace( "return [", "$recurring = Donation::where('reoccurrence', '!=', -1)\n ->whereHas('donationConfirmation', fn ($q) => $q->whereNotNull('confirmed_at'))\n ->count();\n\n return [", 1 # only first occurrence in getTabs ) with open(path, 'w') as f: f.write(c) print('Added Recurring tab to ListDonations') else: print('ListDonations already has recurring tab') print('Navigation update complete!')