diff --git a/src/app/admin/roles/page.tsx b/src/app/admin/roles/page.tsx index 1e2f5cf..b19f744 100644 --- a/src/app/admin/roles/page.tsx +++ b/src/app/admin/roles/page.tsx @@ -1,14 +1,20 @@ 'use client'; import { useState } from 'react'; -import { Shield, Plus, Search, X, Edit, Trash2, Copy, CheckCircle, XCircle, Eye } from 'lucide-react'; +import { Shield, Plus, Search, X, Edit, Trash2, Copy, Check, ChevronDown, ChevronRight, BookOpen, FileSearch, ClipboardList, Settings, BarChart3, Bike, Users, Briefcase, Truck, Store, BatteryCharging, Building2, Wrench, DollarSign, TrendingUp, UserCog } from 'lucide-react'; interface Permission { - module: string; - view: boolean; - create: boolean; - edit: boolean; - delete: boolean; + key: string; + label: string; + enabled: boolean; +} + +interface PermissionGroup { + id: string; + title: string; + description: string; + icon: React.ComponentType<{ className?: string }>; + permissions: Permission[]; } interface Role { @@ -16,23 +22,192 @@ interface Role { name: string; description: string; isDefault: boolean; - permissions: Permission[]; + permissionGroups: PermissionGroup[]; } -const defaultPermissions: Permission[] = [ - { module: 'Dashboard', view: true, create: false, edit: false, delete: false }, - { module: 'KYC', view: false, create: false, edit: false, delete: false }, - { module: 'Rentals', view: false, create: false, edit: false, delete: false }, - { module: 'Bikers', view: false, create: false, edit: false, delete: false }, - { module: 'Investors', view: false, create: false, edit: false, delete: false }, - { module: 'Fleet', view: false, create: false, edit: false, delete: false }, - { module: 'Merchants', view: false, create: false, edit: false, delete: false }, - { module: 'Swap Stations', view: false, create: false, edit: false, delete: false }, - { module: 'Hubs', view: false, create: false, edit: false, delete: false }, - { module: 'Maintenance', view: false, create: false, edit: false, delete: false }, - { module: 'Accounting', view: false, create: false, edit: false, delete: false }, - { module: 'Reports', view: false, create: false, edit: false, delete: false }, - { module: 'Users', view: false, create: false, edit: false, delete: false }, +const buildDefaultGroups = (): PermissionGroup[] => [ + + { + id: 'kyc', + title: 'KYC Requests & Verification', + description: 'The Biker user will request from the app. Investor, Shop, Merchant will request from the website. Front desk officers (hub/head office) can request for Biker, Investor, Shop, Merchant and can upload remaining documents. Admin officers (head office) will approve or reject documents with notes and "make a Biker | Investor | Shop | Merchant".', + icon: FileSearch, + permissions: [ + { key: 'kyc.request', label: 'KYC Request', enabled: false }, + { key: 'kyc.view', label: 'View KYC Requests', enabled: false }, + { key: 'kyc.doc_upload', label: 'Document Upload', enabled: false }, + { key: 'kyc.doc_approve', label: 'Document Approve', enabled: false }, + { key: 'kyc.doc_reject', label: 'Document Reject', enabled: false }, + { key: 'kyc.make_valid_user', label: 'Make a Biker | Investor | Shop | Merchant', enabled: false }, + ] + }, + { + id: 'plans', + title: 'Plan Selection + EV Condition', + description: 'Manage investment plans, swap station plans, and rider request plans', + icon: ClipboardList, + permissions: [ + { key: 'plans.investment.view', label: 'View Investment Plan', enabled: false }, + { key: 'plans.investment.edit', label: 'Edit Investment Plan', enabled: false }, + { key: 'plans.swap_station.view', label: 'View Swap Station Plan', enabled: false }, + { key: 'plans.swap_station.edit', label: 'Edit Swap Station Plan', enabled: false }, + { key: 'plans.rider_request.view', label: 'View Rider Request Plan', enabled: false }, + { key: 'plans.rider_request.edit', label: 'Edit Rider Request Plan', enabled: false }, + ] + }, + { + id: 'settings', + title: 'Settings', + description: 'Manage system settings including KYC documents and plans', + icon: Settings, + permissions: [ + { key: 'settings.kyc_documents.view', label: 'View KYC Documents', enabled: false }, + { key: 'settings.kyc_documents.edit', label: 'Edit KYC Documents', enabled: false }, + { key: 'settings.plan_selection.view', label: 'View Plan Selection with Condition', enabled: false }, + { key: 'settings.plan_selection.edit', label: 'Edit Plan Selection with Condition', enabled: false }, + { key: 'settings.company_policy.view', label: 'View Company Policy', enabled: false }, + { key: 'settings.company_policy.edit', label: 'Edit Company Policy', enabled: false }, + ] + }, + { + id: 'dashboard', + title: 'Dashboard', + description: 'Access to main dashboard', + icon: BarChart3, + permissions: [ + { key: 'dashboard.view', label: 'View Dashboard', enabled: false }, + ] + }, + { + id: 'rentals', + title: 'Rentals', + description: 'Manage rental operations', + icon: Bike, + permissions: [ + { key: 'rentals.view', label: 'View', enabled: false }, + { key: 'rentals.create', label: 'Create', enabled: false }, + { key: 'rentals.edit', label: 'Edit', enabled: false }, + { key: 'rentals.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'bikers', + title: 'Bikers', + description: 'Manage bikers', + icon: Users, + permissions: [ + { key: 'bikers.view', label: 'View', enabled: false }, + { key: 'bikers.create', label: 'Create', enabled: false }, + { key: 'bikers.edit', label: 'Edit', enabled: false }, + { key: 'bikers.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'investors', + title: 'Investors', + description: 'Manage investors', + icon: Briefcase, + permissions: [ + { key: 'investors.view', label: 'View', enabled: false }, + { key: 'investors.create', label: 'Create', enabled: false }, + { key: 'investors.edit', label: 'Edit', enabled: false }, + { key: 'investors.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'fleet', + title: 'Fleet', + description: 'Manage fleet vehicles', + icon: Truck, + permissions: [ + { key: 'fleet.view', label: 'View', enabled: false }, + { key: 'fleet.create', label: 'Create', enabled: false }, + { key: 'fleet.edit', label: 'Edit', enabled: false }, + { key: 'fleet.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'merchants', + title: 'Merchants', + description: 'Manage merchants', + icon: Store, + permissions: [ + { key: 'merchants.view', label: 'View', enabled: false }, + { key: 'merchants.create', label: 'Create', enabled: false }, + { key: 'merchants.edit', label: 'Edit', enabled: false }, + { key: 'merchants.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'swap_stations', + title: 'Swap Stations', + description: 'Manage swap stations', + icon: BatteryCharging, + permissions: [ + { key: 'swap_stations.view', label: 'View', enabled: false }, + { key: 'swap_stations.create', label: 'Create', enabled: false }, + { key: 'swap_stations.edit', label: 'Edit', enabled: false }, + { key: 'swap_stations.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'hubs', + title: 'Hubs', + description: 'Manage hubs', + icon: Building2, + permissions: [ + { key: 'hubs.view', label: 'View', enabled: false }, + { key: 'hubs.create', label: 'Create', enabled: false }, + { key: 'hubs.edit', label: 'Edit', enabled: false }, + { key: 'hubs.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'maintenance', + title: 'Maintenance', + description: 'Manage maintenance requests', + icon: Wrench, + permissions: [ + { key: 'maintenance.view', label: 'View', enabled: false }, + { key: 'maintenance.create', label: 'Create', enabled: false }, + { key: 'maintenance.edit', label: 'Edit', enabled: false }, + { key: 'maintenance.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'accounting', + title: 'Accounting', + description: 'Manage financial records', + icon: DollarSign, + permissions: [ + { key: 'accounting.view', label: 'View', enabled: false }, + { key: 'accounting.create', label: 'Create', enabled: false }, + { key: 'accounting.edit', label: 'Edit', enabled: false }, + { key: 'accounting.delete', label: 'Delete', enabled: false }, + ] + }, + { + id: 'reports', + title: 'Reports', + description: 'View and generate reports', + icon: TrendingUp, + permissions: [ + { key: 'reports.view', label: 'View', enabled: false }, + { key: 'reports.export', label: 'Export', enabled: false }, + ] + }, + { + id: 'users', + title: 'Users', + description: 'Manage system users', + icon: UserCog, + permissions: [ + { key: 'users.view', label: 'View', enabled: false }, + { key: 'users.create', label: 'Create', enabled: false }, + { key: 'users.edit', label: 'Edit', enabled: false }, + { key: 'users.delete', label: 'Delete', enabled: false }, + ] + }, ]; const mockRoles: Role[] = [ @@ -41,76 +216,117 @@ const mockRoles: Role[] = [ name: 'Admin', description: 'Full system access with all permissions', isDefault: false, - permissions: defaultPermissions.map(p => ({ ...p, view: true, create: true, edit: true, delete: true })) + permissionGroups: buildDefaultGroups().map(g => ({ + ...g, + permissions: g.permissions.map(p => ({ ...p, enabled: true })) + })) }, { id: 'ROLE-002', name: 'Manager', description: 'Management access with limited delete permissions', isDefault: false, - permissions: defaultPermissions.map(p => ({ - module: p.module, - view: true, - create: ['Dashboard', 'Reports'].includes(p.module) ? false : true, - edit: ['Dashboard', 'Users'].includes(p.module) ? false : true, - delete: false + permissionGroups: buildDefaultGroups().map(g => ({ + ...g, + permissions: g.permissions.map(p => ({ + ...p, + enabled: !p.key.includes('delete') + })) })) }, { id: 'ROLE-003', - name: 'Biker', - description: 'Limited access for bike riders', + name: 'Front Desk Officer', + description: 'Hub/head office officer - can request KYC and upload documents', isDefault: false, - permissions: defaultPermissions.map(p => ({ - module: p.module, - view: ['Dashboard', 'Fleet', 'Rentals'].includes(p.module), - create: p.module === 'Rentals', - edit: false, - delete: false - })) + permissionGroups: buildDefaultGroups().map(g => { + if (g.id === 'kyc') { + return { + ...g, + permissions: g.permissions.map(p => ({ + ...p, + enabled: ['kyc.request', 'kyc.view', 'kyc.doc_upload'].includes(p.key) + })) + }; + } + if (g.id === 'dashboard') { + return { ...g, permissions: g.permissions.map(p => ({ ...p, enabled: true })) }; + } + return g; + }) }, { id: 'ROLE-004', - name: 'Investor', - description: 'Access for investors to view portfolio', + name: 'Admin Officer', + description: 'Head office officer - can approve/reject KYC documents and make valid users', isDefault: false, - permissions: defaultPermissions.map(p => ({ - module: p.module, - view: ['Dashboard', 'Portfolio', 'Withdraw'].includes(p.module), - create: p.module === 'Withdraw', - edit: false, - delete: false - })) + permissionGroups: buildDefaultGroups().map(g => { + if (g.id === 'kyc') { + return { + ...g, + permissions: g.permissions.map(p => ({ + ...p, + enabled: ['kyc.view', 'kyc.doc_approve', 'kyc.doc_reject', 'kyc.make_valid_user'].includes(p.key) + })) + }; + } + if (g.id === 'dashboard') { + return { ...g, permissions: g.permissions.map(p => ({ ...p, enabled: true })) }; + } + return g; + }) }, { id: 'ROLE-005', - name: 'Shop', - description: 'Access for shop owners', + name: 'Biker', + description: 'Limited access for bike riders - can view dashboard, request KYC, manage rentals', isDefault: false, - permissions: defaultPermissions.map(p => ({ - module: p.module, - view: ['Dashboard', 'Fleet', 'Deliveries'].includes(p.module), - create: p.module === 'Deliveries', - edit: p.module === 'Deliveries', - delete: false - })) - }, - { - id: 'ROLE-006', - name: 'Merchant', - description: 'Access for merchants', - isDefault: true, - permissions: defaultPermissions.map(p => ({ - module: p.module, - view: ['Dashboard', 'Deliveries'].includes(p.module), - create: false, - edit: ['Deliveries'].includes(p.module), - delete: false - })) + permissionGroups: buildDefaultGroups().map(g => { + if (g.id === 'dashboard') { + return { ...g, permissions: g.permissions.map(p => ({ ...p, enabled: true })) }; + } + if (g.id === 'kyc') { + return { + ...g, + permissions: g.permissions.map(p => ({ + ...p, + enabled: ['kyc.request', 'kyc.view'].includes(p.key) + })) + }; + } + if (g.id === 'rentals') { + return { + ...g, + permissions: g.permissions.map(p => ({ + ...p, + enabled: ['rentals.view', 'rentals.create'].includes(p.key) + })) + }; + } + return g; + }) }, ]; -const allModules = ['Dashboard', 'KYC', 'Rentals', 'Bikers', 'Investors', 'Fleet', 'Merchants', 'Swap Stations', 'Hubs', 'Maintenance', 'Accounting', 'Reports', 'Users', 'Portfolio', 'Withdraw', 'Deliveries']; +function Toggle({ checked, onChange, color = 'blue' }: { checked: boolean; onChange: () => void; color?: string }) { + const colors: Record = { + blue: checked ? 'bg-blue-600' : 'bg-slate-200', + green: checked ? 'bg-green-600' : 'bg-slate-200', + amber: checked ? 'bg-amber-600' : 'bg-slate-200', + red: checked ? 'bg-red-600' : 'bg-slate-200', + }; + return ( + + ); +} export default function RolesPage() { const [roles, setRoles] = useState(mockRoles); @@ -118,20 +334,16 @@ export default function RolesPage() { const [showCreateModal, setShowCreateModal] = useState(false); const [editingRole, setEditingRole] = useState(null); const [selectedRole, setSelectedRole] = useState(null); - - const [formData, setFormData] = useState({ - name: '', - description: '', - }); + const [expandedGroups, setExpandedGroups] = useState>({}); + const [formData, setFormData] = useState({ name: '', description: '' }); - const filteredRoles = roles.filter(r => + const filteredRoles = roles.filter(r => r.name.toLowerCase().includes(search.toLowerCase()) || r.description.toLowerCase().includes(search.toLowerCase()) ); const handleSave = () => { if (!formData.name) return; - if (editingRole) { setRoles(roles.map(r => r.id === editingRole.id ? { ...r, ...formData, isDefault: false } : r)); } else { @@ -139,11 +351,10 @@ export default function RolesPage() { id: `ROLE-${String(roles.length + 1).padStart(3, '0')}`, ...formData, isDefault: false, - permissions: defaultPermissions.map(p => ({ ...p, view: false, create: false, edit: false, delete: false })) + permissionGroups: buildDefaultGroups() }; setRoles([...roles, newRole]); } - setShowCreateModal(false); setEditingRole(null); setFormData({ name: '', description: '' }); @@ -162,30 +373,44 @@ export default function RolesPage() { name: `${role.name} (Copy)`, description: role.description, isDefault: false, - permissions: role.permissions.map(p => ({ ...p })) + permissionGroups: role.permissionGroups.map(g => ({ + ...g, + permissions: g.permissions.map(p => ({ ...p })) + })) }; setRoles([...roles, newRole]); + setSelectedRole(newRole); }; const openEdit = (role: Role) => { setEditingRole(role); - setFormData({ - name: role.name, - description: role.description - }); + setFormData({ name: role.name, description: role.description }); setShowCreateModal(true); }; - const togglePermission = (moduleIndex: number, action: 'view' | 'create' | 'edit' | 'delete') => { + const togglePermission = (groupIndex: number, permIndex: number) => { if (!selectedRole) return; - const updated = [...selectedRole.permissions]; - updated[moduleIndex][action] = !updated[moduleIndex][action]; - setSelectedRole({ ...selectedRole, permissions: updated }); - setRoles(roles.map(r => r.id === selectedRole.id ? { ...selectedRole, permissions: updated } : r)); + const updated = [...selectedRole.permissionGroups]; + const perm = updated[groupIndex].permissions[permIndex]; + perm.enabled = !perm.enabled; + setSelectedRole({ ...selectedRole, permissionGroups: updated }); + setRoles(roles.map(r => r.id === selectedRole.id ? { ...selectedRole, permissionGroups: updated } : r)); }; - const getPermissionCount = (role: Role, action: keyof Permission) => { - return role.permissions.filter(p => p[action] === true).length; + const toggleGroupAll = (groupIndex: number, enabled: boolean) => { + if (!selectedRole) return; + const updated = [...selectedRole.permissionGroups]; + updated[groupIndex].permissions = updated[groupIndex].permissions.map(p => ({ ...p, enabled })); + setSelectedRole({ ...selectedRole, permissionGroups: updated }); + setRoles(roles.map(r => r.id === selectedRole.id ? { ...selectedRole, permissionGroups: updated } : r)); + }; + + const isGroupAllEnabled = (group: PermissionGroup) => group.permissions.every(p => p.enabled); + const getEnabledCount = (group: PermissionGroup) => group.permissions.filter(p => p.enabled).length; + const getTotalEnabled = (role: Role) => role.permissionGroups.reduce((a, g) => a + g.permissions.filter(p => p.enabled).length, 0); + + const toggleGroup = (groupId: string) => { + setExpandedGroups(prev => ({ ...prev, [groupId]: !prev[groupId] })); }; return ( @@ -195,7 +420,7 @@ export default function RolesPage() {

Roles & Permissions

Manage roles and access permissions

- + {expandedGroups[group.id] ? ( + + ) : ( + + )} + + + {expandedGroups[group.id] && ( +
+
+

{group.description}

+
+
+ {group.permissions.map((perm, pi) => ( +
+
+ {perm.enabled ? ( + + ) : ( + + )} + {perm.label} + {perm.key} +
+ togglePermission(gi, pi)} + /> +
+ ))} +
+
+ )} - -
- - - - - - - - - - - - {selectedRole.permissions.map((perm, i) => ( - - - - - - - - ))} - -
ModuleViewCreateEditDelete
{perm.module} - - - - - - - -
-
+ ))} ) : ( @@ -409,13 +613,13 @@ export default function RolesPage() {
- -