From 80985828d88dc5f0e6e18d2eb421051c380652db Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Sat, 20 Dec 2025 16:59:14 +0100 Subject: [PATCH] =?UTF-8?q?ung=C3=BCltige=20paket-IDs=20werden=20nun=20abg?= =?UTF-8?q?efangen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Http/Controllers/CheckoutController.php | 12 +++++-- app/Http/Middleware/HandleInertiaRequests.php | 4 ++- resources/js/pages/marketing/Packages.tsx | 10 +++++- resources/lang/de/marketing.php | 1 + resources/lang/en/marketing.php | 1 + routes/web.php | 36 +++++++++++++++---- tests/Feature/Checkout/CheckoutAuthTest.php | 6 ++-- 7 files changed, 57 insertions(+), 13 deletions(-) diff --git a/app/Http/Controllers/CheckoutController.php b/app/Http/Controllers/CheckoutController.php index 8f74df3..7c33fae 100644 --- a/app/Http/Controllers/CheckoutController.php +++ b/app/Http/Controllers/CheckoutController.php @@ -23,8 +23,16 @@ class CheckoutController extends Controller { use PresentsPackages; - public function show(string $locale, string $checkoutSlug, Package $package): \Inertia\Response + public function show(string $locale, string $checkoutSlug, string $package): \Inertia\Response|\Illuminate\Http\RedirectResponse { + $resolvedPackage = Package::query()->find($package); + + if (! $resolvedPackage) { + return redirect() + ->route('packages', ['locale' => $locale]) + ->with('error', __('marketing.packages.package_not_found')); + } + $googleStatus = session()->pull('checkout_google_status'); $googleError = session()->pull('checkout_google_error'); $googleProfile = session()->pull('checkout_google_profile'); @@ -35,7 +43,7 @@ class CheckoutController extends Controller ->all(); return Inertia::render('marketing/CheckoutWizardPage', [ - 'package' => $this->presentPackage($package), + 'package' => $this->presentPackage($resolvedPackage), 'packageOptions' => $packageOptions, 'privacyHtml' => view('legal.datenschutz-partial')->render(), 'auth' => [ diff --git a/app/Http/Middleware/HandleInertiaRequests.php b/app/Http/Middleware/HandleInertiaRequests.php index 0b5290f..527cafd 100644 --- a/app/Http/Middleware/HandleInertiaRequests.php +++ b/app/Http/Middleware/HandleInertiaRequests.php @@ -2,10 +2,10 @@ namespace App\Http\Middleware; +use App\Support\LocaleConfig; use Illuminate\Foundation\Inspiring; use Illuminate\Http\Request; use Inertia\Middleware; -use App\Support\LocaleConfig; class HandleInertiaRequests extends Middleware { @@ -63,6 +63,8 @@ class HandleInertiaRequests extends Middleware 'dashboard' => __('dashboard'), ], 'flash' => [ + 'success' => fn () => $request->session()->get('success'), + 'error' => fn () => $request->session()->get('error'), 'verification' => fn () => $request->session()->get('verification'), ], ]; diff --git a/resources/js/pages/marketing/Packages.tsx b/resources/js/pages/marketing/Packages.tsx index bc7ff0a..75989df 100644 --- a/resources/js/pages/marketing/Packages.tsx +++ b/resources/js/pages/marketing/Packages.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect, useMemo, useRef, useLayoutEffect } from 'react'; -import { Link } from '@inertiajs/react'; +import { Link, usePage } from '@inertiajs/react'; import { useTranslation } from 'react-i18next'; import type { TFunction } from 'i18next'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; @@ -16,6 +16,7 @@ import { useCtaExperiment } from '@/hooks/useCtaExperiment'; import { useLocalizedRoutes } from '@/hooks/useLocalizedRoutes'; import { useLocale } from '@/hooks/useLocale'; import { ArrowRight, Check, Star } from 'lucide-react'; +import toast from 'react-hot-toast'; interface Package { id: number; @@ -255,11 +256,18 @@ const Packages: React.FC = ({ endcustomerPackages, resellerPackag const locale = useLocale(); const { t } = useTranslation('marketing'); const { t: tCommon } = useTranslation('common'); + const { flash } = usePage<{ flash?: { error?: string } }>().props; const { variant: packagesHeroVariant, trackClick: trackPackagesHeroClick, } = useCtaExperiment('packages_hero_cta'); + useEffect(() => { + if (flash?.error) { + toast.error(flash.error); + } + }, [flash?.error]); + useEffect(() => { const urlParams = new URLSearchParams(window.location.search); const packageId = urlParams.get('package_id'); diff --git a/resources/lang/de/marketing.php b/resources/lang/de/marketing.php index e74be33..b6fd4d4 100644 --- a/resources/lang/de/marketing.php +++ b/resources/lang/de/marketing.php @@ -66,6 +66,7 @@ return [ 'limits_label' => 'Limits & Kapazitäten', 'paddle_not_configured' => 'Dieses Package ist noch nicht für den Paddle-Checkout konfiguriert. Bitte kontaktiere den Support.', 'paddle_checkout_failed' => 'Der Paddle-Checkout konnte nicht gestartet werden. Bitte versuche es später erneut.', + 'package_not_found' => 'Dieses Package ist nicht verfügbar. Bitte wähle ein anderes aus.', ], 'nav' => [ 'home' => 'Startseite', diff --git a/resources/lang/en/marketing.php b/resources/lang/en/marketing.php index 6e0dcd5..409a7d2 100644 --- a/resources/lang/en/marketing.php +++ b/resources/lang/en/marketing.php @@ -66,6 +66,7 @@ return [ 'limits_label' => 'Limits & Capacity', 'paddle_not_configured' => 'This package is not ready for Paddle checkout. Please contact support.', 'paddle_checkout_failed' => 'We could not start the Paddle checkout. Please try again later.', + 'package_not_found' => 'This package is no longer available. Please choose another one.', ], 'nav' => [ 'home' => 'Home', diff --git a/routes/web.php b/routes/web.php index cf89040..59debb1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -160,10 +160,18 @@ Route::prefix('{locale}') ->where('checkoutSlug', 'bestellen|checkout') ->name('checkout.show'); } else { - Route::get('/{checkoutSlug}/{package}', function (string $locale, string $checkoutSlug, Package $package) { + Route::get('/{checkoutSlug}/{package}', function (string $locale, string $checkoutSlug, string $package) { + $resolvedPackage = Package::query()->find($package); + + if (! $resolvedPackage) { + return redirect() + ->route('packages', ['locale' => $locale]) + ->with('error', __('marketing.packages.package_not_found')); + } + return redirect()->route('packages', [ - 'locale' => app()->getLocale(), - 'highlight' => $package->slug, + 'locale' => $locale, + 'highlight' => $resolvedPackage->slug, ]); }) ->where('checkoutSlug', 'bestellen|checkout') @@ -325,16 +333,30 @@ Route::middleware('auth')->group(function () { ->name('tenant.events.photos.archive'); }); -Route::get('/purchase-wizard/{package}', function (Request $request, Package $package) use ($determinePreferredLocale) { +Route::get('/purchase-wizard/{package}', function (Request $request, string $package) use ($determinePreferredLocale) { $locale = $determinePreferredLocale($request); + $resolvedPackage = Package::query()->find($package); - return redirect()->to(CheckoutRoutes::wizardUrl($package, $locale), 301); + if (! $resolvedPackage) { + return redirect() + ->route('packages', ['locale' => $locale]) + ->with('error', __('marketing.packages.package_not_found')); + } + + return redirect()->to(CheckoutRoutes::wizardUrl($resolvedPackage, $locale), 301); }); -Route::get('/checkout/{package}', function (Request $request, Package $package) use ($determinePreferredLocale) { +Route::get('/checkout/{package}', function (Request $request, string $package) use ($determinePreferredLocale) { $locale = $determinePreferredLocale($request); + $resolvedPackage = Package::query()->find($package); - return redirect()->to(CheckoutRoutes::wizardUrl($package, $locale), 301); + if (! $resolvedPackage) { + return redirect() + ->route('packages', ['locale' => $locale]) + ->with('error', __('marketing.packages.package_not_found')); + } + + return redirect()->to(CheckoutRoutes::wizardUrl($resolvedPackage, $locale), 301); }); Route::post('/checkout/login', [CheckoutController::class, 'login'])->name('checkout.login'); Route::post('/checkout/register', [CheckoutController::class, 'register'])->name('checkout.register'); diff --git a/tests/Feature/Checkout/CheckoutAuthTest.php b/tests/Feature/Checkout/CheckoutAuthTest.php index 6980316..9c17132 100644 --- a/tests/Feature/Checkout/CheckoutAuthTest.php +++ b/tests/Feature/Checkout/CheckoutAuthTest.php @@ -326,11 +326,13 @@ class CheckoutAuthTest extends TestCase ); } - public function test_checkout_show_with_invalid_package_returns_404() + public function test_checkout_show_with_invalid_package_redirects_to_packages() { $response = $this->get(CheckoutRoutes::wizardUrl(999, 'de')); - $response->assertStatus(404); + $response + ->assertRedirect(route('packages', ['locale' => 'de'])) + ->assertSessionHas('error', __('marketing.packages.package_not_found')); } public function test_checkout_register_missing_required_fields()