Skip to content

Commit 00323fc

Browse files
committed
feat: finla changes and fixes
1 parent 6530eb5 commit 00323fc

21 files changed

Lines changed: 681 additions & 243 deletions

app/Http/Controllers/CourseReviewController.php

Lines changed: 23 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
<?php
22

3-
declare(strict_types=1);
4-
53
namespace App\Http\Controllers;
64

75
use App\Models\Course;
@@ -10,7 +8,6 @@
108
use App\Models\Quiz;
119
use App\Models\QuizAnswer;
1210
use App\Models\QuizAttempt;
13-
use Exception;
1411
use Illuminate\Http\RedirectResponse;
1512
use Illuminate\Http\Request;
1613
use Illuminate\Support\Facades\Auth;
@@ -20,21 +17,20 @@
2017
use Inertia\Inertia;
2118
use Inertia\Response;
2219

23-
final class CourseReviewController extends Controller
20+
class CourseReviewController extends Controller
2421
{
25-
public const REVIEW_QUIZ_WRONG_QUESTIONS_TARGET = 5; // Target number of previously wrong questions
26-
27-
public const REVIEW_QUIZ_NEW_QUESTIONS_TARGET = 5; // Target number of new/random questions
22+
const REVIEW_QUIZ_WRONG_QUESTIONS_TARGET = 5; // Target number of previously wrong questions
23+
const REVIEW_QUIZ_NEW_QUESTIONS_TARGET = 5; // Target number of new/random questions
2824

2925
/**
3026
* Generate and display the final review quiz for a course.
3127
*/
32-
public function generate(Course $course): Response|RedirectResponse
28+
public function generate(Course $course): Response | RedirectResponse
3329
{
3430
$user = Auth::user();
3531

3632
$placeholderQuiz = $course->finalReviewQuiz;
37-
if (! $placeholderQuiz) {
33+
if (!$placeholderQuiz) {
3834
Log::warning("CourseReview: Course {$course->id} has no final_review_quiz_id linked.");
3935
$quizTitle = "{$course->title} - Final Review";
4036
$quizDescription = "A comprehensive review of topics from {$course->title}.";
@@ -70,10 +66,11 @@ public function generate(Course $course): Response|RedirectResponse
7066
->get();
7167
}
7268

69+
// Combine and shuffle questions
7370
$finalQuestions = $wrongQuestions->concat($newQuestions)->shuffle();
7471

7572
if ($finalQuestions->isEmpty()) {
76-
return Inertia::render('Courses/Review/Show', [
73+
return Inertia::render('courses/review/Show', [
7774
'course' => $course->only('id', 'title', 'slug'),
7875
'quizData' => null,
7976
'message' => 'Not enough questions available for a review quiz for this course yet. Try completing more module quizzes.',
@@ -93,13 +90,13 @@ public function generate(Course $course): Response|RedirectResponse
9390
});
9491

9592
$quizDataForView = [
96-
'id' => 'final_review_'.$course->id.'_'.uniqid(),
93+
'id' => 'final_review_' . $course->id . '_' . uniqid(),
9794
'title' => $quizTitle,
9895
'description' => $quizDescription,
9996
'questions' => $displayQuestions,
10097
];
10198

102-
session(['_courseReviewQuestions_'.$course->id => $finalQuestions->keyBy('id')->toArray()]);
99+
session(['_courseReviewQuestions_' . $course->id => $finalQuestions->keyBy('id')->toArray()]);
103100

104101
return Inertia::render('courses/review/Show', [
105102
'course' => $course->only('id', 'title', 'slug'),
@@ -108,21 +105,23 @@ public function generate(Course $course): Response|RedirectResponse
108105
]);
109106
}
110107

108+
111109
/**
112110
* Process and grade the submitted final review quiz.
113111
*/
114-
public function submit(Request $request, Course $course): Response|RedirectResponse
112+
public function submit(Request $request, Course $course): Response | RedirectResponse
115113
{
116114
$user = Auth::user();
117115
$submittedAnswers = $request->input('answers', []);
118116
$request->input('quizId');
119117

120118
$request->validate(['answers' => 'required|array', 'quizId' => 'required|string']);
121119

122-
$correctQuestionsData = session('_courseReviewQuestions_'.$course->id);
123-
session()->forget('_courseReviewQuestions_'.$course->id);
120+
// Retrieve correct answers from session
121+
$correctQuestionsData = session('_courseReviewQuestions_' . $course->id);
122+
session()->forget('_courseReviewQuestions_' . $course->id);
124123

125-
if (! $correctQuestionsData) {
124+
if (!$correctQuestionsData) {
126125
return Redirect::route('course.review.generate', $course)
127126
->with('error', 'Review quiz session expired. Please try again.');
128127
}
@@ -147,7 +146,7 @@ public function submit(Request $request, Course $course): Response|RedirectRespo
147146
]);
148147

149148
foreach ($submittedAnswers as $questionId => $userAnswer) {
150-
if (! $correctQuestions->has($questionId)) {
149+
if (!$correctQuestions->has($questionId)) {
151150
continue;
152151
}
153152

@@ -158,16 +157,16 @@ public function submit(Request $request, Course $course): Response|RedirectRespo
158157
? (json_decode($question->options, true) ?? [])
159158
: ($question->options ?? []);
160159

160+
161161
$isCorrect = false;
162162
$correctAnswer = $question->correct_answer ?? null;
163163

164-
// TODO: Refactor the grading logic to Service/Trait later
165164
switch ($question->type ?? 'multiple_choice') {
166165
case 'multiple_choice':
167166
case 'fill_blank':
168167
case 'true_false':
169168
if (is_string($userAnswer) && is_string($correctAnswer)) {
170-
$isCorrect = mb_strtolower(mb_trim($userAnswer)) === mb_strtolower(mb_trim($correctAnswer));
169+
$isCorrect = strtolower(trim($userAnswer)) === strtolower(trim($correctAnswer));
171170
}
172171
break;
173172
}
@@ -201,9 +200,8 @@ public function submit(Request $request, Course $course): Response|RedirectRespo
201200
$attempt->score = $score;
202201
$attempt->save();
203202
});
204-
} catch (Exception $e) {
205-
Log::error('CourseReviewSubmit: Failed to save attempt.', ['error' => $e->getMessage()]);
206-
203+
} catch (\Exception $e) {
204+
Log::error("CourseReviewSubmit: Failed to save attempt.", ['error' => $e->getMessage()]);
207205
return Redirect::route('course.review.generate', $course)
208206
->with('error', 'An error occurred saving your review attempt.');
209207
}
@@ -213,7 +211,7 @@ public function submit(Request $request, Course $course): Response|RedirectRespo
213211
if ($result['is_correct']) {
214212
continue;
215213
}
216-
if (! $result['lesson_id']) {
214+
if (!$result['lesson_id']) {
217215
continue;
218216
}
219217
if (isset($lessonsToReviewDeeply[$result['lesson_id']])) {
@@ -225,7 +223,7 @@ public function submit(Request $request, Course $course): Response|RedirectRespo
225223
'id' => $lessonModel->id,
226224
'title' => $lessonModel->title,
227225
'url' => route('lessons.show', ['course' => $course->slug, 'lesson' => $lessonModel->slug]),
228-
'external_resources' => $lessonModel->externalResources->map(fn ($res) => $res->only('title', 'url', 'type', 'description'))->toArray(),
226+
'external_resources' => $lessonModel->externalResources->map(fn($res) => $res->only('title', 'url', 'type', 'description'))->toArray(),
229227
];
230228
}
231229
}
@@ -234,7 +232,7 @@ public function submit(Request $request, Course $course): Response|RedirectRespo
234232
'quiz' => ['id' => $attempt->quiz_id, 'title' => $course->finalReviewQuiz?->title ?? "{$course->title} - Final Review"],
235233
'attempt' => $attempt,
236234
'results' => $resultsData,
237-
'reviewSuggestions' => [], // TODO: Legacy, not used here
235+
'reviewSuggestions' => [],
238236
'deepReviewSuggestions' => array_values($lessonsToReviewDeeply),
239237
]);
240238
}

database/migrations/0001_01_01_000000_create_users_table.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ public function up(): void
2020
$table->timestamp('email_verified_at')->nullable();
2121
$table->string('password');
2222
$table->rememberToken();
23-
$table->enum('preferred_learning_style', ['reading', 'visual', 'balanced'])
24-
->default('balanced')
25-
->nullable() // Allow null if user hasn't set it
26-
->after('password'); // Place it after password
23+
$table->enum('preferred_learning_style', ['reading', 'visual'])
24+
->default('reading')
25+
->nullable()
26+
->after('password');
2727

28-
$table->foreignId('learning_path_id') // New column name
28+
$table->foreignId('learning_path_id')
2929
->nullable()
3030
->after('preferred_learning_style')
31-
->constrained('learning_paths') // Foreign key to learning_paths table
31+
->constrained('learning_paths')
3232
->onDelete('set null');
3333
$table->timestamps();
3434
});

database/migrations/2025_04_17_141934_create_lessons_table.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ public function up(): void
2222
$table->text('video_embed_html')->nullable()->after('content');
2323
$table->text('assignment')->nullable()->comment('Assignment description');
2424
$table->text('initial_code')->nullable()->comment('Starting code for editor');
25-
// $table->text('solution')->nullable()->comment('Optional solution code/explanation');
26-
$table->text('expected_output')->nullable()->comment('For simple stdout checks'); // Example addition
25+
$table->text('expected_output')->nullable()->comment('For simple stdout checks');
2726
$table->unsignedSmallInteger('order')->default(0);
2827
$table->timestamps();
2928

database/migrations/2025_04_22_192108_create_questions_table.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,7 @@ public function up(): void
1616
Schema::create('questions', function (Blueprint $table) {
1717
$table->id();
1818
$table->foreignId('quiz_id')->constrained()->onDelete('cascade');
19-
// Crucial link for suggesting review topics!
20-
// Can be null if a question is general, or set null if lesson deleted.
2119
$table->foreignId('lesson_id')->nullable()->constrained()->onDelete('set null');
22-
// Start with multiple choice, add more later if needed
2320
$table->enum('type', ['multiple_choice', 'true_false', 'fill_blank'])->default('multiple_choice');
2421
$table->text('text')->comment('The question text');
2522
$table->json('options')->nullable();

database/migrations/2025_04_22_192108_create_quiz_answers_table.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ public function up(): void
1717
$table->id();
1818
$table->foreignId('quiz_attempt_id')->constrained()->onDelete('cascade');
1919
$table->foreignId('question_id')->constrained()->onDelete('cascade');
20-
// Store the user's selected option ID (e.g., "a", "b")
2120
$table->string('user_answer')->nullable();
2221
$table->boolean('is_correct')->nullable()->comment('Graded result');
2322
$table->timestamps();

database/migrations/2025_04_22_192108_create_quiz_attempts_table.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,9 @@ public function up(): void
1818
$table->foreignId('user_id')->constrained()->onDelete('cascade');
1919
$table->foreignId('quiz_id')->nullable()->constrained()->onDelete('cascade');
2020
$table->string('type')->default('standard')->after('quiz_id');
21-
// Score as percentage (0-100), calculated after submission
2221
$table->unsignedTinyInteger('score')->nullable();
2322
$table->timestamp('started_at')->useCurrent();
24-
$table->timestamp('completed_at')->nullable(); // Set when submitted
23+
$table->timestamp('completed_at')->nullable();
2524
$table->timestamps();
2625
});
2726
}

database/migrations/2025_04_22_192603_create_lesson_quiz_table.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function up(): void
1717
$table->id();
1818
$table->foreignId('lesson_id')->constrained()->onDelete('cascade');
1919
$table->foreignId('quiz_id')->constrained()->onDelete('cascade');
20-
$table->timestamps(); // Optional, but good practice
20+
$table->timestamps();
2121

2222
$table->unique(['lesson_id', 'quiz_id']);
2323
});

database/migrations/2025_04_24_114041_create_user_progress_table.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@ public function up(): void
1515
{
1616
Schema::create('user_progress', function (Blueprint $table) {
1717
$table->id();
18-
// Foreign keys linking to users and lessons
1918
$table->foreignId('user_id')->constrained()->onDelete('cascade');
2019
$table->foreignId('lesson_id')->constrained()->onDelete('cascade');
2120
$table->timestamp('completed_at')->useCurrent(); // Record when completed
2221
$table->timestamps();
2322

24-
// IMPORTANT: A user can complete a specific lesson only once
23+
// A user can complete a specific lesson only once
2524
$table->unique(['user_id', 'lesson_id']);
2625
});
2726
}

database/migrations/2025_05_17_170453_create_learning_path_course_table.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ public function up(): void
1717
$table->id();
1818
$table->foreignId('learning_path_id')->constrained()->onDelete('cascade');
1919
$table->foreignId('course_id')->constrained()->onDelete('cascade');
20-
$table->unsignedSmallInteger('order')->default(0); // Order of the course in the path
21-
$table->timestamps(); // Usually not needed for simple pivot unless tracking when added
20+
$table->unsignedSmallInteger('order')->default(0);
21+
$table->timestamps();
2222

23-
$table->unique(['learning_path_id', 'course_id']); // A course appears once per path
23+
$table->unique(['learning_path_id', 'course_id']);
2424
$table->index(['learning_path_id', 'order']);
2525
});
2626
}

database/seeders/ExternalResourceSeeder.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function run(): void
2929
ExternalResource::create([
3030
'lesson_id' => $lessonDeclare->id,
3131
'title' => 'Understanding var, let, and const in JavaScript (Video)',
32-
'url' => 'https://www.youtube.com/watch?v=s-hLgT_t3uA', // Example video
32+
'url' => 'https://www.youtube.com/watch?v=s-hLgT_t3uA',
3333
'type' => 'video',
3434
'description' => 'A video explaining the differences and use cases for variable declarations.',
3535
]);
@@ -44,6 +44,5 @@ public function run(): void
4444
'type' => 'documentation',
4545
]);
4646
}
47-
// Add more resources for other lessons...
4847
}
4948
}

0 commit comments

Comments
 (0)