import { useEffect, useMemo, useState } from 'react'; import { Link } from 'framework7-react'; import { apiClient, Challenge, errorMessage } from '../services/api'; import Screen from '../components/Screen'; import AiPanel from '../components/AiPanel'; import { FEATURES } from '../features'; import Skeleton from '../components/Skeleton'; import './Challenges.css'; const KIND_LABEL: Record = { badge: '徽章挑战', adhoc: '好友挑战', available: '可参加', inprogress: '进行中', }; /** Percentage complete, if the payload carries a target and a total. */ function progressOf(c: Challenge): number | null { const p = c.payload || {}; const target = p.badgeTargetValue ?? p.targetValue ?? p.challengeTargetValue; const current = p.userRankValue ?? p.badgeProgressValue ?? p.currentValue; if (!target || current == null) return null; return Math.min(100, Math.round((Number(current) / Number(target)) * 100)); } function ChallengesPage() { const [rows, setRows] = useState([]); const [kind, setKind] = useState('all'); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); useEffect(() => { apiClient .getChallenges() .then(setRows) .catch((err) => setError(errorMessage(err, '加载失败'))) .finally(() => setLoading(false)); }, []); const kinds = useMemo( () => ['all', ...Array.from(new Set(rows.map((r) => r.kind)))], [rows] ); const shown = kind === 'all' ? rows : rows.filter((r) => r.kind === kind); if (loading) return ; return ( {error &&
{error}
} {rows.length === 0 ? (

还没有挑战赛数据。

去同步
) : ( <> {FEATURES.ai && } {kinds.length > 2 && (
{kinds.map((k) => ( ))}
)}
{shown.map((c, i) => { const pct = progressOf(c); return (
{c.name || '未命名挑战'} {KIND_LABEL[c.kind] ?? c.kind}
{(c.startDate || c.endDate) && (
{c.startDate} {c.endDate ? `→ ${c.endDate}` : ''}
)} {pct != null && ( <>
{pct}%
)}
); })}
)} ); } export default ChallengesPage;