feat: add course filtering to assignments list and enhance search functionality
This commit is contained in:
parent
a4f615ad20
commit
b097168c09
@ -12,8 +12,10 @@
|
||||
use App\Filament\Support\SystemNotification;
|
||||
use App\Models\Assignment;
|
||||
use App\Models\AssignmentPin;
|
||||
use App\Models\Course;
|
||||
use App\Settings\GeneralSettings;
|
||||
use Filament\Actions\Action;
|
||||
use Filament\Forms\Components\Select;
|
||||
use Filament\Forms\Components\TextInput;
|
||||
use Filament\Resources\Pages\Page;
|
||||
use Filament\Schemas\Schema;
|
||||
@ -27,6 +29,9 @@ class ListAssignments extends Page
|
||||
#[Url]
|
||||
public ?string $search = '';
|
||||
|
||||
#[Url]
|
||||
public ?int $course_id = null;
|
||||
|
||||
protected static string $resource = AssignmentResource::class;
|
||||
|
||||
protected string $view = 'filament.resources.learning.assignments.index';
|
||||
@ -42,7 +47,10 @@ public static function getPagePermission(): string
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->form->fill();
|
||||
$this->form->fill([
|
||||
'search' => $this->search,
|
||||
'course_id' => $this->course_id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function form(Schema $schema): Schema
|
||||
@ -51,13 +59,27 @@ public function form(Schema $schema): Schema
|
||||
->schema([
|
||||
TextInput::make('search')
|
||||
->label('Cari')
|
||||
->placeholder('Cari Judul Tugas atau Mata Kuliah...')
|
||||
->placeholder('Cari Judul Tugas...')
|
||||
->autocomplete(false)
|
||||
->live(debounce: 500)
|
||||
->afterStateUpdated(fn ($state) => $this->search = $state),
|
||||
|
||||
Select::make('course_id')
|
||||
->label('Mata Kuliah')
|
||||
->placeholder('Semua Mata Kuliah')
|
||||
->options(function () {
|
||||
return Course::query()
|
||||
->where('semester', app(GeneralSettings::class)->current_semester)
|
||||
->whereHas('courseSchedules')
|
||||
->pluck('name', 'id')
|
||||
->toArray();
|
||||
})
|
||||
->searchable()
|
||||
->live()
|
||||
->afterStateUpdated(fn ($state) => $this->course_id = $state),
|
||||
])
|
||||
->columns([
|
||||
'sm' => 1,
|
||||
'sm' => 2,
|
||||
]);
|
||||
}
|
||||
|
||||
@ -112,6 +134,15 @@ public function assignments(): Collection
|
||||
->whereHas('course', function ($q) {
|
||||
$q->where('semester', app(GeneralSettings::class)->current_semester);
|
||||
})
|
||||
->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}%"));
|
||||
});
|
||||
})
|
||||
->when($this->course_id, function ($query) {
|
||||
$query->where('course_id', $this->course_id);
|
||||
})
|
||||
->get();
|
||||
}
|
||||
|
||||
@ -134,6 +165,9 @@ public function assignments(): Collection
|
||||
->orWhereHas('course', fn ($cq) => $cq->where('name', 'like', "%{$this->search}%"));
|
||||
});
|
||||
})
|
||||
->when($this->course_id, function ($query) {
|
||||
$query->where('course_id', $this->course_id);
|
||||
})
|
||||
->get();
|
||||
|
||||
return $assignments->sort(function ($a, $b) use ($pinnedIds) {
|
||||
|
||||
@ -1,20 +1,18 @@
|
||||
<x-filament-panels::page>
|
||||
<x-filament::section
|
||||
icon="{{ \App\Filament\Support\SystemNotification::getNotifStyle() === \App\Enums\NotifStyle::Cheerful ? 'heroicon-o-clipboard-document-list' : 'heroicon-o-briefcase' }}"
|
||||
icon-color="primary"
|
||||
>
|
||||
<x-filament::section
|
||||
icon="{{ \App\Filament\Support\SystemNotification::getNotifStyle() === \App\Enums\NotifStyle::Cheerful ? 'heroicon-o-clipboard-document-list' : 'heroicon-o-briefcase' }}"
|
||||
icon-color="primary">
|
||||
<x-slot name="heading">{{ $this->heading }}</x-slot>
|
||||
<x-slot name="description">{{ $this->description }}</x-slot>
|
||||
|
||||
<div class="flex items-center justify-between gap-4 mb-6">
|
||||
<div class="w-full max-w-xl">
|
||||
<div class="flex items-center justify-between gap-4 mb-6">
|
||||
<div class="w-full">
|
||||
{{ $this->form }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-6">
|
||||
@forelse ($this->assignmentCards as $card)
|
||||
|
||||
<div class="{{ $card->card_classes }} flex-col">
|
||||
|
||||
<a href="{{ \App\Filament\Resources\Learning\Assignments\AssignmentResource::getUrl('submit', ['record' => $card->id]) }}"
|
||||
@ -73,13 +71,14 @@ class="inline-flex items-center gap-1.5 rounded-full bg-danger-500 text-white px
|
||||
|
||||
<div class="flex flex-wrap gap-x-4 gap-y-2 mt-4 text-xs text-gray-500 dark:text-gray-400">
|
||||
<span class="flex items-center gap-1.5">
|
||||
<x-filament::icon icon="heroicon-o-clock" class="h-4 w-4 shrink-0 text-primary-500" />
|
||||
<x-filament::icon icon="heroicon-o-clock"
|
||||
class="h-4 w-4 shrink-0 text-primary-500" />
|
||||
<span class="font-medium">Batas: {{ $card->due_date_formatted }}</span>
|
||||
</span>
|
||||
@if ($card->submitted_at_formatted)
|
||||
<span class="flex items-center gap-1.5 text-success-600 dark:text-success-400 font-bold bg-success-50 dark:bg-success-900/25 px-2 py-0.5 rounded-lg">
|
||||
<x-filament::icon icon="heroicon-o-arrow-up-tray"
|
||||
class="h-4 w-4 shrink-0" />
|
||||
<span
|
||||
class="flex items-center gap-1.5 text-success-600 dark:text-success-400 font-bold bg-success-50 dark:bg-success-900/25 px-2 py-0.5 rounded-lg">
|
||||
<x-filament::icon icon="heroicon-o-arrow-up-tray" class="h-4 w-4 shrink-0" />
|
||||
<span>Dikumpulkan: {{ $card->submitted_at_formatted }}</span>
|
||||
</span>
|
||||
@endif
|
||||
@ -88,7 +87,8 @@ class="h-4 w-4 shrink-0" />
|
||||
</a>
|
||||
|
||||
|
||||
<div class="flex flex-wrap items-center gap-3 px-5 py-4 border-t border-gray-100 dark:border-gray-700 bg-gray-50/50 dark:bg-gray-800/20">
|
||||
<div
|
||||
class="flex flex-wrap items-center gap-3 px-5 py-4 border-t border-gray-100 dark:border-gray-700 bg-gray-50/50 dark:bg-gray-800/20">
|
||||
{{ ($this->pinAction)(['record' => $card->id]) }}
|
||||
{{ ($this->shareAssignmentAction)(['record' => $card->id]) }}
|
||||
|
||||
@ -101,9 +101,9 @@ class="h-4 w-4 shrink-0" />
|
||||
|
||||
|
||||
</div>
|
||||
@empty
|
||||
@empty
|
||||
<div class="col-span-full">
|
||||
<x-filament::empty-state icon="heroicon-o-clipboard-document-list"
|
||||
<x-filament::empty-state icon="heroicon-o-clipboard-document-list"
|
||||
heading="{{ \App\Filament\Support\SystemNotification::getMessage('Hore, Belum Ada Tugas! 🎊✨', 'Tidak ada data yang ditemukan') }}"
|
||||
description="{{ \App\Filament\Support\SystemNotification::getMessage('Belum ada tugas baru yang perlu dikerjakan. Hidup tenang tanpa beban tugas itu asik ya! 😊🌈', 'Belum ada tugas baru yang perlu dikerjakan untuk saat ini. Tetap semangat!') }}"
|
||||
iconColor="gray">
|
||||
|
||||
@ -298,6 +298,30 @@
|
||||
->assertDontSee('Tugas Wajib')
|
||||
->assertSee('Hore, Belum Ada Tugas!');
|
||||
});
|
||||
|
||||
it('can filter assignments by course', function () {
|
||||
$course1 = Course::factory()->create(['name' => 'Matematika', 'semester' => $this->currentSemester]);
|
||||
$course2 = Course::factory()->create(['name' => 'Fisika', 'semester' => $this->currentSemester]);
|
||||
|
||||
$assignment1 = Assignment::factory()->create([
|
||||
'title' => 'Tugas Mat',
|
||||
'course_id' => $course1->id,
|
||||
'due_date' => now()->addDays(1),
|
||||
]);
|
||||
$assignment2 = Assignment::factory()->create([
|
||||
'title' => 'Tugas Fis',
|
||||
'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('course_id', $course1->id)
|
||||
->assertSee('Tugas Mat')
|
||||
->assertDontSee('Tugas Fis');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Assignment Sharing', function () {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user