From 5710a579922501d1f1f7a55cda31bb957ac05223 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 30 Aug 2026 13:14:53 +0700 Subject: [PATCH] refactor: remove class_name from CourseClass and related components --- .../Admin/Manage/CourseClassRequest.php | 1 - .../Admin/Manage/CourseClassService.php | 8 +- app/Services/Admin/Users/LecturerService.php | 1 + ..._21_000002_create_course_classes_table.php | 1 - database/seeders/CourseClassSeeder.php | 2 - resources/js/components/app-sidebar.tsx | 20 +- .../academic-classes/assignments/columns.tsx | 8 +- .../academic-classes/assignments/index.tsx | 7 +- .../assignments/submissions.tsx | 6 +- .../academic-classes/attendances/index.tsx | 6 +- .../academic-classes/attendances/session.tsx | 6 +- .../course-registrations/columns.tsx | 3 - .../course-registrations/index.tsx | 3 +- .../academic-classes/materials/columns.tsx | 8 +- .../academic-classes/materials/index.tsx | 7 +- .../academic-classes/schedules/index.tsx | 17 +- .../admin/manage/course-classes/columns.tsx | 9 - .../manage/course-classes/enrollments.tsx | 4 +- .../admin/manage/course-classes/index.tsx | 227 ++++++++++-------- resources/js/types/assignment.ts | 1 - resources/js/types/attendance.ts | 1 - resources/js/types/course-class.ts | 1 - resources/js/types/course-registration.ts | 1 - resources/js/types/material.ts | 1 - resources/js/types/schedule.ts | 1 - 25 files changed, 158 insertions(+), 192 deletions(-) diff --git a/app/Http/Requests/Admin/Manage/CourseClassRequest.php b/app/Http/Requests/Admin/Manage/CourseClassRequest.php index 531e930..3b12ce1 100644 --- a/app/Http/Requests/Admin/Manage/CourseClassRequest.php +++ b/app/Http/Requests/Admin/Manage/CourseClassRequest.php @@ -26,7 +26,6 @@ public function rules(): array Rule::exists('lecturers', 'id')->where('department_id', $departmentId), ], 'academic_term_id' => ['required', 'integer', Rule::exists('academic_terms', 'id')], - 'class_name' => ['nullable', 'string', 'max:50'], 'method' => ['nullable', 'string', Rule::in(ClassMethod::values())], ]; } diff --git a/app/Services/Admin/Manage/CourseClassService.php b/app/Services/Admin/Manage/CourseClassService.php index f96111e..587137d 100644 --- a/app/Services/Admin/Manage/CourseClassService.php +++ b/app/Services/Admin/Manage/CourseClassService.php @@ -10,7 +10,7 @@ class CourseClassService { public function getAllForSelect(): Collection { - return CourseClass::select(['id', 'course_id', 'class_name']) + return CourseClass::select(['id', 'course_id']) ->with('course:id,code,name') ->get(); } @@ -18,11 +18,10 @@ public function getAllForSelect(): Collection public function paginated(int $perPage = 25, string $search = '', ?int $academicTermId = null, ?string $method = null): LengthAwarePaginator { return CourseClass::query() - ->select(['id', 'course_id', 'lecturer_id', 'academic_term_id', 'class_name', 'method']) + ->select(['id', 'course_id', 'lecturer_id', 'academic_term_id', 'method']) ->withCount('enrollments') ->with(['course:id,code,name,department_id', 'lecturer.user.profile', 'academicTerm:id,name,semester,start_date,end_date']) - ->when($search, fn ($q) => $q->where('class_name', 'like', "%{$search}%") - ->orWhereHas('course', fn ($q) => $q->where('name', 'like', "%{$search}%")->orWhere('code', 'like', "%{$search}%"))) + ->when($search, fn ($q) => $q->whereHas('course', fn ($q) => $q->where('name', 'like', "%{$search}%")->orWhere('code', 'like', "%{$search}%"))) ->when($academicTermId, fn ($q) => $q->where('academic_term_id', $academicTermId)) ->when($method, fn ($q) => $q->where('method', $method)) ->latest() @@ -39,7 +38,6 @@ public function update(CourseClass $courseClass, array $data): CourseClass $courseClass->course_id = $data['course_id']; $courseClass->lecturer_id = $data['lecturer_id']; $courseClass->academic_term_id = $data['academic_term_id']; - $courseClass->class_name = $data['class_name'] ?? null; $courseClass->method = $data['method'] ?? null; $courseClass->update(); diff --git a/app/Services/Admin/Users/LecturerService.php b/app/Services/Admin/Users/LecturerService.php index 4d58ad0..5c0eed2 100644 --- a/app/Services/Admin/Users/LecturerService.php +++ b/app/Services/Admin/Users/LecturerService.php @@ -18,6 +18,7 @@ public function getAllForSelect(): Collection ->with([ 'user:id,username', 'user.profile:id,user_id,full_name', + 'departments:id,name', ]) ->get(); } diff --git a/database/migrations/2026_08_21_000002_create_course_classes_table.php b/database/migrations/2026_08_21_000002_create_course_classes_table.php index 41172f1..4615f18 100644 --- a/database/migrations/2026_08_21_000002_create_course_classes_table.php +++ b/database/migrations/2026_08_21_000002_create_course_classes_table.php @@ -14,7 +14,6 @@ public function up(): void $table->foreignId('course_id')->constrained()->cascadeOnDelete(); $table->foreignId('lecturer_id')->constrained()->cascadeOnDelete(); $table->foreignId('academic_term_id')->constrained()->cascadeOnDelete(); - $table->string('class_name', 50)->nullable(); $table->enum('method', ClassMethod::values())->nullable()->default(ClassMethod::Hybrid->value); $table->timestamps(); $table->softDeletes(); diff --git a/database/seeders/CourseClassSeeder.php b/database/seeders/CourseClassSeeder.php index d408ab2..2cb14a1 100644 --- a/database/seeders/CourseClassSeeder.php +++ b/database/seeders/CourseClassSeeder.php @@ -14,7 +14,6 @@ public function run(): void 'course_id' => 1, 'lecturer_id' => 1, 'academic_term_id' => 2, - 'class_name' => 'SI-5A', 'method' => 'hybrid', 'created_at' => '2026-01-10 08:00:00', 'updated_at' => '2026-01-10 08:00:00', @@ -23,7 +22,6 @@ public function run(): void 'course_id' => 2, 'lecturer_id' => 2, 'academic_term_id' => 2, - 'class_name' => 'TI-3A', 'method' => 'offline', 'created_at' => '2026-01-10 08:00:00', 'updated_at' => '2026-01-10 08:00:00', diff --git a/resources/js/components/app-sidebar.tsx b/resources/js/components/app-sidebar.tsx index 229d5a4..a29f3ad 100644 --- a/resources/js/components/app-sidebar.tsx +++ b/resources/js/components/app-sidebar.tsx @@ -107,6 +107,16 @@ const data: { }, ], }, + { + label: 'Kelola', + items: [ + { + name: 'Kelas Mata Kuliah', + url: courseClassesRoute.url(), + icon: School, + }, + ], + }, { label: 'Kelas', items: [ @@ -137,16 +147,6 @@ const data: { }, ], }, - { - label: 'Kelola', - items: [ - { - name: 'Kelas Mata Kuliah', - url: courseClassesRoute.url(), - icon: School, - }, - ], - }, { label: 'Pengumuman', items: [ diff --git a/resources/js/pages/admin/academic-classes/assignments/columns.tsx b/resources/js/pages/admin/academic-classes/assignments/columns.tsx index ec90f3a..fda93c4 100644 --- a/resources/js/pages/admin/academic-classes/assignments/columns.tsx +++ b/resources/js/pages/admin/academic-classes/assignments/columns.tsx @@ -28,7 +28,7 @@ export function createAssignmentColumns( ), }, { - accessorKey: 'course_class.class_name', + accessorKey: 'course_class.course.name', header: () => Kelas, cell: ({ row }) => { const courseClass = row.original.course_class; @@ -37,11 +37,7 @@ export function createAssignmentColumns( return '-'; } - const label = courseClass.class_name - ? `${courseClass.class_name} - ` - : ''; - - return `${label}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; + return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; }, }, { diff --git a/resources/js/pages/admin/academic-classes/assignments/index.tsx b/resources/js/pages/admin/academic-classes/assignments/index.tsx index e73655f..e7bb2fd 100644 --- a/resources/js/pages/admin/academic-classes/assignments/index.tsx +++ b/resources/js/pages/admin/academic-classes/assignments/index.tsx @@ -34,7 +34,6 @@ import { createAssignmentColumns } from './columns'; type CourseClassOption = { id: number; - class_name: string | null; course: { id: number; code: string; name: string } | null; }; @@ -54,11 +53,7 @@ type Props = { }; function courseClassLabel(courseClass: CourseClassOption): string { - const namePart = courseClass.class_name - ? `${courseClass.class_name} - ` - : ''; - - return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; + return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; } export default function AssignmentIndex({ diff --git a/resources/js/pages/admin/academic-classes/assignments/submissions.tsx b/resources/js/pages/admin/academic-classes/assignments/submissions.tsx index 68fd2b0..af9e019 100644 --- a/resources/js/pages/admin/academic-classes/assignments/submissions.tsx +++ b/resources/js/pages/admin/academic-classes/assignments/submissions.tsx @@ -175,11 +175,7 @@ export default function SubmissionIndex({

- Kelas:{' '} - {assignment.course_class?.class_name - ? `${assignment.course_class.class_name} - ` - : ''} - {assignment.course_class?.course?.code}{' '} + Kelas: {assignment.course_class?.course?.code}{' '} {assignment.course_class?.course?.name}

diff --git a/resources/js/pages/admin/academic-classes/attendances/index.tsx b/resources/js/pages/admin/academic-classes/attendances/index.tsx index 0b929a8..525556d 100644 --- a/resources/js/pages/admin/academic-classes/attendances/index.tsx +++ b/resources/js/pages/admin/academic-classes/attendances/index.tsx @@ -35,11 +35,7 @@ type Props = { }; function courseClassLabel(courseClass: AttendanceCourseClass): string { - const namePart = courseClass.class_name - ? `${courseClass.class_name} - ` - : ''; - - return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; + return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; } export default function AttendanceIndex({ sessions, courseClasses }: Props) { diff --git a/resources/js/pages/admin/academic-classes/attendances/session.tsx b/resources/js/pages/admin/academic-classes/attendances/session.tsx index dcbe61f..781730d 100644 --- a/resources/js/pages/admin/academic-classes/attendances/session.tsx +++ b/resources/js/pages/admin/academic-classes/attendances/session.tsx @@ -26,11 +26,7 @@ type Props = { }; function courseClassLabel(courseClass: AttendanceCourseClass): string { - const namePart = courseClass.class_name - ? `${courseClass.class_name} - ` - : ''; - - return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; + return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; } export default function AttendanceSession({ diff --git a/resources/js/pages/admin/academic-classes/course-registrations/columns.tsx b/resources/js/pages/admin/academic-classes/course-registrations/columns.tsx index fad4ecc..30dd4cb 100644 --- a/resources/js/pages/admin/academic-classes/course-registrations/columns.tsx +++ b/resources/js/pages/admin/academic-classes/course-registrations/columns.tsx @@ -54,9 +54,6 @@ export function createCourseRegistrationColumns(

{courseClass?.course?.code} - {courseClass?.class_name - ? ` ยท ${courseClass.class_name}` - : ''}

); diff --git a/resources/js/pages/admin/academic-classes/course-registrations/index.tsx b/resources/js/pages/admin/academic-classes/course-registrations/index.tsx index be8bcfb..3bbaa0b 100644 --- a/resources/js/pages/admin/academic-classes/course-registrations/index.tsx +++ b/resources/js/pages/admin/academic-classes/course-registrations/index.tsx @@ -68,9 +68,8 @@ function studentLabel(student: CourseRegistrationStudent): string { function courseClassLabel(courseClass: CourseRegistrationCourseClass): string { const course = courseClass.course; - const suffix = courseClass.class_name ? ` (${courseClass.class_name})` : ''; - return `${course?.code ?? '-'} - ${course?.name ?? 'N/A'}${suffix}`; + return `${course?.code ?? '-'} - ${course?.name ?? 'N/A'}`; } function lecturerLabel(lecturer: LecturerOption): string { diff --git a/resources/js/pages/admin/academic-classes/materials/columns.tsx b/resources/js/pages/admin/academic-classes/materials/columns.tsx index 2a88c05..1de7270 100644 --- a/resources/js/pages/admin/academic-classes/materials/columns.tsx +++ b/resources/js/pages/admin/academic-classes/materials/columns.tsx @@ -49,7 +49,7 @@ export function createMaterialColumns( ), }, { - accessorKey: 'course_class.class_name', + accessorKey: 'course_class.course.name', header: () => Kelas, cell: ({ row }) => { const courseClass = row.original.course_class; @@ -58,11 +58,7 @@ export function createMaterialColumns( return '-'; } - const label = courseClass.class_name - ? `${courseClass.class_name} - ` - : ''; - - return `${label}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; + return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; }, }, { diff --git a/resources/js/pages/admin/academic-classes/materials/index.tsx b/resources/js/pages/admin/academic-classes/materials/index.tsx index 87aa8ee..9f87fb0 100644 --- a/resources/js/pages/admin/academic-classes/materials/index.tsx +++ b/resources/js/pages/admin/academic-classes/materials/index.tsx @@ -33,7 +33,6 @@ import { createMaterialColumns } from './columns'; type CourseClassOption = { id: number; - class_name: string | null; course: { id: number; code: string; name: string } | null; }; @@ -53,11 +52,7 @@ type Props = { }; function courseClassLabel(courseClass: CourseClassOption): string { - const namePart = courseClass.class_name - ? `${courseClass.class_name} - ` - : ''; - - return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; + return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; } export default function MaterialIndex({ diff --git a/resources/js/pages/admin/academic-classes/schedules/index.tsx b/resources/js/pages/admin/academic-classes/schedules/index.tsx index b0817d8..e637333 100644 --- a/resources/js/pages/admin/academic-classes/schedules/index.tsx +++ b/resources/js/pages/admin/academic-classes/schedules/index.tsx @@ -19,13 +19,16 @@ import { SelectValue, } from '@/components/ui/select'; import { cn } from '@/lib/utils'; -import { destroy, store, update } from '@/routes/admin/academic-classes/schedules'; +import { + destroy, + store, + update, +} from '@/routes/admin/academic-classes/schedules'; import type { Schedule } from '@/types/schedule'; import { DayOfWeekLabels, DaysOfWeek } from '@/types/schedule'; type CourseClassOption = { id: number; - class_name: string | null; course: { id: number; code: string; name: string } | null; }; @@ -40,11 +43,7 @@ const UNSCHEDULED = '__unscheduled__'; const BOARD_COLUMNS = [...DaysOfWeek, UNSCHEDULED] as const; function courseClassLabel(courseClass: CourseClassOption): string { - const namePart = courseClass.class_name - ? `${courseClass.class_name} - ` - : ''; - - return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; + return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`; } function toTimeInput(value: string | null): string { @@ -166,8 +165,6 @@ export default function ScheduleIndex({ {courseClassLabel( schedule.course_class ?? { id: 0, - class_name: - null, course: null, }, )} @@ -253,7 +250,7 @@ export default function ScheduleIndex({ }} title="Hapus Jadwal" description={(schedule) => - `Apakah Anda yakin ingin menghapus jadwal "${schedule.course_class?.class_name ?? schedule.course_class?.course?.name ?? 'ini'}"? Tindakan ini tidak dapat dibatalkan.` + `Apakah Anda yakin ingin menghapus jadwal "${schedule.course_class?.course?.name ?? 'ini'}"? Tindakan ini tidak dapat dibatalkan.` } onConfirm={handleDelete} /> diff --git a/resources/js/pages/admin/manage/course-classes/columns.tsx b/resources/js/pages/admin/manage/course-classes/columns.tsx index d2e60f1..7ab3bd0 100644 --- a/resources/js/pages/admin/manage/course-classes/columns.tsx +++ b/resources/js/pages/admin/manage/course-classes/columns.tsx @@ -19,15 +19,6 @@ export function createCourseClassColumns( const { handleEdit, handleDeleteClick } = params; return [ - { - accessorKey: 'class_name', - header: () => Kelas, - cell: ({ row }) => ( - - {(row.getValue('class_name') as string | null) ?? '-'} - - ), - }, { accessorKey: 'course.name', header: () => Mata Kuliah, diff --git a/resources/js/pages/admin/manage/course-classes/enrollments.tsx b/resources/js/pages/admin/manage/course-classes/enrollments.tsx index 0a256e1..fbf772c 100644 --- a/resources/js/pages/admin/manage/course-classes/enrollments.tsx +++ b/resources/js/pages/admin/manage/course-classes/enrollments.tsx @@ -119,9 +119,7 @@ export default function ClassEnrollmentIndex({ - - {courseClass.class_name ?? courseClass.course?.name} - + Detail Kelas Mata Kuliah

diff --git a/resources/js/pages/admin/manage/course-classes/index.tsx b/resources/js/pages/admin/manage/course-classes/index.tsx index 7edbcc8..6ce036f 100644 --- a/resources/js/pages/admin/manage/course-classes/index.tsx +++ b/resources/js/pages/admin/manage/course-classes/index.tsx @@ -10,7 +10,14 @@ 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 { + Combobox, + ComboboxContent, + ComboboxEmpty, + ComboboxInput, + ComboboxItem, + ComboboxList, +} from '@/components/ui/combobox'; import { Label } from '@/components/ui/label'; import { Select, @@ -34,7 +41,7 @@ type Course = { id: number; code: string; name: string; department_id: number }; type Lecturer = { id: number; lecturer_number: string; - department_id: number; + departments: { id: number; name: string }[]; user: { profile: { full_name: string } | null } | null; }; type AcademicTerm = { id: number; name: string; semester: string }; @@ -189,7 +196,7 @@ export default function CourseClassIndex({ - `Apakah Anda yakin ingin menghapus kelas "${courseClass.class_name ?? courseClass.course?.name}"? Tindakan ini tidak dapat dibatalkan.` + `Apakah Anda yakin ingin menghapus kelas "${courseClass.course?.name}"? Tindakan ini tidak dapat dibatalkan.` } onConfirm={handleDelete} /> @@ -238,18 +245,21 @@ function CreateForm({ academicTerms: AcademicTerm[]; }) { const [courseId, setCourseId] = useState(''); - const [lecturerId, setLecturerId] = useState(''); + const [lecturer, setLecturer] = useState(null); const selectedCourse = courses.find((c) => String(c.id) === courseId); const availableLecturers = selectedCourse - ? lecturers.filter( - (l) => l.department_id === selectedCourse.department_id, + ? lecturers.filter((l) => + l.departments.some( + (department) => + department.id === selectedCourse.department_id, + ), ) : lecturers; function reset() { setCourseId(''); - setLecturerId(''); + setLecturer(null); } return ( @@ -266,6 +276,29 @@ function CreateForm({ > {({ errors }) => (

+
+ + + + +
-
- - - - -
-
- - - -
@@ -409,14 +422,19 @@ function EditForm({ const [courseId, setCourseId] = useState( editing ? String(editing.course_id) : '', ); - const [lecturerId, setLecturerId] = useState( - editing ? String(editing.lecturer_id) : '', + const [lecturer, setLecturer] = useState( + editing + ? (lecturers.find((l) => l.id === editing.lecturer_id) ?? null) + : null, ); const selectedCourse = courses.find((c) => String(c.id) === courseId); const availableLecturers = selectedCourse - ? lecturers.filter( - (l) => l.department_id === selectedCourse.department_id, + ? lecturers.filter((l) => + l.departments.some( + (department) => + department.id === selectedCourse.department_id, + ), ) : lecturers; @@ -446,7 +464,7 @@ function EditForm({ value={courseId} onValueChange={(value) => { setCourseId(value); - setLecturerId(''); + setLecturer(null); }} > @@ -473,28 +491,45 @@ function EditForm({ - + + + + Dosen tidak ditemukan. + + + {availableLecturers.map((lect) => ( + + {lect.user?.profile + ?.full_name ?? 'N/A'}{' '} + - {lect.lecturer_number} + + ))} + + +
@@ -522,16 +557,6 @@ function EditForm({
-
- - - -