diff --git a/distribution_fe/app/(dashboard)/users/roles/[id]/page.tsx b/distribution_fe/app/(dashboard)/users/roles/[id]/page.tsx new file mode 100644 index 0000000..6e0c424 --- /dev/null +++ b/distribution_fe/app/(dashboard)/users/roles/[id]/page.tsx @@ -0,0 +1,117 @@ +'use client' + +import { useEffect, useState } from 'react' +import { useParams, useRouter } from 'next/navigation' +import { HugeiconsIcon } from '@hugeicons/react' +import { ArrowLeft01Icon, PencilEdit01Icon } from '@hugeicons/core-free-icons' + +import { Badge } from '@/components/ui/badge' +import { Button } from '@/components/ui/button' +import { toast } from '@/components/ui/toast' +import { roles as rolesApi, getApiError } from '@/lib/api/index' +import { PERMISSION_CATEGORIES } from '@/config/permissions' +import type { RoleResponse, PermissionResponse } from '@/types/api' + +const fmtDate = (v: string) => + new Date(v).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }) + +// 'orders.view' -> 'View Orders', 'loading-sheet.manage' -> 'Manage Loading Sheet' +function permissionLabel(code: string): string { + const [resource, action] = code.split('.') + const title = (s: string) => s.split(/[-_]/).map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(' ') + return action ? `${title(action)} ${title(resource)}` : title(resource) +} + +function Field({ label, children }: { label: string; children: React.ReactNode }) { + return ( +
+ {label} + {children} +
+ ) +} + +export default function ViewRolePage() { + const { id } = useParams<{ id: string }>() + const router = useRouter() + const goBack = () => router.push('/users/roles') + + const [role, setRole] = useState(null) + const [permissions, setPermissions] = useState([]) + const [loading, setLoading] = useState(true) + + useEffect(() => { + Promise.all([rolesApi.get(id), rolesApi.getPermissions(id)]) + .then(([r, perms]) => { setRole(r); setPermissions(perms) }) + .catch((err) => toast.add({ title: 'Failed to load role', description: getApiError(err), type: 'error' })) + .finally(() => setLoading(false)) + }, [id]) + + return ( +
+
+
+ +
+

Role Details

+

View role details and permissions.

+
+
+ {role && ( + + )} +
+ +
+ {loading && ( +
+ {Array.from({ length: 4 }).map((_, i) => ( +
+ ))} +
+ )} + {!loading && role && ( +
+
+ {role.name} + {role.level} + + {role.isActive ? 'Active' : 'Inactive'} + + {fmtDate(role.createdAt)} +
+ +
+

Permissions

+ {permissions.length === 0 ? ( +

No permissions assigned to this role.

+ ) : ( +
+ {PERMISSION_CATEGORIES.map((cat) => { + const catPerms = permissions.filter((p) => cat.codes.includes(p.code)) + if (catPerms.length === 0) return null + return ( +
+ {cat.label} +
+ {catPerms.map((p) => ( + {permissionLabel(p.code)} + ))} +
+
+ ) + })} +
+ )} +
+
+ )} +
+
+ ) +} diff --git a/distribution_fe/app/(dashboard)/users/roles/_components/role-view-sheet.tsx b/distribution_fe/app/(dashboard)/users/roles/_components/role-view-sheet.tsx deleted file mode 100644 index c6405b1..0000000 --- a/distribution_fe/app/(dashboard)/users/roles/_components/role-view-sheet.tsx +++ /dev/null @@ -1,77 +0,0 @@ -'use client' - -import { useEffect, useState } from 'react' -import { Badge } from '@/components/ui/badge' -import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog' -import { toast } from '@/components/ui/toast' -import { roles as rolesApi, getApiError } from '@/lib/api/index' -import type { RoleResponse, PermissionResponse } from '@/types/api' - -const fmtDate = (v: string) => - new Date(v).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }) - -interface RoleViewSheetProps { - open: boolean - onClose: () => void - role: RoleResponse | null -} - -function Row({ label, value }: { label: string; value: React.ReactNode }) { - return ( -
- {label} - {value} -
- ) -} - -export function RoleViewSheet({ open, onClose, role }: RoleViewSheetProps) { - const [permissions, setPermissions] = useState([]) - const [loading, setLoading] = useState(false) - - useEffect(() => { - if (!open || !role) return - setLoading(true) - rolesApi.getPermissions(role.id) - .then(setPermissions) - .catch((err) => toast.add({ title: 'Failed to load permissions', description: getApiError(err), type: 'error' })) - .finally(() => setLoading(false)) - }, [open, role]) - - if (!role) return null - - return ( - !v && onClose()}> - - - Role Details - - -
- - - {role.isActive ? 'Active' : 'Inactive'}} /> - -
- -
-

Permissions

- {loading ? ( -

Loading…

- ) : permissions.length === 0 ? ( -

No permissions assigned to this role.

- ) : ( -
- {permissions.map((p) => ( -
- {p.code} - {p.description && {p.description}} -
- ))} -
- )} -
-
-
- ) -} diff --git a/distribution_fe/app/(dashboard)/users/roles/_components/roles-client.tsx b/distribution_fe/app/(dashboard)/users/roles/_components/roles-client.tsx index f757c5e..d8e4d79 100644 --- a/distribution_fe/app/(dashboard)/users/roles/_components/roles-client.tsx +++ b/distribution_fe/app/(dashboard)/users/roles/_components/roles-client.tsx @@ -13,8 +13,6 @@ import { toast } from '@/components/ui/toast' import { roles as rolesApi, getApiError } from '@/lib/api/index' import type { RoleResponse } from '@/types/api' -import { RoleViewSheet } from './role-view-sheet' - export function RolesClient() { const router = useRouter() const [data, setData] = useState([]) @@ -22,9 +20,6 @@ export function RolesClient() { const [total, setTotal] = useState(0) const [pageSize, setPageSize] = useState(20) - const [viewOpen, setViewOpen] = useState(false) - const [viewing, setViewing] = useState(null) - const fetchData = useCallback(async () => { setLoading(true) try { @@ -42,7 +37,7 @@ export function RolesClient() { function openCreate() { router.push('/users/roles/new') } function openEdit(role: RoleResponse) { router.push(`/users/roles/${role.id}/edit`) } - function openView(role: RoleResponse) { setViewing(role); setViewOpen(true) } + function openView(role: RoleResponse) { router.push(`/users/roles/${role.id}`) } async function handleDeactivate(role: RoleResponse) { try { @@ -120,12 +115,6 @@ export function RolesClient() { totalCount={total} onServerSideChange={({ page: p }) => setPageSize(p.pageSize)} /> - - setViewOpen(false)} - role={viewing} - /> ) }