2026-03-27 05:35:18 +01:00
|
|
|
import { For, Show, createMemo, createSignal, onMount } from 'solid-js';
|
|
|
|
|
import { useSearchParams } from '@solidjs/router';
|
ui(step-1): match reference layout for dept/designation/employees/roles pages
- All pages: white sticky page header + tab bar with orange underline,
-mx-6 -mt-6 negative margin to stretch headers edge-to-edge
- department: full columns (ID, Name, Description, Created By, etc.),
icon-only action buttons, navy Add Department button
- designation: Designations List / Add Designation tabs, status filter
dropdown, inline create/edit form, full columns with status badge
- employees: View/Add tabs, icon-only action buttons, status badges
- roles/index: clean table with Name+code subtext, Description, actions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 04:47:05 +01:00
|
|
|
import AdminShell from '~/components/AdminShell';
|
2026-03-27 05:35:18 +01:00
|
|
|
import type { CrudRecord } from '~/lib/admin/types';
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
const API = '/api/gateway';
|
|
|
|
|
|
|
|
|
|
type RoleRecord = CrudRecord & {
|
|
|
|
|
code?: string;
|
|
|
|
|
department?: string;
|
|
|
|
|
usersAssigned?: number;
|
|
|
|
|
permissionsCount?: number;
|
2026-03-27 02:28:34 +01:00
|
|
|
status: 'ACTIVE' | 'INACTIVE';
|
2026-03-27 05:35:18 +01:00
|
|
|
createdDate?: string;
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
};
|
|
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
const FALLBACK_ROLES: RoleRecord[] = [
|
|
|
|
|
{ id: 'r1', name: 'System Administrator', code: 'ADM-SYS', department: 'IT', usersAssigned: 12, permissionsCount: 150, status: 'ACTIVE', createdDate: '2026-01-12' },
|
|
|
|
|
{ id: 'r2', name: 'HR Manager', code: 'HR-MGR', department: 'HR', usersAssigned: 4, permissionsCount: 45, status: 'ACTIVE', createdDate: '2026-02-05' },
|
|
|
|
|
{ id: 'r3', name: 'Finance Controller', code: 'FIN-CON', department: 'Finance', usersAssigned: 2, permissionsCount: 60, status: 'INACTIVE', createdDate: '2026-03-18' },
|
2026-03-27 02:28:34 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const MODULES = [
|
2026-03-27 05:35:18 +01:00
|
|
|
'Employee Management', 'Department Management', 'Designation Management', 'Internal Role Management',
|
|
|
|
|
'Verification Management', 'Approval Management', 'Users Management', 'Company Management'
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
];
|
2026-03-25 22:15:06 +01:00
|
|
|
|
2026-03-27 02:28:34 +01:00
|
|
|
function StatusBadge(props: { status: string }) {
|
|
|
|
|
const active = () => props.status === 'ACTIVE';
|
|
|
|
|
return (
|
|
|
|
|
<span style={`display:inline-flex;align-items:center;border-radius:9999px;border:1px solid ${active() ? '#FFD8C2' : '#D1D5DB'};background:${active() ? '#FFF1EB' : '#F3F4F6'};color:${active() ? '#FF5E13' : '#4B5563'};padding:2px 10px;font-size:12px;font-weight:500`}>
|
|
|
|
|
<span style={`display:inline-block;width:6px;height:6px;border-radius:50%;background:${active() ? '#FF5E13' : '#9CA3AF'};margin-right:5px;flex-shrink:0`} />
|
|
|
|
|
{active() ? 'Active' : 'Inactive'}
|
|
|
|
|
</span>
|
|
|
|
|
);
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-27 02:28:34 +01:00
|
|
|
function FormInput(props: { label: string; required?: boolean; value: string; onInput: (v: string) => void; placeholder?: string }) {
|
feat(admin): pixel-perfect UI overhaul for department, designation, roles, employees pages
- Rewrote all layout/spacing with inline styles (Tailwind v4 doesn't generate most utility classes)
- AdminSidebar: all 37 modules in 9 groups, scrollable, 220px/64px collapse, no bottom user section
- AdminShell: header height 64px, user avatar top-right (Gmail-style), removed search bar
- Department: orange-only status badges, dark navy table header (white text), edge-to-edge table, View/Create/All tabs, View action in row menu, form with inline styles
- Designation: full rewrite matching department pattern — same tabs, filter bar, table, form
- Roles/Employees: compact filter bar and table cell sizing fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:56:55 +01:00
|
|
|
return (
|
2026-03-27 02:28:34 +01:00
|
|
|
<label style="display:block">
|
|
|
|
|
<span style="font-size:13px;font-weight:600;color:#374151">
|
2026-03-27 05:35:18 +01:00
|
|
|
{props.label}{props.required && <span style="margin-left:2px;color:#FF5E13">*</span>}
|
2026-03-27 02:28:34 +01:00
|
|
|
</span>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={props.value}
|
|
|
|
|
onInput={(e) => props.onInput(e.currentTarget.value)}
|
|
|
|
|
placeholder={props.placeholder}
|
2026-03-27 05:35:18 +01:00
|
|
|
style="display:block;margin-top:6px;height:40px;width:100%;border-radius:10px;border:1px solid #E5E7EB;background:white;padding:0 14px;font-size:13px;color:#111827;outline:none;box-sizing:border-box"
|
2026-03-27 02:28:34 +01:00
|
|
|
/>
|
|
|
|
|
</label>
|
feat(admin): pixel-perfect UI overhaul for department, designation, roles, employees pages
- Rewrote all layout/spacing with inline styles (Tailwind v4 doesn't generate most utility classes)
- AdminSidebar: all 37 modules in 9 groups, scrollable, 220px/64px collapse, no bottom user section
- AdminShell: header height 64px, user avatar top-right (Gmail-style), removed search bar
- Department: orange-only status badges, dark navy table header (white text), edge-to-edge table, View/Create/All tabs, View action in row menu, form with inline styles
- Designation: full rewrite matching department pattern — same tabs, filter bar, table, form
- Roles/Employees: compact filter bar and table cell sizing fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:56:55 +01:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
export default function RoleManagementPage() {
|
|
|
|
|
const [view, setView] = createSignal<'list' | 'form' | 'detail'>('list');
|
|
|
|
|
const [listTab, setListTab] = createSignal<'all' | 'create' | 'view'>('all');
|
|
|
|
|
const [formTab, setFormTab] = createSignal<'general' | 'permissions' | 'settings'>('general');
|
|
|
|
|
const [detailTab, setDetailTab] = createSignal<'permissions' | 'users' | 'logs'>('permissions');
|
|
|
|
|
|
2026-03-25 22:15:06 +01:00
|
|
|
const [search, setSearch] = createSignal('');
|
2026-03-27 05:35:18 +01:00
|
|
|
const [rows, setRows] = createSignal<RoleRecord[]>([]);
|
|
|
|
|
const [viewingRole, setViewingRole] = createSignal<RoleRecord | null>(null);
|
|
|
|
|
const [editingId, setEditingId] = createSignal<string | null>(null);
|
|
|
|
|
const [openMenuId, setOpenMenuId] = createSignal<string | null>(null);
|
2026-03-25 22:15:06 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
const [name, setName] = createSignal('');
|
|
|
|
|
const [code, setCode] = createSignal('');
|
|
|
|
|
const [dept, setDept] = createSignal('');
|
|
|
|
|
const [desc, setDesc] = createSignal('');
|
2026-03-27 02:28:34 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
const load = async () => {
|
|
|
|
|
setRows(FALLBACK_ROLES);
|
2026-03-25 22:15:06 +01:00
|
|
|
};
|
|
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
onMount(() => void load());
|
2026-03-25 22:15:06 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
const filteredRows = createMemo(() => {
|
|
|
|
|
const q = search().toLowerCase();
|
|
|
|
|
if (!q) return rows();
|
|
|
|
|
return rows().filter(r => r.name.toLowerCase().includes(q) || (r.code || '').toLowerCase().includes(q));
|
|
|
|
|
});
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
const resetForm = () => {
|
|
|
|
|
setEditingId(null); setName(''); setCode(''); setDept(''); setDesc(''); setFormTab('general');
|
2026-03-27 02:28:34 +01:00
|
|
|
};
|
|
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
const openCreate = () => { resetForm(); setView('form'); };
|
|
|
|
|
const openEdit = (row: RoleRecord) => {
|
|
|
|
|
setEditingId(row.id); setName(row.name); setCode(row.code || '');
|
|
|
|
|
setDept(row.department || ''); setView('form'); setOpenMenuId(null);
|
|
|
|
|
};
|
|
|
|
|
const openDetail = (row: RoleRecord) => {
|
|
|
|
|
setViewingRole(row); setView('detail'); setListTab('view'); setOpenMenuId(null);
|
|
|
|
|
};
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<AdminShell>
|
2026-03-27 05:35:18 +01:00
|
|
|
<div class="w-full space-y-6 pb-8">
|
|
|
|
|
|
|
|
|
|
<div style="margin-bottom: 1.5rem">
|
|
|
|
|
<h1 class="text-[28px] font-bold leading-tight text-[#111827]">Internal Role Management</h1>
|
|
|
|
|
<p class="mt-1 text-[14px] text-[#6B7280]">Define and manage organizational access levels with granular permission control</p>
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
</div>
|
2026-03-25 22:15:06 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
{/* ── LIST VIEW ── */}
|
|
|
|
|
<Show when={view() === 'list'}>
|
|
|
|
|
<div style="margin-top:24px;display:flex;align-items:center;gap:24px;border-bottom:1px solid #E5E7EB">
|
|
|
|
|
{([
|
|
|
|
|
{ key: 'all', label: 'All Roles', action: () => setListTab('all') },
|
|
|
|
|
{ key: 'create', label: 'Create Role', action: () => { setListTab('create'); openCreate(); } },
|
|
|
|
|
{ key: 'view', label: 'View Role', action: () => setListTab('view') },
|
|
|
|
|
] as const).map((tab) => (
|
|
|
|
|
<button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={tab.action}
|
|
|
|
|
style={`padding-bottom:12px;font-size:14px;font-weight:500;background:none;border:none;cursor:pointer;${listTab() === tab.key ? 'color:#FF5E13;border-bottom:2px solid #FF5E13;margin-bottom:-1px' : 'color:#6B7280'}`}
|
|
|
|
|
>
|
|
|
|
|
{tab.label}
|
|
|
|
|
</button>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2026-03-26 00:06:47 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
<div style="margin-top:1.5rem;margin-left:-24px;margin-right:-24px;border-radius:0;border-left:none;border-right:none;overflow:hidden;border-top:1px solid #E5E7EB;border-bottom:1px solid #E5E7EB;background:white;box-shadow:0 1px 3px rgba(0,0,0,0.06)">
|
2026-03-27 02:28:34 +01:00
|
|
|
<div style="display:flex;align-items:center;gap:8px;padding:14px 20px;border-bottom:1px solid #F3F4F6">
|
|
|
|
|
<input
|
|
|
|
|
value={search()}
|
|
|
|
|
onInput={(e) => setSearch(e.currentTarget.value)}
|
2026-03-27 05:35:18 +01:00
|
|
|
placeholder="Search roles..."
|
|
|
|
|
style="height:34px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:13px;color:#111827;outline:none"
|
2026-03-27 02:28:34 +01:00
|
|
|
/>
|
2026-03-27 05:35:18 +01:00
|
|
|
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:12px;font-weight:500;color:#374151;cursor:pointer">Filters</button>
|
|
|
|
|
<button type="button" style="display:inline-flex;height:34px;align-items:center;gap:6px;border-radius:8px;background:#0D0D2A;padding:0 12px;font-size:12px;font-weight:600;color:white;border:none;cursor:pointer">Export</button>
|
2026-03-27 02:28:34 +01:00
|
|
|
</div>
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
<div class="overflow-x-auto">
|
|
|
|
|
<table class="min-w-full">
|
2026-03-27 02:28:34 +01:00
|
|
|
<thead>
|
2026-03-27 05:35:18 +01:00
|
|
|
<tr style="background:#0D0D2A;text-align:left">
|
|
|
|
|
{['Role Name', 'Role Code', 'Department', 'Users', 'Status', 'Actions'].map(h => (
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">{h}</th>
|
|
|
|
|
))}
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
</tr>
|
2026-03-27 02:28:34 +01:00
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
2026-03-27 05:35:18 +01:00
|
|
|
<For each={filteredRows()}>
|
|
|
|
|
{(row) => (
|
|
|
|
|
<tr style="border-bottom:1px solid #F3F4F6" class="hover:bg-[#FAFAFA] transition-colors">
|
|
|
|
|
<td style="padding:12px 20px;font-size:14px;font-weight:600;color:#111827">{row.name}</td>
|
|
|
|
|
<td style="padding:12px 20px;font-size:12px;font-family:monospace;color:#6B7280">{row.code || '—'}</td>
|
|
|
|
|
<td style="padding:12px 20px;font-size:13px;color:#6B7280">{row.department || '—'}</td>
|
|
|
|
|
<td style="padding:12px 20px;font-size:13px;color:#6B7280">{row.usersAssigned} users</td>
|
|
|
|
|
<td style="padding:12px 20px"><StatusBadge status={row.status} /></td>
|
|
|
|
|
<td style="padding:12px 20px;position:relative">
|
|
|
|
|
<button type="button" onClick={() => setOpenMenuId(openMenuId() === row.id ? null : row.id)} style="display:inline-flex;height:32px;width:32px;align-items:center;justify-content:center;border-radius:8px;color:#9CA3AF;background:none;border:none;cursor:pointer">
|
|
|
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><circle cx="12" cy="5" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="12" cy="19" r="1.5"/></svg>
|
2026-03-27 02:28:34 +01:00
|
|
|
</button>
|
2026-03-27 05:35:18 +01:00
|
|
|
<Show when={openMenuId() === row.id}>
|
|
|
|
|
<div style="position:absolute;right:20px;top:44px;z-index:20;width:180px;border-radius:12px;border:1px solid #E5E7EB;background:white;padding:6px;box-shadow:0 4px 20px rgba(0,0,0,0.12)">
|
|
|
|
|
<button type="button" onClick={() => openDetail(row)} style="display:flex;width:100%;align-items:center;gap:10px;border-radius:8px;padding:8px 12px;font-size:13px;color:#374151;background:none;border:none;cursor:pointer;text-align:left">View Role</button>
|
|
|
|
|
<button type="button" onClick={() => openEdit(row)} style="display:flex;width:100%;align-items:center;gap:10px;border-radius:8px;padding:8px 12px;font-size:13px;color:#374151;background:none;border:none;cursor:pointer;text-align:left">Edit Role</button>
|
|
|
|
|
<button type="button" style="display:flex;width:100%;align-items:center;gap:10px;border-radius:8px;padding:8px 12px;font-size:13px;color:#DC2626;background:none;border:none;cursor:pointer;text-align:left">Delete Role</button>
|
|
|
|
|
</div>
|
|
|
|
|
</Show>
|
feat(admin): pixel-perfect UI overhaul for department, designation, roles, employees pages
- Rewrote all layout/spacing with inline styles (Tailwind v4 doesn't generate most utility classes)
- AdminSidebar: all 37 modules in 9 groups, scrollable, 220px/64px collapse, no bottom user section
- AdminShell: header height 64px, user avatar top-right (Gmail-style), removed search bar
- Department: orange-only status badges, dark navy table header (white text), edge-to-edge table, View/Create/All tabs, View action in row menu, form with inline styles
- Designation: full rewrite matching department pattern — same tabs, filter bar, table, form
- Roles/Employees: compact filter bar and table cell sizing fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:56:55 +01:00
|
|
|
</td>
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
</tr>
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
2026-03-27 02:28:34 +01:00
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
</div>
|
2026-03-27 02:28:34 +01:00
|
|
|
</Show>
|
2026-03-25 22:15:06 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
{/* ── FORM VIEW ── */}
|
|
|
|
|
<Show when={view() === 'form'}>
|
|
|
|
|
<div style="margin-top:24px;display:flex;align-items:center;gap:24px;border-bottom:1px solid #E5E7EB">
|
|
|
|
|
<button type="button" onClick={() => setView('list')} style="padding-bottom:12px;font-size:14px;font-weight:500;color:#6B7280;background:none;border:none;cursor:pointer">All Roles</button>
|
|
|
|
|
<button type="button" style="padding-bottom:12px;font-size:14px;font-weight:500;color:#FF5E13;border-bottom:2px solid #FF5E13;background:none;cursor:pointer;margin-bottom:-1px">{editingId() ? 'Edit Role' : 'Create Role'}</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style="margin-top:24px;border-radius:16px;border:1px solid #E5E7EB;background:white;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden">
|
|
|
|
|
<div style="display:flex;align-items:center;gap:4px;border-bottom:1px solid #E5E7EB;padding:0 24px">
|
|
|
|
|
{(['general', 'permissions', 'settings'] as const).map((tab, i) => {
|
|
|
|
|
const labels = ['General Information', 'Module Access', 'Role Settings'];
|
|
|
|
|
const active = () => formTab() === tab;
|
|
|
|
|
return (
|
|
|
|
|
<button type="button" onClick={() => setFormTab(tab)} style={`position:relative;padding:14px 8px;font-size:13px;font-weight:500;background:none;border:none;cursor:pointer;color:${active() ? '#FF5E13' : '#6B7280'}`}>
|
|
|
|
|
{labels[i]}
|
|
|
|
|
<Show when={active()}><span style="position:absolute;left:0;right:0;bottom:0;height:2px;background:#FF5E13;border-radius:2px 2px 0 0" /></Show>
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
})}
|
2026-03-27 02:28:34 +01:00
|
|
|
</div>
|
|
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
<div style="padding:24px">
|
|
|
|
|
<Show when={formTab() === 'general'}>
|
2026-03-27 02:28:34 +01:00
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px">
|
2026-03-27 05:35:18 +01:00
|
|
|
<FormInput label="Role Name" required value={name()} onInput={setName} />
|
|
|
|
|
<FormInput label="Role Code" required value={code()} onInput={setCode} />
|
|
|
|
|
<FormInput label="Department" value={dept()} onInput={setDept} />
|
2026-03-27 02:28:34 +01:00
|
|
|
</div>
|
2026-03-27 05:35:18 +01:00
|
|
|
</Show>
|
2026-03-27 02:28:34 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
<Show when={formTab() === 'permissions'}>
|
|
|
|
|
<div style="border:1px solid #E5E7EB;border-radius:12px;overflow:hidden">
|
|
|
|
|
<table style="width:100%;border-collapse:collapse">
|
|
|
|
|
<thead style="background:#F9FAFB">
|
|
|
|
|
<tr style="text-align:left">
|
|
|
|
|
<th style="padding:12px 16px;font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase">Module</th>
|
|
|
|
|
{['View', 'Create', 'Update', 'Delete'].map(p => (
|
|
|
|
|
<th style="padding:12px 16px;font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase;text-align:center">{p}</th>
|
|
|
|
|
))}
|
2026-03-27 02:28:34 +01:00
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<For each={MODULES}>
|
2026-03-27 05:35:18 +01:00
|
|
|
{(mod) => (
|
|
|
|
|
<tr style="border-top:1px solid #E5E7EB">
|
|
|
|
|
<td style="padding:12px 16px;font-size:13px;font-weight:600;color:#111827">{mod}</td>
|
|
|
|
|
{[1, 2, 3, 4].map(() => (
|
|
|
|
|
<td style="padding:12px 16px;text-align:center">
|
|
|
|
|
<input type="checkbox" style="width:16px;height:16px;accent-color:#FF5E13" />
|
2026-03-27 02:28:34 +01:00
|
|
|
</td>
|
2026-03-27 05:35:18 +01:00
|
|
|
))}
|
|
|
|
|
</tr>
|
|
|
|
|
)}
|
2026-03-27 02:28:34 +01:00
|
|
|
</For>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
2026-03-27 05:35:18 +01:00
|
|
|
</Show>
|
2026-03-27 02:28:34 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
<Show when={formTab() === 'settings'}>
|
|
|
|
|
<div style="display:flex;flex-direction:column;gap:20px">
|
|
|
|
|
<div style="display:flex;align-items:center;justify-content:space-between;padding:12px;border-radius:8px;background:#F9FAFB;border:1px solid #E5E7EB">
|
|
|
|
|
<div>
|
|
|
|
|
<p style="font-size:13px;font-weight:600;color:#111827">Allow Role to Approve Requests</p>
|
|
|
|
|
<p style="font-size:12px;color:#6B7280">Users with this role can make final decisions in Approval Management.</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="width:40px;height:20px;background:#FF5E13;border-radius:10px;position:relative;cursor:pointer"><div style="width:16px;height:16px;background:white;border-radius:50%;position:absolute;top:2px;right:2px" /></div>
|
2026-03-27 02:28:34 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-27 05:35:18 +01:00
|
|
|
</Show>
|
|
|
|
|
</div>
|
feat(admin): pixel-perfect UI overhaul for department, designation, roles, employees pages
- Rewrote all layout/spacing with inline styles (Tailwind v4 doesn't generate most utility classes)
- AdminSidebar: all 37 modules in 9 groups, scrollable, 220px/64px collapse, no bottom user section
- AdminShell: header height 64px, user avatar top-right (Gmail-style), removed search bar
- Department: orange-only status badges, dark navy table header (white text), edge-to-edge table, View/Create/All tabs, View action in row menu, form with inline styles
- Designation: full rewrite matching department pattern — same tabs, filter bar, table, form
- Roles/Employees: compact filter bar and table cell sizing fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:56:55 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
<div style="display:flex;align-items:center;justify-content:flex-end;gap:10px;border-top:1px solid #E5E7EB;padding:14px 24px">
|
|
|
|
|
<button type="button" onClick={() => setView('list')} style="height:38px;border-radius:10px;border:1px solid #E5E7EB;background:white;padding:0 20px;font-size:13px;font-weight:600;color:#374151;cursor:pointer">Cancel</button>
|
|
|
|
|
<button type="button" style="height:38px;border-radius:10px;background:#0D0D2A;padding:0 24px;font-size:13px;font-weight:600;color:white;border:none;cursor:pointer">
|
|
|
|
|
{editingId() ? 'Update Role' : 'Create Role'}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Show>
|
feat(admin): redesign sidebar, dashboard, dept, designation & roles UI
- Sidebar: white bg, rounded pill nav items, orange left indicator for active
- Dashboard: remove Export/View All buttons, add Customise Dashboard + drag handles on widgets
- Department/Designation/Roles: new design system with orange label header, stat cards, light table header, 3-dot action menus, status badges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-26 08:01:23 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
{/* ── DETAIL VIEW ── */}
|
|
|
|
|
<Show when={view() === 'detail' && viewingRole()}>
|
|
|
|
|
<div style="margin-top:24px;border-radius:16px;border:1px solid #E5E7EB;background:white;box-shadow:0 1px 4px rgba(0,0,0,0.06);overflow:hidden">
|
|
|
|
|
<div style="padding:24px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;justify-content:space-between">
|
|
|
|
|
<div>
|
|
|
|
|
<div style="display:flex;align-items:center;gap:12px">
|
|
|
|
|
<h2 style="font-size:20px;font-weight:700;color:#111827">{viewingRole()!.name}</h2>
|
|
|
|
|
<StatusBadge status={viewingRole()!.status} />
|
2026-03-27 02:28:34 +01:00
|
|
|
</div>
|
2026-03-27 05:35:18 +01:00
|
|
|
<p style="font-size:14px;color:#6B7280;margin-top:2px">Code: {viewingRole()!.code} • Dept: {viewingRole()!.department} • Assigned: {viewingRole()!.usersAssigned} users</p>
|
2026-03-27 02:28:34 +01:00
|
|
|
</div>
|
2026-03-27 05:35:18 +01:00
|
|
|
<button type="button" onClick={() => openEdit(viewingRole()!)} style="height:36px;border-radius:8px;background:#0D0D2A;padding:0 16px;font-size:13px;font-weight:600;color:white;border:none;cursor:pointer">Edit Role</button>
|
|
|
|
|
</div>
|
feat(admin): pixel-perfect UI overhaul for department, designation, roles, employees pages
- Rewrote all layout/spacing with inline styles (Tailwind v4 doesn't generate most utility classes)
- AdminSidebar: all 37 modules in 9 groups, scrollable, 220px/64px collapse, no bottom user section
- AdminShell: header height 64px, user avatar top-right (Gmail-style), removed search bar
- Department: orange-only status badges, dark navy table header (white text), edge-to-edge table, View/Create/All tabs, View action in row menu, form with inline styles
- Designation: full rewrite matching department pattern — same tabs, filter bar, table, form
- Roles/Employees: compact filter bar and table cell sizing fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:56:55 +01:00
|
|
|
|
2026-03-27 05:35:18 +01:00
|
|
|
<div style="display:flex;align-items:center;gap:4px;border-bottom:1px solid #E5E7EB;padding:0 24px;background:#FAFAFA">
|
|
|
|
|
{(['permissions', 'users', 'logs'] as const).map((tab, i) => {
|
|
|
|
|
const labels = ['Permissions', 'Assigned Users', 'Activity Logs'];
|
|
|
|
|
const active = () => detailTab() === tab;
|
|
|
|
|
return (
|
|
|
|
|
<button type="button" onClick={() => setDetailTab(tab)} style={`position:relative;padding:14px 12px;font-size:13px;font-weight:600;background:none;border:none;cursor:pointer;color:${active() ? '#FF5E13' : '#6B7280'}`}>
|
|
|
|
|
{labels[i]}
|
|
|
|
|
<Show when={active()}><span style="position:absolute;left:0;right:0;bottom:0;height:2px;background:#FF5E13;border-radius:2px 2px 0 0" /></Show>
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style="padding:24px">
|
|
|
|
|
<Show when={detailTab() === 'permissions'}>
|
|
|
|
|
<div style="border:1px solid #E5E7EB;border-radius:12px;overflow:hidden;opacity:0.7">
|
|
|
|
|
<table style="width:100%;border-collapse:collapse">
|
|
|
|
|
<thead style="background:#F9FAFB">
|
|
|
|
|
<tr style="text-align:left">
|
|
|
|
|
<th style="padding:12px 16px;font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase">Module</th>
|
|
|
|
|
{['View', 'Create', 'Update', 'Delete'].map(p => (
|
|
|
|
|
<th style="padding:12px 16px;font-size:11px;font-weight:600;color:#6B7280;text-transform:uppercase;text-align:center">{p}</th>
|
|
|
|
|
))}
|
|
|
|
|
</tr>
|
|
|
|
|
</thead>
|
|
|
|
|
<tbody>
|
|
|
|
|
<For each={MODULES}>
|
|
|
|
|
{(mod) => (
|
|
|
|
|
<tr style="border-top:1px solid #E5E7EB">
|
|
|
|
|
<td style="padding:12px 16px;font-size:13px;font-weight:600;color:#111827">{mod}</td>
|
|
|
|
|
{[1, 2, 3, 4].map(() => (
|
|
|
|
|
<td style="padding:12px 16px;text-align:center">
|
|
|
|
|
<input type="checkbox" checked disabled style="width:16px;height:16px;accent-color:#FF5E13" />
|
|
|
|
|
</td>
|
|
|
|
|
))}
|
|
|
|
|
</tr>
|
|
|
|
|
)}
|
|
|
|
|
</For>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<Show when={detailTab() === 'users'}>
|
|
|
|
|
<div style="padding:20px;text-align:center;font-size:14px;color:#6B7280">Users assigned to this role will appear here.</div>
|
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
<Show when={detailTab() === 'logs'}>
|
|
|
|
|
<div style="display:flex;flex-direction:column;gap:16px">
|
|
|
|
|
<div style="display:flex;gap:12px">
|
|
|
|
|
<div style="width:8px;height:8px;border-radius:50%;background:#FF5E13;margin-top:4px" />
|
|
|
|
|
<div>
|
|
|
|
|
<p style="font-size:13px;font-weight:600;color:#111827">Permissions Updated</p>
|
|
|
|
|
<p style="font-size:12px;color:#6B7280">Admin modified module access levels • 1 day ago</p>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Show>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div style="padding:16px 24px;border-top:1px solid #E5E7EB;display:flex;justify-content:flex-end">
|
|
|
|
|
<button type="button" onClick={() => { setView('list'); setListTab('all'); }} style="height:36px;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 16px;font-size:13px;font-weight:600;color:#374151;cursor:pointer">Back to List</button>
|
feat(admin): pixel-perfect UI overhaul for department, designation, roles, employees pages
- Rewrote all layout/spacing with inline styles (Tailwind v4 doesn't generate most utility classes)
- AdminSidebar: all 37 modules in 9 groups, scrollable, 220px/64px collapse, no bottom user section
- AdminShell: header height 64px, user avatar top-right (Gmail-style), removed search bar
- Department: orange-only status badges, dark navy table header (white text), edge-to-edge table, View/Create/All tabs, View action in row menu, form with inline styles
- Designation: full rewrite matching department pattern — same tabs, filter bar, table, form
- Roles/Employees: compact filter bar and table cell sizing fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 01:56:55 +01:00
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-03-27 02:28:34 +01:00
|
|
|
</Show>
|
2026-03-27 05:35:18 +01:00
|
|
|
|
ui(step-1): match reference layout for dept/designation/employees/roles pages
- All pages: white sticky page header + tab bar with orange underline,
-mx-6 -mt-6 negative margin to stretch headers edge-to-edge
- department: full columns (ID, Name, Description, Created By, etc.),
icon-only action buttons, navy Add Department button
- designation: Designations List / Add Designation tabs, status filter
dropdown, inline create/edit form, full columns with status badge
- employees: View/Add tabs, icon-only action buttons, status badges
- roles/index: clean table with Name+code subtext, Description, actions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 04:47:05 +01:00
|
|
|
</div>
|
feat(admin): build complete admin panel with UI parity and search/filter
- Implement all admin management pages (employees, users, jobs, leads, orders, companies, customers, candidates, approval, invoices, reviews, support, KB, pricing, coupons, credits, discounts, tax, reports, ledger)
- Implement 9 professional vertical pages (developers, designers, tutors, video editors, photographers, makeup artists, graphic designers, social media managers, fitness trainers)
- Implement internal/external dashboard and role management with builder UI
- Fix tab styling: replace inline border-bottom styles with admin-tab CSS class across 8+ pages
- Add search/filter functionality to invoice and review pages
- Add toggle status (activate/deactivate) to employees page with PATCH /api/admin/employees/{id}
- Align UI styling with NextJS admin panel for visual parity
- Add stat cards to approval page showing counts by status
- Implement graceful empty states for all list views
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-19 13:04:10 +01:00
|
|
|
</AdminShell>
|
|
|
|
|
);
|
|
|
|
|
}
|