import { useState, useEffect } from "react"; import { Badge } from "@/components/ui/badge"; import { ClipboardCheck, CheckCheck, SendHorizonal, Lock, Zap, Info, Tag } from "lucide-react"; import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area"; import ResponsiveModal from "@/components/generic/ResponsiveModal"; import { Button } from "@/components/ui/button"; import { useNavigate } from "react-router-dom"; import api from "@/utils/api.util"; import { useClientTiers } from "@/contexts/ClientTiersProvider"; import { resolveTierBadge } from "@/utils/tierBadge.util"; function TierBadge({ tier }) { const { tierMap } = useClientTiers(); const { rank, label, cls } = resolveTierBadge(tier ?? 'free', tierMap); return ( {rank > 0 ? : } {label} ); } // ─── PassQuiz — task requirement block for pass_quiz type ───────────────────── // Mirrors ReadUnit.jsx's fetch-detail-and-navigate pattern. A quiz is always // unit-scoped; navigation goes into the course reader if the unit is attached // to a course, otherwise the standalone unit reader. const PassQuiz = ({ title = "Pass Quizzes", quizzes = [], groupId, taskListId, taskId }) => { const navigate = useNavigate(); const [details, setDetails] = useState({}); const [locked, setLocked] = useState({}); const [lockedInfo, setLockedInfo] = useState({}); const [unavailable, setUnavailable] = useState({}); const [fetching, setFetching] = useState({}); const [selected, setSelected] = useState(null); useEffect(() => { quizzes.forEach(async (q) => { if (!q.reference_id) return; setFetching((prev) => ({ ...prev, [q.reference_id]: true })); try { const res = await api.get(`/client/courses/quiz/uuid/${q.reference_id}`); const d = res.data?.data; if (d) setDetails((prev) => ({ ...prev, [q.reference_id]: d })); } catch (err) { if (err?.response?.status === 403) { setLocked((prev) => ({ ...prev, [q.reference_id]: true })); const course = err.response?.data?.course; if (course) setLockedInfo((prev) => ({ ...prev, [q.reference_id]: course })); } else { setUnavailable((prev) => ({ ...prev, [q.reference_id]: true })); } } finally { setFetching((prev) => ({ ...prev, [q.reference_id]: false })); } }); }, []); const goToQuiz = (info) => { if (!info) return; const taskCtx = taskId ? { has_task: true, groupId, taskListId, taskId } : undefined; if (info.unit?.course?.course_id) { navigate(`/course/${info.unit.course.course_id}/unit`, { state: { quizUnitId: info.unit.unit_id, ...(taskCtx ? { taskCtx } : {}) }, }); } else if (info.unit?.uuid) { navigate(`/units/${info.unit.uuid}/read`, { state: { quizId: true } }); } }; if (!quizzes.length) return null; const hasLocked = Object.values(locked).some(Boolean); return ( <>

{title}

{quizzes.length}
{hasLocked && (

Subscription Required

To complete this activity, subscribe to one of our available tier plans.

)}
{quizzes.map((q) => { const info = details[q.reference_id]; const courseInfo = lockedInfo[q.reference_id]; const isLocked = locked[q.reference_id]; const isUnavailable = unavailable[q.reference_id]; const isFetching = fetching[q.reference_id]; const passed = info?.has_passed || q.completed; if (isLocked) { return (
navigate('/plans')} className="bg-card rounded-2xl border border-dashed p-4 flex flex-col gap-3 hover:bg-muted/60 hover:shadow-sm transition-all cursor-pointer group w-80 shrink-0 opacity-80" >
Quiz

{q.title}

Subscribe to {courseInfo?.title ?? 'this course'} to unlock this quiz.

); } if (isUnavailable) { return (
Quiz Unavailable

{q.title}

This quiz is no longer available.

); } return (
!isFetching && setSelected(q)} className={`bg-card rounded-2xl border p-4 flex flex-col gap-3 transition-all w-80 shrink-0 ${ isFetching ? 'opacity-60 cursor-wait' : 'hover:bg-muted/60 hover:shadow-sm cursor-pointer group' }`} >
Quiz
{info?.unit?.course?.subscription ? : isFetching && Loading… }
{info?.unit?.title && (

in {info.unit.title}

)}

{q.title}

{passed ? ( Passed ) : ( Not Attempted )} {info?.passing_score && ( {info.passing_score}% to pass )}
); })}
!v && setSelected(null)} title={selected?.title} description="Quiz Info" footer={ <> } > {selected && (() => { const info = details[selected.reference_id]; return (
{(info?.has_passed || selected.completed) && (
Already Passed
)} {info?.unit?.title && (

Unit: {info.unit.title}

)} {info?.passing_score && (

Passing score: {info.passing_score}%

)}
); })()}
); }; export default PassQuiz;