91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
import React from 'react';
|
|
import { useParams } from 'react-router-dom';
|
|
import { YStack, XStack } from '@tamagui/stacks';
|
|
import { SizableText as Text } from '@tamagui/text';
|
|
import { Card } from '@tamagui/card';
|
|
import { useTranslation } from '@/guest/i18n/useTranslation';
|
|
import { useLocale } from '@/guest/i18n/LocaleContext';
|
|
import { LegalMarkdown } from '@/guest/components/legal-markdown';
|
|
import EventLogo from '../components/EventLogo';
|
|
import { useGuestThemeVariant } from '../lib/guestTheme';
|
|
|
|
export default function LegalScreen() {
|
|
const { page } = useParams<{ page: string }>();
|
|
const { t } = useTranslation();
|
|
const { locale } = useLocale();
|
|
const { isDark } = useGuestThemeVariant();
|
|
const primaryText = isDark ? '#F8FAFF' : '#0F172A';
|
|
const mutedText = isDark ? 'rgba(226, 232, 240, 0.7)' : 'rgba(15, 23, 42, 0.6)';
|
|
const cardBackground = isDark ? 'rgba(15, 23, 42, 0.75)' : 'rgba(255, 255, 255, 0.9)';
|
|
const cardBorder = isDark ? 'rgba(148, 163, 184, 0.18)' : 'rgba(15, 23, 42, 0.12)';
|
|
const brandName = 'Fotospiel';
|
|
const [loading, setLoading] = React.useState(true);
|
|
const [title, setTitle] = React.useState('');
|
|
const [body, setBody] = React.useState('');
|
|
const [html, setHtml] = React.useState('');
|
|
|
|
React.useEffect(() => {
|
|
if (!page) {
|
|
return;
|
|
}
|
|
|
|
const controller = new AbortController();
|
|
|
|
async function loadLegal() {
|
|
try {
|
|
setLoading(true);
|
|
const res = await fetch(`/api/v1/legal/${encodeURIComponent(page)}?lang=${encodeURIComponent(locale)}`, {
|
|
headers: { 'Cache-Control': 'no-store' },
|
|
signal: controller.signal,
|
|
});
|
|
if (!res.ok) {
|
|
throw new Error('failed');
|
|
}
|
|
const data = await res.json();
|
|
setTitle(data.title || '');
|
|
setBody(data.body_markdown || '');
|
|
setHtml(data.body_html || '');
|
|
} catch (error) {
|
|
if (!controller.signal.aborted) {
|
|
console.error('Failed to load legal page', error);
|
|
setTitle('');
|
|
setBody('');
|
|
setHtml('');
|
|
}
|
|
} finally {
|
|
if (!controller.signal.aborted) {
|
|
setLoading(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
loadLegal();
|
|
return () => controller.abort();
|
|
}, [page, locale]);
|
|
|
|
const fallbackTitle = page ? `Rechtliches: ${page}` : t('settings.legal.fallbackTitle', 'Rechtliche Informationen');
|
|
|
|
return (
|
|
<YStack flex={1} minHeight="100vh" padding="$5" backgroundColor={isDark ? '#0B101E' : '#FFF8F5'}>
|
|
<YStack gap="$4" maxWidth={720} width="100%" alignSelf="center">
|
|
<XStack alignItems="center" gap="$3">
|
|
<EventLogo name={brandName} size="s" />
|
|
<Text fontSize="$5" fontFamily="$display" fontWeight="$8" color={primaryText}>
|
|
{brandName}
|
|
</Text>
|
|
</XStack>
|
|
<Text fontSize="$7" fontFamily="$display" fontWeight="$9" color={primaryText}>
|
|
{title || fallbackTitle}
|
|
</Text>
|
|
<Card padding="$4" backgroundColor={cardBackground} borderColor={cardBorder} borderWidth={1}>
|
|
{loading ? (
|
|
<Text color={mutedText}>{t('settings.legal.loading', 'Lade...')}</Text>
|
|
) : (
|
|
<LegalMarkdown markdown={body} html={html} />
|
|
)}
|
|
</Card>
|
|
</YStack>
|
|
</YStack>
|
|
);
|
|
}
|