import { jsx, jsxs } from "react/jsx-runtime"; import { c as cn } from "./utils-DLCPGU0v.js"; import { B as Button } from "./button-CdJZJLGw.js"; import { I as Index } from "./index-CzkkaexN.js"; import { M as Main } from "./main-BKBelQb-.js"; import { Head, router } from "@inertiajs/react"; import { ChevronLeft, ChevronRight, AlertTriangle } from "lucide-react"; import { useState, useEffect } from "react"; import AttemptNavbar from "./attempt-navbar-2WlfrPQ4.js"; import QuestionNavigator from "./question-navigator-BNETVdM2.js"; import QuestionRenderer from "./question-renderer-CEDeFJdm.js"; import TimerComponent from "./timer-component-BZ0pE4jM.js"; import "clsx"; import "tailwind-merge"; import "@radix-ui/react-slot"; import "class-variance-authority"; import "./app-logo-DWyi5bLn.js"; import "lucide-react/dynamic"; import "next-themes"; import "sonner"; import "./use-screen-B7SDA5zE.js"; import "./badge-J-zeQvMg.js"; import "./card-B-gBwpxd.js"; import "./question-type-badge-CdL_99ID.js"; import "./fill-blank-question-DHOFVwov.js"; import "./input-BsvJqbcd.js"; import "./label-0rIIfpX0.js"; import "@radix-ui/react-label"; import "./listening-question-XvCsGH9c.js"; import "./radio-group-Wf8uu9ZY.js"; import "@radix-ui/react-radio-group"; import "./slider-6gv2Y3fS.js"; import "@radix-ui/react-slider"; import "./matching-question-BNHgZgyB.js"; import "./select-BYx0MCUK.js"; import "@radix-ui/react-select"; import "./mcq-question-C6ifvSYZ.js"; import "./multiple-select-question-Cokv890S.js"; import "./checkbox--3Zj5G-w.js"; import "@radix-ui/react-checkbox"; import "./ordering-question-DQb6NScg.js"; import "./short-answer-question-aygLWm6w.js"; import "./textarea-Z0d4V-ti.js"; const AlertDialog = ({ open, onOpenChange, children }) => { if (!open) return null; return /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-50 flex items-center justify-center", children: [ /* @__PURE__ */ jsx( "div", { className: "fixed inset-0 bg-black/80", onClick: () => onOpenChange(false) } ), /* @__PURE__ */ jsx("div", { className: "relative z-50", children }) ] }); }; const AlertDialogContent = ({ className, children, ...props }) => /* @__PURE__ */ jsx( "div", { className: cn( "w-full max-w-lg bg-white border rounded-lg shadow-lg p-6 space-y-4", className ), ...props, children } ); const AlertDialogHeader = ({ className, children, ...props }) => /* @__PURE__ */ jsx( "div", { className: cn("space-y-2", className), ...props, children } ); const AlertDialogFooter = ({ className, children, ...props }) => /* @__PURE__ */ jsx( "div", { className: cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className), ...props, children } ); const AlertDialogTitle = ({ className, children, ...props }) => /* @__PURE__ */ jsx( "h2", { className: cn("text-lg font-semibold", className), ...props, children } ); const AlertDialogDescription = ({ className, children, ...props }) => /* @__PURE__ */ jsx( "p", { className: cn("text-sm text-gray-600", className), ...props, children } ); const AlertDialogAction = ({ className, children, ...props }) => /* @__PURE__ */ jsx( Button, { className: cn("", className), ...props, children } ); const AlertDialogCancel = ({ className, children, ...props }) => /* @__PURE__ */ jsx( Button, { variant: "outline", className: cn("mt-2 sm:mt-0", className), ...props, children } ); const TakeExam = ({ attempt }) => { const [currentQuestionIndex, setCurrentQuestionIndex] = useState(0); const [answers, setAnswers] = useState({}); const [markedQuestions, setMarkedQuestions] = useState(/* @__PURE__ */ new Set()); const [showSubmitDialog, setShowSubmitDialog] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const durationSeconds = ((attempt.exam.duration_hours || 0) * 60 + (attempt.exam.duration_minutes || 0)) * 60; const attemptStart = attempt.start_time ? new Date(attempt.start_time).getTime() : Date.now(); const effectiveDuration = durationSeconds > 0 ? durationSeconds : 60 * 60; const computedDeadline = attempt.end_time ? attempt.end_time : new Date(attemptStart + effectiveDuration * 1e3).toISOString(); const questions = attempt.exam.questions || []; const currentQuestion = questions[currentQuestionIndex]; const answeredQuestions = new Set(Object.keys(answers).map(Number)); useEffect(() => { const savedAnswers = localStorage.getItem(`exam-attempt-${attempt.id}`); if (savedAnswers) { try { const parsed = JSON.parse(savedAnswers); setAnswers(parsed.answers || {}); setMarkedQuestions(new Set(parsed.marked || [])); } catch (error) { console.error("Failed to load saved answers:", error); } } }, [attempt.id]); useEffect(() => { const interval = setInterval(() => { saveToLocalStorage(); }, 3e4); return () => clearInterval(interval); }, [answers, markedQuestions]); useEffect(() => { const handleBeforeUnload = (e) => { e.preventDefault(); e.returnValue = ""; }; window.addEventListener("beforeunload", handleBeforeUnload); return () => window.removeEventListener("beforeunload", handleBeforeUnload); }, []); const saveToLocalStorage = () => { localStorage.setItem( `exam-attempt-${attempt.id}`, JSON.stringify({ answers, marked: Array.from(markedQuestions), lastSaved: (/* @__PURE__ */ new Date()).toISOString() }) ); }; const saveAnswerToBackend = async (questionId, answer) => { await router.post( route("exam-attempts.answer", attempt.id), { question_id: questionId, answer_data: answer }, { preserveScroll: true, preserveState: true } ); }; const handleAnswerChange = (answer) => { if (!currentQuestion) return; setAnswers((prev) => ({ ...prev, [currentQuestion.id]: answer })); saveAnswerToBackend(currentQuestion.id, answer); saveToLocalStorage(); }; const handlePrevious = () => { if (currentQuestionIndex > 0) { setCurrentQuestionIndex(currentQuestionIndex - 1); } }; const handleNext = () => { if (currentQuestionIndex < questions.length - 1) { setCurrentQuestionIndex(currentQuestionIndex + 1); } }; const handleSubmit = async () => { setIsSubmitting(true); saveToLocalStorage(); const formattedAnswers = Object.entries(answers).map(([questionId, value]) => ({ exam_question_id: Number(questionId), answer_data: value })); router.post( route("exam-attempts.submit", attempt.id), { exam_attempt_id: attempt.id, answers: formattedAnswers }, { onError: (errors) => { console.log(errors); }, onSuccess: () => { localStorage.removeItem(`exam-attempt-${attempt.id}`); }, onFinish: () => { setIsSubmitting(false); } } ); }; useEffect(() => { const handleKeyPress = (e) => { if (e.key === "ArrowRight" && currentQuestionIndex < questions.length - 1) { handleNext(); } else if (e.key === "ArrowLeft" && currentQuestionIndex > 0) { handlePrevious(); } }; window.addEventListener("keydown", handleKeyPress); return () => window.removeEventListener("keydown", handleKeyPress); }, [currentQuestionIndex, questions.length]); const unansweredCount = questions.length - answeredQuestions.size; return /* @__PURE__ */ jsxs(Main, { children: [ /* @__PURE__ */ jsx(Head, { title: `Taking: ${attempt.exam.title}` }), /* @__PURE__ */ jsxs("main", { className: "flex min-h-screen flex-col justify-between overflow-x-hidden", children: [ /* @__PURE__ */ jsx(AttemptNavbar, { attempt, questionIndex: currentQuestionIndex }), /* @__PURE__ */ jsxs("div", { className: "container py-12", children: [ /* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-4 lg:grid-cols-4", children: [ /* @__PURE__ */ jsxs("div", { className: "space-y-4 lg:col-span-3", children: [ /* @__PURE__ */ jsx(TimerComponent, { attempt, endTime: computedDeadline, questionIndex: currentQuestionIndex }), currentQuestion && /* @__PURE__ */ jsx( QuestionRenderer, { question: currentQuestion, questionNumber: currentQuestionIndex + 1, answer: answers[currentQuestion.id], onAnswerChange: handleAnswerChange } ), /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between rounded-lg bg-white p-4 shadow", children: [ /* @__PURE__ */ jsxs(Button, { onClick: handlePrevious, disabled: currentQuestionIndex === 0, variant: "outline", children: [ /* @__PURE__ */ jsx(ChevronLeft, { className: "mr-2 h-4 w-4" }), "Previous" ] }), currentQuestionIndex < questions.length - 1 ? /* @__PURE__ */ jsxs(Button, { onClick: handleNext, children: [ "Next", /* @__PURE__ */ jsx(ChevronRight, { className: "ml-2 h-4 w-4" }) ] }) : /* @__PURE__ */ jsx(Button, { onClick: () => setShowSubmitDialog(true), variant: "default", children: "Submit Exam" }) ] }) ] }), /* @__PURE__ */ jsx("div", { className: "lg:col-span-1", children: /* @__PURE__ */ jsx( QuestionNavigator, { questions, currentQuestionIndex, answeredQuestions, markedQuestions, onNavigate: setCurrentQuestionIndex } ) }) ] }) }), /* @__PURE__ */ jsx(AlertDialog, { open: showSubmitDialog, onOpenChange: setShowSubmitDialog, children: /* @__PURE__ */ jsxs(AlertDialogContent, { children: [ /* @__PURE__ */ jsxs(AlertDialogHeader, { children: [ /* @__PURE__ */ jsxs(AlertDialogTitle, { className: "flex items-center gap-2", children: [ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-5 w-5 text-yellow-600" }), "Submit Exam?" ] }), /* @__PURE__ */ jsxs(AlertDialogDescription, { className: "space-y-3", children: [ /* @__PURE__ */ jsx("p", { children: "Are you sure you want to submit your exam? This action cannot be undone." }), unansweredCount > 0 && /* @__PURE__ */ jsx("div", { className: "rounded-lg bg-yellow-50 p-3", children: /* @__PURE__ */ jsxs("p", { className: "text-sm font-semibold text-yellow-800", children: [ "Warning: You have ", unansweredCount, " unanswered question", unansweredCount > 1 ? "s" : "", "!" ] }) }), /* @__PURE__ */ jsxs("div", { className: "text-sm", children: [ /* @__PURE__ */ jsxs("p", { children: [ /* @__PURE__ */ jsx("strong", { children: "Answered:" }), " ", answeredQuestions.size, " / ", questions.length ] }), /* @__PURE__ */ jsxs("p", { children: [ /* @__PURE__ */ jsx("strong", { children: "Marked for review:" }), " ", markedQuestions.size ] }) ] }) ] }) ] }), /* @__PURE__ */ jsxs(AlertDialogFooter, { children: [ /* @__PURE__ */ jsx(AlertDialogCancel, { onClick: () => setShowSubmitDialog(false), children: "Cancel" }), /* @__PURE__ */ jsx(AlertDialogAction, { onClick: handleSubmit, disabled: isSubmitting, children: isSubmitting ? "Submitting..." : "Yes, Submit Exam" }) ] }) ] }) }) ] }), /* @__PURE__ */ jsx(Index, {}) ] }) ] }); }; export { TakeExam as default };