Skip to content

Commit 713cfd6

Browse files
scott graysonscott grayson
authored andcommitted
feat: add test step perfect score requirement and retry step feature
- Add require_perfect_score and retry_step_id columns to lms_steps table - Combine migrations into single add_test_step_features_to_lms_steps_table migration - Add retry step selection in StepResource (only visible when require_perfect_score is enabled) - Implement test step completion logic requiring 100% score when enabled - Add retake test functionality to allow users to retry failed tests - Replace custom GradedKeyValueEntry with standard Filament infolist components - Add reusable next-button component for consistent styling across step types - Hide correct answers from detailed results view - Add comprehensive test coverage for test step completion feature - Clean up unused GradedKeyValueEntry component and view
1 parent 198df74 commit 713cfd6

23 files changed

+600
-157
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Illuminate\Database\Migrations\Migration;
6+
use Illuminate\Database\Schema\Blueprint;
7+
use Illuminate\Support\Facades\Schema;
8+
9+
return new class extends Migration
10+
{
11+
/**
12+
* Run the migrations.
13+
*/
14+
public function up(): void
15+
{
16+
Schema::table('lms_steps', function (Blueprint $table): void {
17+
$table->foreignId('retry_step_id')->nullable()->after('material_type')->constrained('lms_steps')->onDelete('set null');
18+
$table->boolean('require_perfect_score')->default(false)->after('retry_step_id');
19+
});
20+
}
21+
22+
/**
23+
* Reverse the migrations.
24+
*/
25+
public function down(): void
26+
{
27+
Schema::table('lms_steps', function (Blueprint $table): void {
28+
$table->dropForeign(['retry_step_id']);
29+
$table->dropColumn(['retry_step_id', 'require_perfect_score']);
30+
});
31+
}
32+
};

dist/filament-lms.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@
3838
.step-material-container iframe[src*=".pdf"] {
3939
min-height: 60vh;
4040
}
41+
42+
/* Next button spacing */
43+
.next-button {
44+
margin-top: 2rem !important;
45+
}

resources/css/plugin.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,8 @@
3838
.step-material-container iframe[src*=".pdf"] {
3939
min-height: 60vh;
4040
}
41+
42+
/* Next button spacing */
43+
.next-button {
44+
margin-top: 2rem !important;
45+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
@props([
2+
'disabled' => false,
3+
'fixed' => true,
4+
])
5+
6+
@if($fixed)
7+
<div class="fixed bottom-0 right-0 p-4 md:p-6 lg:p-8">
8+
<x-filament::button
9+
color="primary"
10+
size="xl"
11+
wire:click="$dispatch('complete-step')"
12+
:disabled="$disabled"
13+
class="next-button"
14+
>
15+
Next
16+
</x-filament::button>
17+
</div>
18+
@else
19+
<x-filament::button
20+
color="primary"
21+
size="xl"
22+
wire:click="$dispatch('complete-step')"
23+
:disabled="$disabled"
24+
class="next-button"
25+
>
26+
Next
27+
</x-filament::button>
28+
@endif

resources/views/livewire/document-step.blade.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,5 @@ class="step-material-container rounded-lg border border-gray-300"
2424
</x-filament::button>
2525
</x-filament::section>
2626

27-
<div class="fixed bottom-0 right-0 p-4 md:p-6 lg:p-8">
28-
<x-filament::button color="gray" wire:click="$dispatch('complete-step')" class="next-button">
29-
Next
30-
</x-filament::button>
31-
</div>
27+
<x-filament-lms::next-button />
3228
</div>

resources/views/livewire/form-step.blade.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,5 @@
55
@livewire('tapp.filament-form-builder.livewire.filament-form.show', [$form, 'blockRedirect' => true])
66
@endif
77

8-
<div class="fixed bottom-0 right-0 p-4 md:p-6 lg:p-8">
9-
<x-filament::button color="gray" wire:click="$dispatch('complete-step')" :disabled="!$step->is_optional && !$entry" class="next-button">
10-
Next
11-
</x-filament::button>
12-
</div>
8+
<x-filament-lms::next-button :disabled="!$step->is_optional && !$entry" />
139
</div>

resources/views/livewire/graded-key-value-entry.blade.php

Lines changed: 0 additions & 82 deletions
This file was deleted.

resources/views/livewire/image-step.blade.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,5 @@ class="step-material-container rounded-lg border border-gray-300"
1313
</div>
1414
</x-filament::section>
1515

16-
<div class="fixed bottom-0 right-0 p-4 md:p-6 lg:p-8">
17-
<x-filament::button color="gray" wire:click="$dispatch('complete-step')" class="next-button">
18-
Next
19-
</x-filament::button>
20-
</div>
16+
<x-filament-lms::next-button />
2117
</div>

resources/views/livewire/link-step.blade.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,5 @@ class="step-material-container rounded-lg border border-gray-300 cursor-pointer"
3030
</x-filament::button>
3131
</x-filament::section>
3232

33-
<div class="fixed bottom-0 right-0 p-4 md:p-6 lg:p-8">
34-
<x-filament::button color="gray" wire:click="$dispatch('complete-step')" :disabled="!$step->is_optional && !$visited" class="next-button">
35-
Next
36-
</x-filament::button>
37-
</div>
33+
<x-filament-lms::next-button :disabled="!$step->is_optional && !$visited" />
3834
</div>
Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,63 @@
11
<div>
22
@if($entry)
3-
@livewire('view-graded-entry', ['test' => $test, 'entry' => $entry])
3+
<div class="mb-8">
4+
@livewire('view-graded-entry', ['test' => $test, 'entry' => $entry])
5+
</div>
6+
7+
@if(!$testPassed && $step->require_perfect_score)
8+
<x-filament::section class="mt-8">
9+
<div class="space-y-4">
10+
<div class="rounded-lg bg-danger-50 dark:bg-danger-900/20 p-4">
11+
<div class="flex">
12+
<div class="flex-shrink-0">
13+
<x-filament::icon
14+
icon="heroicon-o-exclamation-triangle"
15+
class="h-5 w-5 text-danger-600 dark:text-danger-400"
16+
/>
17+
</div>
18+
<div class="ml-3">
19+
<h3 class="text-sm font-medium text-danger-800 dark:text-danger-200">
20+
Test Not Passed
21+
</h3>
22+
<div class="mt-2 text-sm text-danger-700 dark:text-danger-300">
23+
<p>
24+
You must answer all questions correctly to proceed. Please review the material and try again.
25+
</p>
26+
</div>
27+
<div class="mt-4 flex gap-3">
28+
@if($step->retryStep)
29+
@php
30+
$retryStep = $step->retryStep;
31+
if (!$retryStep->relationLoaded('lesson')) {
32+
$retryStep->load('lesson.course');
33+
}
34+
$retryStepUrl = '/lms/courses/' . $retryStep->lesson->course->slug . '/' . $retryStep->lesson->slug . '/' . $retryStep->slug;
35+
@endphp
36+
<x-filament::button
37+
tag="a"
38+
:href="$retryStepUrl"
39+
color="danger"
40+
outlined
41+
>
42+
Review Material
43+
</x-filament::button>
44+
@endif
45+
<x-filament::button
46+
wire:click="retakeTest"
47+
color="primary"
48+
>
49+
Retake Test
50+
</x-filament::button>
51+
</div>
52+
</div>
53+
</div>
54+
</div>
55+
</div>
56+
</x-filament::section>
57+
@endif
458
@else
559
@livewire('create-test-entry', ['test' => $test])
660
@endif
761

8-
<div class="fixed bottom-0 right-0 p-4 md:p-6 lg:p-8">
9-
<x-filament::button color="gray" wire:click="$dispatch('complete-step')" :disabled="!$step->is_optional && !$entry" class="next-button">
10-
Next
11-
</x-filament::button>
12-
</div>
62+
<x-filament-lms::next-button :disabled="!$step->is_optional && (!$entry || ($step->require_perfect_score && !$testPassed))" />
1363
</div>

0 commit comments

Comments
 (0)