diff --git a/resources/js/admin/i18n/locales/de/management.json b/resources/js/admin/i18n/locales/de/management.json index 2130ecc4..0593a314 100644 --- a/resources/js/admin/i18n/locales/de/management.json +++ b/resources/js/admin/i18n/locales/de/management.json @@ -95,7 +95,10 @@ "noPackage": "Für dieses Event ist derzeit kein Paket zugewiesen.", "addonsLabel": "Add-ons für dieses Event", "noAddons": "Für dieses Event wurden noch keine Add-ons gekauft.", - "eventAddonSource": "Quelle: Event-Paket" + "eventAddonSource": "Quelle: Event-Paket", + "openAddonShop": "Add-ons für dieses Event kaufen", + "openAddonUpsell": "Control-Room-Upgrades öffnen", + "noAddonCatalog": "Aktuell sind keine Add-ons zum Kauf verfügbar." }, "invoices": { "title": "Rechnungen & Zahlungen", @@ -106,7 +109,8 @@ "title": "Add-on-Kaufverlauf", "hint": "Verlauf aller Add-on-Käufe über alle Events. Ein Eintrag hier ist nicht automatisch für das aktuell ausgewählte Event aktiv.", "empty": "Keine Add-ons gebucht.", - "otherEventNotice": "Für ein anderes Event gekauft" + "otherEventNotice": "Für ein anderes Event gekauft", + "openShop": "Jetzt Add-ons kaufen" }, "overview": { "title": "Paketübersicht", @@ -497,6 +501,25 @@ "buyMoreGuests": "Mehr Gäste freischalten", "extendGallery": "Galerie verlängern" }, + "addons": { + "title": "Event-Add-ons", + "event": "Event", + "packageExpires": "Galerie aktiv bis {{date}}", + "noPackage": "Für dieses Event ist derzeit kein Paket zugewiesen.", + "recommendedTitle": "Jetzt empfohlen", + "recommendedBody": "Basierend auf deiner Event-Nutzung sind diese Add-ons aktuell besonders relevant.", + "recommendedBadge": "Empfohlen", + "buyAction": "Add-on kaufen", + "historyTitle": "Gekaufte Add-ons für dieses Event", + "noAddonAvailable": "Aktuell sind keine Add-ons verfügbar.", + "groups": { + "photos": "Foto-Kapazität", + "guests": "Gäste-Kapazität", + "gallery": "Galerie-Laufzeit", + "bundle": "Bundles", + "feature": "Feature-Freischaltungen" + } + }, "form": { "editTitle": "Event bearbeiten", "createTitle": "Neues Event erstellen", diff --git a/resources/js/admin/i18n/locales/en/management.json b/resources/js/admin/i18n/locales/en/management.json index aa6a3993..59cf8ba6 100644 --- a/resources/js/admin/i18n/locales/en/management.json +++ b/resources/js/admin/i18n/locales/en/management.json @@ -95,7 +95,10 @@ "noPackage": "No package is currently assigned to this event.", "addonsLabel": "Add-ons for this event", "noAddons": "No add-ons purchased for this event.", - "eventAddonSource": "Source: event package" + "eventAddonSource": "Source: event package", + "openAddonShop": "Buy add-ons for this event", + "openAddonUpsell": "Open control-room upgrades", + "noAddonCatalog": "No add-ons are currently available for purchase." }, "invoices": { "title": "Invoices & payments", @@ -106,7 +109,8 @@ "title": "Add-on purchase history", "hint": "History of all add-on purchases across all events. An entry here is not automatically active for the currently selected event.", "empty": "No add-ons booked.", - "otherEventNotice": "Purchased for another event" + "otherEventNotice": "Purchased for another event", + "openShop": "Buy add-ons now" }, "overview": { "title": "Package overview", @@ -493,6 +497,25 @@ "buyMoreGuests": "Unlock more guests", "extendGallery": "Extend gallery" }, + "addons": { + "title": "Event add-ons", + "event": "Event", + "packageExpires": "Gallery active until {{date}}", + "noPackage": "No package is currently assigned to this event.", + "recommendedTitle": "Recommended now", + "recommendedBody": "Based on your event usage, these add-ons are likely most relevant.", + "recommendedBadge": "Recommended", + "buyAction": "Buy add-on", + "historyTitle": "Purchased add-ons for this event", + "noAddonAvailable": "No add-ons are currently available.", + "groups": { + "photos": "Photo capacity", + "guests": "Guest capacity", + "gallery": "Gallery runtime", + "bundle": "Bundles", + "feature": "Feature unlocks" + } + }, "form": { "editTitle": "Edit event", "createTitle": "Create new event", diff --git a/resources/js/admin/mobile/EventAddonsPage.tsx b/resources/js/admin/mobile/EventAddonsPage.tsx index 6f3f903f..dfaff7e9 100644 --- a/resources/js/admin/mobile/EventAddonsPage.tsx +++ b/resources/js/admin/mobile/EventAddonsPage.tsx @@ -148,6 +148,21 @@ function resolveScopeFromQuery(input: string | null): 'photos' | 'guests' | 'gal return null; } +function resolveEventName( + name: TenantEvent['name'], + t: (key: string, fallback: string) => string, +): string { + if (typeof name === 'string' && name.trim() !== '') { + return name; + } + + if (name && typeof name === 'object') { + return name.de ?? name.en ?? Object.values(name)[0] ?? t('events.placeholders.untitled', 'Untitled event'); + } + + return t('events.placeholders.untitled', 'Untitled event'); +} + export default function MobileEventAddonsPage() { const { slug } = useParams<{ slug: string }>(); const navigate = useNavigate(); @@ -355,7 +370,7 @@ export default function MobileEventAddonsPage() { {t('events.addons.event', 'Event')} - {typeof event.name === 'string' ? event.name : t('events.placeholders.untitled', 'Untitled event')} + {resolveEventName(event.name, t as any)} {event.package?.name ? ( @@ -403,7 +418,7 @@ export default function MobileEventAddonsPage() { {!hasSellableAddons ? ( - {t('events.recap.noAddonAvailable', 'No add-ons are currently available.')} + {t('events.addons.noAddonAvailable', 'No add-ons are currently available.')} ) : ( diff --git a/resources/js/admin/mobile/__tests__/EventAddonsPage.test.tsx b/resources/js/admin/mobile/__tests__/EventAddonsPage.test.tsx index e86dc617..c8ced1ab 100644 --- a/resources/js/admin/mobile/__tests__/EventAddonsPage.test.tsx +++ b/resources/js/admin/mobile/__tests__/EventAddonsPage.test.tsx @@ -7,7 +7,7 @@ const navigateMock = vi.fn(); const fixtures = vi.hoisted(() => ({ event: { id: 42, - name: 'Demo Event', + name: { de: 'Demo Event DE', en: 'Demo Event EN' }, slug: 'demo-event', status: 'published', event_date: '2026-02-01T12:00:00Z', @@ -165,6 +165,7 @@ describe('MobileEventAddonsPage', () => { it('renders add-ons and event-specific purchase history', async () => { render(); + expect(await screen.findByText('Demo Event DE')).toBeInTheDocument(); expect((await screen.findAllByText('Extend gallery 30 days')).length).toBeGreaterThan(0); expect(screen.getByText('Extra photos 500')).toBeInTheDocument(); expect(screen.getByText('Purchased add-ons for this event')).toBeInTheDocument();