feat: update CreateForm and EditForm to filter courses and lecturers based on selected lecturer, enhancing user experience
This commit is contained in:
parent
1b68cf6125
commit
cdd81caf22
@ -349,26 +349,19 @@ function CreateForm({
|
|||||||
.map((a) => a.course_id),
|
.map((a) => a.course_id),
|
||||||
);
|
);
|
||||||
const selectedCourseIds = new Set(selectedCourses.map((c) => c.id));
|
const selectedCourseIds = new Set(selectedCourses.map((c) => c.id));
|
||||||
const availableCourses = courses.filter(
|
const lecturerDepartmentIds = new Set(
|
||||||
(c) =>
|
lecturer ? lecturer.departments.map((d) => d.id) : [],
|
||||||
!takenCourseIds.has(c.id) &&
|
|
||||||
!selectedCourseIds.has(c.id) &&
|
|
||||||
courseMatchesTermParity(c, selectedTerm),
|
|
||||||
);
|
);
|
||||||
|
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 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() {
|
function reset() {
|
||||||
setAcademicTermId('');
|
setAcademicTermId('');
|
||||||
@ -405,7 +398,6 @@ function CreateForm({
|
|||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setAcademicTermId(value);
|
setAcademicTermId(value);
|
||||||
setSelectedCourses([]);
|
setSelectedCourses([]);
|
||||||
setLecturer(null);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
@ -424,6 +416,52 @@ function CreateForm({
|
|||||||
</Select>
|
</Select>
|
||||||
<InputError message={errors.academic_term_id} />
|
<InputError message={errors.academic_term_id} />
|
||||||
</div>
|
</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">
|
<div className="grid gap-2">
|
||||||
<Label>
|
<Label>
|
||||||
Mata Kuliah{' '}
|
Mata Kuliah{' '}
|
||||||
@ -441,12 +479,10 @@ function CreateForm({
|
|||||||
items={courseGroups}
|
items={courseGroups}
|
||||||
multiple
|
multiple
|
||||||
value={selectedCourses}
|
value={selectedCourses}
|
||||||
onValueChange={(value) => {
|
onValueChange={setSelectedCourses}
|
||||||
setSelectedCourses(value);
|
|
||||||
setLecturer(null);
|
|
||||||
}}
|
|
||||||
itemToStringLabel={(c) => `${c.code} - ${c.name}`}
|
itemToStringLabel={(c) => `${c.code} - ${c.name}`}
|
||||||
isItemEqualToValue={(a, b) => a.id === b.id}
|
isItemEqualToValue={(a, b) => a.id === b.id}
|
||||||
|
disabled={!lecturer}
|
||||||
>
|
>
|
||||||
<ComboboxChips ref={courseAnchor}>
|
<ComboboxChips ref={courseAnchor}>
|
||||||
{selectedCourses.map((c) => (
|
{selectedCourses.map((c) => (
|
||||||
@ -458,10 +494,13 @@ function CreateForm({
|
|||||||
</ComboboxChip>
|
</ComboboxChip>
|
||||||
))}
|
))}
|
||||||
<ComboboxChipsInput
|
<ComboboxChipsInput
|
||||||
|
disabled={!lecturer}
|
||||||
placeholder={
|
placeholder={
|
||||||
selectedCourses.length === 0
|
!lecturer
|
||||||
? 'Pilih mata kuliah (bisa lebih dari satu)'
|
? 'Pilih dosen pengampu terlebih dahulu'
|
||||||
: ''
|
: selectedCourses.length === 0
|
||||||
|
? 'Pilih mata kuliah (bisa lebih dari satu)'
|
||||||
|
: ''
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</ComboboxChips>
|
</ComboboxChips>
|
||||||
@ -495,55 +534,6 @@ function CreateForm({
|
|||||||
</Combobox>
|
</Combobox>
|
||||||
<InputError message={errors.course_ids} />
|
<InputError message={errors.course_ids} />
|
||||||
</div>
|
</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">
|
<div className="grid gap-2">
|
||||||
<Label>Metode</Label>
|
<Label>Metode</Label>
|
||||||
<input type="hidden" name="method" />
|
<input type="hidden" name="method" />
|
||||||
@ -610,18 +600,18 @@ function EditForm({
|
|||||||
)
|
)
|
||||||
.map((a) => a.course_id),
|
.map((a) => a.course_id),
|
||||||
);
|
);
|
||||||
const availableCourses = courses.filter(
|
const lecturerDepartmentIds = new Set(
|
||||||
(c) =>
|
lecturer ? lecturer.departments.map((d) => d.id) : [],
|
||||||
!takenCourseIds.has(c.id) && courseMatchesTermParity(c, selectedTerm),
|
|
||||||
);
|
);
|
||||||
const courseGroups = groupCoursesByDepartmentAndSemester(availableCourses);
|
const availableCourses = lecturer
|
||||||
const availableLecturers = course
|
? courses.filter(
|
||||||
? lecturers.filter((l) =>
|
(c) =>
|
||||||
l.departments.some(
|
lecturerDepartmentIds.has(c.department_id) &&
|
||||||
(department) => department.id === course.department_id,
|
!takenCourseIds.has(c.id) &&
|
||||||
),
|
courseMatchesTermParity(c, selectedTerm),
|
||||||
)
|
)
|
||||||
: lecturers;
|
: [];
|
||||||
|
const courseGroups = groupCoursesByDepartmentAndSemester(availableCourses);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormDialog
|
<FormDialog
|
||||||
@ -635,6 +625,85 @@ function EditForm({
|
|||||||
{({ errors }) =>
|
{({ errors }) =>
|
||||||
editing && (
|
editing && (
|
||||||
<div className="grid gap-4">
|
<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">
|
<div className="grid gap-2">
|
||||||
<Label>
|
<Label>
|
||||||
Mata Kuliah{' '}
|
Mata Kuliah{' '}
|
||||||
@ -648,17 +717,20 @@ function EditForm({
|
|||||||
<Combobox
|
<Combobox
|
||||||
items={courseGroups}
|
items={courseGroups}
|
||||||
value={course}
|
value={course}
|
||||||
onValueChange={(value) => {
|
onValueChange={setCourse}
|
||||||
setCourse(value);
|
|
||||||
setLecturer(null);
|
|
||||||
}}
|
|
||||||
itemToStringLabel={(c) =>
|
itemToStringLabel={(c) =>
|
||||||
`${c.code} - ${c.name}`
|
`${c.code} - ${c.name}`
|
||||||
}
|
}
|
||||||
isItemEqualToValue={(a, b) => a.id === b.id}
|
isItemEqualToValue={(a, b) => a.id === b.id}
|
||||||
|
disabled={!lecturer}
|
||||||
>
|
>
|
||||||
<ComboboxInput
|
<ComboboxInput
|
||||||
placeholder="Pilih mata kuliah"
|
disabled={!lecturer}
|
||||||
|
placeholder={
|
||||||
|
lecturer
|
||||||
|
? 'Pilih mata kuliah'
|
||||||
|
: 'Pilih dosen pengampu terlebih dahulu'
|
||||||
|
}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
/>
|
/>
|
||||||
<ComboboxContent>
|
<ComboboxContent>
|
||||||
@ -692,89 +764,6 @@ function EditForm({
|
|||||||
</Combobox>
|
</Combobox>
|
||||||
<InputError message={errors.course_id} />
|
<InputError message={errors.course_id} />
|
||||||
</div>
|
</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">
|
<div className="grid gap-2">
|
||||||
<Label>Metode</Label>
|
<Label>Metode</Label>
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user