feat: rename 'name' to 'academic_year' in AcademicTerm and related components for consistency
This commit is contained in:
parent
6c55fb5f36
commit
ded7217dbc
@ -16,13 +16,13 @@ public function authorize(): bool
|
|||||||
public function rules(): array
|
public function rules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'name' => [
|
'academic_year' => [
|
||||||
'required',
|
'required',
|
||||||
'string',
|
'string',
|
||||||
'max:20',
|
'max:20',
|
||||||
function ($attribute, $value, $fail) {
|
function ($attribute, $value, $fail) {
|
||||||
if (! preg_match('/^(\d{4})\/(\d{4})$/', $value, $matches)) {
|
if (! preg_match('/^(\d{4})\/(\d{4})$/', $value, $matches)) {
|
||||||
$fail('Format name harus YYYY/YYYY, contoh: 2025/2026.');
|
$fail('Format tahun ajaran harus YYYY/YYYY, contoh: 2025/2026.');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -40,16 +40,16 @@ function ($attribute, $value, $fail) {
|
|||||||
'string',
|
'string',
|
||||||
Rule::in(Semester::values()),
|
Rule::in(Semester::values()),
|
||||||
Rule::unique('academic_terms')->where(function ($query) {
|
Rule::unique('academic_terms')->where(function ($query) {
|
||||||
return $query->where('name', $this->input('name'));
|
return $query->where('academic_year', $this->input('academic_year'));
|
||||||
})->ignore($this->route('academic_term')),
|
})->ignore($this->route('academic_term')),
|
||||||
],
|
],
|
||||||
'start_date' => [
|
'start_date' => [
|
||||||
'required',
|
'required',
|
||||||
'date',
|
'date',
|
||||||
function ($attribute, $value, $fail) {
|
function ($attribute, $value, $fail) {
|
||||||
$name = $this->input('name');
|
$academicYear = $this->input('academic_year');
|
||||||
$semester = $this->input('semester');
|
$semester = $this->input('semester');
|
||||||
if ($name && preg_match('/^(\d{4})\/(\d{4})$/', $name, $matches)) {
|
if ($academicYear && preg_match('/^(\d{4})\/(\d{4})$/', $academicYear, $matches)) {
|
||||||
$startYear = (int) $matches[1];
|
$startYear = (int) $matches[1];
|
||||||
$endYear = (int) $matches[2];
|
$endYear = (int) $matches[2];
|
||||||
$dateYear = (int) date('Y', strtotime($value));
|
$dateYear = (int) date('Y', strtotime($value));
|
||||||
@ -65,9 +65,9 @@ function ($attribute, $value, $fail) {
|
|||||||
'date',
|
'date',
|
||||||
'after_or_equal:start_date',
|
'after_or_equal:start_date',
|
||||||
function ($attribute, $value, $fail) {
|
function ($attribute, $value, $fail) {
|
||||||
$name = $this->input('name');
|
$academicYear = $this->input('academic_year');
|
||||||
$semester = $this->input('semester');
|
$semester = $this->input('semester');
|
||||||
if ($name && preg_match('/^(\d{4})\/(\d{4})$/', $name, $matches)) {
|
if ($academicYear && preg_match('/^(\d{4})\/(\d{4})$/', $academicYear, $matches)) {
|
||||||
$startYear = (int) $matches[1];
|
$startYear = (int) $matches[1];
|
||||||
$endYear = (int) $matches[2];
|
$endYear = (int) $matches[2];
|
||||||
$dateYear = (int) date('Y', strtotime($value));
|
$dateYear = (int) date('Y', strtotime($value));
|
||||||
|
|||||||
@ -33,7 +33,7 @@ public function paginated(
|
|||||||
->select(['id', 'student_id', 'academic_term_id', 'amount_due', 'due_date'])
|
->select(['id', 'student_id', 'academic_term_id', 'amount_due', 'due_date'])
|
||||||
->withSum('payments as paid_total', 'amount_paid')
|
->withSum('payments as paid_total', 'amount_paid')
|
||||||
->withCount('payments')
|
->withCount('payments')
|
||||||
->with(['student.user.profile', 'student.department', 'academicTerm:id,name,semester,start_date,end_date'])
|
->with(['student.user.profile', 'student.department', 'academicTerm:id,academic_year,semester,start_date,end_date'])
|
||||||
->when($status, fn ($q) => match ($status) {
|
->when($status, fn ($q) => match ($status) {
|
||||||
'paid' => $q->havingRaw('COALESCE(paid_total, 0) >= amount_due'),
|
'paid' => $q->havingRaw('COALESCE(paid_total, 0) >= amount_due'),
|
||||||
'partial' => $q->havingRaw('COALESCE(paid_total, 0) > 0 AND COALESCE(paid_total, 0) < amount_due'),
|
'partial' => $q->havingRaw('COALESCE(paid_total, 0) > 0 AND COALESCE(paid_total, 0) < amount_due'),
|
||||||
|
|||||||
@ -20,7 +20,7 @@ public function paginated(int $perPage = 25, string $search = '', ?int $academic
|
|||||||
return CourseClass::query()
|
return CourseClass::query()
|
||||||
->select(['id', 'course_id', 'lecturer_id', 'academic_term_id', '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,academic_year,semester,start_date,end_date'])
|
||||||
->when($search, fn ($q) => $q->whereHas('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($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))
|
||||||
|
|||||||
@ -113,7 +113,7 @@ public function withDetails(CourseRegistrationSubmission $submission): CourseReg
|
|||||||
'student.user.profile',
|
'student.user.profile',
|
||||||
'student.department.currentLeader.lecturer.user.profile',
|
'student.department.currentLeader.lecturer.user.profile',
|
||||||
'student.academicAdvisor.user.profile',
|
'student.academicAdvisor.user.profile',
|
||||||
'academicTerm:id,name,semester,start_date,end_date',
|
'academicTerm:id,academic_year,semester,start_date,end_date',
|
||||||
'reviewer.profile',
|
'reviewer.profile',
|
||||||
'courseRegistrations.courseClass.course',
|
'courseRegistrations.courseClass.course',
|
||||||
'logs' => fn ($q) => $q->oldest(),
|
'logs' => fn ($q) => $q->oldest(),
|
||||||
|
|||||||
@ -11,7 +11,7 @@ class AcademicTermService
|
|||||||
{
|
{
|
||||||
public function getAllForSelect(): Collection
|
public function getAllForSelect(): Collection
|
||||||
{
|
{
|
||||||
return AcademicTerm::select(['id', 'name', 'semester', 'start_date', 'end_date', 'is_active', 'open_semesters'])->latest()->get();
|
return AcademicTerm::select(['id', 'academic_year', 'semester', 'start_date', 'end_date', 'is_active', 'open_semesters'])->latest()->get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,8 +27,8 @@ public function getActive(): ?AcademicTerm
|
|||||||
public function paginated(int $perPage = 25, string $search = '', ?string $semester = null, ?bool $isActive = null): LengthAwarePaginator
|
public function paginated(int $perPage = 25, string $search = '', ?string $semester = null, ?bool $isActive = null): LengthAwarePaginator
|
||||||
{
|
{
|
||||||
return AcademicTerm::query()
|
return AcademicTerm::query()
|
||||||
->select(['id', 'name', 'semester', 'start_date', 'end_date', 'is_active', 'open_semesters'])
|
->select(['id', 'academic_year', 'semester', 'start_date', 'end_date', 'is_active', 'open_semesters'])
|
||||||
->when($search, fn($q) => $q->where('name', 'like', "%{$search}%"))
|
->when($search, fn($q) => $q->where('academic_year', 'like', "%{$search}%"))
|
||||||
->when($semester, fn($q) => $q->where('semester', $semester))
|
->when($semester, fn($q) => $q->where('semester', $semester))
|
||||||
->when($isActive !== null, fn($q) => $q->where('is_active', $isActive))
|
->when($isActive !== null, fn($q) => $q->where('is_active', $isActive))
|
||||||
->latest()
|
->latest()
|
||||||
@ -45,7 +45,7 @@ public function create(array $data): AcademicTerm
|
|||||||
|
|
||||||
public function update(AcademicTerm $academicTerm, array $data): AcademicTerm
|
public function update(AcademicTerm $academicTerm, array $data): AcademicTerm
|
||||||
{
|
{
|
||||||
$academicTerm->name = $data['name'];
|
$academicTerm->academic_year = $data['academic_year'];
|
||||||
$academicTerm->semester = $data['semester'];
|
$academicTerm->semester = $data['semester'];
|
||||||
$academicTerm->start_date = $data['start_date'];
|
$academicTerm->start_date = $data['start_date'];
|
||||||
$academicTerm->end_date = $data['end_date'];
|
$academicTerm->end_date = $data['end_date'];
|
||||||
|
|||||||
@ -11,7 +11,7 @@ public function up(): void
|
|||||||
{
|
{
|
||||||
Schema::create('academic_terms', function (Blueprint $table) {
|
Schema::create('academic_terms', function (Blueprint $table) {
|
||||||
$table->id();
|
$table->id();
|
||||||
$table->string('name', 20);
|
$table->string('academic_year', 20);
|
||||||
$table->enum('semester', Semester::values());
|
$table->enum('semester', Semester::values());
|
||||||
$table->date('start_date');
|
$table->date('start_date');
|
||||||
$table->date('end_date');
|
$table->date('end_date');
|
||||||
|
|||||||
@ -12,7 +12,7 @@ public function run(): void
|
|||||||
{
|
{
|
||||||
AcademicTerm::insert([
|
AcademicTerm::insert([
|
||||||
[
|
[
|
||||||
'name' => '2026/2027',
|
'academic_year' => '2026/2027',
|
||||||
'semester' => Semester::odd->value,
|
'semester' => Semester::odd->value,
|
||||||
'start_date' => '2026-08-01',
|
'start_date' => '2026-08-01',
|
||||||
'end_date' => '2027-01-15',
|
'end_date' => '2027-01-15',
|
||||||
@ -21,7 +21,7 @@ public function run(): void
|
|||||||
'updated_at' => now(),
|
'updated_at' => now(),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'name' => '2026/2027',
|
'academic_year' => '2026/2027',
|
||||||
'semester' => Semester::even->value,
|
'semester' => Semester::even->value,
|
||||||
'start_date' => '2027-02-01',
|
'start_date' => '2027-02-01',
|
||||||
'end_date' => '2027-07-15',
|
'end_date' => '2027-07-15',
|
||||||
|
|||||||
@ -51,7 +51,7 @@ export function createTuitionInvoiceColumns(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'academic_term.name',
|
accessorKey: 'academic_term.academic_year',
|
||||||
header: () => <span>Periode</span>,
|
header: () => <span>Periode</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const term = row.original.academic_term;
|
const term = row.original.academic_term;
|
||||||
|
|||||||
@ -69,7 +69,11 @@ import {
|
|||||||
} from '@/types/tuition-payment';
|
} from '@/types/tuition-payment';
|
||||||
import { createTuitionInvoiceColumns } from './columns';
|
import { createTuitionInvoiceColumns } from './columns';
|
||||||
|
|
||||||
type AcademicTermOption = { id: number; name: string; semester: string };
|
type AcademicTermOption = {
|
||||||
|
id: number;
|
||||||
|
academic_year: string;
|
||||||
|
semester: string;
|
||||||
|
};
|
||||||
|
|
||||||
type InvoiceSummary = {
|
type InvoiceSummary = {
|
||||||
unpaid_students: number;
|
unpaid_students: number;
|
||||||
|
|||||||
@ -45,7 +45,7 @@ export function createCourseClassColumns(
|
|||||||
row.original.lecturer?.user?.profile?.full_name ?? '-',
|
row.original.lecturer?.user?.profile?.full_name ?? '-',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessorKey: 'academic_term.name',
|
accessorKey: 'academic_term.academic_year',
|
||||||
header: () => <span>Periode</span>,
|
header: () => <span>Periode</span>,
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const term = row.original.academic_term;
|
const term = row.original.academic_term;
|
||||||
|
|||||||
@ -46,7 +46,11 @@ type Lecturer = {
|
|||||||
departments: { id: number; name: string }[];
|
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;
|
||||||
|
academic_year: string;
|
||||||
|
semester: string;
|
||||||
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
courseClasses: {
|
courseClasses: {
|
||||||
|
|||||||
@ -32,11 +32,11 @@ export function createAcademicTermColumns(
|
|||||||
|
|
||||||
const columns: ColumnDef<AcademicTerm>[] = [
|
const columns: ColumnDef<AcademicTerm>[] = [
|
||||||
{
|
{
|
||||||
accessorKey: 'name',
|
accessorKey: 'academic_year',
|
||||||
header: () => <span>Nama</span>,
|
header: () => <span>Tahun Ajaran</span>,
|
||||||
cell: ({ row }) => (
|
cell: ({ row }) => (
|
||||||
<span className="font-medium">
|
<span className="font-medium">
|
||||||
{row.getValue('name') as string}
|
{row.getValue('academic_year') as string}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@ -182,7 +182,7 @@ export default function AcademicTermIndex({
|
|||||||
<DataTable
|
<DataTable
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={academicTerms.data}
|
data={academicTerms.data}
|
||||||
searchKey="name"
|
searchKey="academic_year"
|
||||||
pagination={pagination}
|
pagination={pagination}
|
||||||
onPageChange={handlePageChange}
|
onPageChange={handlePageChange}
|
||||||
onPerPageChange={handlePerPageChange}
|
onPerPageChange={handlePerPageChange}
|
||||||
@ -206,7 +206,7 @@ export default function AcademicTermIndex({
|
|||||||
}}
|
}}
|
||||||
title="Hapus Periode Akademik"
|
title="Hapus Periode Akademik"
|
||||||
description={(academicTerm) =>
|
description={(academicTerm) =>
|
||||||
`Apakah Anda yakin ingin menghapus periode akademik "${academicTerm.name}"? Tindakan ini tidak dapat dibatalkan.`
|
`Apakah Anda yakin ingin menghapus periode akademik "${academicTerm.academic_year}"? Tindakan ini tidak dapat dibatalkan.`
|
||||||
}
|
}
|
||||||
onConfirm={handleDelete}
|
onConfirm={handleDelete}
|
||||||
/>
|
/>
|
||||||
@ -241,15 +241,16 @@ function CreateForm({
|
|||||||
{({ errors }) => (
|
{({ errors }) => (
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label htmlFor="name">
|
<Label htmlFor="academic_year">
|
||||||
Nama <span className="text-destructive">*</span>
|
Tahun Ajaran{' '}
|
||||||
|
<span className="text-destructive">*</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="name"
|
id="academic_year"
|
||||||
name="name"
|
name="academic_year"
|
||||||
placeholder="Masukkan nama periode akademik"
|
placeholder="Masukkan tahun ajaran, contoh: 2025/2026"
|
||||||
/>
|
/>
|
||||||
<InputError message={errors.name} />
|
<InputError message={errors.academic_year} />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label>
|
<Label>
|
||||||
@ -369,16 +370,17 @@ function EditForm({
|
|||||||
editing && (
|
editing && (
|
||||||
<div className="grid gap-4">
|
<div className="grid gap-4">
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label htmlFor="edit-name">
|
<Label htmlFor="edit-academic_year">
|
||||||
Nama <span className="text-destructive">*</span>
|
Tahun Ajaran{' '}
|
||||||
|
<span className="text-destructive">*</span>
|
||||||
</Label>
|
</Label>
|
||||||
<Input
|
<Input
|
||||||
id="edit-name"
|
id="edit-academic_year"
|
||||||
name="name"
|
name="academic_year"
|
||||||
placeholder="Masukkan nama periode akademik"
|
placeholder="Masukkan tahun ajaran, contoh: 2025/2026"
|
||||||
defaultValue={editing.name}
|
defaultValue={editing.academic_year}
|
||||||
/>
|
/>
|
||||||
<InputError message={errors.name} />
|
<InputError message={errors.academic_year} />
|
||||||
</div>
|
</div>
|
||||||
<div className="grid gap-2">
|
<div className="grid gap-2">
|
||||||
<Label>
|
<Label>
|
||||||
|
|||||||
@ -10,7 +10,7 @@ export const SemesterLabels: Record<Semester, string> = {
|
|||||||
|
|
||||||
export type AcademicTerm = {
|
export type AcademicTerm = {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
academic_year: string;
|
||||||
semester: Semester;
|
semester: Semester;
|
||||||
start_date: string;
|
start_date: string;
|
||||||
formatted_start_date: string;
|
formatted_start_date: string;
|
||||||
@ -23,10 +23,10 @@ export type AcademicTerm = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function formatAcademicTermLabel(term: {
|
export function formatAcademicTermLabel(term: {
|
||||||
name: string;
|
academic_year: string;
|
||||||
semester: string;
|
semester: string;
|
||||||
}): string {
|
}): string {
|
||||||
const label = SemesterLabels[term.semester as Semester];
|
const label = SemesterLabels[term.semester as Semester];
|
||||||
|
|
||||||
return label ? `${term.name} (${label})` : term.name;
|
return label ? `${term.academic_year} (${label})` : term.academic_year;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,11 @@ export type CourseClass = {
|
|||||||
user: { profile: { full_name: string } | null } | null;
|
user: { profile: { full_name: string } | null } | null;
|
||||||
} | null;
|
} | null;
|
||||||
academic_term_id: number;
|
academic_term_id: number;
|
||||||
academic_term: { id: number; name: string; semester: string } | null;
|
academic_term: {
|
||||||
|
id: number;
|
||||||
|
academic_year: string;
|
||||||
|
semester: string;
|
||||||
|
} | null;
|
||||||
method: ClassMethod | null;
|
method: ClassMethod | null;
|
||||||
enrollments_count: number;
|
enrollments_count: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
|
|||||||
@ -82,7 +82,11 @@ export type CourseRegistrationSubmission = {
|
|||||||
advisor_signature_url: string | null;
|
advisor_signature_url: string | null;
|
||||||
has_registrations: boolean;
|
has_registrations: boolean;
|
||||||
student: CourseRegistrationSubmissionStudent | null;
|
student: CourseRegistrationSubmissionStudent | null;
|
||||||
academic_term: { id: number; name: string; semester: string } | null;
|
academic_term: {
|
||||||
|
id: number;
|
||||||
|
academic_year: string;
|
||||||
|
semester: string;
|
||||||
|
} | null;
|
||||||
course_registrations: CourseRegistrationSubmissionEntry[];
|
course_registrations: CourseRegistrationSubmissionEntry[];
|
||||||
logs: CourseRegistrationSubmissionLog[];
|
logs: CourseRegistrationSubmissionLog[];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -11,7 +11,11 @@ export type TuitionInvoice = {
|
|||||||
student_id: number;
|
student_id: number;
|
||||||
student: TuitionInvoiceStudent | null;
|
student: TuitionInvoiceStudent | null;
|
||||||
academic_term_id: number;
|
academic_term_id: number;
|
||||||
academic_term: { id: number; name: string; semester: string } | null;
|
academic_term: {
|
||||||
|
id: number;
|
||||||
|
academic_year: string;
|
||||||
|
semester: string;
|
||||||
|
} | null;
|
||||||
amount_due: string;
|
amount_due: string;
|
||||||
due_date: string | null;
|
due_date: string | null;
|
||||||
paid_total: string | null;
|
paid_total: string | null;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user