From 10db3f922e07b22846bc4e61400e730fa505c69b Mon Sep 17 00:00:00 2001 From: amaliadwiy Date: Mon, 24 Nov 2025 16:27:35 +0800 Subject: [PATCH] up: dashboard admin Deskripsi: - akses role pada menu dashboard - akses role pada setting - akses role pada pelayanan surat - akses role pada pengaduan warga - akses role pada warga NO Issues --- src/components/DesaSetting.tsx | 6 +- src/components/KategoriPelayananSurat.tsx | 32 +-- src/components/KategoriPengaduan.tsx | 31 +-- src/components/ProfileUser.tsx | 24 ++- src/components/UserRoleSetting.tsx | 31 +-- src/components/UserSetting.tsx | 32 +-- src/lib/listPermission.json | 198 +++++++++++++++--- src/pages/scr/dashboard/dashboard_layout.tsx | 23 +- .../pelayanan-surat/detail_pelayanan_page.tsx | 11 + .../scr/dashboard/pengaduan/detail_page.tsx | 11 + .../dashboard/setting/detail_setting_page.tsx | 123 +++++++---- src/server/routes/user_route.ts | 10 +- 12 files changed, 397 insertions(+), 135 deletions(-) diff --git a/src/components/DesaSetting.tsx b/src/components/DesaSetting.tsx index 9bb41ce..938cd96 100644 --- a/src/components/DesaSetting.tsx +++ b/src/components/DesaSetting.tsx @@ -16,13 +16,14 @@ import { } from "@mantine/core"; import { useDisclosure, useShallowEffect } from "@mantine/hooks"; import { IconEdit } from "@tabler/icons-react"; +import type { JsonValue } from "generated/prisma/runtime/library"; import _ from "lodash"; import { useState } from "react"; import useSWR from "swr"; import ModalFile from "./ModalFile"; import notification from "./notificationGlobal"; -export default function DesaSetting() { +export default function DesaSetting({ permissions }: { permissions: JsonValue[] }) { const [btnDisable, setBtnDisable] = useState(false); const [btnLoading, setBtnLoading] = useState(false); const [opened, { open, close }] = useDisclosure(false); @@ -213,12 +214,13 @@ export default function DesaSetting() { } - + chooseEdit({ data: v })} + disabled={!permissions.includes("setting.desa.edit")} > diff --git a/src/components/KategoriPelayananSurat.tsx b/src/components/KategoriPelayananSurat.tsx index 1982bf8..0121ea2 100644 --- a/src/components/KategoriPelayananSurat.tsx +++ b/src/components/KategoriPelayananSurat.tsx @@ -18,11 +18,12 @@ import { } from "@mantine/core"; import { useDisclosure, useShallowEffect } from "@mantine/hooks"; import { IconEdit, IconEye, IconPlus, IconTrash } from "@tabler/icons-react"; +import type { JsonValue } from "generated/prisma/runtime/library"; import { useState } from "react"; import useSWR from "swr"; import notification from "./notificationGlobal"; -export default function KategoriPelayananSurat() { +export default function KategoriPelayananSurat({ permissions }: { permissions: JsonValue[] }) { const [openedDelete, { open: openDelete, close: closeDelete }] = useDisclosure(false); const [openedDetail, { open: openDetail, close: closeDetail }] = @@ -52,6 +53,7 @@ export default function KategoriPelayananSurat() { mutate(); }, []); + async function handleCreate() { try { setBtnLoading(true); @@ -533,15 +535,19 @@ export default function KategoriPelayananSurat() { Kategori Pelayanan Surat - - - + { + permissions.includes("setting.kategori_pelayanan.tambah") && ( + + + + ) + } @@ -572,7 +578,7 @@ export default function KategoriPelayananSurat() { - + - + diff --git a/src/components/KategoriPengaduan.tsx b/src/components/KategoriPengaduan.tsx index fd2ea73..0f85343 100644 --- a/src/components/KategoriPengaduan.tsx +++ b/src/components/KategoriPengaduan.tsx @@ -15,11 +15,12 @@ import { } from "@mantine/core"; import { useDisclosure, useShallowEffect } from "@mantine/hooks"; import { IconEdit, IconPlus, IconTrash } from "@tabler/icons-react"; +import type { JsonValue } from "generated/prisma/runtime/library"; import { useState } from "react"; import useSWR from "swr"; import notification from "./notificationGlobal"; -export default function KategoriPengaduan() { +export default function KategoriPengaduan({ permissions }: { permissions: JsonValue[] }) { const [openedDelete, { open: openDelete, close: closeDelete }] = useDisclosure(false); const [btnDisable, setBtnDisable] = useState(true); @@ -293,15 +294,19 @@ export default function KategoriPengaduan() { Kategori Pengaduan - - - + { + permissions.includes("setting.kategori_pengaduan.tambah") && ( + + + + ) + } @@ -318,17 +323,18 @@ export default function KategoriPengaduan() { {v.name} - + chooseEdit({ data: v })} + disabled={!permissions.includes("setting.kategori_pengaduan.edit")} > - + diff --git a/src/components/ProfileUser.tsx b/src/components/ProfileUser.tsx index d622062..9f0250f 100644 --- a/src/components/ProfileUser.tsx +++ b/src/components/ProfileUser.tsx @@ -9,10 +9,11 @@ import { Stack, Title, } from "@mantine/core"; +import type { JsonValue } from "generated/prisma/runtime/library"; import { useEffect, useState } from "react"; import notification from "./notificationGlobal"; -export default function ProfileUser() { +export default function ProfileUser({ permissions }: { permissions: JsonValue[] }) { const [opened, setOpened] = useState(false); const [openedPassword, setOpenedPassword] = useState(false); const [pwdBaru, setPwdBaru] = useState(""); @@ -126,12 +127,21 @@ export default function ProfileUser() { Profile Pengguna - - + { + permissions.includes("setting.profile.edit") && ( + + ) + } + + { + permissions.includes("setting.profile.password") && ( + + ) + } diff --git a/src/components/UserRoleSetting.tsx b/src/components/UserRoleSetting.tsx index 1cafc1e..8c9624b 100644 --- a/src/components/UserRoleSetting.tsx +++ b/src/components/UserRoleSetting.tsx @@ -16,12 +16,13 @@ import { } from "@mantine/core"; import { useDisclosure, useShallowEffect } from "@mantine/hooks"; import { IconEdit, IconPlus, IconTrash } from "@tabler/icons-react"; +import type { JsonValue } from "generated/prisma/runtime/library"; import { useState } from "react"; import useSWR from "swr"; import notification from "./notificationGlobal"; import PermissionRole from "./PermissionRole"; -export default function UserRoleSetting() { +export default function UserRoleSetting({ permissions }: { permissions: JsonValue[] }) { const [btnDisable, setBtnDisable] = useState(true); const [btnLoading, setBtnLoading] = useState(false); const [opened, { open, close }] = useDisclosure(false); @@ -391,15 +392,19 @@ export default function UserRoleSetting() { Daftar Role - - - + { + permissions.includes('setting.user_role.tambah') && ( + + + + ) + } @@ -421,17 +426,18 @@ export default function UserRoleSetting() { - + chooseEdit({ data: v })} + disabled={!permissions.includes('setting.user_role.edit')} > - + diff --git a/src/components/UserSetting.tsx b/src/components/UserSetting.tsx index 1861a15..65e7acc 100644 --- a/src/components/UserSetting.tsx +++ b/src/components/UserSetting.tsx @@ -16,11 +16,12 @@ import { } from "@mantine/core"; import { useDisclosure, useShallowEffect } from "@mantine/hooks"; import { IconEdit, IconPlus, IconTrash } from "@tabler/icons-react"; +import type { JsonValue } from "generated/prisma/runtime/library"; import { useState } from "react"; import useSWR from "swr"; import notification from "./notificationGlobal"; -export default function UserSetting() { +export default function UserSetting({ permissions }: { permissions: JsonValue[] }) { const [btnDisable, setBtnDisable] = useState(true); const [btnLoading, setBtnLoading] = useState(false); const [opened, { open, close }] = useDisclosure(false); @@ -390,15 +391,20 @@ export default function UserSetting() { Daftar User - - - + { + permissions.includes('setting.user.tambah') && ( + + + + ) + } + @@ -422,17 +428,18 @@ export default function UserSetting() { {v.roleId} - + chooseEdit({ data: v })} + disabled={!permissions.includes('setting.user.edit')} > - + diff --git a/src/lib/listPermission.json b/src/lib/listPermission.json index b746a2e..148ed4d 100644 --- a/src/lib/listPermission.json +++ b/src/lib/listPermission.json @@ -27,8 +27,16 @@ "label": "Antrian", "default": true, "children": [ - { "key": "pengaduan.antrian.tolak", "label": "Menolak", "default": true }, - { "key": "pengaduan.antrian.terima", "label": "Menerima", "default": true } + { + "key": "pengaduan.antrian.tolak", + "label": "Menolak", + "default": true + }, + { + "key": "pengaduan.antrian.terima", + "label": "Menerima", + "default": true + } ] }, { @@ -36,7 +44,11 @@ "label": "Diterima", "default": true, "children": [ - { "key": "pengaduan.diterima.dikerjakan", "label": "Dikerjakan", "default": true } + { + "key": "pengaduan.diterima.dikerjakan", + "label": "Dikerjakan", + "default": true + } ] }, { @@ -44,7 +56,11 @@ "label": "Dikerjakan", "default": true, "children": [ - { "key": "pengaduan.dikerjakan.selesai", "label": "Diselesaikan", "default": true } + { + "key": "pengaduan.dikerjakan.selesai", + "label": "Diselesaikan", + "default": true + } ] } ] @@ -64,8 +80,16 @@ "label": "Antrian", "default": true, "children": [ - { "key": "pelayanan.antrian.tolak", "label": "Menolak", "default": true }, - { "key": "pelayanan.antrian.terima", "label": "Menerima", "default": true } + { + "key": "pelayanan.antrian.tolak", + "label": "Menolak", + "default": true + }, + { + "key": "pelayanan.antrian.terima", + "label": "Menerima", + "default": true + } ] }, { @@ -73,8 +97,16 @@ "label": "Diterima", "default": true, "children": [ - { "key": "pelayanan.diterima.tolak", "label": "Menolak", "default": true }, - { "key": "pelayanan.diterima.setujui", "label": "Menyetujui", "default": true } + { + "key": "pelayanan.diterima.tolak", + "label": "Menolak", + "default": true + }, + { + "key": "pelayanan.diterima.setujui", + "label": "Menyetujui", + "default": true + } ] } ] @@ -101,9 +133,21 @@ "label": "Profile", "default": true, "children": [ - { "key": "setting.profile.view", "label": "View", "default": true }, - { "key": "setting.profile.edit", "label": "Edit", "default": true }, - { "key": "setting.profile.password", "label": "Ubah Password", "default": true } + { + "key": "setting.profile.view", + "label": "View", + "default": true + }, + { + "key": "setting.profile.edit", + "label": "Edit", + "default": true + }, + { + "key": "setting.profile.password", + "label": "Ubah Password", + "default": true + } ] }, { @@ -111,10 +155,26 @@ "label": "User", "default": true, "children": [ - { "key": "setting.user.view", "label": "View List", "default": true }, - { "key": "setting.user.tambah", "label": "Tambah", "default": true }, - { "key": "setting.user.edit", "label": "Edit", "default": true }, - { "key": "setting.user.delete", "label": "Delete", "default": true } + { + "key": "setting.user.view", + "label": "View List", + "default": true + }, + { + "key": "setting.user.tambah", + "label": "Tambah", + "default": true + }, + { + "key": "setting.user.edit", + "label": "Edit", + "default": true + }, + { + "key": "setting.user.delete", + "label": "Delete", + "default": true + } ] }, { @@ -122,10 +182,26 @@ "label": "User Role", "default": true, "children": [ - { "key": "setting.user_role.view", "label": "View List", "default": true }, - { "key": "setting.user_role.tambah", "label": "Tambah", "default": true }, - { "key": "setting.user_role.edit", "label": "Edit", "default": true }, - { "key": "setting.user_role.delete", "label": "Delete", "default": true } + { + "key": "setting.user_role.view", + "label": "View List", + "default": true + }, + { + "key": "setting.user_role.tambah", + "label": "Tambah", + "default": true + }, + { + "key": "setting.user_role.edit", + "label": "Edit", + "default": true + }, + { + "key": "setting.user_role.delete", + "label": "Delete", + "default": true + } ] }, { @@ -133,10 +209,26 @@ "label": "Kategori Pengaduan", "default": true, "children": [ - { "key": "setting.kategori_pengaduan.view", "label": "View List", "default": true }, - { "key": "setting.kategori_pengaduan.tambah", "label": "Tambah", "default": true }, - { "key": "setting.kategori_pengaduan.edit", "label": "Edit", "default": true }, - { "key": "setting.kategori_pengaduan.delete", "label": "Delete", "default": true } + { + "key": "setting.kategori_pengaduan.view", + "label": "View List", + "default": true + }, + { + "key": "setting.kategori_pengaduan.tambah", + "label": "Tambah", + "default": true + }, + { + "key": "setting.kategori_pengaduan.edit", + "label": "Edit", + "default": true + }, + { + "key": "setting.kategori_pengaduan.delete", + "label": "Delete", + "default": true + } ] }, { @@ -144,11 +236,31 @@ "label": "Kategori Pelayanan Surat", "default": true, "children": [ - { "key": "setting.kategori_pelayanan.view", "label": "View List", "default": true }, - { "key": "setting.kategori_pelayanan.detail", "label": "View Detail", "default": true }, - { "key": "setting.kategori_pelayanan.tambah", "label": "Tambah", "default": true }, - { "key": "setting.kategori_pelayanan.edit", "label": "Edit", "default": true }, - { "key": "setting.kategori_pelayanan.delete", "label": "Delete", "default": true } + { + "key": "setting.kategori_pelayanan.view", + "label": "View List", + "default": true + }, + { + "key": "setting.kategori_pelayanan.detail", + "label": "View Detail", + "default": true + }, + { + "key": "setting.kategori_pelayanan.tambah", + "label": "Tambah", + "default": true + }, + { + "key": "setting.kategori_pelayanan.edit", + "label": "Edit", + "default": true + }, + { + "key": "setting.kategori_pelayanan.delete", + "label": "Delete", + "default": true + } ] }, { @@ -156,8 +268,16 @@ "label": "Desa", "default": true, "children": [ - { "key": "setting.desa.view", "label": "View List", "default": true }, - { "key": "setting.desa.edit", "label": "Edit", "default": true } + { + "key": "setting.desa.view", + "label": "View List", + "default": true + }, + { + "key": "setting.desa.edit", + "label": "Edit", + "default": true + } ] } ] @@ -166,13 +286,25 @@ "key": "api_key", "label": "API Key", "default": true, - "children": [] + "children": [ + { + "key": "api_key.view", + "label": "View List", + "default": true + } + ] }, { "key": "credential", "label": "Credential", "default": true, - "children": [] + "children": [ + { + "key": "credential.viewØ", + "label": "View List", + "default": true + } + ] } ] -} +} \ No newline at end of file diff --git a/src/pages/scr/dashboard/dashboard_layout.tsx b/src/pages/scr/dashboard/dashboard_layout.tsx index 2fc3115..ca3f687 100644 --- a/src/pages/scr/dashboard/dashboard_layout.tsx +++ b/src/pages/scr/dashboard/dashboard_layout.tsx @@ -35,6 +35,7 @@ import { IconUsersGroup, } from "@tabler/icons-react"; import type { User } from "generated/prisma"; +import type { JsonValue } from "generated/prisma/runtime/library"; import { useEffect, useState } from "react"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; @@ -212,36 +213,54 @@ function HostView() { function NavigationDashboard() { const navigate = useNavigate(); const location = useLocation(); + const [permissions, setPermissions] = useState([]); + + useEffect(() => { + async function fetchPermissions() { + const { data } = await apiFetch.api.user.find.get(); + if (Array.isArray(data?.permissions)) { + setPermissions(data.permissions); + } else { + setPermissions([]); + } + } + fetchPermissions(); + }, []); const isActive = (path: keyof typeof clientRoute) => location.pathname.startsWith(clientRoute[path]); const navItems = [ { + key: "dashboard", path: "/scr/dashboard/dashboard-home", icon: , label: "Dashboard Overview", description: "Quick summary and insights", }, { + key: "pengaduan", path: "/scr/dashboard/pengaduan/list", icon: , label: "Pengaduan Warga", description: "Manage pengaduan warga", }, { + key: "pelayanan", path: "/scr/dashboard/pelayanan-surat/list-pelayanan", icon: , label: "Pelayanan Surat", description: "Manage pelayanan surat", }, { + key: "warga", path: "/scr/dashboard/warga/list-warga", icon: , label: "Warga", description: "Manage warga", }, { + key: "setting", path: "/scr/dashboard/setting/detail-setting", icon: , label: "Setting", @@ -249,12 +268,14 @@ function NavigationDashboard() { "Manage setting (category pengaduan dan pelayanan surat, desa, etc)", }, { + key: "api_key", path: "/scr/dashboard/apikey/apikey", icon: , label: "API Key Manager", description: "Create and manage API keys", }, { + key: "credential", path: "/scr/dashboard/credential/credential", icon: , label: "Credentials", @@ -264,7 +285,7 @@ function NavigationDashboard() { return ( - {navItems.map((item) => ( + {navItems.filter((item) => permissions.includes(item.key)).map((item) => ( (null); const [noSurat, setNoSurat] = useState(""); const [openedPreview, setOpenedPreview] = useState(false); + const [permissions, setPermissions] = useState([]); useEffect(() => { async function fetchHost() { const { data } = await apiFetch.api.user.find.get(); setHost(data?.user ?? null); + + if (data?.permissions && Array.isArray(data.permissions)) { + const onlySetting = data.permissions.filter((p: any) => p.startsWith("pelayanan")); + setPermissions(onlySetting); + } } fetchHost(); }, []); @@ -276,6 +283,7 @@ function DetailDataPengajuan({ data, syaratDokumen, dataText, onAction }: { data data?.status === "antrian" ? (