import React from 'react'; import { Link, useParams } from 'react-router-dom'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Loader2, RefreshCcw } from 'lucide-react'; import { Page } from './_util'; import { useLocale } from '../i18n/LocaleContext'; import { useTranslation } from '../i18n/useTranslation'; import { getHelpArticles, type HelpArticleSummary } from '../services/helpApi'; import PullToRefresh from '../components/PullToRefresh'; export default function HelpCenterPage() { const params = useParams<{ token?: string }>(); const { locale } = useLocale(); const { t } = useTranslation(); const [articles, setArticles] = React.useState([]); const [query, setQuery] = React.useState(''); const [state, setState] = React.useState<'idle' | 'loading' | 'ready' | 'error'>('loading'); const [servedFromCache, setServedFromCache] = React.useState(false); const [isOnline, setIsOnline] = React.useState(() => (typeof navigator !== 'undefined' ? navigator.onLine : true)); const basePath = params.token ? `/e/${encodeURIComponent(params.token)}/help` : '/help'; const loadArticles = React.useCallback(async (forceRefresh = false) => { setState('loading'); try { const result = await getHelpArticles(locale, { forceRefresh }); setArticles(result.articles); setServedFromCache(result.servedFromCache); setState('ready'); } catch (error) { console.error('[HelpCenter] Failed to load articles', error); setState('error'); } }, [locale]); React.useEffect(() => { loadArticles(); }, [loadArticles]); React.useEffect(() => { if (typeof window === 'undefined') { return; } const handleOnline = () => setIsOnline(true); const handleOffline = () => setIsOnline(false); window.addEventListener('online', handleOnline); window.addEventListener('offline', handleOffline); return () => { window.removeEventListener('online', handleOnline); window.removeEventListener('offline', handleOffline); }; }, []); const showOfflineBadge = servedFromCache && !isOnline; const filteredArticles = React.useMemo(() => { if (!query.trim()) { return articles; } const needle = query.trim().toLowerCase(); return articles.filter((article) => `${article.title} ${article.summary}`.toLowerCase().includes(needle), ); }, [articles, query]); return ( loadArticles(true)} pullLabel={t('common.pullToRefresh')} releaseLabel={t('common.releaseToRefresh')} refreshingLabel={t('common.refreshing')} >

{t('help.center.subtitle')}

setQuery(event.target.value)} className="flex-1" aria-label={t('help.center.searchPlaceholder')} />
{showOfflineBadge && (
{t('help.center.offlineBadge')} {t('help.center.offlineDescription')}
)}

{t('help.center.listTitle')}

{state === 'loading' && (
{t('common.actions.loading')}
)} {state === 'error' && (

{t('help.center.error')}

)} {state === 'ready' && filteredArticles.length === 0 && (
{t('help.center.empty')}
)} {state === 'ready' && filteredArticles.length > 0 && (
{filteredArticles.map((article) => (

{article.title}

{article.summary}

{article.updated_at ? formatDate(article.updated_at, locale) : ''}
))}
)}
); } function formatDate(value: string, locale: string): string { try { return new Date(value).toLocaleDateString(locale, { day: '2-digit', month: 'short', year: 'numeric', }); } catch { return value; } }