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"
>
{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;