115 lines
4.4 KiB
TypeScript
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>
|
|
);
|
|
}
|