import React from 'react'; import { useNavigate, useParams } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Image as ImageIcon, RefreshCcw, Save, Sparkles } from 'lucide-react'; import { YStack, XStack } from '@tamagui/stacks'; import { SizableText as Text } from '@tamagui/text'; import { Button } from '@tamagui/button'; import { AppCard, PrimaryCTA, BottomNav } from '../tamagui/primitives'; import { AdminLayout } from '../components/AdminLayout'; import { TenantEvent, getEvent, updateEvent } from '../api'; import { getApiErrorMessage } from '../lib/apiError'; import { isAuthError } from '../auth/tokens'; import { adminPath } from '../constants'; type BrandingForm = { primary: string; accent: string; headingFont: string; bodyFont: string; }; export default function EventBrandingPage() { const { slug: slugParam } = useParams<{ slug?: string }>(); const slug = slugParam ?? null; const navigate = useNavigate(); const { t } = useTranslation('management'); const [event, setEvent] = React.useState(null); const [form, setForm] = React.useState({ primary: '#007AFF', accent: '#5AD2F4', headingFont: '', bodyFont: '', }); const [loading, setLoading] = React.useState(true); const [saving, setSaving] = React.useState(false); const [error, setError] = React.useState(null); React.useEffect(() => { if (!slug) return; setLoading(true); (async () => { try { const data = await getEvent(slug); setEvent(data); const branding = extractBranding(data); setForm(branding); setError(null); } catch (err) { if (!isAuthError(err)) { setError(getApiErrorMessage(err, t('events.errors.loadFailed', 'Branding konnte nicht geladen werden.'))); } } finally { setLoading(false); } })(); }, [slug, t]); async function handleSave() { if (!event?.slug) return; setSaving(true); setError(null); try { const nextSettings = { ...(event.settings ?? {}) }; nextSettings.branding = { ...(typeof nextSettings.branding === 'object' ? (nextSettings.branding as Record) : {}), primary_color: form.primary, accent_color: form.accent, heading_font: form.headingFont, body_font: form.bodyFont, }; const updated = await updateEvent(event.slug, { settings: nextSettings }); setEvent(updated); } catch (err) { if (!isAuthError(err)) { setError(getApiErrorMessage(err, t('events.errors.saveFailed', 'Branding konnte nicht gespeichert werden.'))); } } finally { setSaving(false); } } function handleReset() { if (event) { setForm(extractBranding(event)); } } const previewTitle = event ? resolveName(event.name) : t('events.placeholders.untitled', 'Unbenanntes Event'); return ( {error ? ( {error} ) : null} {t('events.branding.previewTitle', 'Guest App Preview')} {previewTitle} {t('events.branding.previewSubtitle', 'Aktuelle Branding-Farben und Schriften')} {t('events.branding.colors', 'Colors')} setForm((prev) => ({ ...prev, primary: value }))} /> setForm((prev) => ({ ...prev, accent: value }))} /> {t('events.branding.fonts', 'Fonts')} setForm((prev) => ({ ...prev, headingFont: value }))} /> setForm((prev) => ({ ...prev, bodyFont: value }))} /> {t('events.branding.logo', 'Logo')} {t('events.branding.logoHint', 'Logo Upload folgt – nutze aktuelle Farben.')} handleSave()} /> { if (key === 'events') navigate(adminPath('/events')); if (key === 'analytics') navigate(adminPath('/dashboard')); if (key === 'settings') navigate(adminPath('/settings')); }} /> ); } function extractBranding(event: TenantEvent): BrandingForm { const source = (event.settings as Record) ?? {}; const branding = (source.branding as Record) ?? source; const readColor = (key: string, fallback: string) => { const value = branding[key]; return typeof value === 'string' && value.startsWith('#') ? value : fallback; }; const readText = (key: string) => { const value = branding[key]; return typeof value === 'string' ? value : ''; }; return { primary: readColor('primary_color', '#007AFF'), accent: readColor('accent_color', '#5AD2F4'), headingFont: readText('heading_font'), bodyFont: readText('body_font'), }; } function resolveName(name: TenantEvent['name']): string { if (typeof name === 'string') return name; if (name && typeof name === 'object') { return name.de ?? name.en ?? Object.values(name)[0] ?? ''; } return ''; } function ColorField({ label, value, onChange }: { label: string; value: string; onChange: (next: string) => void }) { return ( {label} onChange(event.target.value)} style={{ width: 52, height: 52, borderRadius: 12, border: '1px solid #e5e7eb', background: 'white' }} /> {value} ); } function ColorSwatch({ color, label }: { color: string; label: string }) { return ( {label} ); } function InputField({ label, value, placeholder, onChange, }: { label: string; value: string; placeholder?: string; onChange: (next: string) => void; }) { return ( {label} onChange(event.target.value)} style={{ width: '100%', height: 48, borderRadius: 14, border: '1px solid #e5e7eb', padding: '0 12px', fontSize: 14, }} /> ); }