import { useEffect, useRef, useState } from 'react'; import { Bell, ChevronLeft, Coins, Crown, Flame, Hand, PartyPopper, Star } from 'lucide-react'; import type { HomeNode } from '@/api'; import { useAppData } from '@/state/AppData'; import { findContinue, unitColor, unitProgress } from '@/state/curriculum'; import { useNav } from '@/nav/Navigator'; import { SeyarMascot } from '@/mascots/SeyarMascot'; import { IslandPath } from '@/components/IslandPath'; import { IslandSheet } from '@/components/IslandSheet'; import { EmptyState, ErrorState, LoadingState, Screen, Sep } from '@/components/ui'; import { onWhite, shade } from '@/lib/color'; import { toFa } from '@/lib/format'; import { MathText } from '@/lib/MathText'; import { BrandFooter } from '@/components/BrandFooter'; import { BrandMark } from '@/components/BrandMark'; import { StreakFlame, flameState } from '@/components/StreakFlame'; /** * خانه = خودِ مسیر، مثلِ دولینگو: همه‌ی فصل‌های پایه پشتِ هم، و جزیره‌ی فعلی با * یک دکمه‌ی «شروع» روی سرش. قبلاً خانه داشبوردی از شش کارت بود (ادامه، نقشه، * دستیار، فصل‌ها، چالش) و بچه نمی‌دانست کدام را بزند؛ حالا یک کارِ واضح دارد. */ export function HomeScreen() { const { profile, gradeTitle, summary, home, homeError, companion, unreadCount, refreshHome } = useAppData(); const nav = useNav(); // فصلِ غیرِ اول بی‌اشتراک: زدنِ جزیره یک‌راست فهرستِ اشتراک‌ها را باز می‌کند. const paywall = () => nav.push({ name: 'subscription', view: 'subscription' }); const [openNode, setOpenNode] = useState<{ node: HomeNode; color: string } | null>(null); const currentRef = useRef(null); const scrolled = useRef(false); const cont = findContinue(home); // بارِ اول تا جزیره‌ی فعلی اسکرول کن، نه هر بار که نقشه تازه می‌شود. useEffect(() => { if (!home || scrolled.current) return; scrolled.current = true; const frame = requestAnimationFrame(() => currentRef.current?.scrollIntoView({ block: 'center' })); return () => cancelAnimationFrame(frame); }, [home]); const name = profile.name || 'دوستِ من'; const flame = flameState(summary?.streak); const streak = summary?.streak; // زنجیره‌ی در خطر یا یخ‌زده جلوتر از پیامِ معمول می‌آید: از دست دادن انگیزه‌ی قوی‌تری از به‌دست آوردن است، // ولی لحن مهربان می‌ماند و قدمِ بعدی را می‌گوید. const streakNote = cont && streak ? flame === 'frozen' ? <>{name}، زنجیره‌ی {toFa(streak.lost)} روزه‌ت یخ زد یه جزیره بزن تا دوباره آتیشش روشن بشه! : flame === 'risk' ? <>{name}، امروز هنوز تمرین نکردی! زنجیره‌ی {toFa(streak.current)} روزه‌ت منتظرته : null : null; const bubble = !home ? 'دارم مسیرت رو میارم…' : !home.units.length ? 'هنوز درسی برای این پایه ثبت نشده.' : streakNote ? streakNote : cont ? <>سلام {name}! وقتشه جزیره‌ی «» رو شروع کنی؛ دکمه‌ی شروع رو بزن. : <>آفرین {name}! همه‌ی جزیره‌های این پایه رو تموم کردی ; const stats = [ { icon: Flame, value: summary?.streak.current ?? 0, label: 'روزِ پیاپی', color: '#FF7A3D', fill: true, to: 'streak' as const }, { icon: Star, value: summary?.xp ?? 0, label: 'امتیاز', color: '#E8A400', fill: true, to: 'leaderboard' as const }, { icon: Coins, value: summary?.coins ?? 0, label: 'سکه', color: '#9B7BFF', fill: false, to: 'characters' as const }, ]; return (
{gradeTitle && ( )}
{stats.map(({ icon: Icon, value, label, color, fill, to }) => ( ))}
{bubble}
{!home ? ( homeError ? void refreshHome()} /> : ) : home.units.length === 0 ? ( ) : (
{home.units.map((unit, i) => { const color = unitColor(i); const p = unitProgress(unit); const isCurrentUnit = cont?.unit.id === unit.id; return (
(unit.requiresSubscription ? paywall() : setOpenNode({ node, color }))} onStart={(node) => (unit.requiresSubscription ? paywall() : nav.push({ name: 'quiz', nodeId: node.id }))} />
); })}
)}
setOpenNode(null)} />
); }