import React from 'react';
import { Link } from 'react-router-dom';
import { YStack, XStack } from '@tamagui/stacks';
import { SizableText as Text } from '@tamagui/text';
import { Button } from '@tamagui/button';
import { Input } from '@tamagui/input';
import { Card } from '@tamagui/card';
import { Switch } from '@tamagui/switch';
import { Check, Moon, RotateCcw, Sun, Languages, FileText, LifeBuoy } from 'lucide-react';
import { useTranslation } from '@/guest/i18n/useTranslation';
import { useLocale } from '@/guest/i18n/LocaleContext';
import { useOptionalGuestIdentity } from '../context/GuestIdentityContext';
import { useHapticsPreference } from '@/guest/hooks/useHapticsPreference';
import { triggerHaptic } from '@/guest/lib/haptics';
import { useConsent } from '@/contexts/consent';
import { useAppearance } from '@/hooks/use-appearance';
import { useEventData } from '../context/EventDataContext';
import { buildEventPath } from '../lib/routes';
import { useGuestThemeVariant } from '../lib/guestTheme';
const legalLinks = [
{ slug: 'impressum', labelKey: 'settings.legal.section.impressum', fallback: 'Impressum' },
{ slug: 'datenschutz', labelKey: 'settings.legal.section.privacy', fallback: 'Datenschutz' },
{ slug: 'agb', labelKey: 'settings.legal.section.terms', fallback: 'AGB' },
] as const;
type SettingsContentProps = {
onNavigate?: () => void;
showHeader?: boolean;
onOpenLegal?: (slug: (typeof legalLinks)[number]['slug'], labelKey: (typeof legalLinks)[number]['labelKey']) => void;
};
export default function SettingsContent({ onNavigate, showHeader = true, onOpenLegal }: SettingsContentProps) {
const { t } = useTranslation();
const locale = useLocale();
const identity = useOptionalGuestIdentity();
const { enabled: hapticsEnabled, setEnabled: setHapticsEnabled, supported: hapticsSupported } = useHapticsPreference();
const { preferences, savePreferences } = useConsent();
const matomoEnabled = typeof window !== 'undefined' && Boolean((window as any).__MATOMO_GUEST__?.enabled);
const { appearance, updateAppearance } = useAppearance();
const { isDark } = useGuestThemeVariant();
const { token } = useEventData();
const cardBackground = isDark ? 'rgba(15, 23, 42, 0.65)' : 'rgba(255, 255, 255, 0.82)';
const cardBorder = isDark ? 'rgba(148, 163, 184, 0.18)' : 'rgba(15, 23, 42, 0.12)';
const primaryText = isDark ? '#F8FAFF' : '#0F172A';
const mutedText = isDark ? 'rgba(226, 232, 240, 0.7)' : 'rgba(15, 23, 42, 0.6)';
const mutedButton = isDark ? 'rgba(248, 250, 255, 0.08)' : 'rgba(15, 23, 42, 0.06)';
const mutedButtonBorder = isDark ? 'rgba(248, 250, 255, 0.2)' : 'rgba(15, 23, 42, 0.12)';
const [nameDraft, setNameDraft] = React.useState(identity?.name ?? '');
const [status, setStatus] = React.useState<'idle' | 'saved'>('idle');
const helpPath = token ? buildEventPath(token, '/help') : '/help';
const supportsInlineLegal = Boolean(onOpenLegal);
React.useEffect(() => {
if (identity?.hydrated) {
setNameDraft(identity.name ?? '');
setStatus('idle');
}
}, [identity?.hydrated, identity?.name]);
const canSaveName = Boolean(
identity?.hydrated && nameDraft.trim() && nameDraft.trim() !== (identity?.name ?? '')
);
const handleSaveName = React.useCallback(() => {
if (!identity || !canSaveName) {
return;
}
identity.setName(nameDraft);
setStatus('saved');
window.setTimeout(() => setStatus('idle'), 2000);
}, [identity, nameDraft, canSaveName]);
const handleResetName = React.useCallback(() => {
if (!identity) {
return;
}
identity.clearName();
setNameDraft('');
setStatus('idle');
}, [identity]);
return (
{showHeader ? (
{t('settings.title', 'Settings')}
{t('settings.subtitle', 'Make this app yours.')}
) : null}
{locale.availableLocales.map((option) => (
))}
{t('settings.name.title', 'Your name')}
{status === 'saved' ? (
{t('settings.name.saved', 'Saved')}
) : null}
{t('settings.haptics.label', 'Haptic feedback')}
{
setHapticsEnabled(checked);
if (checked) {
triggerHaptic('selection');
}
}}
aria-label="haptics-toggle"
backgroundColor={hapticsEnabled ? '$primary' : mutedButton}
borderColor={mutedButtonBorder}
borderWidth={1}
>
{!hapticsSupported ? (
{t('settings.haptics.unsupported', 'Haptics are not available on this device.')}
) : null}
{matomoEnabled ? (
{t('settings.analytics.label', 'Share anonymous analytics')}
savePreferences({ analytics: checked })}
backgroundColor={preferences?.analytics ? '$primary' : mutedButton}
borderColor={mutedButtonBorder}
borderWidth={1}
>
{t('settings.analytics.note', 'You can change this anytime.')}
) : null}
{t('settings.legal.title', 'Legal')}
{legalLinks.map((page) => {
const label = t(page.labelKey, page.fallback);
if (supportsInlineLegal) {
return (
);
}
return (
);
})}
{t('settings.cache.title', 'Offline cache')}
{t('settings.cache.note', 'This only affects this browser. Pending uploads may be lost.')}
{t('settings.help.title', 'Help Center')}
);
}
function ClearCacheButton() {
const { t } = useTranslation();
const [busy, setBusy] = React.useState(false);
const [done, setDone] = React.useState(false);
const { isDark } = useGuestThemeVariant();
const mutedButton = isDark ? 'rgba(248, 250, 255, 0.08)' : 'rgba(15, 23, 42, 0.06)';
const mutedButtonBorder = isDark ? 'rgba(248, 250, 255, 0.2)' : 'rgba(15, 23, 42, 0.12)';
const mutedText = isDark ? 'rgba(226, 232, 240, 0.7)' : 'rgba(15, 23, 42, 0.6)';
const clearAll = React.useCallback(async () => {
setBusy(true);
setDone(false);
try {
if ('caches' in window) {
const keys = await caches.keys();
await Promise.all(keys.map((key) => caches.delete(key)));
}
if ('indexedDB' in window) {
const databases = ['guest-upload-queue', 'upload-queue'];
await Promise.all(
databases.map(
(name) =>
new Promise((resolve) => {
const request = indexedDB.deleteDatabase(name);
request.onsuccess = () => resolve(null);
request.onerror = () => resolve(null);
})
)
);
}
setDone(true);
} finally {
setBusy(false);
window.setTimeout(() => setDone(false), 2500);
}
}, []);
return (
{done ? (
{t('settings.cache.cleared', 'Cache cleared.')}
) : null}
);
}