feat: implement role-based access control for KYC workflows and add permissions documentation
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
import Link from 'next/link';
|
||||
import { usePathname } from 'next/navigation';
|
||||
import { useState } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import {
|
||||
Bike,
|
||||
Settings,
|
||||
@@ -24,6 +24,18 @@ import {
|
||||
Calculator,
|
||||
Wrench
|
||||
} from 'lucide-react';
|
||||
import { getUserName, getUserRole, logout } from '@/lib/auth';
|
||||
|
||||
const ROLE_LABELS: Record<string, string> = {
|
||||
super_admin: 'Super Admin',
|
||||
admin_manager: 'Admin Manager',
|
||||
staff: 'Front Desk',
|
||||
accountant: 'Accountant',
|
||||
investor: 'Investor',
|
||||
biker: 'Biker',
|
||||
'swap-station': 'Swap Station',
|
||||
merchant: 'Merchant',
|
||||
};
|
||||
|
||||
const adminNavItems = [
|
||||
{ label: 'Dashboard', href: '/admin', icon: BarChart3 },
|
||||
@@ -67,11 +79,20 @@ export default function Sidebar() {
|
||||
const pathname = usePathname();
|
||||
const [mobileOpen, setMobileOpen] = useState(false);
|
||||
const [expandedMenu, setExpandedMenu] = useState<string | null>(null);
|
||||
const [userName, setUserName] = useState('User');
|
||||
const [userRole, setUserRole] = useState('admin');
|
||||
|
||||
useEffect(() => {
|
||||
setUserName(getUserName() || 'User');
|
||||
setUserRole(getUserRole() || 'staff');
|
||||
}, []);
|
||||
|
||||
const isAdmin = pathname.startsWith('/admin');
|
||||
const isInvestor = pathname.startsWith('/investor');
|
||||
const isShop = pathname.startsWith('/shop');
|
||||
|
||||
const roleLabel = ROLE_LABELS[userRole] || userRole;
|
||||
|
||||
const navItems = isAdmin ? adminNavItems :
|
||||
isInvestor ? investorNavItems :
|
||||
isShop ? shopNavItems : bikerNavItems;
|
||||
@@ -109,7 +130,7 @@ export default function Sidebar() {
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="px-2 py-1 bg-accent-light rounded text-xs font-semibold text-accent">
|
||||
{isAdmin ? 'Admin' : isInvestor ? 'Investor' : isShop ? 'Shop' : 'Biker'}
|
||||
{roleLabel}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setMobileOpen(false)}
|
||||
@@ -148,23 +169,16 @@ export default function Sidebar() {
|
||||
<div className="absolute bottom-0 left-0 right-0 p-3 border-t border-slate-100 bg-white">
|
||||
<Link href="/admin/users/USR-001" className="flex items-center gap-3 px-3 py-2 hover:bg-slate-50 rounded-lg -mx-1">
|
||||
<div className="w-8 h-8 rounded-full bg-accent-light flex items-center justify-center">
|
||||
<span className="text-sm font-bold text-accent">A</span>
|
||||
<span className="text-sm font-bold text-accent">{userName.charAt(0).toUpperCase()}</span>
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-slate-700 truncate">Admin User</p>
|
||||
<p className="text-xs text-slate-400">admin@jaiben.com</p>
|
||||
<p className="text-sm font-medium text-slate-700 truncate">{userName}</p>
|
||||
<p className="text-xs text-slate-400">{roleLabel}</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => {
|
||||
// Import and call logout function
|
||||
// Note: We can't use client-only imports in server components directly
|
||||
// For now, we'll just clear sessionStorage and redirect
|
||||
if (typeof window !== 'undefined') {
|
||||
window.sessionStorage.removeItem('authToken');
|
||||
window.sessionStorage.removeItem('userRole');
|
||||
window.sessionStorage.removeItem('userName');
|
||||
window.location.href = '/login';
|
||||
}
|
||||
logout();
|
||||
window.location.href = '/login';
|
||||
}}
|
||||
className="p-1.5 hover:bg-slate-100 rounded-lg"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user