From 982051ee2e09297c4540ae54831e62761f55a4b7 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 30 Aug 2026 11:18:20 +0700 Subject: [PATCH] feat: add active status management for academic terms, users, and students with new UpdateStatusRequest --- .../Admin/Master/AcademicTermController.php | 8 +++++ .../Admin/Users/AdministratorController.php | 4 +-- .../Admin/Users/LecturerController.php | 4 +-- .../Admin/Users/StudentController.php | 4 +-- ...tusRequest.php => UpdateStatusRequest.php} | 4 +-- .../Admin/Master/AcademicTermService.php | 12 +++++++ ...ve-switch.tsx => active-status-switch.tsx} | 7 ++-- .../admin/master/academic-terms/columns.tsx | 33 ++++++++++++------- .../admin/master/academic-terms/index.tsx | 10 ++++++ .../admin/users/administrators/columns.tsx | 4 +-- .../pages/admin/users/lecturers/columns.tsx | 4 +-- .../js/pages/admin/users/students/columns.tsx | 4 +-- routes/admin.php | 1 + 13 files changed, 72 insertions(+), 27 deletions(-) rename app/Http/Requests/Admin/{Users/UpdateUserStatusRequest.php => UpdateStatusRequest.php} (73%) rename resources/js/components/{user-active-switch.tsx => active-status-switch.tsx} (76%) diff --git a/app/Http/Controllers/Admin/Master/AcademicTermController.php b/app/Http/Controllers/Admin/Master/AcademicTermController.php index dbcb771..eee8a25 100644 --- a/app/Http/Controllers/Admin/Master/AcademicTermController.php +++ b/app/Http/Controllers/Admin/Master/AcademicTermController.php @@ -4,6 +4,7 @@ use App\Http\Controllers\Controller; use App\Http\Requests\Admin\Master\AcademicTermRequest; +use App\Http\Requests\Admin\UpdateStatusRequest; use App\Http\Requests\PaginatedRequest; use App\Models\AcademicTerm; use App\Services\Admin\Master\AcademicTermService; @@ -53,4 +54,11 @@ public function destroy(AcademicTerm $academicTerm): RedirectResponse return Inertia::flash('toast', ['type' => 'success', 'message' => 'Periode akademik berhasil dihapus.'])->back(); } + + public function updateStatus(UpdateStatusRequest $request, AcademicTerm $academicTerm): RedirectResponse + { + $this->service->updateActiveStatus($academicTerm, $request->boolean('is_active')); + + return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status periode akademik berhasil diperbarui.'])->back(); + } } diff --git a/app/Http/Controllers/Admin/Users/AdministratorController.php b/app/Http/Controllers/Admin/Users/AdministratorController.php index 19e614a..0d11934 100644 --- a/app/Http/Controllers/Admin/Users/AdministratorController.php +++ b/app/Http/Controllers/Admin/Users/AdministratorController.php @@ -3,8 +3,8 @@ namespace App\Http\Controllers\Admin\Users; use App\Http\Controllers\Controller; +use App\Http\Requests\Admin\UpdateStatusRequest; use App\Http\Requests\Admin\Users\AdministratorRequest; -use App\Http\Requests\Admin\Users\UpdateUserStatusRequest; use App\Http\Requests\PaginatedRequest; use App\Models\User; use App\Services\Admin\Users\AdministratorService; @@ -79,7 +79,7 @@ public function resetPassword(User $user): RedirectResponse return Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil direset.'])->back(); } - public function updateUserStatus(UpdateUserStatusRequest $request, User $user): RedirectResponse + public function updateUserStatus(UpdateStatusRequest $request, User $user): RedirectResponse { $this->service->updateUserStatus($user, $request->boolean('is_active')); diff --git a/app/Http/Controllers/Admin/Users/LecturerController.php b/app/Http/Controllers/Admin/Users/LecturerController.php index f7f19ac..1e77aa9 100644 --- a/app/Http/Controllers/Admin/Users/LecturerController.php +++ b/app/Http/Controllers/Admin/Users/LecturerController.php @@ -4,8 +4,8 @@ use App\Exports\LecturersExport; use App\Http\Controllers\Controller; +use App\Http\Requests\Admin\UpdateStatusRequest; use App\Http\Requests\Admin\Users\LecturerRequest; -use App\Http\Requests\Admin\Users\UpdateUserStatusRequest; use App\Http\Requests\PaginatedRequest; use App\Models\User; use App\Services\Admin\Master\DepartmentService; @@ -85,7 +85,7 @@ public function resetPassword(User $user): RedirectResponse return Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi berhasil direset.'])->back(); } - public function updateUserStatus(UpdateUserStatusRequest $request, User $user): RedirectResponse + public function updateUserStatus(UpdateStatusRequest $request, User $user): RedirectResponse { $this->service->updateUserStatus($user, $request->boolean('is_active')); diff --git a/app/Http/Controllers/Admin/Users/StudentController.php b/app/Http/Controllers/Admin/Users/StudentController.php index 9f716c4..ebe74f6 100644 --- a/app/Http/Controllers/Admin/Users/StudentController.php +++ b/app/Http/Controllers/Admin/Users/StudentController.php @@ -5,9 +5,9 @@ use App\Enums\StudentStatus; use App\Exports\StudentsExport; use App\Http\Controllers\Controller; +use App\Http\Requests\Admin\UpdateStatusRequest; use App\Http\Requests\Admin\Users\Student\StudentRequest; use App\Http\Requests\Admin\Users\Student\StudentStatusRequest; -use App\Http\Requests\Admin\Users\UpdateUserStatusRequest; use App\Http\Requests\PaginatedRequest; use App\Models\User; use App\Services\Admin\Master\DepartmentService; @@ -100,7 +100,7 @@ public function updateStatus(StudentStatusRequest $request, User $user): Redirec return Inertia::flash('toast', ['type' => 'success', 'message' => 'Status mahasiswa berhasil diperbarui.'])->back(); } - public function updateUserStatus(UpdateUserStatusRequest $request, User $user): RedirectResponse + public function updateUserStatus(UpdateStatusRequest $request, User $user): RedirectResponse { $this->service->updateUserStatus($user, $request->boolean('is_active')); diff --git a/app/Http/Requests/Admin/Users/UpdateUserStatusRequest.php b/app/Http/Requests/Admin/UpdateStatusRequest.php similarity index 73% rename from app/Http/Requests/Admin/Users/UpdateUserStatusRequest.php rename to app/Http/Requests/Admin/UpdateStatusRequest.php index 4cb9cbf..ebdb74f 100644 --- a/app/Http/Requests/Admin/Users/UpdateUserStatusRequest.php +++ b/app/Http/Requests/Admin/UpdateStatusRequest.php @@ -1,10 +1,10 @@ delete(); } + + public function updateActiveStatus(AcademicTerm $academicTerm, bool $isActive): void + { + DB::transaction(function () use ($academicTerm, $isActive) { + if ($isActive) { + AcademicTerm::where('id', '!=', $academicTerm->id)->update(['is_active' => false]); + } + + $academicTerm->update(['is_active' => $isActive]); + }); + } } diff --git a/resources/js/components/user-active-switch.tsx b/resources/js/components/active-status-switch.tsx similarity index 76% rename from resources/js/components/user-active-switch.tsx rename to resources/js/components/active-status-switch.tsx index 696c8e7..ddaf9ed 100644 --- a/resources/js/components/user-active-switch.tsx +++ b/resources/js/components/active-status-switch.tsx @@ -1,11 +1,14 @@ import { Switch } from '@/components/ui/switch'; -type UserActiveSwitchProps = { +type ActiveStatusSwitchProps = { isActive: boolean; onChange: (isActive: boolean) => void; }; -export function UserActiveSwitch({ isActive, onChange }: UserActiveSwitchProps) { +export function ActiveStatusSwitch({ + isActive, + onChange, +}: ActiveStatusSwitchProps) { return (
diff --git a/resources/js/pages/admin/master/academic-terms/columns.tsx b/resources/js/pages/admin/master/academic-terms/columns.tsx index a801476..8697413 100644 --- a/resources/js/pages/admin/master/academic-terms/columns.tsx +++ b/resources/js/pages/admin/master/academic-terms/columns.tsx @@ -1,21 +1,23 @@ -import { RowActions } from '@/components/row-actions'; -import { Badge } from '@/components/ui/badge'; -import type { AcademicTerm } from '@/types/academic-term'; -import { SemesterLabels, type Semester } from '@/types/academic-term'; import type { ColumnDef } from '@tanstack/react-table'; import { Pencil, Trash2 } from 'lucide-react'; +import { ActiveStatusSwitch } from '@/components/active-status-switch'; +import { RowActions } from '@/components/row-actions'; +import { SemesterLabels } from '@/types/academic-term'; +import type { AcademicTerm } from '@/types/academic-term'; +import type { Semester } from '@/types/academic-term'; export type { AcademicTerm } from '@/types/academic-term'; type CreateColumnsParams = { handleEdit: (academicTerm: AcademicTerm) => void; handleDeleteClick: (academicTerm: AcademicTerm) => void; + handleStatusChange: (academicTerm: AcademicTerm, isActive: boolean) => void; }; export function createAcademicTermColumns( params: CreateColumnsParams, ): ColumnDef[] { - const { handleEdit, handleDeleteClick } = params; + const { handleEdit, handleDeleteClick, handleStatusChange } = params; return [ { @@ -32,6 +34,7 @@ export function createAcademicTermColumns( header: () => Semester, cell: ({ row }) => { const semester = row.getValue('semester') as Semester; + return {SemesterLabels[semester]}; }, }, @@ -39,14 +42,18 @@ export function createAcademicTermColumns( accessorKey: 'formatted_start_date', header: () => Tanggal Mulai, cell: ({ row }) => ( - {row.getValue('formatted_start_date') as string | null} + + {row.getValue('formatted_start_date') as string | null} + ), }, { accessorKey: 'formatted_end_date', header: () => Tanggal Selesai, cell: ({ row }) => ( - {row.getValue('formatted_end_date') as string | null} + + {row.getValue('formatted_end_date') as string | null} + ), }, { @@ -57,12 +64,16 @@ export function createAcademicTermColumns( headerClassName: 'w-[100px] text-center', }, cell: ({ row }) => { - const isActive = row.getValue('is_active') as boolean; + const academicTerm = row.original; + return (
- - {isActive ? 'Aktif' : 'Nonaktif'} - + + handleStatusChange(academicTerm, isActive) + } + />
); }, diff --git a/resources/js/pages/admin/master/academic-terms/index.tsx b/resources/js/pages/admin/master/academic-terms/index.tsx index aaa7d10..23d6e26 100644 --- a/resources/js/pages/admin/master/academic-terms/index.tsx +++ b/resources/js/pages/admin/master/academic-terms/index.tsx @@ -21,6 +21,7 @@ import { destroy, store, update, + update_status, } from '@/routes/admin/master/academic-terms'; import type { AcademicTerm } from '@/types/academic-term'; import { Semester, SemesterLabels } from '@/types/academic-term'; @@ -98,9 +99,18 @@ export default function AcademicTermIndex({ }); } + function handleStatusChange(academicTerm: AcademicTerm, isActive: boolean) { + router.patch( + update_status.url(academicTerm.id), + { is_active: isActive }, + { preserveScroll: true }, + ); + } + const columns = createAcademicTermColumns({ handleEdit: (academicTerm) => setEditing(academicTerm), handleDeleteClick: (academicTerm) => setDeleting(academicTerm), + handleStatusChange, }); return ( diff --git a/resources/js/pages/admin/users/administrators/columns.tsx b/resources/js/pages/admin/users/administrators/columns.tsx index 173a967..54da5e5 100644 --- a/resources/js/pages/admin/users/administrators/columns.tsx +++ b/resources/js/pages/admin/users/administrators/columns.tsx @@ -1,8 +1,8 @@ import type { ColumnDef } from '@tanstack/react-table'; import { Key, Pencil, Trash2 } from 'lucide-react'; +import { ActiveStatusSwitch } from '@/components/active-status-switch'; import { GenderBadge } from '@/components/gender-badge'; import { RowActions } from '@/components/row-actions'; -import { UserActiveSwitch } from '@/components/user-active-switch'; export type Administrator = { id: number; @@ -69,7 +69,7 @@ export function createAdministratorColumns( accessorKey: 'is_active', header: () => Status Akun, cell: ({ row }) => ( - handleUserStatusChange(row.original, isActive) diff --git a/resources/js/pages/admin/users/lecturers/columns.tsx b/resources/js/pages/admin/users/lecturers/columns.tsx index 2dd0623..84fcecc 100644 --- a/resources/js/pages/admin/users/lecturers/columns.tsx +++ b/resources/js/pages/admin/users/lecturers/columns.tsx @@ -1,8 +1,8 @@ import type { ColumnDef } from '@tanstack/react-table'; import { Key, Pencil, Trash2 } from 'lucide-react'; +import { ActiveStatusSwitch } from '@/components/active-status-switch'; import { GenderBadge } from '@/components/gender-badge'; import { RowActions } from '@/components/row-actions'; -import { UserActiveSwitch } from '@/components/user-active-switch'; export type Lecturer = { id: number; @@ -79,7 +79,7 @@ export function createLecturerColumns( accessorKey: 'is_active', header: () => Status Akun, cell: ({ row }) => ( - handleUserStatusChange(row.original, isActive) diff --git a/resources/js/pages/admin/users/students/columns.tsx b/resources/js/pages/admin/users/students/columns.tsx index 4c2aab0..3e49a8c 100644 --- a/resources/js/pages/admin/users/students/columns.tsx +++ b/resources/js/pages/admin/users/students/columns.tsx @@ -1,9 +1,9 @@ import type { ColumnDef } from '@tanstack/react-table'; import { Key, Pencil, Trash2 } from 'lucide-react'; +import { ActiveStatusSwitch } from '@/components/active-status-switch'; import { GenderBadge } from '@/components/gender-badge'; import { RowActions } from '@/components/row-actions'; import { StudentStatusBadge } from '@/components/student-status-badge'; -import { UserActiveSwitch } from '@/components/user-active-switch'; export type Student = { id: number; @@ -106,7 +106,7 @@ export function createStudentColumns( accessorKey: 'is_active', header: () => Status Akun, cell: ({ row }) => ( - handleUserStatusChange(row.original, isActive) diff --git a/routes/admin.php b/routes/admin.php index b529517..d3600bc 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -27,6 +27,7 @@ Route::middleware(['auth', 'verified'])->group(function () { Route::prefix('admin/master')->name('admin.master.')->group(function () { Route::resource('academic-terms', AcademicTermController::class)->except(['create', 'edit', 'show']); + Route::patch('academic-terms/{academic_term}/status', [AcademicTermController::class, 'updateStatus'])->name('academic-terms.update_status'); Route::resource('departments', DepartmentController::class)->except(['create', 'edit', 'show']); }); -- 2.45.2