157 lines
5.4 KiB
TypeScript
157 lines
5.4 KiB
TypeScript
import { Head } from '@inertiajs/react';
|
|
import { Plus } from 'lucide-react';
|
|
import { useState } from 'react';
|
|
import { DataTable } from '@/components/data-table';
|
|
import { DateTimeField } from '@/components/datetime-field';
|
|
import { FormDialog } from '@/components/form-dialog';
|
|
import InputError from '@/components/input-error';
|
|
import { PageHeader } from '@/components/page-header';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
import { store } from '@/routes/lecturer/academic-advising-logs';
|
|
import type { AcademicAdvisingLog } from '@/types/academic-advising-log';
|
|
import { advisingLogColumns } from './columns';
|
|
|
|
type Advisee = {
|
|
id: number;
|
|
student_number: string;
|
|
user: { profile: { full_name: string } | null } | null;
|
|
};
|
|
|
|
type Props = {
|
|
logs: AcademicAdvisingLog[];
|
|
advisees: Advisee[];
|
|
};
|
|
|
|
function adviseeLabel(advisee: Advisee): string {
|
|
return `${advisee.user?.profile?.full_name ?? 'N/A'} - ${advisee.student_number}`;
|
|
}
|
|
|
|
export default function LecturerAcademicAdvisingLogIndex({
|
|
logs,
|
|
advisees,
|
|
}: Props) {
|
|
const [createOpen, setCreateOpen] = useState(false);
|
|
|
|
return (
|
|
<>
|
|
<Head title="Bimbingan Akademik" />
|
|
|
|
<div className="flex h-full flex-1 flex-col gap-6 overflow-x-auto p-4 md:p-6">
|
|
<PageHeader
|
|
title="Bimbingan Akademik"
|
|
actions={
|
|
<Button asChild>
|
|
<button
|
|
type="button"
|
|
onClick={() => setCreateOpen(true)}
|
|
>
|
|
<Plus className="h-4 w-4" />
|
|
Tambah Bimbingan
|
|
</button>
|
|
</Button>
|
|
}
|
|
/>
|
|
|
|
<CreateForm
|
|
open={createOpen}
|
|
onOpenChange={setCreateOpen}
|
|
advisees={advisees}
|
|
/>
|
|
|
|
<DataTable
|
|
columns={advisingLogColumns}
|
|
data={logs}
|
|
emptyText="Belum ada log bimbingan akademik."
|
|
/>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|
|
|
|
function CreateForm({
|
|
open,
|
|
onOpenChange,
|
|
advisees,
|
|
}: {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
advisees: Advisee[];
|
|
}) {
|
|
return (
|
|
<FormDialog
|
|
open={open}
|
|
onOpenChange={onOpenChange}
|
|
title="Tambah Bimbingan Akademik"
|
|
action={store()}
|
|
resetOnSuccess
|
|
onSuccess={() => onOpenChange(false)}
|
|
>
|
|
{({ errors }) => (
|
|
<div className="grid gap-4">
|
|
<div className="grid gap-2">
|
|
<Label>
|
|
Mahasiswa{' '}
|
|
<span className="text-destructive">*</span>
|
|
</Label>
|
|
<Select name="student_id">
|
|
<SelectTrigger className="w-full">
|
|
<SelectValue placeholder="Pilih mahasiswa bimbingan" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{advisees.map((advisee) => (
|
|
<SelectItem
|
|
key={advisee.id}
|
|
value={String(advisee.id)}
|
|
>
|
|
{adviseeLabel(advisee)}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
{advisees.length === 0 && (
|
|
<p className="text-xs text-muted-foreground">
|
|
Anda belum memiliki mahasiswa bimbingan.
|
|
</p>
|
|
)}
|
|
<InputError message={errors.student_id} />
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="topic">Topik</Label>
|
|
<Input
|
|
id="topic"
|
|
name="topic"
|
|
placeholder="Masukkan topik bimbingan"
|
|
/>
|
|
<InputError message={errors.topic} />
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="notes">Catatan</Label>
|
|
<Textarea
|
|
id="notes"
|
|
name="notes"
|
|
placeholder="Masukkan catatan bimbingan"
|
|
/>
|
|
<InputError message={errors.notes} />
|
|
</div>
|
|
<DateTimeField
|
|
label="Tanggal Sesi"
|
|
name="session_date"
|
|
placeholder="Pilih tanggal sesi"
|
|
error={errors.session_date}
|
|
/>
|
|
</div>
|
|
)}
|
|
</FormDialog>
|
|
);
|
|
}
|