/* Admin → Settings → Roles & Access (full RBAC view) */ const JL_ROLES = [ { id:'super', name:'Super Admin', scope:'District-wide', initials:'DR', color:'gold', count:3 }, { id:'admin', name:'School Admin', scope:'Single school', initials:'SA', color:'navy', count:12 }, { id:'teacher', name:'Teacher', scope:'Own classes', initials:'MJ', color:'blue', count:86 }, { id:'driver', name:'Driver', scope:'Assigned route', initials:'MT', color:'green', count:25 }, { id:'parent', name:'Parent', scope:'Own children', initials:'JH', color:'cyan', count:1248 }, { id:'student', name:'Student', scope:'Own profile', initials:'EJ', color:'red', count:1248 }, ]; /* access level per capability per role: 'full' | 'own' | 'none' */ const JL_CAPS = [ { cap:'View student records', icon:'users', a:{ super:'full', admin:'full', teacher:'own', driver:'own', parent:'own', student:'own' } }, { cap:'Live bus tracking', icon:'bus', a:{ super:'full', admin:'full', teacher:'none', driver:'own', parent:'own', student:'own' } }, { cap:'Message families', icon:'message-circle', a:{ super:'full', admin:'full', teacher:'full', driver:'none', parent:'full', student:'none' } }, { cap:'Pickup & dismissal', icon:'car-front', a:{ super:'full', admin:'full', teacher:'own', driver:'own', parent:'own', student:'own' } }, { cap:'Process payments', icon:'credit-card', a:{ super:'full', admin:'full', teacher:'none', driver:'none', parent:'own', student:'none' } }, { cap:'Reports & analytics', icon:'bar-chart-3', a:{ super:'full', admin:'own', teacher:'own', driver:'none', parent:'none', student:'none' } }, { cap:'Manage roles & settings', icon:'settings', a:{ super:'full', admin:'own', teacher:'none', driver:'none', parent:'none', student:'none' } }, ]; function AccessCell({ level }) { const map = { full: { icon:'check', bg:'var(--success-100)', fg:'var(--success-600)', label:'Full' }, own: { icon:'user', bg:'var(--warning-100)', fg:'var(--warning-600)', label:'Own data' }, none: { icon:'minus', bg:'var(--gray-100)', fg:'var(--gray-400)', label:'None' }, }; const m = map[level]; return ( ); } function RolesAccess() { const [active, setActive] = React.useState('admin'); const fmt = n => n >= 1000 ? (n/1000).toFixed(n%1000?1:0)+'k' : ''+n; return (
{/* role cards */} jlToast('New custom role', { icon:'plus' })} style={{ display:'flex', alignItems:'center', gap:6, background:'var(--navy-600)', color:'#fff', border:0, borderRadius:9, padding:'8px 13px', fontWeight:700, fontSize:12.5, cursor:'pointer', fontFamily:'var(--font-sans)' }}>Add Role}>
{JL_ROLES.map(r => { const on = active===r.id; return ( ); })}
{/* permissions matrix */} } pad={false}>
{/* header */}
Capability {JL_ROLES.map(r => ( {r.name.replace(' Admin',' Adm.')} ))}
{/* rows */} {JL_CAPS.map((row, i) => (
0?'1px solid var(--gray-100)':'0' }}> {row.cap} {JL_ROLES.map(r => ( ))}
))}
{/* data-scope note */}
Row-level security is enforced everywhere. “Own data” means a teacher sees only their class, a parent only their children, a driver only their route, and a student only their own profile — never another family's information.
); } function Legend({ level, label }) { return ( {label} ); } Object.assign(window, { RolesAccess, JL_ROLES, JL_CAPS });