Skip to content

Commit a11f4b5

Browse files
Merge pull request #501 from CodebilityDev/oboarding-steps/videos/errors
Fix Onboarding Page: Video Player
2 parents d8d0fd6 + 1730eec commit a11f4b5

3 files changed

Lines changed: 56 additions & 12 deletions

File tree

‎apps/codebility/app/applicant/onboarding/_components/Commitment.tsx‎

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,18 @@ export default function Commitment({ userName, onComplete }: CommitmentProps) {
4646

4747
setIsDrawing(true);
4848
const rect = canvas.getBoundingClientRect();
49-
const x = "touches" in e ? e.touches[0].clientX - rect.left : e.clientX - rect.left;
50-
const y = "touches" in e ? e.touches[0].clientY - rect.top : e.clientY - rect.top;
49+
50+
// Safe access to touch coordinates with null check
51+
const x = "touches" in e && e.touches[0]
52+
? e.touches[0].clientX - rect.left
53+
: "clientX" in e
54+
? e.clientX - rect.left
55+
: 0;
56+
const y = "touches" in e && e.touches[0]
57+
? e.touches[0].clientY - rect.top
58+
: "clientY" in e
59+
? e.clientY - rect.top
60+
: 0;
5161

5262
ctx.beginPath();
5363
ctx.moveTo(x, y);
@@ -63,8 +73,18 @@ export default function Commitment({ userName, onComplete }: CommitmentProps) {
6373
if (!ctx) return;
6474

6575
const rect = canvas.getBoundingClientRect();
66-
const x = "touches" in e ? e.touches[0].clientX - rect.left : e.clientX - rect.left;
67-
const y = "touches" in e ? e.touches[0].clientY - rect.top : e.clientY - rect.top;
76+
77+
// Safe access to touch coordinates with null check
78+
const x = "touches" in e && e.touches[0]
79+
? e.touches[0].clientX - rect.left
80+
: "clientX" in e
81+
? e.clientX - rect.left
82+
: 0;
83+
const y = "touches" in e && e.touches[0]
84+
? e.touches[0].clientY - rect.top
85+
: "clientY" in e
86+
? e.clientY - rect.top
87+
: 0;
6888

6989
ctx.lineTo(x, y);
7090
ctx.stroke();
@@ -288,4 +308,4 @@ export default function Commitment({ userName, onComplete }: CommitmentProps) {
288308
)}
289309
</div>
290310
);
291-
}
311+
}

‎apps/codebility/app/applicant/onboarding/_components/Quiz.tsx‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,25 @@ export default function Quiz({ applicantId, onQuizComplete, onBackToVideos }: Qu
2020

2121
const currentQuestion = quizQuestions[currentQuestionIndex];
2222
const isLastQuestion = currentQuestionIndex === quizQuestions.length - 1;
23-
const hasSelectedAnswer = selectedAnswers[currentQuestion.id] !== undefined;
23+
const hasSelectedAnswer = currentQuestion ? selectedAnswers[currentQuestion.id] !== undefined : false;
24+
25+
// Early return if no current question (safety check)
26+
if (!currentQuestion && !showResults) {
27+
return (
28+
<div className="space-y-6 text-center">
29+
<p className="text-red-400">Error: No quiz questions available.</p>
30+
{onBackToVideos && (
31+
<Button onClick={onBackToVideos} variant="outline">
32+
← Back to Videos
33+
</Button>
34+
)}
35+
</div>
36+
);
37+
}
2438

2539
const handleSelectAnswer = (optionIndex: number) => {
40+
if (!currentQuestion) return;
41+
2642
setSelectedAnswers({
2743
...selectedAnswers,
2844
[currentQuestion.id]: optionIndex,
@@ -131,7 +147,7 @@ export default function Quiz({ applicantId, onQuizComplete, onBackToVideos }: Qu
131147
</div>
132148
<p className="mb-1 text-sm text-gray-400">
133149
Your answer: <span className={isCorrect ? "text-green-400" : "text-red-400"}>
134-
{question.options[userAnswer]}
150+
{userAnswer !== undefined ? question.options[userAnswer] : "Not answered"}
135151
</span>
136152
</p>
137153
{!isCorrect && (
@@ -184,6 +200,9 @@ export default function Quiz({ applicantId, onQuizComplete, onBackToVideos }: Qu
184200
);
185201
}
186202

203+
// This check is now safe because of the early return above
204+
if (!currentQuestion) return null;
205+
187206
return (
188207
<div className="space-y-6">
189208
{/* Progress */}
@@ -258,4 +277,4 @@ export default function Quiz({ applicantId, onQuizComplete, onBackToVideos }: Qu
258277
</div>
259278
</div>
260279
);
261-
}
280+
}

‎apps/codebility/app/applicant/onboarding/_components/VideoPlayer.tsx‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,15 @@ export default function VideoPlayer({
2525
const [hasWatched, setHasWatched] = useState(false);
2626
const [currentTime, setCurrentTime] = useState(0);
2727
const [duration, setDuration] = useState(0);
28+
29+
// Use ref to track if we've already saved progress
30+
const progressSavedRef = useRef(false);
2831

2932
const saveVideoProgress = async () => {
3033
const video = videoRef.current;
31-
if (!video) return;
34+
if (!video || progressSavedRef.current) return;
35+
36+
progressSavedRef.current = true;
3237

3338
await updateVideoProgress({
3439
applicantId,
@@ -53,7 +58,7 @@ export default function VideoPlayer({
5358

5459
// Mark as watched if they've seen 98% or more (to unlock Next button)
5560
// But don't auto-advance - user must click Next manually
56-
if (percentWatched >= 98 && !hasWatched) {
61+
if (percentWatched >= 98 && !progressSavedRef.current) {
5762
setHasWatched(true);
5863
// Save progress in background without triggering navigation
5964
saveVideoProgress();
@@ -78,7 +83,7 @@ export default function VideoPlayer({
7883
video.removeEventListener("play", handlePlay);
7984
video.removeEventListener("pause", handlePause);
8085
};
81-
}, [hasWatched]);
86+
}, []); // Empty dependency array - only set up listeners once
8287

8388
const formatTime = (seconds: number) => {
8489
const mins = Math.floor(seconds / 60);
@@ -160,4 +165,4 @@ export default function VideoPlayer({
160165
)}
161166
</div>
162167
);
163-
}
168+
}

0 commit comments

Comments
 (0)