feat: add enrollment year filter and export functionality for students
Some checks failed
tests / ci (pull_request) Has been cancelled

This commit is contained in:
Yoga Pangestu 2026-08-30 12:21:03 +07:00
parent 82d7b9bb1e
commit c0858e02ec
5 changed files with 35 additions and 8 deletions

View File

@ -22,6 +22,7 @@ public function __construct(
private readonly ?string $gender = null,
private readonly ?int $departmentId = null,
private readonly ?string $status = null,
private readonly ?int $enrollmentYear = null,
) {}
public function title(): string
@ -31,7 +32,7 @@ public function title(): string
public function collection(): Enumerable
{
return app(StudentService::class)->forExport($this->search, $this->gender, $this->departmentId, $this->status);
return app(StudentService::class)->forExport($this->search, $this->gender, $this->departmentId, $this->status, $this->enrollmentYear);
}
public function headings(): array

View File

@ -35,10 +35,12 @@ public function index(PaginatedRequest $request): Response
gender: $request->validated('gender'),
departmentId: $request->validated('department_id'),
status: $request->validated('status'),
enrollmentYear: $request->validated('enrollment_year'),
),
'departments' => $this->departmentService->getAllForSelect(),
'statuses' => StudentStatus::options(),
'filters' => $request->only(['gender', 'department_id', 'status']),
'enrollmentYears' => $this->service->getEnrollmentYears(),
'filters' => $request->only(['gender', 'department_id', 'status', 'enrollment_year']),
]);
}
@ -114,6 +116,7 @@ public function export(PaginatedRequest $request): BinaryFileResponse
gender: $request->validated('gender'),
departmentId: $request->validated('department_id'),
status: $request->validated('status'),
enrollmentYear: $request->validated('enrollment_year'),
), 'mahasiswa.xlsx');
}
}

View File

@ -24,6 +24,7 @@ public function rules(): array
'gender' => ['nullable', 'string', Rule::in(Gender::values())],
'department_id' => ['nullable', 'integer'],
'status' => ['nullable', 'string'],
'enrollment_year' => ['nullable', 'integer'],
'semester' => ['nullable', 'string', Rule::in(Semester::values())],
'is_active' => ['nullable', Rule::in(['true', 'false'])],
'academic_term_id' => ['nullable', 'integer'],

View File

@ -23,21 +23,31 @@ public function getAllForSelect(): Collection
->get();
}
public function paginated(int $perPage = 25, string $search = '', ?string $gender = null, ?int $departmentId = null, ?string $status = null): LengthAwarePaginator
public function getEnrollmentYears(): array
{
return $this->filteredQuery($search, $gender, $departmentId, $status)
return Student::query()
->select('enrollment_year')
->distinct()
->orderByDesc('enrollment_year')
->pluck('enrollment_year')
->all();
}
public function paginated(int $perPage = 25, string $search = '', ?string $gender = null, ?int $departmentId = null, ?string $status = null, ?int $enrollmentYear = null): LengthAwarePaginator
{
return $this->filteredQuery($search, $gender, $departmentId, $status, $enrollmentYear)
->latest()
->paginate($perPage);
}
public function forExport(string $search = '', ?string $gender = null, ?int $departmentId = null, ?string $status = null): Collection
public function forExport(string $search = '', ?string $gender = null, ?int $departmentId = null, ?string $status = null, ?int $enrollmentYear = null): Collection
{
return $this->filteredQuery($search, $gender, $departmentId, $status)
return $this->filteredQuery($search, $gender, $departmentId, $status, $enrollmentYear)
->orderBy('created_at', 'desc')
->get();
}
private function filteredQuery(string $search, ?string $gender, ?int $departmentId, ?string $status): Builder
private function filteredQuery(string $search, ?string $gender, ?int $departmentId, ?string $status, ?int $enrollmentYear = null): Builder
{
return User::select(['id', 'username', 'email', 'is_active'])
->with([
@ -54,7 +64,8 @@ private function filteredQuery(string $search, ?string $gender, ?int $department
}))
->when($gender, fn ($q) => $q->whereHas('profile', fn ($q) => $q->where('gender', $gender)))
->when($departmentId, fn ($q) => $q->whereHas('student', fn ($q) => $q->where('department_id', $departmentId)))
->when($status, fn ($q) => $q->whereHas('student', fn ($q) => $q->where('status', $status)));
->when($status, fn ($q) => $q->whereHas('student', fn ($q) => $q->where('status', $status)))
->when($enrollmentYear, fn ($q) => $q->whereHas('student', fn ($q) => $q->where('enrollment_year', $enrollmentYear)));
}
public function create(array $data): User

View File

@ -37,10 +37,12 @@ type Props = {
};
departments: Department[];
statuses: StatusOption[];
enrollmentYears: number[];
filters: {
gender?: string;
department_id?: string;
status?: string;
enrollment_year?: string;
};
};
@ -48,6 +50,7 @@ export default function StudentIndex({
students,
departments,
statuses,
enrollmentYears,
filters,
}: Props) {
const [deleting, setDeleting] = useState<Student | null>(null);
@ -75,6 +78,14 @@ export default function StudentIndex({
label: 'Status',
options: statuses,
},
{
key: 'enrollment_year',
label: 'Angkatan',
options: enrollmentYears.map((year) => ({
value: String(year),
label: String(year),
})),
},
];
const pagination: PaginationState = {