import React, { useEffect, useMemo, useState } from 'react'; import { Head, Link, router, usePage } from '@inertiajs/react'; import { useTranslation } from 'react-i18next'; import MatomoTracker, { MatomoConfig } from '@/components/analytics/MatomoTracker'; import { useLocalizedRoutes } from '@/hooks/useLocalizedRoutes'; import Footer from '@/layouts/app/Footer'; import { useAppearance } from '@/hooks/use-appearance'; import { Button } from '@/components/ui/button'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; import { MoreHorizontal, Sun, Moon, Languages, LayoutDashboard, LogOut, LogIn } from 'lucide-react'; interface MarketingLayoutProps { children: React.ReactNode; title?: string; } type PageProps = { translations?: Record>; locale?: string; analytics?: { matomo?: MatomoConfig }; supportedLocales?: string[]; appUrl?: string; auth?: { user?: { name?: string; email?: string } }; }; const MarketingLayout: React.FC = ({ children, title }) => { const page = usePage(); const { url } = page; const { t } = useTranslation('marketing'); const i18n = useTranslation(); const { locale, analytics, supportedLocales = ['de', 'en'], appUrl, auth } = page.props; const user = auth?.user ?? null; const { localizedPath } = useLocalizedRoutes(); const { appearance, updateAppearance } = useAppearance(); const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const occasionLinks = useMemo(() => ([ { key: 'wedding', label: t('nav.occasions_types.weddings', 'Hochzeiten'), href: localizedPath('/anlaesse/hochzeit'), }, { key: 'birthday', label: t('nav.occasions_types.birthdays', 'Geburtstage'), href: localizedPath('/anlaesse/geburtstag'), }, { key: 'corporate', label: t('nav.occasions_types.corporate', 'Firmenevents'), href: localizedPath('/anlaesse/firmenevent'), }, { key: 'confirmation', label: t('nav.occasions_types.confirmation', 'Konfirmation'), href: localizedPath('/anlaesse/konfirmation'), }, ]), [localizedPath, t]); const navLinks = useMemo(() => ([ { key: 'how', label: t('nav.how_it_works', "So funktioniert's"), href: localizedPath('/so-funktionierts'), }, { key: 'packages', label: t('nav.packages', 'Pakete'), href: localizedPath('/packages'), }, { key: 'occasions', label: t('nav.occasions', 'Anlässe'), children: occasionLinks, }, { key: 'blog', label: t('nav.blog', 'Blog'), href: localizedPath('/blog'), }, { key: 'contact', label: t('nav.contact', 'Kontakt'), href: localizedPath('/kontakt'), }, ]), [localizedPath, occasionLinks, t]); const ctaHref = localizedPath('/demo'); const themeIsDark = appearance === 'dark'; const themeLabel = themeIsDark ? t('nav.theme_light', 'Helles Design') : t('nav.theme_dark', 'Dunkles Design'); const toggleTheme = () => updateAppearance(themeIsDark ? 'light' : 'dark'); const handleLogout = () => { router.post('/logout'); }; useEffect(() => { if (locale && i18n.i18n.language !== locale) { i18n.i18n.changeLanguage(locale); } }, [locale, i18n]); const marketing = page.props.translations?.marketing ?? {}; const getString = (key: string, fallback: string) => { const value = marketing[key]; return typeof value === 'string' ? value : fallback; }; const activeLocale = locale || supportedLocales[0] || 'de'; const baseUrl = (typeof appUrl === 'string' && appUrl.length > 0) ? appUrl.replace(/\/+$/, '') : 'https://fotospiel.app'; const [rawPath, rawQuery = ''] = url.split('?'); const localePattern = supportedLocales.length > 0 ? supportedLocales.join('|') : 'de|en'; const localeRegex = new RegExp(`^/(${localePattern})(?=/|$)`, 'i'); const relativePath = rawPath.replace(localeRegex, '') || '/'; const canonicalPath = localizedPath(relativePath, activeLocale); const canonicalUrl = `${baseUrl}${canonicalPath}${rawQuery ? `?${rawQuery}` : ''}`; const buildAlternateUrl = (targetLocale: string) => { const alternatePath = localizedPath(relativePath, targetLocale); return `${baseUrl}${alternatePath}${rawQuery ? `?${rawQuery}` : ''}`; }; const alternates = supportedLocales.reduce>((acc, currentLocale) => { acc[currentLocale] = buildAlternateUrl(currentLocale); return acc; }, {}); const handleLocaleChange = (nextLocale: string) => { const targetPath = localizedPath(relativePath, nextLocale); const targetUrl = `${targetPath}${rawQuery ? `?${rawQuery}` : ''}`; i18n.i18n.changeLanguage(nextLocale); setMobileMenuOpen(false); router.visit(targetUrl, { replace: true, preserveState: false, }); }; return ( <> {title || t('meta.title', getString('title', 'Fotospiel'))} {supportedLocales .filter((code) => code !== activeLocale) .map((code) => ( ))} {Object.entries(alternates).map(([code, href]) => ( ))}
setMobileMenuOpen(false)} > Fotospiel App Logo Die Fotospiel App
{t('nav.preferences', 'Einstellungen')} { event.preventDefault(); toggleTheme(); }} className="flex items-center gap-2 font-sans-marketing" > {themeIsDark ? : } {themeLabel} {t('nav.language', 'Sprache')} {supportedLocales.map((code) => ( {code.toUpperCase()} ))} {user ? ( <> {user.name ?? user.email} { event.preventDefault(); router.visit('/event-admin'); }} className="flex items-center gap-2 font-sans-marketing" > {t('nav.dashboard', 'Zum Admin-Bereich')} { event.preventDefault(); handleLogout(); }} className="flex items-center gap-2 font-sans-marketing" > {t('nav.logout', 'Abmelden')} ) : ( <> { event.preventDefault(); router.visit(localizedPath('/login')); }} className="flex items-center gap-2 font-sans-marketing" > {t('nav.login', 'Anmelden')} )}
{mobileMenuOpen && (
{navLinks.map((item) => ( item.children ? (

{item.label}

{item.children.map((child) => ( setMobileMenuOpen(false)} > {child.label} ))}
) : ( setMobileMenuOpen(false)} > {item.label} ) ))}
)}
{children}
); }; export default MarketingLayout;