feat: refactor navigation structure in AppSidebar to use permissions for dynamic item rendering

This commit is contained in:
Yoga Pangestu 2026-08-31 16:34:31 +07:00
parent 6834d47e2b
commit 4350f7d9ea

View File

@ -64,164 +64,216 @@ const STAFF_ROLES = ['developer', 'staff-admin', 'staff-keuangan', 'kaprodi'];
function buildNavMain({ function buildNavMain({
isMahasiswa, isMahasiswa,
isDosen, isDosen,
canViewLogs, permissions,
canViewRoles,
}: { }: {
isMahasiswa: boolean; isMahasiswa: boolean;
isDosen: boolean; isDosen: boolean;
canViewLogs: boolean; permissions: string[];
canViewRoles: boolean;
}): (NavGroup | NavItem)[] { }): (NavGroup | NavItem)[] {
return [ const can = (permission: string) => permissions.includes(permission);
const penggunaItems: NavItem[] = [
...(can('view-administrators')
? [
{
name: 'Administrator',
url: administratorsRoute.url(),
icon: User,
},
]
: []),
...(can('view-lecturers')
? [{ name: 'Dosen', url: lecturersRoute.url(), icon: Users }]
: []),
...(can('view-students')
? [
{
name: 'Mahasiswa',
url: studentsRoute.url(),
icon: GraduationCap,
},
]
: []),
];
const masterItems: NavItem[] = [
...(can('view-academic-terms')
? [
{
name: 'Periode Akademik',
url: academicTerm.url(),
icon: Calendar,
},
]
: []),
...(can('view-departments')
? [
{
name: 'Jurusan',
url: departmentsRoute.url(),
icon: Building2,
},
]
: []),
...(can('view-courses')
? [{ name: 'Mata Kuliah', url: coursesRoute.url(), icon: BookOpen }]
: []),
];
const kelolaItems: NavItem[] = [
...(isMahasiswa || can('view-course-registrations')
? [
{
name: 'Registrasi KRS',
url: isMahasiswa
? studentCourseRegistrationsRoute.url()
: courseRegistrationsRoute.url(),
icon: FileCheck2,
},
]
: []),
...(can('view-course-classes')
? [
{
name: 'Kelas Mata Kuliah',
url: courseClassesRoute.url(),
icon: School,
},
]
: []),
...(can('view-announcements')
? [
{
name: 'Pengumuman',
url: announcementsRoute.url(),
icon: Megaphone,
},
]
: []),
];
const kelasItems: NavItem[] = [
...(can('view-materials')
? [{ name: 'Materi', url: materialsRoute.url(), icon: FileText }]
: []),
...(can('view-assignments')
? [
{
name: 'Tugas',
url: assignmentsRoute.url(),
icon: ClipboardList,
},
]
: []),
...(can('view-schedules')
? [
{
name: 'Jadwal',
url: schedulesRoute.url(),
icon: CalendarClock,
},
]
: []),
...(can('view-attendances')
? [
{
name: 'Kehadiran',
url: attendancesRoute.url(),
icon: ClipboardCheck,
},
]
: []),
];
const keuanganItems: NavItem[] = [
...(can('view-tuition-invoices')
? [
{
name: 'Tagihan',
url: tuitionInvoicesRoute.url(),
icon: Receipt,
},
]
: []),
];
const layananItems: NavItem[] = [
...(isMahasiswa || can('view-letter-requests')
? [
{
name: 'Surat Permohonan',
url: isMahasiswa
? studentLetterRequestsRoute.url()
: letterRequestsRoute.url(),
icon: Mail,
},
]
: []),
...(isDosen || can('view-academic-advising-logs')
? [
{
name: 'Bimbingan Akademik',
url: isDosen
? lecturerAcademicAdvisingLogsRoute.url()
: academicAdvisingLogsRoute.url(),
icon: MessageCircle,
},
]
: []),
];
const pengembangItems: NavItem[] = [
...(can('view-logs')
? [{ name: 'Logs', url: logsRoute.url(), icon: ScrollText }]
: []),
...(can('view-roles')
? [
{
name: 'Role & Permission',
url: rolePermissionsRoute.url(),
icon: ShieldCheck,
},
]
: []),
];
const groups: (NavGroup | NavItem)[] = [
{ {
name: 'Dasbor', name: 'Dasbor',
url: '#', url: '#',
icon: IconGridDots, icon: IconGridDots,
}, },
{
label: 'Pengguna',
items: [
{
name: 'Administrator',
url: administratorsRoute.url(),
icon: User,
},
{
name: 'Dosen',
url: lecturersRoute.url(),
icon: Users,
},
{
name: 'Mahasiswa',
url: studentsRoute.url(),
icon: GraduationCap,
},
],
},
{
label: 'Master',
items: [
{
name: 'Periode Akademik',
url: academicTerm.url(),
icon: Calendar,
},
{
name: 'Jurusan',
url: departmentsRoute.url(),
icon: Building2,
},
{
name: 'Mata Kuliah',
url: coursesRoute.url(),
icon: BookOpen,
},
],
},
{
label: 'Kelola',
items: [
{
name: 'Registrasi KRS',
url: isMahasiswa
? studentCourseRegistrationsRoute.url()
: courseRegistrationsRoute.url(),
icon: FileCheck2,
},
{
name: 'Kelas Mata Kuliah',
url: courseClassesRoute.url(),
icon: School,
},
{
name: 'Pengumuman',
url: announcementsRoute.url(),
icon: Megaphone,
},
],
},
{
label: 'Kelas',
items: [
{
name: 'Materi',
url: materialsRoute.url(),
icon: FileText,
},
{
name: 'Tugas',
url: assignmentsRoute.url(),
icon: ClipboardList,
},
{
name: 'Jadwal',
url: schedulesRoute.url(),
icon: CalendarClock,
},
{
name: 'Kehadiran',
url: attendancesRoute.url(),
icon: ClipboardCheck,
},
],
},
{
label: 'Keuangan',
items: [
{
name: 'Tagihan',
url: tuitionInvoicesRoute.url(),
icon: Receipt,
},
],
},
{
label: 'Layanan',
items: [
{
name: 'Surat Permohonan',
url: isMahasiswa
? studentLetterRequestsRoute.url()
: letterRequestsRoute.url(),
icon: Mail,
},
{
name: 'Bimbingan Akademik',
url: isDosen
? lecturerAcademicAdvisingLogsRoute.url()
: academicAdvisingLogsRoute.url(),
icon: MessageCircle,
},
],
},
...(canViewLogs || canViewRoles
? [
{
label: 'Pengembang',
items: [
...(canViewLogs
? [
{
name: 'Logs',
url: logsRoute.url(),
icon: ScrollText,
},
]
: []),
...(canViewRoles
? [
{
name: 'Role & Permission',
url: rolePermissionsRoute.url(),
icon: ShieldCheck,
},
]
: []),
],
},
]
: []),
]; ];
if (penggunaItems.length > 0) {
groups.push({ label: 'Pengguna', items: penggunaItems });
}
if (masterItems.length > 0) {
groups.push({ label: 'Master', items: masterItems });
}
if (kelolaItems.length > 0) {
groups.push({ label: 'Kelola', items: kelolaItems });
}
if (kelasItems.length > 0) {
groups.push({ label: 'Kelas', items: kelasItems });
}
if (keuanganItems.length > 0) {
groups.push({ label: 'Keuangan', items: keuanganItems });
}
if (layananItems.length > 0) {
groups.push({ label: 'Layanan', items: layananItems });
}
if (pengembangItems.length > 0) {
groups.push({ label: 'Pengembang', items: pengembangItems });
}
return groups;
} }
function buildNavSecondary( function buildNavSecondary(
@ -249,13 +301,11 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
const isStaff = roleNames.some((role) => STAFF_ROLES.includes(role)); const isStaff = roleNames.some((role) => STAFF_ROLES.includes(role));
const isMahasiswa = !isStaff && roleNames.includes('mahasiswa'); const isMahasiswa = !isStaff && roleNames.includes('mahasiswa');
const isDosen = !isStaff && roleNames.includes('dosen'); const isDosen = !isStaff && roleNames.includes('dosen');
const canViewLogs = (auth?.permissions ?? []).includes('view-logs'); const permissions = auth?.permissions ?? [];
const canViewRoles = (auth?.permissions ?? []).includes('view-roles');
const navMain = buildNavMain({ const navMain = buildNavMain({
isMahasiswa, isMahasiswa,
isDosen, isDosen,
canViewLogs, permissions,
canViewRoles,
}); });
return ( return (