feat: update CreateForm and EditForm to filter courses and lecturers based on selected lecturer, enhancing user experience

This commit is contained in:
Yoga Pangestu 2026-09-02 18:04:14 +07:00
parent 1b68cf6125
commit cdd81caf22

View File

@ -349,26 +349,19 @@ function CreateForm({
.map((a) => a.course_id),
);
const selectedCourseIds = new Set(selectedCourses.map((c) => c.id));
const availableCourses = courses.filter(
(c) =>
!takenCourseIds.has(c.id) &&
!selectedCourseIds.has(c.id) &&
courseMatchesTermParity(c, selectedTerm),
const lecturerDepartmentIds = new Set(
lecturer ? lecturer.departments.map((d) => d.id) : [],
);
const availableCourses = lecturer
? courses.filter(
(c) =>
lecturerDepartmentIds.has(c.department_id) &&
!takenCourseIds.has(c.id) &&
!selectedCourseIds.has(c.id) &&
courseMatchesTermParity(c, selectedTerm),
)
: [];
const courseGroups = groupCoursesByDepartmentAndSemester(availableCourses);
const selectedDepartmentIds = new Set(
selectedCourses.map((c) => c.department_id),
);
const availableLecturers =
selectedCourses.length > 0
? lecturers.filter((l) =>
[...selectedDepartmentIds].every((departmentId) =>
l.departments.some(
(department) => department.id === departmentId,
),
),
)
: lecturers;
function reset() {
setAcademicTermId('');
@ -405,7 +398,6 @@ function CreateForm({
onValueChange={(value) => {
setAcademicTermId(value);
setSelectedCourses([]);
setLecturer(null);
}}
>
<SelectTrigger className="w-full">
@ -424,6 +416,52 @@ function CreateForm({
</Select>
<InputError message={errors.academic_term_id} />
</div>
<div className="grid gap-2">
<Label>
Dosen Pengampu{' '}
<span className="text-destructive">*</span>
</Label>
<input
type="hidden"
name="lecturer_id"
value={lecturer?.id ?? ''}
/>
<Combobox
items={lecturers}
value={lecturer}
onValueChange={(value) => {
setLecturer(value);
setSelectedCourses([]);
}}
itemToStringLabel={(lect) =>
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
}
isItemEqualToValue={(a, b) => a.id === b.id}
>
<ComboboxInput
placeholder="Pilih dosen pengampu"
className="w-full"
/>
<ComboboxContent>
<ComboboxEmpty>
Dosen tidak ditemukan.
</ComboboxEmpty>
<ComboboxList>
{(lect: Lecturer) => (
<ComboboxItem
key={lect.id}
value={lect}
>
{lect.user?.profile?.full_name ??
'N/A'}{' '}
- {lect.lecturer_number}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<InputError message={errors.lecturer_id} />
</div>
<div className="grid gap-2">
<Label>
Mata Kuliah{' '}
@ -441,12 +479,10 @@ function CreateForm({
items={courseGroups}
multiple
value={selectedCourses}
onValueChange={(value) => {
setSelectedCourses(value);
setLecturer(null);
}}
onValueChange={setSelectedCourses}
itemToStringLabel={(c) => `${c.code} - ${c.name}`}
isItemEqualToValue={(a, b) => a.id === b.id}
disabled={!lecturer}
>
<ComboboxChips ref={courseAnchor}>
{selectedCourses.map((c) => (
@ -458,10 +494,13 @@ function CreateForm({
</ComboboxChip>
))}
<ComboboxChipsInput
disabled={!lecturer}
placeholder={
selectedCourses.length === 0
? 'Pilih mata kuliah (bisa lebih dari satu)'
: ''
!lecturer
? 'Pilih dosen pengampu terlebih dahulu'
: selectedCourses.length === 0
? 'Pilih mata kuliah (bisa lebih dari satu)'
: ''
}
/>
</ComboboxChips>
@ -495,55 +534,6 @@ function CreateForm({
</Combobox>
<InputError message={errors.course_ids} />
</div>
<div className="grid gap-2">
<Label>
Dosen Pengampu{' '}
<span className="text-destructive">*</span>
</Label>
<input
type="hidden"
name="lecturer_id"
value={lecturer?.id ?? ''}
/>
<Combobox
items={availableLecturers}
value={lecturer}
onValueChange={setLecturer}
itemToStringLabel={(lect) =>
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
}
isItemEqualToValue={(a, b) => a.id === b.id}
disabled={selectedCourses.length === 0}
>
<ComboboxInput
disabled={selectedCourses.length === 0}
placeholder={
selectedCourses.length > 0
? 'Pilih dosen pengampu'
: 'Pilih mata kuliah terlebih dahulu'
}
className="w-full"
/>
<ComboboxContent>
<ComboboxEmpty>
Dosen tidak ditemukan.
</ComboboxEmpty>
<ComboboxList>
{(lect: Lecturer) => (
<ComboboxItem
key={lect.id}
value={lect}
>
{lect.user?.profile?.full_name ??
'N/A'}{' '}
- {lect.lecturer_number}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<InputError message={errors.lecturer_id} />
</div>
<div className="grid gap-2">
<Label>Metode</Label>
<input type="hidden" name="method" />
@ -610,18 +600,18 @@ function EditForm({
)
.map((a) => a.course_id),
);
const availableCourses = courses.filter(
(c) =>
!takenCourseIds.has(c.id) && courseMatchesTermParity(c, selectedTerm),
const lecturerDepartmentIds = new Set(
lecturer ? lecturer.departments.map((d) => d.id) : [],
);
const courseGroups = groupCoursesByDepartmentAndSemester(availableCourses);
const availableLecturers = course
? lecturers.filter((l) =>
l.departments.some(
(department) => department.id === course.department_id,
),
const availableCourses = lecturer
? courses.filter(
(c) =>
lecturerDepartmentIds.has(c.department_id) &&
!takenCourseIds.has(c.id) &&
courseMatchesTermParity(c, selectedTerm),
)
: lecturers;
: [];
const courseGroups = groupCoursesByDepartmentAndSemester(availableCourses);
return (
<FormDialog
@ -635,6 +625,85 @@ function EditForm({
{({ errors }) =>
editing && (
<div className="grid gap-4">
<div className="grid gap-2">
<Label>
Periode Akademik{' '}
<span className="text-destructive">*</span>
</Label>
<input
type="hidden"
name="academic_term_id"
value={academicTermId}
/>
<Select
value={academicTermId}
onValueChange={(value) => {
setAcademicTermId(value);
setCourse(null);
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Pilih periode akademik" />
</SelectTrigger>
<SelectContent>
{academicTerms.map((term) => (
<SelectItem
key={term.id}
value={String(term.id)}
>
{formatAcademicTermLabel(term)}
</SelectItem>
))}
</SelectContent>
</Select>
<InputError message={errors.academic_term_id} />
</div>
<div className="grid gap-2">
<Label>
Dosen Pengampu{' '}
<span className="text-destructive">*</span>
</Label>
<input
type="hidden"
name="lecturer_id"
value={lecturer?.id ?? ''}
/>
<Combobox
items={lecturers}
value={lecturer}
onValueChange={(value) => {
setLecturer(value);
setCourse(null);
}}
itemToStringLabel={(lect) =>
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
}
isItemEqualToValue={(a, b) => a.id === b.id}
>
<ComboboxInput
placeholder="Pilih dosen pengampu"
className="w-full"
/>
<ComboboxContent>
<ComboboxEmpty>
Dosen tidak ditemukan.
</ComboboxEmpty>
<ComboboxList>
{(lect: Lecturer) => (
<ComboboxItem
key={lect.id}
value={lect}
>
{lect.user?.profile
?.full_name ?? 'N/A'}{' '}
- {lect.lecturer_number}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<InputError message={errors.lecturer_id} />
</div>
<div className="grid gap-2">
<Label>
Mata Kuliah{' '}
@ -648,17 +717,20 @@ function EditForm({
<Combobox
items={courseGroups}
value={course}
onValueChange={(value) => {
setCourse(value);
setLecturer(null);
}}
onValueChange={setCourse}
itemToStringLabel={(c) =>
`${c.code} - ${c.name}`
}
isItemEqualToValue={(a, b) => a.id === b.id}
disabled={!lecturer}
>
<ComboboxInput
placeholder="Pilih mata kuliah"
disabled={!lecturer}
placeholder={
lecturer
? 'Pilih mata kuliah'
: 'Pilih dosen pengampu terlebih dahulu'
}
className="w-full"
/>
<ComboboxContent>
@ -692,89 +764,6 @@ function EditForm({
</Combobox>
<InputError message={errors.course_id} />
</div>
<div className="grid gap-2">
<Label>
Dosen Pengampu{' '}
<span className="text-destructive">*</span>
</Label>
<input
type="hidden"
name="lecturer_id"
value={lecturer?.id ?? ''}
/>
<Combobox
items={availableLecturers}
value={lecturer}
onValueChange={setLecturer}
itemToStringLabel={(lect) =>
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
}
isItemEqualToValue={(a, b) => a.id === b.id}
disabled={!course}
>
<ComboboxInput
disabled={!course}
placeholder={
course
? 'Pilih dosen pengampu'
: 'Pilih mata kuliah terlebih dahulu'
}
className="w-full"
/>
<ComboboxContent>
<ComboboxEmpty>
Dosen tidak ditemukan.
</ComboboxEmpty>
<ComboboxList>
{(lect: Lecturer) => (
<ComboboxItem
key={lect.id}
value={lect}
>
{lect.user?.profile
?.full_name ?? 'N/A'}{' '}
- {lect.lecturer_number}
</ComboboxItem>
)}
</ComboboxList>
</ComboboxContent>
</Combobox>
<InputError message={errors.lecturer_id} />
</div>
<div className="grid gap-2">
<Label>
Periode Akademik{' '}
<span className="text-destructive">*</span>
</Label>
<input
type="hidden"
name="academic_term_id"
value={academicTermId}
/>
<Select
value={academicTermId}
onValueChange={(value) => {
setAcademicTermId(value);
setCourse(null);
setLecturer(null);
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Pilih periode akademik" />
</SelectTrigger>
<SelectContent>
{academicTerms.map((term) => (
<SelectItem
key={term.id}
value={String(term.id)}
>
{formatAcademicTermLabel(term)}
</SelectItem>
))}
</SelectContent>
</Select>
<InputError message={errors.academic_term_id} />
</div>
<div className="grid gap-2">
<Label>Metode</Label>
<Select