- Wired the checkout wizard for Google “comfort login”: added Socialite controller + dependency, new Google env

hooks in config/services.php/.env.example, and updated wizard steps/controllers to store session payloads,
attach packages, and surface localized success/error states.
- Retooled payment handling for both Stripe and PayPal, adding richer status management in CheckoutController/
PayPalController, fallback flows in the wizard’s PaymentStep.tsx, and fresh feature tests for intent
creation, webhooks, and the wizard CTA.
- Introduced a consent-aware Matomo analytics stack: new consent context, cookie-banner UI, useAnalytics/
useCtaExperiment hooks, and MatomoTracker component, then instrumented marketing pages (Home, Packages,
Checkout) with localized copy and experiment tracking.
- Polished package presentation across marketing UIs by centralizing formatting in PresentsPackages, surfacing
localized description tables/placeholders, tuning badges/layouts, and syncing guest/marketing translations.
- Expanded docs & reference material (docs/prp/*, TODOs, public gallery overview) and added a Playwright smoke
test for the hero CTA while reconciling outstanding checklist items.
This commit is contained in:
Codex Agent
2025-10-19 11:41:03 +02:00
parent ae9b9160ac
commit a949c8d3af
113 changed files with 5169 additions and 712 deletions

View File

@@ -20,6 +20,7 @@ use Filament\Tables\Columns\IconColumn;
use App\Filament\Resources\TenantResource\RelationManagers\PackagePurchasesRelationManager;
use App\Filament\Resources\TenantResource\RelationManagers\TenantPackagesRelationManager;
use Filament\Resources\RelationManagers\RelationGroup;
use Filament\Notifications\Notification;
use UnitEnum;
use BackedEnum;
use Illuminate\Support\Facades\Route;
@@ -56,6 +57,10 @@ class TenantResource extends Resource
->email()
->required()
->maxLength(255),
TextInput::make('event_credits_balance')
->label(__('admin.tenants.fields.event_credits_balance'))
->numeric()
->readOnly(),
TextInput::make('total_revenue')
->label(__('admin.tenants.fields.total_revenue'))
->prefix('€')
@@ -99,6 +104,10 @@ class TenantResource extends Resource
->getStateUsing(fn (Tenant $record) => $record->user?->full_name ?? 'Unbekannt'),
Tables\Columns\TextColumn::make('slug')->searchable(),
Tables\Columns\TextColumn::make('contact_email'),
Tables\Columns\TextColumn::make('event_credits_balance')
->label(__('admin.tenants.fields.event_credits_balance'))
->badge()
->color(fn (int $state): string => $state <= 0 ? 'danger' : ($state < 5 ? 'warning' : 'success')),
Tables\Columns\TextColumn::make('active_reseller_package_id')
->label(__('admin.tenants.fields.active_package'))
->badge()
@@ -159,10 +168,49 @@ class TenantResource extends Resource
'metadata' => ['reason' => $data['reason'] ?? 'manual assignment'],
]);
}),
Actions\Action::make('adjust_credits')
->label(__('admin.tenants.actions.adjust_credits'))
->icon('heroicon-o-banknotes')
->authorize(fn (Tenant $record): bool => auth()->user()?->can('adjustCredits', $record) ?? false)
->form([
Forms\Components\TextInput::make('delta')
->label(__('admin.tenants.actions.adjust_credits_delta'))
->numeric()
->required()
->rule('integer')
->helperText(__('admin.tenants.actions.adjust_credits_delta_hint')),
Forms\Components\Textarea::make('reason')
->label(__('admin.tenants.actions.adjust_credits_reason'))
->rows(3)
->maxLength(500),
])
->action(function (Tenant $record, array $data): void {
$delta = (int) ($data['delta'] ?? 0);
if ($delta === 0) {
return;
}
$newBalance = max(0, $record->event_credits_balance + $delta);
$record->forceFill([
'event_credits_balance' => $newBalance,
])->save();
Notification::make()
->title(__('admin.tenants.actions.adjust_credits_success_title'))
->body(__('admin.tenants.actions.adjust_credits_success_body', [
'delta' => $delta,
'balance' => $newBalance,
]))
->success()
->send();
}),
Actions\Action::make('suspend')
->label('Suspendieren')
->color('danger')
->requiresConfirmation()
->authorize(fn (Tenant $record): bool => auth()->user()?->can('suspend', $record) ?? false)
->action(fn (Tenant $record) => $record->update(['is_suspended' => true])),
Actions\Action::make('export')
->label('Daten exportieren')