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

159 lines
5.3 KiB
TypeScript

import React from 'react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { useQuery } from '@tanstack/react-query';
import { ChevronRight, HelpCircle } from 'lucide-react';
import { YStack, XStack } 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_PROFILE_PATH } from '../constants';
import { fetchHelpCenterArticles, type HelpCenterArticleSummary } from '../api';
const FAQ_SLUGS = new Set(['admin-issue-resolution']);
function isFaqArticle(article: HelpCenterArticleSummary): boolean {
const title = article.title?.toLowerCase() ?? '';
return FAQ_SLUGS.has(article.slug) || article.slug.startsWith('faq-') || title.includes('faq');
}
export default function MobileHelpCenterPage() {
const navigate = useNavigate();
const { t, i18n } = useTranslation(['management', 'dashboard']);
const theme = useAdminTheme();
const back = useBackNavigation(ADMIN_PROFILE_PATH);
const locale = i18n.language;
const { data, isLoading, isError, refetch } = useQuery({
queryKey: ['mobile', 'help-center', locale],
queryFn: () => fetchHelpCenterArticles(locale),
});
const articles = Array.isArray(data) ? data : [];
const faqArticles = articles.filter(isFaqArticle);
const guideArticles = articles.filter((article) => !isFaqArticle(article));
return (
<MobileShell activeTab="profile" title={t('common.help', 'Help')} onBack={back}>
{isLoading ? (
<YStack space="$2">
<SkeletonCard height={120} />
<SkeletonCard height={120} />
</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 && !isError ? (
<YStack space="$3">
<HelpSection
title={t('dashboard:help.title', 'FAQ')}
icon={HelpCircle}
items={faqArticles}
emptyLabel={t('dashboard:help.description', 'Noch keine FAQ-Artikel verfügbar.')}
onSelect={(slug) => navigate(adminPath(`/mobile/help/${encodeURIComponent(slug)}`))}
/>
<HelpSection
title={t('dashboard:help.documentationTitle', 'Guides & Dokus')}
items={guideArticles}
emptyLabel={t('dashboard:help.description', 'Noch keine Help-Artikel verfügbar.')}
onSelect={(slug) => navigate(adminPath(`/mobile/help/${encodeURIComponent(slug)}`))}
/>
</YStack>
) : null}
</MobileShell>
);
}
function HelpSection({
title,
items,
emptyLabel,
icon: IconCmp,
onSelect,
}: {
title: string;
items: HelpCenterArticleSummary[];
emptyLabel: string;
icon?: React.ComponentType<{ size?: number; color?: string }>;
onSelect: (slug: string) => void;
}) {
const theme = useAdminTheme();
return (
<MobileCard padding="$0">
<YStack padding="$3" space="$2">
<XStack alignItems="center" space="$2">
{IconCmp ? (
<XStack
width={28}
height={28}
borderRadius={10}
alignItems="center"
justifyContent="center"
backgroundColor={theme.surfaceMuted}
borderWidth={1}
borderColor={theme.border}
>
<IconCmp size={14} color={theme.textStrong} />
</XStack>
) : null}
<Text fontSize="$md" fontWeight="800" color={theme.textStrong}>
{title}
</Text>
</XStack>
{items.length === 0 ? (
<Text fontSize="$sm" color={theme.muted}>
{emptyLabel}
</Text>
) : (
<YGroup {...({ borderRadius: '$4', borderWidth: 1, borderColor: theme.border, overflow: 'hidden' } as any)}>
{items.map((item) => (
<YGroup.Item key={item.slug}>
<ListItem
hoverTheme
pressTheme
paddingVertical="$2"
paddingHorizontal="$3"
onPress={() => onSelect(item.slug)}
title={
<Text fontSize="$sm" fontWeight="700" color={theme.textStrong}>
{item.title}
</Text>
}
subTitle={
item.summary ? (
<Text fontSize="$xs" color={theme.muted}>
{item.summary}
</Text>
) : undefined
}
iconAfter={<ChevronRight size={16} color={theme.muted} />}
/>
</YGroup.Item>
))}
</YGroup>
)}
</YStack>
</MobileCard>
);
}