diff --git a/app/Services/Admin/Master/DepartmentService.php b/app/Services/Admin/Master/DepartmentService.php index 37ad4ee..d5cb6bd 100644 --- a/app/Services/Admin/Master/DepartmentService.php +++ b/app/Services/Admin/Master/DepartmentService.php @@ -14,7 +14,11 @@ class DepartmentService public function paginated(int $perPage = 25, string $search = ''): LengthAwarePaginator { return Department::query() - ->with(['currentLeader.lecturer.user.profile']) + ->with([ + 'currentLeader.lecturer.user.profile', + 'leaderships' => fn ($q) => $q->orderByRaw('ended_at IS NULL DESC')->orderByDesc('started_at'), + 'leaderships.lecturer.user.profile', + ]) ->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")->orWhere('code', 'like', "%{$search}%")) ->latest() ->paginate($perPage, ['id', 'code', 'name', 'degree_level']); diff --git a/resources/js/pages/admin/master/departments/columns.tsx b/resources/js/pages/admin/master/departments/columns.tsx index 921a5bd..ab9d941 100644 --- a/resources/js/pages/admin/master/departments/columns.tsx +++ b/resources/js/pages/admin/master/departments/columns.tsx @@ -1,5 +1,5 @@ import type { ColumnDef } from '@tanstack/react-table'; -import { Pencil, Trash2 } from 'lucide-react'; +import { History, Pencil, Trash2 } from 'lucide-react'; import { RowActions } from '@/components/row-actions'; import { Badge } from '@/components/ui/badge'; import type { Department } from '@/types/department'; @@ -9,6 +9,7 @@ export type { Department } from '@/types/department'; type CreateColumnsParams = { handleEdit: (department: Department) => void; handleDeleteClick: (department: Department) => void; + handleViewHistory: (department: Department) => void; canUpdate: boolean; canDelete: boolean; }; @@ -16,7 +17,13 @@ type CreateColumnsParams = { export function createDepartmentColumns( params: CreateColumnsParams, ): ColumnDef[] { - const { handleEdit, handleDeleteClick, canUpdate, canDelete } = params; + const { + handleEdit, + handleDeleteClick, + handleViewHistory, + canUpdate, + canDelete, + } = params; const columns: ColumnDef[] = [ { @@ -72,7 +79,7 @@ export function createDepartmentColumns( }, ]; - if (canUpdate || canDelete) { + { columns.push({ id: 'actions', header: () => Aksi, @@ -86,6 +93,11 @@ export function createDepartmentColumns( return ( , + onClick: () => handleViewHistory(department), + }, { label: 'Edit', icon: , diff --git a/resources/js/pages/admin/master/departments/index.tsx b/resources/js/pages/admin/master/departments/index.tsx index ae15349..4c35632 100644 --- a/resources/js/pages/admin/master/departments/index.tsx +++ b/resources/js/pages/admin/master/departments/index.tsx @@ -9,6 +9,7 @@ import { DeleteConfirmDialog } from '@/components/delete-confirm-dialog'; import { FormDialog } from '@/components/form-dialog'; import InputError from '@/components/input-error'; import { PageHeader } from '@/components/page-header'; +import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Combobox, @@ -18,6 +19,12 @@ import { ComboboxItem, ComboboxList, } from '@/components/ui/combobox'; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { @@ -63,6 +70,8 @@ export default function DepartmentIndex({ const [createOpen, setCreateOpen] = useState(false); const [editing, setEditing] = useState(null); const [deleting, setDeleting] = useState(null); + const [historyDepartment, setHistoryDepartment] = + useState(null); const { hasPermission } = usePermissions(); const canCreate = hasPermission('create-departments'); const canUpdate = hasPermission('update-departments'); @@ -98,6 +107,7 @@ export default function DepartmentIndex({ const columns = createDepartmentColumns({ handleEdit: (department) => setEditing(department), handleDeleteClick: (department) => setDeleting(department), + handleViewHistory: (department) => setHistoryDepartment(department), canUpdate, canDelete, }); @@ -188,11 +198,79 @@ export default function DepartmentIndex({ } onConfirm={handleDelete} /> + + { + if (!open) { + setHistoryDepartment(null); + } + }} + /> ); } +function LeadershipHistoryDialog({ + department, + onOpenChange, +}: { + department: Department | null; + onOpenChange: (open: boolean) => void; +}) { + const entries = department?.leaderships ?? []; + + return ( + + + + + Riwayat Kaprodi + {department ? ` — ${department.name}` : ''} + + + +
+ {entries.length === 0 && ( +

+ Belum ada riwayat kaprodi untuk jurusan ini. +

+ )} + + {entries.map((entry) => ( +
+
+

+ {entry.lecturer?.user?.profile + ?.full_name ?? 'N/A'} +

+

+ {format( + new Date(entry.started_at), + 'd MMM yyyy', + )}{' '} + -{' '} + {entry.ended_at + ? format( + new Date(entry.ended_at), + 'd MMM yyyy', + ) + : 'Sekarang'} +

+
+ {!entry.ended_at && Sekarang} +
+ ))} +
+
+
+ ); +} + function KaprodiFields({ errors, lecturers, diff --git a/resources/js/types/department.ts b/resources/js/types/department.ts index 537a796..6f744b1 100644 --- a/resources/js/types/department.ts +++ b/resources/js/types/department.ts @@ -23,6 +23,7 @@ export type Department = { name: string; degree_level: DegreeLevel | null; current_leader: DepartmentLeadership | null; + leaderships: DepartmentLeadership[]; created_at: string; updated_at: string; };