'use client'; import React from 'react'; import { Dialog, DialogContent, DialogTitle, DialogDescription, } from '@/components/ui/dialog'; import { BiX } from 'react-icons/bi'; import { OnlineExamQuestion, StudentAnswer, } from '@/components/store/slices/examSlice'; import { useTranslate } from '@/components/hooks/useTranslate'; interface ViewExamSummaryModalProps { open: boolean; onOpenChange: (open: boolean) => void; examQuestions: OnlineExamQuestion[]; studentAnswers: StudentAnswer[]; totalMarks: number; onNavigateToQuestion: (questionIndex: number) => void; } /** * View Exam Summary Modal Component * * Displays a comprehensive review of the exam before submission. * Fully responsive for mobile and desktop devices. */ export default function ViewExamSummaryModal({ open, onOpenChange, examQuestions, studentAnswers, totalMarks, onNavigateToQuestion, }: ViewExamSummaryModalProps) { const translate = useTranslate(); // Calculate answered and unanswered questions const answeredQuestions = studentAnswers.length; const unansweredQuestions = examQuestions.length - answeredQuestions; // Group questions by marks const questionsByMarks = examQuestions.reduce((acc, question) => { const marks = question.marks; if (!acc[marks]) { acc[marks] = []; } acc[marks].push(question); return acc; }, {} as Record<number, OnlineExamQuestion[]>); // Check if a question is answered const isQuestionAnswered = (questionId: number) => { return studentAnswers.some((answer) => answer.questionId === questionId); }; // Handle close modal const handleClose = () => { onOpenChange(false); }; // Handle question navigation const handleQuestionClick = (questionId: number) => { const questionIndex = examQuestions.findIndex((q) => q.id === questionId); if (questionIndex !== -1) { onNavigateToQuestion(questionIndex); onOpenChange(false); // Close modal after navigation } }; return ( <Dialog open={open} onOpenChange={onOpenChange}> <DialogContent className="w-[95vw] max-w-[95vw] sm:w-[660px]! sm:max-w-[660px]! p-0 bg-white rounded-[12px] sm:rounded-[16px] shadow-xl" showCloseButton={false} > {/* Header Section */} <div className="px-4 sm:px-6 pt-4 sm:pt-6 pb-2 relative"> <div className="pr-10 sm:pr-8"> <DialogTitle className="text-lg sm:text-xl font-bold text-gray-900 mb-2 sm:mb-3"> {translate('viewExamSummary')} </DialogTitle> <DialogDescription className="text-sm sm:text-base text-gray-600 leading-relaxed"> {translate('reviewYourAnswersAndScores')} </DialogDescription> </div> {/* Close Button */} <button onClick={handleClose} className="absolute top-3 right-3 sm:top-6 sm:right-6 w-8 h-8 sm:w-10 sm:h-10 flex items-center justify-center rounded-lg bg-gray-100 hover:bg-gray-200 text-gray-500 hover:text-gray-700 transition-colors" > <BiX className="w-5 h-5 sm:w-6 sm:h-6" /> </button> </div> {/* Divider */} <div className="h-px bg-gray-200"></div> {/* Exam Summary Section */} <div className="px-4 sm:px-6 py-3 sm:py-1 bg-white"> <div className="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-2 sm:gap-0"> <div className="text-base sm:text-xl font-medium text-gray-900"> {translate('totalQuestions')} {examQuestions.length} </div> <div className="text-base sm:text-xl font-medium text-gray-900"> {translate('totalMarks')} {totalMarks} </div> </div> </div> {/* Question Breakdown Section */} <div className="px-4 sm:px-6 pb-4 space-y-3 sm:space-y-5 overflow-y-auto max-h-[50vh] sm:max-h-[300px]"> {/* Render questions grouped by marks */} {Object.entries(questionsByMarks) .sort(([a], [b]) => parseInt(a) - parseInt(b)) .map(([marks, questions]) => ( <div key={marks} className="bg-[#F5F5F5] rounded-[12px] p-3 border border-gray-200" > {/* Question Type Header */} <div className="flex items-center justify-between mb-3 sm:mb-4"> <div className="text-base sm:text-xl font-normal text-gray-800"> {marks} {translate('marksQuestion')} </div> <div className="text-base sm:text-xl font-normal text-gray-800"> [{questions.length}] </div> </div> {/* Individual Question Buttons */} <div className="flex flex-wrap gap-2 sm:gap-3"> {questions.map((question) => { const questionNumber = examQuestions.findIndex((q) => q.id === question.id) + 1; const isAnswered = isQuestionAnswered(question.id); return ( <button key={question.id} onClick={() => handleQuestionClick(question.id)} className="w-8 h-8 sm:w-9 sm:h-9 rounded-[4px] text-base sm:text-xl font-normal transition-all cursor-pointer bg-[#57CC99] text-white" title={`${translate('question')} ${questionNumber} - ${ isAnswered ? translate('answered') : translate('unanswered') } - ${translate('clickToNavigate')}`} > {questionNumber} </button> ); })} </div> </div> ))} </div> {/* Answer Status Section */} <div className="px-4 sm:px-6 pb-4"> <div className="flex gap-3 sm:gap-4"> {/* Answered Status */} <div className="flex-1 bg-[#57CC99] rounded-[8px] p-3 sm:p-4 flex items-center justify-between shadow-sm"> <span className="text-base sm:text-xl font-medium text-white"> {translate('answered')} </span> <span className="text-xl sm:text-2xl font-bold text-white"> {answeredQuestions} </span> </div> {/* Unanswered Status */} <div className="flex-1 bg-[#FF6B6B] rounded-[8px] p-3 sm:p-4 flex items-center justify-between shadow-sm"> <span className="text-base sm:text-xl font-medium text-white"> {translate('unanswered')} </span> <span className="text-xl sm:text-2xl font-bold text-white"> {unansweredQuestions} </span> </div> </div> </div> </DialogContent> </Dialog> ); }