- 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

@@ -22,23 +22,35 @@ use Stripe\PaymentIntent;
use Stripe\Stripe;
use App\Http\Controllers\PayPalController;
use App\Support\Concerns\PresentsPackages;
class CheckoutController extends Controller
{
use PresentsPackages;
public function show(Package $package)
{
// Alle verfügbaren Pakete laden
$packages = Package::all();
$googleStatus = session()->pull('checkout_google_status');
$googleError = session()->pull('checkout_google_error');
$packageOptions = Package::orderBy('price')->get()
->map(fn (Package $pkg) => $this->presentPackage($pkg))
->values()
->all();
return Inertia::render('marketing/CheckoutWizardPage', [
'package' => $package,
'packageOptions' => $packages,
'package' => $this->presentPackage($package),
'packageOptions' => $packageOptions,
'stripePublishableKey' => config('services.stripe.key'),
'paypalClientId' => config('services.paypal.client_id'),
'privacyHtml' => view('legal.datenschutz-partial')->render(),
'auth' => [
'user' => Auth::user(),
],
'googleAuth' => [
'status' => $googleStatus,
'error' => $googleError,
],
]);
}
@@ -97,11 +109,14 @@ class CheckoutController extends Controller
'event_default_type' => 'general',
]),
]);
$user->forceFill(['tenant_id' => $tenant->id])->save();
// Package zuweisen
$tenant->packages()->attach($package->id, [
'price' => $package->price,
'purchased_at' => now(),
'expires_at' => $package->is_free ? null : now()->addYear(),
'is_active' => $package->is_free, // Kostenlose Pakete sofort aktivieren
'expires_at' => $this->packageIsFree($package) ? now()->addYear() : now()->addYear(),
'active' => $this->packageIsFree($package), // Kostenlose Pakete sofort aktivieren
]);
// E-Mail-Verifizierung senden
@@ -241,7 +256,9 @@ class CheckoutController extends Controller
'user_id' => Auth::id(),
]);
if ($package->is_free) {
$isFreePackage = $this->packageIsFree($package);
if ($isFreePackage) {
\Log::info('Free package detected, returning null client_secret');
return response()->json([
'client_secret' => null,
@@ -305,9 +322,10 @@ class CheckoutController extends Controller
// Package dem Tenant zuweisen
$user->tenant->packages()->attach($package->id, [
'price' => $package->price,
'purchased_at' => now(),
'expires_at' => now()->addYear(),
'is_active' => true,
'active' => true,
]);
// pending_purchase zurücksetzen
@@ -362,9 +380,10 @@ class CheckoutController extends Controller
// TenantPackage zuweisen (ähnlich Stripe)
$user->tenant->packages()->attach($package->id, [
'price' => $package->price,
'purchased_at' => now(),
'expires_at' => now()->addYear(),
'is_active' => true,
'active' => true,
]);
// pending_purchase zurücksetzen
@@ -379,4 +398,15 @@ class CheckoutController extends Controller
return redirect('/checkout')->with('error', 'Fehler beim Abschließen der Zahlung: ' . $e->getMessage());
}
}
private function packageIsFree(Package $package): bool
{
if (isset($package->is_free)) {
return (bool) $package->is_free;
}
$price = (float) $package->price;
return $price <= 0;
}
}