feat: add department selection and advisor filtering in student create and edit forms

This commit is contained in:
Yoga Pangestu 2026-09-01 20:59:56 +07:00
parent a7aec7245b
commit 6621757713
3 changed files with 60 additions and 17 deletions

View File

@ -73,7 +73,8 @@ public function rules(): array
'academic_advisor_id' => [ 'academic_advisor_id' => [
'required', 'required',
'integer', 'integer',
Rule::exists('lecturers', 'id'), Rule::exists('lecturer_department', 'lecturer_id')
->where('department_id', $this->input('department_id')),
], ],
'status' => [ 'status' => [
'nullable', 'nullable',

View File

@ -35,6 +35,7 @@ type Lecturer = {
id: number; id: number;
lecturer_number: string; lecturer_number: string;
user: { profile: { full_name: string } | null } | null; user: { profile: { full_name: string } | null } | null;
departments: { id: number }[];
}; };
type Props = { type Props = {
@ -45,8 +46,15 @@ type Props = {
export default function StudentCreate({ departments, lecturers }: Props) { export default function StudentCreate({ departments, lecturers }: Props) {
const [gender, setGender] = useState(''); const [gender, setGender] = useState('');
const [birthDate, setBirthDate] = useState<Date | undefined>(); const [birthDate, setBirthDate] = useState<Date | undefined>();
const [departmentId, setDepartmentId] = useState('');
const [advisor, setAdvisor] = useState<Lecturer | null>(null); const [advisor, setAdvisor] = useState<Lecturer | null>(null);
const availableAdvisors = departmentId
? lecturers.filter((l) =>
l.departments.some((d) => String(d.id) === departmentId),
)
: [];
return ( return (
<> <>
<Head title="Tambah Mahasiswa" /> <Head title="Tambah Mahasiswa" />
@ -279,8 +287,15 @@ export default function StudentCreate({ departments, lecturers }: Props) {
<input <input
type="hidden" type="hidden"
name="department_id" name="department_id"
value={departmentId}
/> />
<Select name="department_id"> <Select
value={departmentId}
onValueChange={(value) => {
setDepartmentId(value);
setAdvisor(null);
}}
>
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
<SelectValue placeholder="Pilih jurusan" /> <SelectValue placeholder="Pilih jurusan" />
</SelectTrigger> </SelectTrigger>
@ -354,8 +369,9 @@ export default function StudentCreate({ departments, lecturers }: Props) {
value={advisor?.id ?? ''} value={advisor?.id ?? ''}
/> />
<Combobox <Combobox
items={lecturers} items={availableAdvisors}
value={advisor} value={advisor}
disabled={!departmentId}
onValueChange={setAdvisor} onValueChange={setAdvisor}
itemToStringLabel={(lect) => itemToStringLabel={(lect) =>
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}` `${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
@ -365,12 +381,18 @@ export default function StudentCreate({ departments, lecturers }: Props) {
} }
> >
<ComboboxInput <ComboboxInput
placeholder="Pilih pembimbing akademik" disabled={!departmentId}
placeholder={
departmentId
? 'Pilih pembimbing akademik'
: 'Pilih jurusan terlebih dahulu'
}
className="w-full" className="w-full"
/> />
<ComboboxContent> <ComboboxContent>
<ComboboxEmpty> <ComboboxEmpty>
Dosen tidak ditemukan. Dosen tidak
ditemukan.
</ComboboxEmpty> </ComboboxEmpty>
<ComboboxList> <ComboboxList>
{(lect: Lecturer) => ( {(lect: Lecturer) => (

View File

@ -35,6 +35,7 @@ type Lecturer = {
id: number; id: number;
lecturer_number: string; lecturer_number: string;
user: { profile: { full_name: string } | null } | null; user: { profile: { full_name: string } | null } | null;
departments: { id: number }[];
}; };
type User = { type User = {
@ -71,12 +72,23 @@ export default function StudentEdit({ user, departments, lecturers }: Props) {
? new Date(user.profile.birth_date) ? new Date(user.profile.birth_date)
: undefined, : undefined,
); );
const [departmentId, setDepartmentId] = useState(
user.student?.department_id
? String(user.student.department_id)
: '',
);
const [advisor, setAdvisor] = useState<Lecturer | null>( const [advisor, setAdvisor] = useState<Lecturer | null>(
lecturers.find( lecturers.find(
(lect) => lect.id === user.student?.academic_advisor_id, (lect) => lect.id === user.student?.academic_advisor_id,
) ?? null, ) ?? null,
); );
const availableAdvisors = departmentId
? lecturers.filter((l) =>
l.departments.some((d) => String(d.id) === departmentId),
)
: [];
return ( return (
<> <>
<Head title="Edit Mahasiswa" /> <Head title="Edit Mahasiswa" />
@ -318,16 +330,17 @@ export default function StudentEdit({ user, departments, lecturers }: Props) {
* *
</span> </span>
</Label> </Label>
<Select <input
type="hidden"
name="department_id" name="department_id"
defaultValue={ value={departmentId}
user.student?.department_id />
? String( <Select
user.student value={departmentId}
.department_id, onValueChange={(value) => {
) setDepartmentId(value);
: undefined setAdvisor(null);
} }}
> >
<SelectTrigger className="w-full"> <SelectTrigger className="w-full">
<SelectValue placeholder="Pilih jurusan" /> <SelectValue placeholder="Pilih jurusan" />
@ -407,8 +420,9 @@ export default function StudentEdit({ user, departments, lecturers }: Props) {
value={advisor?.id ?? ''} value={advisor?.id ?? ''}
/> />
<Combobox <Combobox
items={lecturers} items={availableAdvisors}
value={advisor} value={advisor}
disabled={!departmentId}
onValueChange={setAdvisor} onValueChange={setAdvisor}
itemToStringLabel={(lect) => itemToStringLabel={(lect) =>
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}` `${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
@ -418,12 +432,18 @@ export default function StudentEdit({ user, departments, lecturers }: Props) {
} }
> >
<ComboboxInput <ComboboxInput
placeholder="Pilih pembimbing akademik" disabled={!departmentId}
placeholder={
departmentId
? 'Pilih pembimbing akademik'
: 'Pilih jurusan terlebih dahulu'
}
className="w-full" className="w-full"
/> />
<ComboboxContent> <ComboboxContent>
<ComboboxEmpty> <ComboboxEmpty>
Dosen tidak ditemukan. Dosen tidak
ditemukan.
</ComboboxEmpty> </ComboboxEmpty>
<ComboboxList> <ComboboxList>
{(lect: Lecturer) => ( {(lect: Lecturer) => (