@@ -16,33 +16,30 @@ import {
1616 Chip ,
1717 Divider ,
1818 Grid ,
19+ Avatar , // <--- Ensure Avatar is imported
1920} from '@mui/material' ;
2021import {
2122 Visibility ,
2223 VisibilityOff ,
2324 LightbulbOutlined as LightbulbOutlinedIcon ,
24- WorkOutline as WorkOutlineIcon , // For Job Role
25- InfoOutlined as InfoOutlinedIcon , // For Content/Process Details
26- ForumOutlined as ForumOutlinedIcon , // For Interviewer Mindset
27- BusinessOutlined as BusinessOutlinedIcon , // For Company Name
28- LocalOfferOutlined as LocalOfferOutlinedIcon , // For Tags/Keywords
25+ WorkOutline as WorkOutlineIcon ,
26+ InfoOutlined as InfoOutlinedIcon ,
27+ ForumOutlined as ForumOutlinedIcon ,
28+ BusinessOutlined as BusinessOutlinedIcon ,
29+ LocalOfferOutlined as LocalOfferOutlinedIcon ,
2930} from '@mui/icons-material' ;
3031import api from '../serverApi' ; // Assuming you have a configured axios instance
3132import { config } from '../config' ;
3233
3334// Define interfaces for the API response schemas
34- interface GeneratedQuestion {
35- question : string ;
36- }
37-
3835interface QuizGenerationResponse {
3936 _id : string ;
4037 title : string ;
4138 tags : string [ ] ;
4239 content : string ;
4340 job_role : string ;
4441 company_name_en : string ;
45- company_name_he : string ; // Not used in display, but included for completeness
42+ company_name_he : string ;
4643 process_details : string ;
4744 question_list : string [ ] ;
4845 answer_list : string [ ] ;
@@ -61,7 +58,7 @@ interface UserAnsweredQuiz {
6158 process_details : string ;
6259 question_list : string [ ] ;
6360 answer_list : string [ ] ;
64- user_answer_list : string [ ] ; // New field for user answers
61+ user_answer_list : string [ ] ;
6562 keywords : string [ ] ;
6663 interviewer_mindset : string ;
6764}
@@ -83,9 +80,9 @@ interface QuizGradingResponse {
8380interface QuizStateQuestion {
8481 originalQuestion : string ;
8582 userAnswer : string ;
86- correctAnswer ?: string ; // Will be populated after grading
87- grade ?: number ; // Will be populated after grading
88- tip ?: string ; // Will be populated after grading
83+ correctAnswer ?: string ;
84+ grade ?: number ;
85+ tip ?: string ;
8986}
9087
9188interface QuizState {
@@ -110,27 +107,27 @@ const Quiz: React.FC = () => {
110107 const [ subject , setSubject ] = useState < string > ( '' ) ;
111108 const [ quiz , setQuiz ] = useState < QuizState | null > ( null ) ;
112109 const [ loading , setLoading ] = useState < boolean > ( false ) ;
113- const [ showAnswer , setShowAnswer ] = useState < { [ key : number ] : boolean } > ( { } ) ; // To toggle answer visibility
114- const [ quizSubmitted , setQuizSubmitted ] = useState < boolean > ( false ) ; // To control UI after submission
110+ const [ showAnswer , setShowAnswer ] = useState < { [ key : number ] : boolean } > ( { } ) ;
111+ const [ quizSubmitted , setQuizSubmitted ] = useState < boolean > ( false ) ;
115112
116113 const handleGenerateQuiz = async ( ) => {
117- if ( ! subject . trim ( ) ) return ; // Ensure subject is not empty or just whitespace
114+ if ( ! subject . trim ( ) ) return ;
118115 setLoading ( true ) ;
119- setQuiz ( null ) ; // Clear previous quiz
120- setQuizSubmitted ( false ) ; // Reset submission status
121- setShowAnswer ( { } ) ; // Reset answer visibility
116+ setQuiz ( null ) ;
117+ setQuizSubmitted ( false ) ;
118+ setShowAnswer ( { } ) ;
122119 try {
123120 const response = await api . post < QuizGenerationResponse > ( `${ config . app . backend_url ( ) } /quiz/generate` , { subject } ) ;
124121
125122 const generatedQuestions : QuizStateQuestion [ ] = response . data . question_list . map ( ( q : string , idx : number ) => ( {
126123 originalQuestion : q ,
127- userAnswer : '' , // Initialize empty user answer
124+ userAnswer : '' ,
128125 correctAnswer : response . data . answer_list [ idx ] , // Populate correct answer immediately
129126 } ) ) ;
130127
131128 setQuiz ( {
132129 _id : response . data . _id ,
133- subject : subject , // Use the input subject for consistency
130+ subject : subject ,
134131 questions : generatedQuestions ,
135132 title : response . data . title ,
136133 tags : response . data . tags ,
@@ -140,17 +137,9 @@ const Quiz: React.FC = () => {
140137 processDetails : response . data . process_details ,
141138 keywords : response . data . keywords ,
142139 interviewerMindset : response . data . interviewer_mindset ,
143- answer_list : response . data . answer_list , // Store for later use if needed, but questions now have it
140+ answer_list : response . data . answer_list ,
144141 } ) ;
145142
146- // Do NOT automatically show answers here. User should toggle.
147- // const initialShowAnswer: { [key: number]: boolean } = {};
148- // generatedQuestions.forEach((_, index) => {
149- // initialShowAnswer[index] = true;
150- // });
151- // setShowAnswer(initialShowAnswer);
152-
153-
154143 } catch ( error ) {
155144 console . error ( 'Error generating quiz:' , error ) ;
156145 alert ( 'Failed to generate quiz. Please try again.' ) ;
@@ -175,21 +164,20 @@ const Quiz: React.FC = () => {
175164 } ;
176165
177166 const handleSubmitQuiz = async ( ) => {
178- if ( ! quiz || quizSubmitted ) return ; // Prevent multiple submissions
167+ if ( ! quiz || quizSubmitted ) return ;
179168 setLoading ( true ) ;
180169
181- // Construct the request body as per the UserAnsweredQuiz schema
182170 const answeredQuizData : UserAnsweredQuiz = {
183171 _id : quiz . _id ,
184172 title : quiz . title || '' ,
185173 tags : quiz . tags || [ ] ,
186174 content : quiz . content || '' ,
187175 job_role : quiz . jobRole || '' ,
188176 company_name_en : quiz . companyNameEn || '' ,
189- company_name_he : '' , // Assuming this isn't strictly required for grading or can be empty
177+ company_name_he : '' ,
190178 process_details : quiz . processDetails || '' ,
191179 question_list : quiz . questions . map ( q => q . originalQuestion ) ,
192- answer_list : quiz . answer_list || [ ] , // Send the original correct answers if available
180+ answer_list : quiz . answer_list || [ ] ,
193181 user_answer_list : quiz . questions . map ( q => q . userAnswer ) ,
194182 keywords : quiz . keywords || [ ] ,
195183 interviewer_mindset : quiz . interviewerMindset || '' ,
@@ -200,13 +188,12 @@ const Quiz: React.FC = () => {
200188
201189 const gradedQuizData = response . data ;
202190 const updatedQuestions = quiz . questions . map ( ( q , index ) => {
203- // Find the corresponding graded answer by matching the question string
204191 const gradedAnswer = gradedQuizData . graded_answers . find ( ga => ga . question === q . originalQuestion ) ;
205192 return {
206193 ...q ,
207194 grade : gradedAnswer ?. grade ,
208195 tip : gradedAnswer ?. tip ,
209- // correctAnswer is already present from generation, no need to set again here
196+ // correctAnswer is already present from generation
210197 } ;
211198 } ) ;
212199
@@ -216,9 +203,9 @@ const Quiz: React.FC = () => {
216203 finalGrade : gradedQuizData . final_quiz_grade ,
217204 finalTip : gradedQuizData . final_summary_tip ,
218205 } ) ;
219- setQuizSubmitted ( true ) ; // Mark quiz as submitted
206+ setQuizSubmitted ( true ) ;
220207
221- // After submission, it's generally good UX to show all correct answers and grades
208+ // After submission, automatically show all correct answers and grades
222209 const initialShowAnswer : { [ key : number ] : boolean } = { } ;
223210 updatedQuestions . forEach ( ( _ , index ) => {
224211 initialShowAnswer [ index ] = true ;
@@ -375,14 +362,30 @@ const Quiz: React.FC = () => {
375362 </ Typography >
376363 { quiz . questions . map ( ( q , index ) => (
377364 < Paper key = { index } sx = { { p : 2 , mb : 3 , border : '1px solid #e0e0e0' } } >
378- < Box display = "flex" justifyContent = "space-between" alignItems = "center" mb = { 1 } >
365+ < Box display = "flex" justifyContent = "space-between" alignItems = "flex-start" mb = { 1 } >
366+ { /* Circled Numbering (Option 2) */ }
367+ < Avatar
368+ sx = { {
369+ bgcolor : 'primary.main' ,
370+ width : 32 ,
371+ height : 32 ,
372+ fontSize : '0.9rem' ,
373+ fontWeight : 'bold' ,
374+ mr : 1.5 ,
375+ boxShadow : 2 ,
376+ flexShrink : 0 , // Prevent shrinking on small screens
377+ } }
378+ >
379+ { index + 1 }
380+ </ Avatar >
381+ { /* Question Text */ }
379382 < Typography variant = "h6" sx = { { flexGrow : 1 } } >
380- Question { index + 1 } : { q . originalQuestion }
383+ { q . originalQuestion }
381384 </ Typography >
382- { /* REMOVED: quizSubmitted condition here */ }
383- { q . correctAnswer && ( // Only show if a correct answer exists
385+ { /* Blinking Eye Icon (now always visible if answer exists) */ }
386+ { q . correctAnswer && (
384387 < Tooltip title = { showAnswer [ index ] ? 'Hide Answer' : 'Show Answer' } arrow >
385- < IconButton onClick = { ( ) => handleToggleAnswerVisibility ( index ) } size = "small" >
388+ < IconButton onClick = { ( ) => handleToggleAnswerVisibility ( index ) } size = "small" sx = { { flexShrink : 0 , ml : 1 } } >
386389 { showAnswer [ index ] ? < VisibilityOff /> : < Visibility /> }
387390 </ IconButton >
388391 </ Tooltip >
@@ -397,7 +400,7 @@ const Quiz: React.FC = () => {
397400 value = { q . userAnswer }
398401 onChange = { e => handleUserAnswerChange ( index , e . target . value ) }
399402 sx = { { mb : 2 } }
400- disabled = { quizSubmitted } // Disable input after submission
403+ disabled = { quizSubmitted }
401404 />
402405
403406 { /* Grade and Tip are still shown only after submission */ }
@@ -414,7 +417,7 @@ const Quiz: React.FC = () => {
414417 min = { 0 }
415418 max = { 100 }
416419 sx = { { width : '90%' , mx : 'auto' } }
417- disabled // Make it non-interactive
420+ disabled
418421 />
419422 </ Box >
420423 < Box sx = { { mt : 2 } } >
0 commit comments