itmpwk.ac.id/resources/js/pages/admin/academic-classes/attendances/index.tsx

143 lines
5.7 KiB
TypeScript

import { Head, Link } from '@inertiajs/react';
import type { FilterField } from '@/components/filter-dialog';
import { FilterDialog } from '@/components/filter-dialog';
import { PageHeader } from '@/components/page-header';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { useServerTable } from '@/hooks/use-server-table';
import {
index as attendanceIndex,
show,
} from '@/routes/admin/academic-classes/attendances';
import { formatAcademicTermLabel } from '@/types/academic-term';
import type { AttendanceCourseClassOverview } from '@/types/attendance';
type AcademicTermOption = {
id: number;
academic_year: string;
semester: string;
};
type Props = {
courseClasses: AttendanceCourseClassOverview[];
academicTerms: AcademicTermOption[];
filters: {
academic_term_id?: string;
};
};
function courseClassLabel(courseClass: AttendanceCourseClassOverview): string {
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
}
export default function AttendanceIndex({
courseClasses,
academicTerms,
filters,
}: Props) {
const filterFields: FilterField[] = [
{
key: 'academic_term_id',
label: 'Periode Akademik',
options: academicTerms.map((term) => ({
value: String(term.id),
label: formatAcademicTermLabel(term),
})),
},
];
const { applyFilters } = useServerTable({
route: () => attendanceIndex.url(),
pagination: {
current_page: 1,
last_page: 1,
per_page: 999999,
total: courseClasses.length,
},
filters,
});
function handleApplyFilters(newFilters: Record<string, string>) {
// Tanpa `academic_term_id` eksplisit, backend akan kembali ke
// periode aktif, jadi menghapus filter ini perlu dikirim eksplisit
// alih-alih hanya menghilangkan key-nya.
const clearedAcademicTerm =
Boolean(filters.academic_term_id) && !newFilters.academic_term_id;
applyFilters({
...newFilters,
...(clearedAcademicTerm ? { academic_term_id: '' } : {}),
});
}
return (
<>
<Head title="Kehadiran" />
<div className="flex h-full flex-1 flex-col gap-6 p-4 md:p-6">
<PageHeader
title="Kehadiran"
actions={
<FilterDialog
fields={filterFields}
activeFilters={filters}
onApply={handleApplyFilters}
/>
}
/>
{courseClasses.length === 0 ? (
<p className="rounded-md border border-dashed p-6 text-center text-sm text-muted-foreground">
Tidak ada kelas untuk periode ini.
</p>
) : (
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-3">
{courseClasses.map((courseClass) => (
<Link
key={courseClass.id}
href={show(courseClass.id).url}
>
<Card className="h-full transition-colors hover:border-primary">
<CardHeader>
<CardTitle className="text-base leading-tight">
{courseClassLabel(courseClass)}
</CardTitle>
</CardHeader>
<CardContent className="flex flex-col gap-2">
<div className="flex flex-wrap items-center gap-1.5">
<Badge
variant="secondary"
className="w-fit text-[10px] font-normal"
>
{courseClass.meetings_count}{' '}
Pertemuan
</Badge>
<Badge
variant="outline"
className="w-fit text-[10px] font-normal"
>
{courseClass.enrollments_count}{' '}
Mahasiswa
</Badge>
{courseClass.academic_term && (
<Badge
variant="outline"
className="w-fit text-[10px] font-normal"
>
{formatAcademicTermLabel(
courseClass.academic_term,
)}
</Badge>
)}
</div>
</CardContent>
</Card>
</Link>
))}
</div>
)}
</div>
</>
);
}