Skip to content

Commit 623acd7

Browse files
authored
Merge pull request #199 from codeunia-dev/projectshowcase
Fixed the test timings
2 parents 0205f1c + 128ad10 commit 623acd7

2 files changed

Lines changed: 149 additions & 26 deletions

File tree

‎app/api/tests/submit/route.ts‎

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { NextRequest, NextResponse } from 'next/server'
2+
import { createClient } from '@/lib/supabase/server'
3+
import { createClient as createServiceClient } from '@supabase/supabase-js'
4+
5+
export async function POST(request: NextRequest) {
6+
try {
7+
const { attemptId, score, maxScore, passed, timeTakenMinutes, answers } = await request.json()
8+
9+
if (!attemptId || score === undefined || maxScore === undefined || passed === undefined || timeTakenMinutes === undefined) {
10+
return NextResponse.json(
11+
{ error: 'Missing required fields' },
12+
{ status: 400 }
13+
)
14+
}
15+
16+
// Use service role client to bypass RLS
17+
const serviceSupabase = createServiceClient(
18+
process.env.NEXT_PUBLIC_SUPABASE_URL!,
19+
process.env.SUPABASE_SERVICE_ROLE_KEY!
20+
)
21+
22+
// Update the test attempt
23+
const { data, error } = await serviceSupabase
24+
.from('test_attempts')
25+
.update({
26+
submitted_at: new Date().toISOString(),
27+
score,
28+
max_score: maxScore,
29+
passed,
30+
time_taken_minutes: timeTakenMinutes,
31+
status: 'submitted'
32+
})
33+
.eq('id', attemptId)
34+
.select()
35+
36+
if (error) {
37+
console.error('Error updating test attempt:', error)
38+
return NextResponse.json(
39+
{ error: 'Failed to update test attempt' },
40+
{ status: 500 }
41+
)
42+
}
43+
44+
if (!data || data.length === 0) {
45+
return NextResponse.json(
46+
{ error: 'No rows were updated' },
47+
{ status: 404 }
48+
)
49+
}
50+
51+
// Save answers if provided
52+
if (answers && Object.keys(answers).length > 0) {
53+
const answerRecords = Object.entries(answers).map(([questionId, selectedOptions]) => ({
54+
attempt_id: attemptId,
55+
question_id: questionId,
56+
selected_options: selectedOptions,
57+
answered_at: new Date().toISOString()
58+
}))
59+
60+
const { error: answersError } = await serviceSupabase
61+
.from('test_answers')
62+
.insert(answerRecords)
63+
64+
if (answersError) {
65+
console.error('Error saving answers:', answersError)
66+
return NextResponse.json(
67+
{ error: 'Failed to save answers' },
68+
{ status: 500 }
69+
)
70+
}
71+
}
72+
73+
return NextResponse.json({
74+
success: true,
75+
data: data[0]
76+
})
77+
78+
} catch (error) {
79+
console.error('Error in test submit API:', error)
80+
return NextResponse.json(
81+
{ error: 'Internal server error' },
82+
{ status: 500 }
83+
)
84+
}
85+
}

‎app/tests/[id]/take/page.tsx‎

Lines changed: 64 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)