From 15b9ebc084b05be211940d7dcfea54e82000de7a Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Wed, 1 Apr 2026 13:57:48 +0700 Subject: [PATCH] feat: implement search functionality for assignments with course name filtering and update permissions --- .../Assignments/Pages/ListAssignments.php | 38 ++++++++ .../learning/assignments/index.blade.php | 8 +- tests/Feature/AssignmentTest.php | 92 +++++++++++++++++-- 3 files changed, 129 insertions(+), 9 deletions(-) diff --git a/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php b/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php index 61bc771..db8e770 100644 --- a/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php +++ b/app/Filament/Resources/Learning/Assignments/Pages/ListAssignments.php @@ -13,13 +13,19 @@ use App\Models\AssignmentPin; use App\Settings\GeneralSettings; use Filament\Actions\Action; +use Filament\Forms\Components\TextInput; use Filament\Resources\Pages\Page; +use Filament\Schemas\Schema; use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Arr; use Livewire\Attributes\Computed; +use Livewire\Attributes\Url; class ListAssignments extends Page { + #[Url] + public ?string $search = ''; + protected static string $resource = AssignmentResource::class; protected string $view = 'filament.resources.learning.assignments.index'; @@ -28,6 +34,32 @@ class ListAssignments extends Page protected static ?string $recordTitleAttribute = 'title'; + public static function getPagePermission(): string + { + return 'View:CourseSchedule'; + } + + public function mount(): void + { + $this->form->fill(); + } + + public function form(Schema $schema): Schema + { + return $schema + ->schema([ + TextInput::make('search') + ->label('Cari') + ->placeholder('Cari Judul Tugas atau Mata Kuliah...') + ->autocomplete(false) + ->live(debounce: 500) + ->afterStateUpdated(fn ($state) => $this->search = $state), + ]) + ->columns([ + 'sm' => 1, + ]); + } + protected function getHeaderActions(): array { return [ @@ -90,6 +122,12 @@ public function assignments(): Collection $query->whereHas('students', fn ($q) => $q->whereKey($studentProfile->id)) ->orWhereHas('studyGroups', fn ($q) => $q->where('leader_id', $studentProfile->id)->orWhereHas('students', fn ($sq) => $sq->whereKey($studentProfile->id))); }) + ->when($this->search, function ($query) { + $query->where(function ($q) { + $q->where('title', 'like', "%{$this->search}%") + ->orWhereHas('course', fn ($cq) => $cq->where('name', 'like', "%{$this->search}%")); + }); + }) ->get(); return $assignments->sort(function ($a, $b) use ($pinnedIds) { diff --git a/resources/views/filament/resources/learning/assignments/index.blade.php b/resources/views/filament/resources/learning/assignments/index.blade.php index 084e798..762990d 100644 --- a/resources/views/filament/resources/learning/assignments/index.blade.php +++ b/resources/views/filament/resources/learning/assignments/index.blade.php @@ -6,6 +6,12 @@ {{ $this->heading }} {{ $this->description }} +
+
+ {{ $this->form }} +
+
+
@forelse ($this->assignmentCards as $card) @@ -107,7 +113,7 @@ class="{{ $card->indicator_icon_classes }}"
@endif - @empty + @empty create(); $developer->assignRole(RoleEnum::Developer); - $developer->givePermissionTo(['ViewAny:Assignment', 'Create:Assignment']); + $developer->givePermissionTo(['ViewAny:Assignment', 'Create:Assignment', 'View:CourseSchedule']); $studentUser = User::factory()->create(); $studentUser->assignRole(RoleEnum::Student); - $studentUser->givePermissionTo(['ViewAny:Assignment']); + $studentUser->givePermissionTo(['ViewAny:Assignment', 'View:CourseSchedule']); $student = Student::factory()->create(['user_id' => $studentUser->id]); $this->actingAs($developer); @@ -81,7 +82,7 @@ beforeEach(function () { $user = User::factory()->create(); $user->assignRole(RoleEnum::Developer); - $user->givePermissionTo(['ViewAny:Assignment', 'Create:Assignment', 'Update:Assignment', 'Delete:Assignment']); + $user->givePermissionTo(['ViewAny:Assignment', 'Create:Assignment', 'Update:Assignment', 'Delete:Assignment', 'View:CourseSchedule']); $this->actingAs($user); }); @@ -126,7 +127,7 @@ it('allows individual submission', function () { $user = User::factory()->create(); $user->assignRole(RoleEnum::Student); - $user->givePermissionTo(['ViewAny:Assignment']); + $user->givePermissionTo(['ViewAny:Assignment', 'View:CourseSchedule']); $student = Student::factory()->create(['user_id' => $user->id]); $assignment = Assignment::factory()->create([ @@ -156,12 +157,12 @@ $leaderUser = User::factory()->create(); $leaderUser->assignRole(RoleEnum::Student); - $leaderUser->givePermissionTo(['ViewAny:Assignment']); + $leaderUser->givePermissionTo(['ViewAny:Assignment', 'View:CourseSchedule']); $leader = Student::factory()->create(['user_id' => $leaderUser->id]); $memberUser = User::factory()->create(); $memberUser->assignRole(RoleEnum::Student); - $memberUser->givePermissionTo(['ViewAny:Assignment']); + $memberUser->givePermissionTo(['ViewAny:Assignment', 'View:CourseSchedule']); $member = Student::factory()->create(['user_id' => $memberUser->id]); $group = StudyGroup::factory()->create([ @@ -195,7 +196,7 @@ beforeEach(function () { $user = User::factory()->create(); $user->assignRole(RoleEnum::Student); - $user->givePermissionTo(['ViewAny:Assignment']); + $user->givePermissionTo(['ViewAny:Assignment', 'View:CourseSchedule']); $this->studentProfile = Student::factory()->create(['user_id' => $user->id]); $this->actingAs($user); $this->currentSemester = app(GeneralSettings::class)->current_semester; @@ -224,11 +225,86 @@ }); }); +describe('Assignment Search', function () { + beforeEach(function () { + $user = User::factory()->create(); + $user->assignRole(RoleEnum::Student); + $user->givePermissionTo(['ViewAny:Assignment', 'View:CourseSchedule']); + $this->studentProfile = Student::factory()->create(['user_id' => $user->id]); + $this->actingAs($user); + $this->currentSemester = app(GeneralSettings::class)->current_semester; + }); + + it('can search assignments by title', function () { + $course = Course::factory()->create(['semester' => $this->currentSemester]); + + $assignment1 = Assignment::factory()->create([ + 'title' => 'Tugas Matematika 1', + 'course_id' => $course->id, + 'due_date' => now()->addDays(1), + ]); + $assignment2 = Assignment::factory()->create([ + 'title' => 'Tugas Biologi 2', + 'course_id' => $course->id, + 'due_date' => now()->addDays(1), + ]); + + $assignment1->students()->attach($this->studentProfile->id); + $assignment2->students()->attach($this->studentProfile->id); + + Livewire::test(ListAssignments::class) + ->set('search', 'Matematika') + ->assertSee('Tugas Matematika 1') + ->assertDontSee('Tugas Biologi 2'); + }); + + it('can search assignments by course name', function () { + $course1 = Course::factory()->create(['name' => 'Fisika Dasar', 'semester' => $this->currentSemester]); + $course2 = Course::factory()->create(['name' => 'Sejarah Indonesia', 'semester' => $this->currentSemester]); + + $assignment1 = Assignment::factory()->create([ + 'title' => 'Laporan Praktikum', + 'course_id' => $course1->id, + 'due_date' => now()->addDays(1), + ]); + $assignment2 = Assignment::factory()->create([ + 'title' => 'Makalah', + 'course_id' => $course2->id, + 'due_date' => now()->addDays(1), + ]); + + $assignment1->students()->attach($this->studentProfile->id); + $assignment2->students()->attach($this->studentProfile->id); + + Livewire::test(ListAssignments::class) + ->set('search', 'Fisika') + ->assertSee('Laporan Praktikum') + ->assertSee('Fisika Dasar') + ->assertDontSee('Makalah') + ->assertDontSee('Sejarah Indonesia'); + }); + + it('shows empty state when no assignments found with search', function () { + $course = Course::factory()->create(['semester' => $this->currentSemester]); + $assignment = Assignment::factory()->create([ + 'title' => 'Tugas Wajib', + 'course_id' => $course->id, + 'due_date' => now()->addDays(1), + ]); + $assignment->students()->attach($this->studentProfile->id); + + Livewire::test(ListAssignments::class) + ->set('search', 'Random string yang ga ada') + ->assertDontSee('Tugas Wajib') + ->assertSee('Hore, Belum Ada Tugas!'); + }); +}); + describe('Assignment Details and Preview', function () { beforeEach(function () { $user = User::factory()->create(); $user->assignRole(RoleEnum::Developer); - $user->givePermissionTo(['ViewAny:Assignment', 'View:Assignment']); + $user->givePermissionTo(['ViewAny:Assignment', 'View:Assignment', 'View:CourseSchedule']); $this->actingAs($user); $this->currentSemester = app(GeneralSettings::class)->current_semester; });