- Added public gallery API with token-expiry enforcement, branding payload, cursor pagination, and per-photo download stream (app/Http/Controllers/Api/EventPublicController.php:1, routes/api.php:16). 410 is returned when the package gallery duration has lapsed.

- Served the guest PWA at /g/{token} and introduced a mobile-friendly gallery page with lazy-loaded thumbnails, themed colors, lightbox, and download links plus new gallery data client (resources/js/guest/pages/PublicGalleryPage.tsx:1, resources/js/guest/services/galleryApi.ts:1, resources/js/guest/router.tsx:1). Added i18n strings for the public gallery experience (resources/js/guest/i18n/messages.ts:1).
- Ensured checkout step changes snap back to the progress bar on mobile via smooth scroll anchoring (resources/ js/pages/marketing/checkout/CheckoutWizard.tsx:1).
- Enabled tenant admins to export all approved event photos through a new download action that streams a ZIP archive, with translations and routing in place (app/Http/Controllers/Tenant/EventPhotoArchiveController.php:1, app/Filament/Resources/EventResource.php:1, routes/web.php:1, resources/lang/de/admin.php:1, resources/lang/en/admin.php:1).
This commit is contained in:
Codex Agent
2025-10-17 23:24:06 +02:00
parent 5817270c35
commit ae9b9160ac
20 changed files with 1410 additions and 3 deletions

View File

@@ -38,6 +38,12 @@ Route::prefix('v1')->name('api.v1.')->group(function () {
Route::get('/photos/{id}', [EventPublicController::class, 'photo'])->name('photos.show');
Route::post('/photos/{id}/like', [EventPublicController::class, 'like'])->name('photos.like');
Route::post('/events/{token}/upload', [EventPublicController::class, 'upload'])->name('events.upload');
Route::get('/gallery/{token}', [EventPublicController::class, 'gallery'])->name('gallery.show');
Route::get('/gallery/{token}/photos', [EventPublicController::class, 'galleryPhotos'])->name('gallery.photos');
Route::get('/gallery/{token}/photos/{photo}/download', [EventPublicController::class, 'galleryPhotoDownload'])
->whereNumber('photo')
->name('gallery.photos.download');
});
Route::middleware(['tenant.token', 'tenant.isolation', 'throttle:tenant-api'])->prefix('tenant')->group(function () {

View File

@@ -4,6 +4,7 @@ use App\Http\Controllers\CheckoutController;
use App\Http\Controllers\LocaleController;
use App\Http\Controllers\LegalPageController;
use App\Http\Controllers\MarketingController;
use App\Http\Controllers\Tenant\EventPhotoArchiveController;
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;
@@ -39,10 +40,16 @@ Route::get('/anlaesse/{type}', [MarketingController::class, 'occasionsType'])->n
Route::get('/success/{packageId?}', [MarketingController::class, 'success'])->name('marketing.success');
Route::view('/event-admin/{view?}', 'admin')->where('view', '.*')->name('tenant.admin.app');
Route::view('/event', 'guest')->name('guest.pwa.landing');
Route::view('/g/{token}', 'guest')->where('token', '.*')->name('guest.gallery');
Route::middleware('auth')->group(function () {
Route::get('/buy/{packageId}', [MarketingController::class, 'buyPackages'])->name('marketing.buy');
});
Route::middleware('auth')->group(function () {
Route::get('/tenant/events/{event}/photos/archive', EventPhotoArchiveController::class)
->name('tenant.events.photos.archive');
});
Route::get('/purchase-wizard/{package}', [CheckoutController::class, 'show'])->name('purchase.wizard');
Route::get('/checkout/{package}', [CheckoutController::class, 'show'])->name('checkout.show');
Route::post('/checkout/login', [CheckoutController::class, 'login'])->name('checkout.login');