refactor: remove class_name from CourseClass and related components
Some checks failed
tests / ci (pull_request) Has been cancelled
Some checks failed
tests / ci (pull_request) Has been cancelled
This commit is contained in:
parent
6c28782484
commit
5710a57992
@ -26,7 +26,6 @@ public function rules(): array
|
|||||||
Rule::exists('lecturers', 'id')->where('department_id', $departmentId),
|
Rule::exists('lecturers', 'id')->where('department_id', $departmentId),
|
||||||
],
|
],
|
||||||
'academic_term_id' => ['required', 'integer', Rule::exists('academic_terms', 'id')],
|
'academic_term_id' => ['required', 'integer', Rule::exists('academic_terms', 'id')],
|
||||||
'class_name' => ['nullable', 'string', 'max:50'],
|
|
||||||
'method' => ['nullable', 'string', Rule::in(ClassMethod::values())],
|
'method' => ['nullable', 'string', Rule::in(ClassMethod::values())],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ class CourseClassService
|
|||||||
{
|
{
|
||||||
public function getAllForSelect(): Collection
|
public function getAllForSelect(): Collection
|
||||||
{
|
{
|
||||||
return CourseClass::select(['id', 'course_id', 'class_name'])
|
return CourseClass::select(['id', 'course_id'])
|
||||||
->with('course:id,code,name')
|
->with('course:id,code,name')
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
@ -18,11 +18,10 @@ public function getAllForSelect(): Collection
|
|||||||
public function paginated(int $perPage = 25, string $search = '', ?int $academicTermId = null, ?string $method = null): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', ?int $academicTermId = null, ?string $method = null): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return CourseClass::query()
|
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')
|
->withCount('enrollments')
|
||||||
->with(['course:id,code,name,department_id', 'lecturer.user.profile', 'academicTerm:id,name,semester,start_date,end_date'])
|
->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}%")
|
->when($search, fn ($q) => $q->whereHas('course', fn ($q) => $q->where('name', 'like', "%{$search}%")->orWhere('code', 'like', "%{$search}%")))
|
||||||
->orWhereHas('course', fn ($q) => $q->where('name', 'like', "%{$search}%")->orWhere('code', 'like', "%{$search}%")))
|
|
||||||
->when($academicTermId, fn ($q) => $q->where('academic_term_id', $academicTermId))
|
->when($academicTermId, fn ($q) => $q->where('academic_term_id', $academicTermId))
|
||||||
->when($method, fn ($q) => $q->where('method', $method))
|
->when($method, fn ($q) => $q->where('method', $method))
|
||||||
->latest()
|
->latest()
|
||||||
@ -39,7 +38,6 @@ public function update(CourseClass $courseClass, array $data): CourseClass
|
|||||||
$courseClass->course_id = $data['course_id'];
|
$courseClass->course_id = $data['course_id'];
|
||||||
$courseClass->lecturer_id = $data['lecturer_id'];
|
$courseClass->lecturer_id = $data['lecturer_id'];
|
||||||
$courseClass->academic_term_id = $data['academic_term_id'];
|
$courseClass->academic_term_id = $data['academic_term_id'];
|
||||||
$courseClass->class_name = $data['class_name'] ?? null;
|
|
||||||
$courseClass->method = $data['method'] ?? null;
|
$courseClass->method = $data['method'] ?? null;
|
||||||
$courseClass->update();
|
$courseClass->update();
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ public function getAllForSelect(): Collection
|
|||||||
->with([
|
->with([
|
||||||
'user:id,username',
|
'user:id,username',
|
||||||
'user.profile:id,user_id,full_name',
|
'user.profile:id,user_id,full_name',
|
||||||
|
'departments:id,name',
|
||||||
])
|
])
|
||||||
->get();
|
->get();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,6 @@ public function up(): void
|
|||||||
$table->foreignId('course_id')->constrained()->cascadeOnDelete();
|
$table->foreignId('course_id')->constrained()->cascadeOnDelete();
|
||||||
$table->foreignId('lecturer_id')->constrained()->cascadeOnDelete();
|
$table->foreignId('lecturer_id')->constrained()->cascadeOnDelete();
|
||||||
$table->foreignId('academic_term_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->enum('method', ClassMethod::values())->nullable()->default(ClassMethod::Hybrid->value);
|
||||||
$table->timestamps();
|
$table->timestamps();
|
||||||
$table->softDeletes();
|
$table->softDeletes();
|
||||||
|
|||||||
@ -14,7 +14,6 @@ public function run(): void
|
|||||||
'course_id' => 1,
|
'course_id' => 1,
|
||||||
'lecturer_id' => 1,
|
'lecturer_id' => 1,
|
||||||
'academic_term_id' => 2,
|
'academic_term_id' => 2,
|
||||||
'class_name' => 'SI-5A',
|
|
||||||
'method' => 'hybrid',
|
'method' => 'hybrid',
|
||||||
'created_at' => '2026-01-10 08:00:00',
|
'created_at' => '2026-01-10 08:00:00',
|
||||||
'updated_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,
|
'course_id' => 2,
|
||||||
'lecturer_id' => 2,
|
'lecturer_id' => 2,
|
||||||
'academic_term_id' => 2,
|
'academic_term_id' => 2,
|
||||||
'class_name' => 'TI-3A',
|
|
||||||
'method' => 'offline',
|
'method' => 'offline',
|
||||||
'created_at' => '2026-01-10 08:00:00',
|
'created_at' => '2026-01-10 08:00:00',
|
||||||
'updated_at' => '2026-01-10 08:00:00',
|
'updated_at' => '2026-01-10 08:00:00',
|
||||||
|
|||||||
@ -107,6 +107,16 @@ const data: {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Kelola',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
name: 'Kelas Mata Kuliah',
|
||||||
|
url: courseClassesRoute.url(),
|
||||||
|
icon: School,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Kelas',
|
label: 'Kelas',
|
||||||
items: [
|
items: [
|
||||||
@ -137,16 +147,6 @@ const data: {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Kelola',
|
|
||||||
items: [
|
|
||||||
{
|
|
||||||
name: 'Kelas Mata Kuliah',
|
|
||||||
url: courseClassesRoute.url(),
|
|
||||||
icon: School,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Pengumuman',
|
label: 'Pengumuman',
|
||||||
items: [
|
items: [
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export function createAssignmentColumns(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'course_class.class_name',
|
accessorKey: 'course_class.course.name',
|
||||||
header: () => <span>Kelas</span>,
|
header: () => <span>Kelas</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const courseClass = row.original.course_class;
|
const courseClass = row.original.course_class;
|
||||||
@ -37,11 +37,7 @@ export function createAssignmentColumns(
|
|||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
const label = courseClass.class_name
|
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
||||||
? `${courseClass.class_name} - `
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return `${label}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -34,7 +34,6 @@ import { createAssignmentColumns } from './columns';
|
|||||||
|
|
||||||
type CourseClassOption = {
|
type CourseClassOption = {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; name: string } | null;
|
course: { id: number; code: string; name: string } | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,11 +53,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function courseClassLabel(courseClass: CourseClassOption): string {
|
function courseClassLabel(courseClass: CourseClassOption): string {
|
||||||
const namePart = courseClass.class_name
|
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
||||||
? `${courseClass.class_name} - `
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AssignmentIndex({
|
export default function AssignmentIndex({
|
||||||
|
|||||||
@ -175,11 +175,7 @@ export default function SubmissionIndex({
|
|||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="grid gap-1 text-sm text-muted-foreground">
|
<CardContent className="grid gap-1 text-sm text-muted-foreground">
|
||||||
<p>
|
<p>
|
||||||
Kelas:{' '}
|
Kelas: {assignment.course_class?.course?.code}{' '}
|
||||||
{assignment.course_class?.class_name
|
|
||||||
? `${assignment.course_class.class_name} - `
|
|
||||||
: ''}
|
|
||||||
{assignment.course_class?.course?.code}{' '}
|
|
||||||
{assignment.course_class?.course?.name}
|
{assignment.course_class?.course?.name}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@ -35,11 +35,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function courseClassLabel(courseClass: AttendanceCourseClass): string {
|
function courseClassLabel(courseClass: AttendanceCourseClass): string {
|
||||||
const namePart = courseClass.class_name
|
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
||||||
? `${courseClass.class_name} - `
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AttendanceIndex({ sessions, courseClasses }: Props) {
|
export default function AttendanceIndex({ sessions, courseClasses }: Props) {
|
||||||
|
|||||||
@ -26,11 +26,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function courseClassLabel(courseClass: AttendanceCourseClass): string {
|
function courseClassLabel(courseClass: AttendanceCourseClass): string {
|
||||||
const namePart = courseClass.class_name
|
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
||||||
? `${courseClass.class_name} - `
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AttendanceSession({
|
export default function AttendanceSession({
|
||||||
|
|||||||
@ -54,9 +54,6 @@ export function createCourseRegistrationColumns(
|
|||||||
</p>
|
</p>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{courseClass?.course?.code}
|
{courseClass?.course?.code}
|
||||||
{courseClass?.class_name
|
|
||||||
? ` · ${courseClass.class_name}`
|
|
||||||
: ''}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -68,9 +68,8 @@ function studentLabel(student: CourseRegistrationStudent): string {
|
|||||||
|
|
||||||
function courseClassLabel(courseClass: CourseRegistrationCourseClass): string {
|
function courseClassLabel(courseClass: CourseRegistrationCourseClass): string {
|
||||||
const course = courseClass.course;
|
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 {
|
function lecturerLabel(lecturer: LecturerOption): string {
|
||||||
|
|||||||
@ -49,7 +49,7 @@ export function createMaterialColumns(
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'course_class.class_name',
|
accessorKey: 'course_class.course.name',
|
||||||
header: () => <span>Kelas</span>,
|
header: () => <span>Kelas</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const courseClass = row.original.course_class;
|
const courseClass = row.original.course_class;
|
||||||
@ -58,11 +58,7 @@ export function createMaterialColumns(
|
|||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
const label = courseClass.class_name
|
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
||||||
? `${courseClass.class_name} - `
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return `${label}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -33,7 +33,6 @@ import { createMaterialColumns } from './columns';
|
|||||||
|
|
||||||
type CourseClassOption = {
|
type CourseClassOption = {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; name: string } | null;
|
course: { id: number; code: string; name: string } | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,11 +52,7 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function courseClassLabel(courseClass: CourseClassOption): string {
|
function courseClassLabel(courseClass: CourseClassOption): string {
|
||||||
const namePart = courseClass.class_name
|
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
||||||
? `${courseClass.class_name} - `
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MaterialIndex({
|
export default function MaterialIndex({
|
||||||
|
|||||||
@ -19,13 +19,16 @@ import {
|
|||||||
SelectValue,
|
SelectValue,
|
||||||
} from '@/components/ui/select';
|
} from '@/components/ui/select';
|
||||||
import { cn } from '@/lib/utils';
|
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 type { Schedule } from '@/types/schedule';
|
||||||
import { DayOfWeekLabels, DaysOfWeek } from '@/types/schedule';
|
import { DayOfWeekLabels, DaysOfWeek } from '@/types/schedule';
|
||||||
|
|
||||||
type CourseClassOption = {
|
type CourseClassOption = {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; 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;
|
const BOARD_COLUMNS = [...DaysOfWeek, UNSCHEDULED] as const;
|
||||||
|
|
||||||
function courseClassLabel(courseClass: CourseClassOption): string {
|
function courseClassLabel(courseClass: CourseClassOption): string {
|
||||||
const namePart = courseClass.class_name
|
return `${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
||||||
? `${courseClass.class_name} - `
|
|
||||||
: '';
|
|
||||||
|
|
||||||
return `${namePart}${courseClass.course?.code ?? ''} ${courseClass.course?.name ?? ''}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toTimeInput(value: string | null): string {
|
function toTimeInput(value: string | null): string {
|
||||||
@ -166,8 +165,6 @@ export default function ScheduleIndex({
|
|||||||
{courseClassLabel(
|
{courseClassLabel(
|
||||||
schedule.course_class ?? {
|
schedule.course_class ?? {
|
||||||
id: 0,
|
id: 0,
|
||||||
class_name:
|
|
||||||
null,
|
|
||||||
course: null,
|
course: null,
|
||||||
},
|
},
|
||||||
)}
|
)}
|
||||||
@ -253,7 +250,7 @@ export default function ScheduleIndex({
|
|||||||
}}
|
}}
|
||||||
title="Hapus Jadwal"
|
title="Hapus Jadwal"
|
||||||
description={(schedule) =>
|
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}
|
onConfirm={handleDelete}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -19,15 +19,6 @@ export function createCourseClassColumns(
|
|||||||
const { handleEdit, handleDeleteClick } = params;
|
const { handleEdit, handleDeleteClick } = params;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
|
||||||
accessorKey: 'class_name',
|
|
||||||
header: () => <span>Kelas</span>,
|
|
||||||
cell: ({ row }) => (
|
|
||||||
<span className="font-medium">
|
|
||||||
{(row.getValue('class_name') as string | null) ?? '-'}
|
|
||||||
</span>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessorKey: 'course.name',
|
accessorKey: 'course.name',
|
||||||
header: () => <span>Mata Kuliah</span>,
|
header: () => <span>Mata Kuliah</span>,
|
||||||
|
|||||||
@ -119,9 +119,7 @@ export default function ClassEnrollmentIndex({
|
|||||||
|
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
<CardTitle>
|
<CardTitle>Detail Kelas Mata Kuliah</CardTitle>
|
||||||
{courseClass.class_name ?? courseClass.course?.name}
|
|
||||||
</CardTitle>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="grid gap-1 text-sm text-muted-foreground">
|
<CardContent className="grid gap-1 text-sm text-muted-foreground">
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@ -10,7 +10,14 @@ import { FormDialog } from '@/components/form-dialog';
|
|||||||
import InputError from '@/components/input-error';
|
import InputError from '@/components/input-error';
|
||||||
import { PageHeader } from '@/components/page-header';
|
import { PageHeader } from '@/components/page-header';
|
||||||
import { Button } from '@/components/ui/button';
|
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 { Label } from '@/components/ui/label';
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
@ -34,7 +41,7 @@ type Course = { id: number; code: string; name: string; department_id: number };
|
|||||||
type Lecturer = {
|
type Lecturer = {
|
||||||
id: number;
|
id: number;
|
||||||
lecturer_number: string;
|
lecturer_number: string;
|
||||||
department_id: number;
|
departments: { id: number; name: string }[];
|
||||||
user: { profile: { full_name: string } | null } | null;
|
user: { profile: { full_name: string } | null } | null;
|
||||||
};
|
};
|
||||||
type AcademicTerm = { id: number; name: string; semester: string };
|
type AcademicTerm = { id: number; name: string; semester: string };
|
||||||
@ -189,7 +196,7 @@ export default function CourseClassIndex({
|
|||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={courseClasses.data}
|
data={courseClasses.data}
|
||||||
searchKey="class_name"
|
searchKey="course"
|
||||||
searchPlaceholder="Cari kelas mata kuliah..."
|
searchPlaceholder="Cari kelas mata kuliah..."
|
||||||
emptyText="Belum ada data kelas mata kuliah."
|
emptyText="Belum ada data kelas mata kuliah."
|
||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
@ -215,7 +222,7 @@ export default function CourseClassIndex({
|
|||||||
}}
|
}}
|
||||||
title="Hapus Kelas Mata Kuliah"
|
title="Hapus Kelas Mata Kuliah"
|
||||||
description={(courseClass) =>
|
description={(courseClass) =>
|
||||||
`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}
|
onConfirm={handleDelete}
|
||||||
/>
|
/>
|
||||||
@ -238,18 +245,21 @@ function CreateForm({
|
|||||||
academicTerms: AcademicTerm[];
|
academicTerms: AcademicTerm[];
|
||||||
}) {
|
}) {
|
||||||
const [courseId, setCourseId] = useState('');
|
const [courseId, setCourseId] = useState('');
|
||||||
const [lecturerId, setLecturerId] = useState('');
|
const [lecturer, setLecturer] = useState<Lecturer | null>(null);
|
||||||
|
|
||||||
const selectedCourse = courses.find((c) => String(c.id) === courseId);
|
const selectedCourse = courses.find((c) => String(c.id) === courseId);
|
||||||
const availableLecturers = selectedCourse
|
const availableLecturers = selectedCourse
|
||||||
? lecturers.filter(
|
? lecturers.filter((l) =>
|
||||||
(l) => l.department_id === selectedCourse.department_id,
|
l.departments.some(
|
||||||
|
(department) =>
|
||||||
|
department.id === selectedCourse.department_id,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: lecturers;
|
: lecturers;
|
||||||
|
|
||||||
function reset() {
|
function reset() {
|
||||||
setCourseId('');
|
setCourseId('');
|
||||||
setLecturerId('');
|
setLecturer(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -266,6 +276,29 @@ function CreateForm({
|
|||||||
>
|
>
|
||||||
{({ errors }) => (
|
{({ errors }) => (
|
||||||
<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" />
|
||||||
|
<Select name="academic_term_id">
|
||||||
|
<SelectTrigger className="w-full">
|
||||||
|
<SelectValue placeholder="Pilih periode akademik" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
{academicTerms.map((term) => (
|
||||||
|
<SelectItem
|
||||||
|
key={term.id}
|
||||||
|
value={String(term.id)}
|
||||||
|
>
|
||||||
|
{term.name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<InputError message={errors.academic_term_id} />
|
||||||
|
</div>
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label>
|
<Label>
|
||||||
Mata Kuliah{' '}
|
Mata Kuliah{' '}
|
||||||
@ -280,7 +313,7 @@ function CreateForm({
|
|||||||
value={courseId}
|
value={courseId}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setCourseId(value);
|
setCourseId(value);
|
||||||
setLecturerId('');
|
setLecturer(null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
@ -307,67 +340,47 @@ function CreateForm({
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="lecturer_id"
|
name="lecturer_id"
|
||||||
value={lecturerId}
|
value={lecturer?.id ?? ''}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Combobox
|
||||||
value={lecturerId}
|
items={availableLecturers}
|
||||||
onValueChange={setLecturerId}
|
value={lecturer}
|
||||||
|
onValueChange={setLecturer}
|
||||||
|
itemToStringLabel={(lect) =>
|
||||||
|
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
|
||||||
|
}
|
||||||
|
isItemEqualToValue={(a, b) => a.id === b.id}
|
||||||
|
disabled={!selectedCourse}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<ComboboxInput
|
||||||
<SelectValue
|
disabled={!selectedCourse}
|
||||||
placeholder={
|
placeholder={
|
||||||
selectedCourse
|
selectedCourse
|
||||||
? 'Pilih dosen pengampu'
|
? 'Pilih dosen pengampu'
|
||||||
: 'Pilih mata kuliah terlebih dahulu'
|
: 'Pilih mata kuliah terlebih dahulu'
|
||||||
}
|
}
|
||||||
|
className="w-full"
|
||||||
/>
|
/>
|
||||||
</SelectTrigger>
|
<ComboboxContent>
|
||||||
<SelectContent>
|
<ComboboxEmpty>
|
||||||
|
Dosen tidak ditemukan.
|
||||||
|
</ComboboxEmpty>
|
||||||
|
<ComboboxList>
|
||||||
{availableLecturers.map((lect) => (
|
{availableLecturers.map((lect) => (
|
||||||
<SelectItem
|
<ComboboxItem
|
||||||
key={lect.id}
|
key={lect.id}
|
||||||
value={String(lect.id)}
|
value={lect}
|
||||||
>
|
>
|
||||||
{lect.user?.profile?.full_name ?? 'N/A'}{' '}
|
{lect.user?.profile?.full_name ??
|
||||||
|
'N/A'}{' '}
|
||||||
- {lect.lecturer_number}
|
- {lect.lecturer_number}
|
||||||
</SelectItem>
|
</ComboboxItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</ComboboxList>
|
||||||
</Select>
|
</ComboboxContent>
|
||||||
|
</Combobox>
|
||||||
<InputError message={errors.lecturer_id} />
|
<InputError message={errors.lecturer_id} />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label>
|
|
||||||
Periode Akademik{' '}
|
|
||||||
<span className="text-destructive">*</span>
|
|
||||||
</Label>
|
|
||||||
<input type="hidden" name="academic_term_id" />
|
|
||||||
<Select name="academic_term_id">
|
|
||||||
<SelectTrigger className="w-full">
|
|
||||||
<SelectValue placeholder="Pilih periode akademik" />
|
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
{academicTerms.map((term) => (
|
|
||||||
<SelectItem
|
|
||||||
key={term.id}
|
|
||||||
value={String(term.id)}
|
|
||||||
>
|
|
||||||
{term.name}
|
|
||||||
</SelectItem>
|
|
||||||
))}
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<InputError message={errors.academic_term_id} />
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label htmlFor="class_name">Nama Kelas</Label>
|
|
||||||
<Input
|
|
||||||
id="class_name"
|
|
||||||
name="class_name"
|
|
||||||
placeholder="Contoh: SI-5A"
|
|
||||||
/>
|
|
||||||
<InputError message={errors.class_name} />
|
|
||||||
</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" />
|
||||||
@ -409,14 +422,19 @@ function EditForm({
|
|||||||
const [courseId, setCourseId] = useState(
|
const [courseId, setCourseId] = useState(
|
||||||
editing ? String(editing.course_id) : '',
|
editing ? String(editing.course_id) : '',
|
||||||
);
|
);
|
||||||
const [lecturerId, setLecturerId] = useState(
|
const [lecturer, setLecturer] = useState<Lecturer | null>(
|
||||||
editing ? String(editing.lecturer_id) : '',
|
editing
|
||||||
|
? (lecturers.find((l) => l.id === editing.lecturer_id) ?? null)
|
||||||
|
: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectedCourse = courses.find((c) => String(c.id) === courseId);
|
const selectedCourse = courses.find((c) => String(c.id) === courseId);
|
||||||
const availableLecturers = selectedCourse
|
const availableLecturers = selectedCourse
|
||||||
? lecturers.filter(
|
? lecturers.filter((l) =>
|
||||||
(l) => l.department_id === selectedCourse.department_id,
|
l.departments.some(
|
||||||
|
(department) =>
|
||||||
|
department.id === selectedCourse.department_id,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: lecturers;
|
: lecturers;
|
||||||
|
|
||||||
@ -446,7 +464,7 @@ function EditForm({
|
|||||||
value={courseId}
|
value={courseId}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setCourseId(value);
|
setCourseId(value);
|
||||||
setLecturerId('');
|
setLecturer(null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
@ -473,28 +491,45 @@ function EditForm({
|
|||||||
<input
|
<input
|
||||||
type="hidden"
|
type="hidden"
|
||||||
name="lecturer_id"
|
name="lecturer_id"
|
||||||
value={lecturerId}
|
value={lecturer?.id ?? ''}
|
||||||
/>
|
/>
|
||||||
<Select
|
<Combobox
|
||||||
value={lecturerId}
|
items={availableLecturers}
|
||||||
onValueChange={setLecturerId}
|
value={lecturer}
|
||||||
|
onValueChange={setLecturer}
|
||||||
|
itemToStringLabel={(lect) =>
|
||||||
|
`${lect.user?.profile?.full_name ?? 'N/A'} - ${lect.lecturer_number}`
|
||||||
|
}
|
||||||
|
isItemEqualToValue={(a, b) => a.id === b.id}
|
||||||
|
disabled={!selectedCourse}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<ComboboxInput
|
||||||
<SelectValue placeholder="Pilih dosen pengampu" />
|
disabled={!selectedCourse}
|
||||||
</SelectTrigger>
|
placeholder={
|
||||||
<SelectContent>
|
selectedCourse
|
||||||
|
? 'Pilih dosen pengampu'
|
||||||
|
: 'Pilih mata kuliah terlebih dahulu'
|
||||||
|
}
|
||||||
|
className="w-full"
|
||||||
|
/>
|
||||||
|
<ComboboxContent>
|
||||||
|
<ComboboxEmpty>
|
||||||
|
Dosen tidak ditemukan.
|
||||||
|
</ComboboxEmpty>
|
||||||
|
<ComboboxList>
|
||||||
{availableLecturers.map((lect) => (
|
{availableLecturers.map((lect) => (
|
||||||
<SelectItem
|
<ComboboxItem
|
||||||
key={lect.id}
|
key={lect.id}
|
||||||
value={String(lect.id)}
|
value={lect}
|
||||||
>
|
>
|
||||||
{lect.user?.profile?.full_name ??
|
{lect.user?.profile
|
||||||
'N/A'}{' '}
|
?.full_name ?? 'N/A'}{' '}
|
||||||
- {lect.lecturer_number}
|
- {lect.lecturer_number}
|
||||||
</SelectItem>
|
</ComboboxItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</ComboboxList>
|
||||||
</Select>
|
</ComboboxContent>
|
||||||
|
</Combobox>
|
||||||
<InputError message={errors.lecturer_id} />
|
<InputError message={errors.lecturer_id} />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
@ -522,16 +557,6 @@ function EditForm({
|
|||||||
</Select>
|
</Select>
|
||||||
<InputError message={errors.academic_term_id} />
|
<InputError message={errors.academic_term_id} />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2">
|
|
||||||
<Label htmlFor="edit-class_name">Nama Kelas</Label>
|
|
||||||
<Input
|
|
||||||
id="edit-class_name"
|
|
||||||
name="class_name"
|
|
||||||
placeholder="Contoh: SI-5A"
|
|
||||||
defaultValue={editing.class_name ?? ''}
|
|
||||||
/>
|
|
||||||
<InputError message={errors.class_name} />
|
|
||||||
</div>
|
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label>Metode</Label>
|
<Label>Metode</Label>
|
||||||
<Select
|
<Select
|
||||||
|
|||||||
@ -3,7 +3,6 @@ export type Assignment = {
|
|||||||
course_class_id: number;
|
course_class_id: number;
|
||||||
course_class: {
|
course_class: {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; name: string } | null;
|
course: { id: number; code: string; name: string } | null;
|
||||||
} | null;
|
} | null;
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@ -9,7 +9,6 @@ export const AttendanceStatusLabels: Record<AttendanceStatus, string> = {
|
|||||||
|
|
||||||
export type AttendanceCourseClass = {
|
export type AttendanceCourseClass = {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; name: string } | null;
|
course: { id: number; code: string; name: string } | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -26,7 +26,6 @@ export type CourseClass = {
|
|||||||
} | null;
|
} | null;
|
||||||
academic_term_id: number;
|
academic_term_id: number;
|
||||||
academic_term: { id: number; name: string; semester: string } | null;
|
academic_term: { id: number; name: string; semester: string } | null;
|
||||||
class_name: string | null;
|
|
||||||
method: ClassMethod | null;
|
method: ClassMethod | null;
|
||||||
enrollments_count: number;
|
enrollments_count: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
|||||||
@ -21,7 +21,6 @@ export type CourseRegistrationStudent = {
|
|||||||
|
|
||||||
export type CourseRegistrationCourseClass = {
|
export type CourseRegistrationCourseClass = {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; name: string } | null;
|
course: { id: number; code: string; name: string } | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,6 @@ export type Material = {
|
|||||||
course_class_id: number;
|
course_class_id: number;
|
||||||
course_class: {
|
course_class: {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; name: string } | null;
|
course: { id: number; code: string; name: string } | null;
|
||||||
} | null;
|
} | null;
|
||||||
title: string;
|
title: string;
|
||||||
|
|||||||
@ -25,7 +25,6 @@ export type Schedule = {
|
|||||||
course_class_id: number;
|
course_class_id: number;
|
||||||
course_class: {
|
course_class: {
|
||||||
id: number;
|
id: number;
|
||||||
class_name: string | null;
|
|
||||||
course: { id: number; code: string; name: string } | null;
|
course: { id: number; code: string; name: string } | null;
|
||||||
} | null;
|
} | null;
|
||||||
day_of_week: string | null;
|
day_of_week: string | null;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user