feat: Filter course-related data by current semester from general settings and rename attendance management page.

This commit is contained in:
Yoga Pangestu 2026-03-12 08:03:51 +07:00
parent 2019928fb3
commit c8f2ac6c26
8 changed files with 70 additions and 95 deletions

View File

@ -7,6 +7,7 @@
use App\Filament\Pages\Information\CourseSchedule\Actions\EditScheduleAction;
use App\Models\Course;
use App\Models\CourseSchedule;
use App\Settings\GeneralSettings;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
@ -43,8 +44,6 @@ class Index extends Page implements HasActions, HasForms
protected string $view = 'filament.pages.information.list-course-schedules';
public ?int $course_semester = null;
public ?string $search = '';
public static function getPagePermission(): string
@ -54,24 +53,13 @@ public static function getPagePermission(): string
public function mount(): void
{
$this->course_semester = null;
$this->form->fill([
'course_semester' => $this->course_semester,
]);
$this->form->fill();
}
public function form(Schema $schema): Schema
{
return $schema
->schema([
Select::make('course_semester')
->label('Semester')
->options(array_combine(range(1, 8), array_map(fn ($i) => "Semester $i", range(1, 8))))
->native(false)
->live()
->afterStateUpdated(fn ($state) => $this->course_semester = $state),
TextInput::make('search')
->label('Cari')
->placeholder('Cari Mata Kuliah atau Dosen...')
@ -81,7 +69,6 @@ public function form(Schema $schema): Schema
])
->columns([
'sm' => 1,
'md' => 3,
]);
}
@ -113,9 +100,7 @@ public function getSchedules(): Collection
$query->whereHas('course', fn ($q) => $q->where('lecturer_id', $lecturer->id));
}
if ($this->course_semester) {
$query->whereHas('course', fn ($q) => $q->where('semester', $this->course_semester));
}
$query->whereHas('course', fn ($q) => $q->where('semester', app(GeneralSettings::class)->current_semester));
if ($this->search) {
$query->where(function ($q) {
@ -156,20 +141,15 @@ public function scheduleFormSchema(): array
Select::make('course_id')
->label('Mata Kuliah')
->options(function () {
return Course::all()
->groupBy('semester')
->mapWithKeys(function ($courses, $semester) {
return [
"Semester $semester" => $courses->pluck('name', 'id')->toArray(),
];
})
return Course::query()
->where('semester', app(GeneralSettings::class)->current_semester)
->pluck('name', 'id')
->toArray();
})
->searchable()
->live()
->required()
->columnSpanFull()
->optionsLimit(100),
->columnSpanFull(),
Grid::make(3)
->schema([

View File

@ -8,6 +8,7 @@
use App\Models\Course;
use App\Models\Student;
use App\Models\StudyGroup;
use App\Settings\GeneralSettings;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
@ -58,22 +59,20 @@ public function form(Schema $schema): Schema
->schema([
Select::make('course_id')
->label('Mata Kuliah')
->placeholder('Semua Mata Kuliah')
->options(function () {
return Course::all()
->groupBy('semester')
->mapWithKeys(function ($courses, $semester) {
return [
"Semester $semester" => $courses->pluck('name', 'id')->toArray(),
];
})
return Course::query()
->where('semester', app(GeneralSettings::class)->current_semester)
->pluck('name', 'id')
->toArray();
})
->searchable()
->required()
->optionsLimit(100),
->live(),
])
->columns(1);
->columns([
'sm' => 1,
]);
}
protected function getHeaderActions(): array
@ -95,7 +94,8 @@ protected function deleteStudyGroupAction(): Action
public function getStudyGroups(): Collection
{
$query = StudyGroup::with(['leader', 'students', 'courses']);
$query = StudyGroup::with(['leader', 'students', 'courses'])
->whereHas('courses', fn ($q) => $q->where('courses.semester', app(GeneralSettings::class)->current_semester));
if ($this->course_id) {
$query->whereHas('courses', fn ($q) => $q->where('courses.id', $this->course_id));
@ -114,7 +114,7 @@ protected function getViewData(): array
public function isMyGroup(StudyGroup $record): bool
{
$studentId = $this->studentId;
$studentId = auth()->user()?->student?->id;
if (! $studentId) {
return false;
@ -131,19 +131,14 @@ public function studyGroupFormSchema(): array
Select::make('course_id')
->label('Mata Kuliah')
->options(function () {
return Course::all()
->groupBy('semester')
->mapWithKeys(function ($courses, $semester) {
return [
"Semester $semester" => $courses->pluck('name', 'id')->toArray(),
];
})
return Course::query()
->where('semester', app(GeneralSettings::class)->current_semester)
->pluck('name', 'id')
->toArray();
})
->multiple()
->searchable()
->required()
->optionsLimit(100)
->columnSpanFull(),
TextInput::make('name')

View File

@ -6,6 +6,7 @@
use App\Filament\Resources\Learning\Assignments\Actions\SelectAllStudentsAction;
use App\Models\Course;
use App\Models\Student;
use App\Settings\GeneralSettings;
use Asmit\FilamentUpload\Enums\PdfViewFit;
use Asmit\FilamentUpload\Forms\Components\AdvancedFileUpload;
use Filament\Forms\Components\DateTimePicker;
@ -43,19 +44,14 @@ public static function configure(Schema $schema): Schema
Select::make('course_id')
->label('Mata Kuliah')
->options(function () {
return Course::all()
->groupBy('semester')
->mapWithKeys(function ($courses, $semester) {
return [
"Semester $semester" => $courses->pluck('name', 'id')->toArray(),
];
})
return Course::query()
->where('semester', app(GeneralSettings::class)->current_semester)
->pluck('name', 'id')
->toArray();
})
->searchable()
->live()
->required()
->optionsLimit(100),
->required(),
DateTimePicker::make('due_date')
->label('Batas Waktu')

View File

@ -2,7 +2,7 @@
namespace App\Filament\Resources\Learning\Attendances;
use App\Filament\Resources\Learning\Attendances\Pages\AttendancePage;
use App\Filament\Resources\Learning\Attendances\Pages\ManageAttendances;
use App\Models\Attendance;
use BackedEnum;
use Filament\Resources\Resource;
@ -28,7 +28,7 @@ class AttendanceResource extends Resource
public static function getPages(): array
{
return [
'index' => AttendancePage::route('/'),
'index' => ManageAttendances::route('/'),
];
}
}

View File

@ -7,9 +7,10 @@
use App\Models\Attendance;
use App\Models\CourseSchedule;
use App\Models\User;
use App\Settings\GeneralSettings;
use Filament\Resources\Pages\Page;
class AttendancePage extends Page
class ManageAttendances extends Page
{
protected static string $resource = AttendanceResource::class;
@ -23,11 +24,23 @@ public function getSchedules()
{
$student = auth()->user()->student;
$today = now()->dayOfWeek;
if (! $student) {
return collect();
}
$today = now()->dayOfWeekIso;
$semester = app(GeneralSettings::class)->current_semester;
return CourseSchedule::query()
->where('day_of_week', $today)
->with(['course', 'attendances' => function ($q) use ($student) {
->whereHas('course', function ($q) use ($semester, $student) {
$q->where('semester', $semester)
->whereHas('studyGroups', function ($sq) use ($student) {
$sq->where('leader_id', $student->id)
->orWhereHas('students', fn ($asq) => $asq->where('students.id', $student->id));
});
})
->with(['course.lecturer.user', 'attendances' => function ($q) use ($student) {
$q->where('student_id', $student->id)
->whereDate('date', now()->toDateString());
}])
@ -64,6 +77,7 @@ public function getScheduleCards()
return (object) [
'id' => $schedule->id,
'course_name' => $schedule->course->name,
'lecturer_name' => $schedule->course->lecturer?->full_name ?? 'Belum Ditentukan',
'time_range' => $schedule->start_time->format('H:i').' - '.$schedule->end_time->format('H:i'),
'is_attended' => $isAttended,
'can_attend' => $canAttend && ! $isAttended,

View File

@ -11,6 +11,7 @@
use App\Filament\Resources\Learning\Materials\Pages\ManageMaterials;
use App\Models\Course;
use App\Models\Material;
use App\Settings\GeneralSettings;
use Asmit\FilamentUpload\Enums\PdfViewFit;
use Asmit\FilamentUpload\Forms\Components\AdvancedFileUpload;
use BackedEnum;
@ -60,19 +61,14 @@ public static function form(Schema $schema): Schema
Select::make('course_id')
->label('Mata Kuliah')
->options(function () {
return Course::all()
->groupBy('semester')
->mapWithKeys(function ($courses, $semester) {
return [
"Semester $semester" => $courses->pluck('name', 'id')->toArray(),
];
})
return Course::query()
->where('semester', app(GeneralSettings::class)->current_semester)
->pluck('name', 'id')
->toArray();
})
->searchable()
->live()
->required()
->optionsLimit(100),
->required(),
DatePicker::make('published_at')
->label('Tanggal Publikasi')
@ -147,17 +143,12 @@ public static function table(Table $table): Table
SelectFilter::make('course_id')
->label('Mata Kuliah')
->options(function () {
return Course::all()
->groupBy('semester')
->mapWithKeys(function ($courses, $semester) {
return [
"Semester $semester" => $courses->pluck('name', 'id')->toArray(),
];
})
return Course::query()
->where('semester', app(GeneralSettings::class)->current_semester)
->pluck('name', 'id')
->toArray();
})
->searchable()
->optionsLimit(100),
->searchable(),
Filter::make('published_at')
->schema([

View File

@ -12,7 +12,7 @@ class="fi-section-content rounded-xl border border-info-200 bg-info-50 dark:bg-i
</div>
<div class="flex items-center justify-between gap-4 mb-6">
<div class="w-full">
<div class="w-full max-w-xl">
{{ $this->form }}
</div>
</div>

View File

@ -25,34 +25,33 @@ class="inline-flex items-center gap-1 rounded-full bg-primary-600 px-3 py-1 text
@endif
<div class="p-6 space-y-4 flex-1">
<div class="flex flex-wrap items-center gap-1.5">
<span @class([
'inline-flex items-center rounded-md px-2.5 py-1 text-[10px] font-bold ring-1 ring-inset uppercase tracking-tight',
'bg-primary-50 dark:bg-primary-500/10 text-primary-700 dark:text-primary-300 ring-primary-600/20' => !$card->is_attended,
'bg-white dark:bg-primary-800/40 text-primary-700 dark:text-primary-200 ring-primary-500/30' =>
$card->is_attended,
])>
{{ $card->course_name }}
</span>
</div>
<div class="space-y-1">
<h3 @class([
'text-lg font-bold leading-tight flex items-center gap-2 transition-colors',
'text-gray-950 dark:text-white group-hover:text-primary-600 dark:group-hover:text-primary-400' => !$card->is_attended,
'text-primary-900 dark:text-primary-100' => $card->is_attended,
])>
<x-heroicon-o-finger-print @class([
<x-heroicon-o-book-open @class([
'w-5 h-5 shrink-0',
'opacity-40' => !$card->is_attended,
'text-primary-500' => $card->is_attended,
]) />
Presensi Kuliah
{{ $card->course_name }}
</h3>
<div @class([
'flex items-center gap-1.5',
'text-gray-500 dark:text-gray-400' => !$card->is_attended,
'text-primary-600 dark:text-primary-400' => $card->is_attended,
])>
<x-heroicon-m-user @class(['w-3.5 h-3.5 shrink-0', 'opacity-50' => !$card->is_attended]) />
<span class="text-[11px] font-medium leading-none">
{{ $card->lecturer_name }}
</span>
</div>
</div>
<div class="space-y-4">
<div class="flex items-center text-sm text-gray-600 dark:text-gray-400">
<div class="flex items-center text-sm text-gray-600 dark:text-gray-400 py-4">
<div @class([
'w-8 h-8 rounded-full flex items-center justify-center mr-3 shrink-0 border',
'bg-primary-100 dark:bg-primary-900/40 border-primary-200 dark:border-primary-800' => !$card->is_attended,
@ -80,7 +79,7 @@ class="text-[10px] font-bold uppercase text-gray-400 tracking-widest leading-non
</div>
<div @class([
'pt-4 border-t',
'border-t',
'border-gray-100 dark:border-gray-800' => !$card->is_attended,
'border-primary-200 dark:border-primary-800' => $card->is_attended,
])>