@@ -24,6 +24,7 @@ export default function TakeTestPage() {
2424 const [ timeRemaining , setTimeRemaining ] = useState ( 0 )
2525 const [ testStarted , setTestStarted ] = useState ( false )
2626 const [ attemptId , setAttemptId ] = useState < string | null > ( null )
27+ const [ testStartTime , setTestStartTime ] = useState < Date | null > ( null )
2728 const [ isFullScreen , setIsFullScreen ] = useState ( false )
2829 const [ violations , setViolations ] = useState ( 0 )
2930 const [ showWarning , setShowWarning ] = useState ( false )
@@ -63,7 +64,12 @@ export default function TakeTestPage() {
6364 } , [ fetchTestAndQuestions ] )
6465
6566 const handleSubmitTest = useCallback ( async ( ) => {
66- if ( ! attemptId || ! test ) return
67+ console . log ( '🚀 handleSubmitTest called with:' , { attemptId, test : ! ! test , testStartTime } )
68+
69+ if ( ! attemptId || ! test ) {
70+ console . log ( '❌ Early return: missing attemptId or test' , { attemptId, test : ! ! test } )
71+ return
72+ }
6773
6874 try {
6975 // Calculate score
@@ -83,36 +89,58 @@ export default function TakeTestPage() {
8389
8490 const passed = ( score / maxScore ) * 100 >= test . passing_score
8591
86- // Update attempt
87- const { error : updateError } = await supabase
88- . from ( 'test_attempts' )
89- . update ( {
90- submitted_at : new Date ( ) . toISOString ( ) ,
92+
93+ // Calculate time taken more accurately
94+ const currentTime = new Date ( )
95+ let timeTakenMinutes = 0
96+
97+ if ( testStartTime ) {
98+ // Use actual start time for most accurate calculation
99+ const timeTakenMs = currentTime . getTime ( ) - testStartTime . getTime ( )
100+ timeTakenMinutes = Math . max ( 0 , Math . floor ( timeTakenMs / ( 1000 * 60 ) ) )
101+ } else {
102+ // Fallback to the original calculation if start time is not available
103+ timeTakenMinutes = Math . max ( 0 , Math . floor ( ( test . duration_minutes * 60 - timeRemaining ) / 60 ) )
104+ }
105+
106+ console . log ( 'Time calculation:' , {
107+ timeTakenMinutes,
108+ testStartTime : testStartTime ?. toISOString ( ) ,
109+ currentTime : currentTime . toISOString ( ) ,
110+ usingStartTime : ! ! testStartTime
111+ } )
112+
113+
114+
115+ // Use API route to update the database (bypasses RLS)
116+
117+ const response = await fetch ( '/api/tests/submit' , {
118+ method : 'POST' ,
119+ headers : {
120+ 'Content-Type' : 'application/json' ,
121+ } ,
122+ body : JSON . stringify ( {
123+ attemptId,
91124 score,
92- max_score : maxScore ,
125+ maxScore,
93126 passed,
94- time_taken_minutes : Math . floor ( ( test . duration_minutes * 60 - timeRemaining ) / 60 ) ,
95- status : 'submitted'
127+ timeTakenMinutes ,
128+ answers
96129 } )
97- . eq ( 'id' , attemptId )
130+ } )
98131
99- if ( updateError ) throw updateError
132+ if ( ! response . ok ) {
133+ const errorData = await response . json ( )
134+ console . error ( 'API update failed:' , errorData )
135+ throw new Error ( `API update failed: ${ errorData . error } ` )
136+ }
100137
101- // Save answers
102- const answerRecords = Object . entries ( answers ) . map ( ( [ questionId , selectedOptions ] ) => ( {
103- attempt_id : attemptId ,
104- question_id : questionId ,
105- selected_options : selectedOptions ,
106- answered_at : new Date ( ) . toISOString ( )
107- } ) )
138+ const result = await response . json ( )
108139
109- if ( answerRecords . length > 0 ) {
110- const { error : answersError } = await supabase
111- . from ( 'test_answers' )
112- . insert ( answerRecords )
140+ // Wait a moment to ensure the database update is fully committed
141+ await new Promise ( resolve => setTimeout ( resolve , 500 ) )
113142
114- if ( answersError ) throw answersError
115- }
143+ // Answers are now saved by the API route
116144
117145 // Log activity for points
118146 try {
@@ -138,13 +166,15 @@ export default function TakeTestPage() {
138166 toast . error ( 'Failed to submit test' )
139167 console . error ( 'Test submission error:' , error )
140168 }
141- } , [ attemptId , test , questions , answers , testId , timeRemaining , supabase , router ] )
169+ } , [ attemptId , test , questions , answers , testId , timeRemaining , testStartTime , supabase , router ] )
142170
143171 useEffect ( ( ) => {
144172 if ( testStarted && timeRemaining > 0 ) {
173+ console . log ( '⏰ Timer started, timeRemaining:' , timeRemaining )
145174 const timer = setInterval ( ( ) => {
146175 setTimeRemaining ( prev => {
147176 if ( prev <= 1 ) {
177+ console . log ( '⏰ Timer expired, calling handleSubmitTest' )
148178 handleSubmitTest ( )
149179 return 0
150180 }
@@ -188,8 +218,10 @@ export default function TakeTestPage() {
188218
189219 // Auto-submit test after 2 violations
190220 if ( newViolations >= 2 ) {
221+ console . log ( '🚨 Maximum violations reached, auto-submitting test' )
191222 toast . error ( 'Maximum violations reached! Test will be submitted automatically.' )
192223 setTimeout ( ( ) => {
224+ console . log ( '🚨 Auto-submitting test due to violations' )
193225 handleSubmitTest ( )
194226 } , 2000 )
195227 return
@@ -387,6 +419,9 @@ export default function TakeTestPage() {
387419
388420 setAttemptId ( attemptDataResult . id )
389421 setTestStarted ( true )
422+ const startTime = new Date ( )
423+ setTestStartTime ( startTime ) // Record the actual start time
424+ console . log ( '🎯 Test started at:' , startTime . toISOString ( ) )
390425 toast . success ( 'Test started! Entering full-screen mode...' )
391426
392427 // Force full-screen immediately
@@ -654,7 +689,10 @@ export default function TakeTestPage() {
654689 < div className = "flex items-center gap-2" >
655690 { currentQuestionIndex === questions . length - 1 ? (
656691 < Button
657- onClick = { handleSubmitTest }
692+ onClick = { ( ) => {
693+ console . log ( '🔘 Manual submit button clicked' )
694+ handleSubmitTest ( )
695+ } }
658696 className = "bg-green-600 hover:bg-green-700 text-white"
659697 >
660698 Submit Test
0 commit comments