"use client"; import Link from "next/link"; import { useParams, useRouter } from "next/navigation"; import { useEffect } from "react"; import { useQuery } from "@tanstack/react-query"; import { ArrowRight, Lock, TreePine } from "lucide-react"; import { VideoPlayer } from "@/components/video-player"; import { NotFoundState, notFoundSentence } from "@/components/not-found-state"; import { ApiError, http, toUserError } from "@/lib/api"; import type { Lesson, LessonProgress } from "@/lib/types"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Skeleton } from "@/components/ui/skeleton"; import { useAuth } from "@/lib/auth-store"; import { formatFaNumber } from "@/lib/utils"; import { hasInfiniteHearts } from "@/lib/hearts"; function isLessonLockedError(error: unknown): boolean { if (!(error instanceof ApiError)) return false; if (error.status !== 403) return false; return error.message.includes("قفل"); } export default function PlayerPage() { const { lessonId } = useParams<{ lessonId: string }>(); const id = Number(lessonId); const idOk = Number.isFinite(id) && id > 0; const router = useRouter(); const user = useAuth((s) => s.user); const { data, isLoading, isError, error, refetch } = useQuery({ queryKey: ["lesson", id], queryFn: () => http.get<{ lesson: Lesson; videoUrl: string; videoIsSample?: boolean; progress: LessonProgress | null; quizStatus: string; }>(`/api/lessons/${id}`), enabled: idOk && !!user && (!user.isLocked || hasInfiniteHearts(user.role)), staleTime: 5 * 60_000, retry: (count, err) => { if (isLessonLockedError(err)) return false; return count < 2; }, }); useEffect(() => { if (user?.isLocked && !hasInfiniteHearts(user.role)) router.replace("/lockout"); }, [user?.isLocked, user?.role, router]); if (user?.isLocked && !hasInfiniteHearts(user.role)) { return null; } if (!idOk) { return ( ); } if (isLoading) { return (
); } if (isError || !data) { if (isLessonLockedError(error)) { return router.push("/cap")} />; } if (error instanceof ApiError && error.status === 404) { return ( ); } return (

{toUserError(error, "بارگذاری درس ممکن نشد")}

); } const { lesson, videoUrl, videoIsSample, progress, quizStatus } = data; const passed = !!progress?.passedQuiz; return (

{lesson.title}

{lesson.description}

{videoIsSample && ( نمونهٔ موقت )} {passed ? ( تکمیل شده ) : ( {formatFaNumber(lesson.xpReward)} امتیاز پاداش )}
{videoUrl ? (
{videoIsSample && (

ویدیوی اختصاصی هنوز وصل نشده — sample.mp4 به‌عنوان حداقل پخش نمایش داده می‌شود تا پلیر خالی نماند.

)}
) : (
این درس هنوز ویدیو ندارد.
)}
آزمون با {`≥${lesson.completionThresholdPct}`}٪ زمان تماشای تاییدشده باز می‌شود. {quizStatus === "failed" && ( تلاش قبلی ناموفق بود — هر وقت آماده بودید دوباره تلاش کنید. )}
{passed && ( )}
); } function LockedLessonState({ onBack }: { onBack: () => void }) { return (

پیش‌نیاز باز نشده

این درس هنوز قفل است

اول درس قبلی را کامل تماشا کنید و در آزمونش قبول شوید؛ بعد این شاخه خودش باز می‌شود.

); }