Files
fotospiel-app/resources/js/admin/mobile/HelpArticlePage.tsx
2026-01-23 08:55:37 +01:00

115 lines
4.4 KiB
TypeScript

import React from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useQuery } from '@tanstack/react-query';
import { ChevronRight } from 'lucide-react';
import { YStack } from '@tamagui/stacks';
import { SizableText as Text } from '@tamagui/text';
import { YGroup } from '@tamagui/group';
import { ListItem } from '@tamagui/list-item';
import { MobileShell } from './components/MobileShell';
import { MobileCard, CTAButton, SkeletonCard } from './components/Primitives';
import { useAdminTheme } from './theme';
import { useBackNavigation } from './hooks/useBackNavigation';
import { adminPath, ADMIN_FAQ_PATH } from '../constants';
import { fetchHelpCenterArticle, type HelpCenterArticle } from '../api';
export default function MobileHelpArticlePage() {
const { slug } = useParams<{ slug: string }>();
const { t, i18n } = useTranslation(['management', 'dashboard']);
const theme = useAdminTheme();
const back = useBackNavigation(ADMIN_FAQ_PATH);
const navigate = useNavigate();
const locale = i18n.language;
const { data, isLoading, isError, refetch } = useQuery({
queryKey: ['mobile', 'help-article', slug, locale],
enabled: Boolean(slug),
queryFn: () => fetchHelpCenterArticle(slug ?? '', locale),
});
const article: HelpCenterArticle | null = data ?? null;
return (
<MobileShell activeTab="profile" title={article?.title ?? t('common.help', 'Help')} onBack={back}>
{isLoading ? (
<YStack space="$2">
<SkeletonCard height={120} />
<SkeletonCard height={160} />
</YStack>
) : null}
{isError ? (
<MobileCard>
<YStack space="$2">
<Text fontSize="$sm" fontWeight="700" color={theme.textStrong}>
{t('dashboard:help.error', 'Help could not be loaded.')}
</Text>
<CTAButton
label={t('common.retry', 'Erneut versuchen')}
onPress={() => refetch()}
fullWidth={false}
/>
</YStack>
</MobileCard>
) : null}
{!isLoading && article ? (
<YStack space="$3">
<MobileCard>
<YStack space="$2">
<Text fontSize="$lg" fontWeight="800" color={theme.textStrong}>
{article.title}
</Text>
{article.updated_at ? (
<Text fontSize="$xs" color={theme.muted}>
{t('help.article.updated', 'Aktualisiert')}:{' '}
{new Date(article.updated_at).toLocaleDateString(locale, {
day: '2-digit',
month: 'short',
year: 'numeric',
})}
</Text>
) : null}
<div
className="prose prose-sm max-w-none dark:prose-invert [&_table]:w-full [&_table]:text-sm [&_:where(p,ul,ol,li)]:text-foreground [&_:where(h1,h2,h3,h4,h5,h6)]:text-foreground"
dangerouslySetInnerHTML={{ __html: article.body_html ?? article.body_markdown ?? '' }}
/>
</YStack>
</MobileCard>
{article.related && article.related.length > 0 ? (
<MobileCard>
<YStack space="$2">
<Text fontSize="$sm" fontWeight="700" color={theme.textStrong}>
{t('help.article.relatedTitle', 'Weitere Artikel')}
</Text>
<YGroup {...({ borderRadius: '$4', borderWidth: 1, borderColor: theme.border, overflow: 'hidden' } as any)}>
{article.related.map((rel) => (
<YGroup.Item key={rel.slug}>
<ListItem
hoverTheme
pressTheme
paddingVertical="$2"
paddingHorizontal="$3"
onPress={() => navigate(adminPath(`/mobile/help/${encodeURIComponent(rel.slug)}`))}
title={
<Text fontSize="$sm" color={theme.textStrong}>
{rel.title ?? rel.slug}
</Text>
}
iconAfter={<ChevronRight size={16} color={theme.muted} />}
/>
</YGroup.Item>
))}
</YGroup>
</YStack>
</MobileCard>
) : null}
</YStack>
) : null}
</MobileShell>
);
}