diff --git a/Modules/Exam/app/Http/Requests/ExamRequest.php b/Modules/Exam/app/Http/Requests/ExamRequest.php index b080b6e0..64a65081 100644 --- a/Modules/Exam/app/Http/Requests/ExamRequest.php +++ b/Modules/Exam/app/Http/Requests/ExamRequest.php @@ -24,7 +24,7 @@ class ExamRequest extends FormRequest 'duration_minutes' => request('duration_minutes') ? (int) request('duration_minutes') : 0, 'pass_mark' => request('pass_mark') ? (float) request('pass_mark') : null, 'total_marks' => request('total_marks') ? (float) request('total_marks') : null, - 'max_attempts' => request('max_attempts') ? (int) request('max_attempts') : null, + 'max_attempts' => request()->has('max_attempts') ? (int) request('max_attempts') : 0, ]); } @@ -59,7 +59,7 @@ class ExamRequest extends FormRequest 'duration_minutes' => 'required|integer|min:0|max:59', 'pass_mark' => 'required|numeric|min:0|max:100', 'total_marks' => 'required|numeric|min:1', - 'max_attempts' => 'required|integer|min:1', + 'max_attempts' => 'required|integer|min:0', // Status & Level 'status' => 'nullable|string|in:draft,published,archived', diff --git a/Modules/Exam/app/Http/Requests/UpdateExamRequest.php b/Modules/Exam/app/Http/Requests/UpdateExamRequest.php index e3cd8576..cc0940af 100644 --- a/Modules/Exam/app/Http/Requests/UpdateExamRequest.php +++ b/Modules/Exam/app/Http/Requests/UpdateExamRequest.php @@ -19,7 +19,7 @@ class UpdateExamRequest extends FormRequest 'duration_minutes' => request('duration_minutes') ? (int) request('duration_minutes') : 0, 'pass_mark' => request('pass_mark') ? (float) request('pass_mark') : null, 'total_marks' => request('total_marks') ? (float) request('total_marks') : null, - 'max_attempts' => request('max_attempts') ? (int) request('max_attempts') : null, + 'max_attempts' => request()->has('max_attempts') ? (int) request('max_attempts') : 0, ]); } @@ -103,7 +103,7 @@ class UpdateExamRequest extends FormRequest 'duration_minutes' => 'required|integer|min:0|max:59', 'pass_mark' => 'required|numeric|min:0|max:100', 'total_marks' => 'required|numeric|min:1', - 'max_attempts' => 'required|integer|min:1', + 'max_attempts' => 'required|integer|min:0', ]; } diff --git a/Modules/Exam/app/Services/ExamAttemptService.php b/Modules/Exam/app/Services/ExamAttemptService.php index b975843b..d2ef32e1 100644 --- a/Modules/Exam/app/Services/ExamAttemptService.php +++ b/Modules/Exam/app/Services/ExamAttemptService.php @@ -12,14 +12,16 @@ class ExamAttemptService { /** * Start a new exam attempt - */ + */ public function startAttempt(User $user, Exam $exam): ?ExamAttempt { $previousAttempts = ExamAttempt::where('user_id', $user->id) ->where('exam_id', $exam->id) ->count(); - if ($previousAttempts >= $exam->max_attempts) { + $hasAttemptLimit = $exam->max_attempts > 0; + + if ($hasAttemptLimit && $previousAttempts >= $exam->max_attempts) { return null; } diff --git a/Modules/Exam/app/Services/ExamEnrollmentService.php b/Modules/Exam/app/Services/ExamEnrollmentService.php index 192260bf..f861b094 100644 --- a/Modules/Exam/app/Services/ExamEnrollmentService.php +++ b/Modules/Exam/app/Services/ExamEnrollmentService.php @@ -112,7 +112,9 @@ class ExamEnrollmentService extends MediaService 'enrollment' => $enrollment, 'is_active' => $enrollment->isActive(), 'attempts_used' => $attempts->count(), - 'attempts_remaining' => max(0, $exam->max_attempts - $attempts->count()), + 'attempts_remaining' => $exam->max_attempts > 0 + ? max(0, $exam->max_attempts - $attempts->count()) + : null, 'completed_attempts' => $completedAttempts, 'best_score' => $bestScore, 'has_passed' => $hasPassed, diff --git a/app/Http/Requests/StoreQuizRequest.php b/app/Http/Requests/StoreQuizRequest.php index 3869be42..fbe07f64 100644 --- a/app/Http/Requests/StoreQuizRequest.php +++ b/app/Http/Requests/StoreQuizRequest.php @@ -63,7 +63,7 @@ class StoreQuizRequest extends FormRequest } } ], - 'retake' => 'required|numeric|min:1', + 'retake' => 'required|numeric|min:0', ]; } } diff --git a/app/Http/Requests/UpdateQuizRequest.php b/app/Http/Requests/UpdateQuizRequest.php index 30232e31..2a21cd5a 100644 --- a/app/Http/Requests/UpdateQuizRequest.php +++ b/app/Http/Requests/UpdateQuizRequest.php @@ -62,7 +62,7 @@ class UpdateQuizRequest extends FormRequest } } ], - 'retake' => 'required|numeric|min:1', + 'retake' => 'required|numeric|min:0', ]; } } diff --git a/app/Services/Course/SectionQuizService.php b/app/Services/Course/SectionQuizService.php index 022b16d2..7ed297c6 100644 --- a/app/Services/Course/SectionQuizService.php +++ b/app/Services/Course/SectionQuizService.php @@ -50,13 +50,15 @@ class SectionQuizService extends CourseSectionService ->where('section_quiz_id', $quiz->id) ->first(); + $hasAttemptLimit = $quiz->retake > 0; + // Get or create quiz submission if ($submission) { - if ($submission->attempts >= $quiz->retake) { + if ($hasAttemptLimit && $submission->attempts >= $quiz->retake) { return false; - } else { - $submission->increment('attempts'); } + + $submission->increment('attempts'); } else { $submission = QuizSubmission::create([ 'section_quiz_id' => $quiz->id, diff --git a/resources/js/components/cards/exam-card-7.tsx b/resources/js/components/cards/exam-card-7.tsx index d8ad0156..df439f24 100644 --- a/resources/js/components/cards/exam-card-7.tsx +++ b/resources/js/components/cards/exam-card-7.tsx @@ -62,7 +62,7 @@ const ExamCard7 = ({ exam, attempts, bestAttempt, className }: Props) => {
Attempts - {totalAttempts} / {exam.max_attempts} + {exam.max_attempts === 0 ? `${totalAttempts} / Unlimited` : `${totalAttempts} / ${exam.max_attempts}`}
@@ -87,7 +87,7 @@ const ExamCard7 = ({ exam, attempts, bestAttempt, className }: Props) => { )} - {totalAttempts < exam.max_attempts && ( + {(exam.max_attempts === 0 || totalAttempts < exam.max_attempts) && ({frontend.retake}
-: {quiz.retake}
+: {hasAttemptLimit ? quiz.retake : 'Unlimited'}
{frontend.retake_attempts}
-: {submissions[0]?.attempts || 0}
+: {attemptsUsed}
{frontend.correct_answers}
@@ -218,7 +220,7 @@ const QuizViewer = ({ quiz }: QuizViewerProps) => {0 = Unlimited attempts
0 = Unlimited attempts
Maximum number of attempts allowed per student
+0 = Unlimited attempts
Max Attempts
-{exam.max_attempts}
+{exam.max_attempts === 0 ? 'Unlimited' : exam.max_attempts}
Level
diff --git a/resources/js/pages/exams/partials/details.tsx b/resources/js/pages/exams/partials/details.tsx index b5119333..81dc71ef 100644 --- a/resources/js/pages/exams/partials/details.tsx +++ b/resources/js/pages/exams/partials/details.tsx @@ -38,7 +38,9 @@ const Details = () => {Max Attempts
-{exam.max_attempts} attempts
++ {exam.max_attempts === 0 ? 'Unlimited attempts' : `${exam.max_attempts} attempts`} +