2026-04-15 06:23:29 +02:00
|
|
|
|
import { For, Show, createMemo, createSignal, onMount } from "solid-js";
|
|
|
|
|
|
import { useSearchParams } from "@solidjs/router";
|
|
|
|
|
|
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-04-15 06:23:29 +02:00
|
|
|
|
const API = "";
|
2026-03-26 20:58:39 +01:00
|
|
|
|
|
2026-03-26 06:20:22 +01:00
|
|
|
|
type DepartmentRecord = CrudRecord & {
|
|
|
|
|
|
code?: 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
|
|
|
|
description?: string;
|
2026-03-26 06:20:22 +01:00
|
|
|
|
totalEmployees?: number;
|
|
|
|
|
|
createdDate?: string;
|
|
|
|
|
|
departmentHead?: string;
|
|
|
|
|
|
departmentEmail?: 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
|
|
|
|
};
|
|
|
|
|
|
|
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
|
|
|
|
const permissionGroups = [
|
2026-04-15 06:23:29 +02:00
|
|
|
|
{
|
|
|
|
|
|
title: "Employee Management",
|
|
|
|
|
|
items: ["View Employees", "Create Employees", "Edit Employees", "Delete Employees"],
|
|
|
|
|
|
},
|
|
|
|
|
|
{ title: "Role Management", items: ["View Roles", "Assign Roles"] },
|
|
|
|
|
|
{ title: "Department Settings", items: ["Manage Department Settings"] },
|
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-26 20:58:39 +01:00
|
|
|
|
type DepartmentListResponse = {
|
|
|
|
|
|
departments?: any[];
|
|
|
|
|
|
data?: any[];
|
|
|
|
|
|
items?: any[];
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
function normalizeDepartment(item: any, idx: number): DepartmentRecord {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const status = String(item.status ?? "").toUpperCase();
|
|
|
|
|
|
const isActive =
|
|
|
|
|
|
typeof item.is_active === "boolean" ? item.is_active : status ? status === "ACTIVE" : true;
|
2026-03-26 20:58:39 +01:00
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
id: String(item.id ?? `dep-${idx + 1}`),
|
2026-04-15 06:23:29 +02:00
|
|
|
|
name: String(item.name ?? ""),
|
2026-03-27 19:22:55 +01:00
|
|
|
|
code: item.code ? String(item.code) : undefined,
|
|
|
|
|
|
description: item.description ? String(item.description) : undefined,
|
|
|
|
|
|
totalEmployees: Number(item.total_employees ?? 0),
|
|
|
|
|
|
departmentHead: item.department_head ? String(item.department_head) : undefined,
|
|
|
|
|
|
departmentEmail: item.department_email ? String(item.department_email) : undefined,
|
2026-04-15 06:23:29 +02:00
|
|
|
|
status: isActive ? "ACTIVE" : "INACTIVE",
|
|
|
|
|
|
updatedAt: String(item.updated_at ?? ""),
|
|
|
|
|
|
createdDate: String(item.created_at ?? ""),
|
2026-03-26 20:58:39 +01:00
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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
|
|
|
|
function StatusBadge(props: { status: string }) {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const active = () => props.status === "ACTIVE";
|
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
|
|
|
|
return (
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<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"}
|
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
|
|
|
|
</span>
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-04-15 06:23:29 +02:00
|
|
|
|
function FormInput(props: {
|
|
|
|
|
|
label: string;
|
|
|
|
|
|
required?: boolean;
|
|
|
|
|
|
value: string;
|
|
|
|
|
|
onInput: (v: string) => void;
|
|
|
|
|
|
placeholder?: string;
|
|
|
|
|
|
type?: string;
|
|
|
|
|
|
}) {
|
|
|
|
|
|
return (
|
|
|
|
|
|
<label style="display:block">
|
|
|
|
|
|
<span style="font-size:13px;font-weight:600;color:#374151">
|
|
|
|
|
|
{props.label}
|
|
|
|
|
|
{props.required && <span style="margin-left:2px;color:#FF5E13">*</span>}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
<input
|
|
|
|
|
|
type={props.type ?? "text"}
|
|
|
|
|
|
value={props.value}
|
|
|
|
|
|
onInput={(e) => props.onInput(e.currentTarget.value)}
|
|
|
|
|
|
placeholder={props.placeholder}
|
|
|
|
|
|
required={props.required}
|
|
|
|
|
|
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"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
);
|
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-26 06:20:22 +01:00
|
|
|
|
export default function DepartmentManagementPage() {
|
2026-03-26 20:58:39 +01:00
|
|
|
|
const [searchParams] = useSearchParams();
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const isPreview = () => searchParams._preview === "1";
|
|
|
|
|
|
|
|
|
|
|
|
const [view, setView] = createSignal<"list" | "form">("list");
|
|
|
|
|
|
const [formTab, setFormTab] = createSignal<"general" | "settings" | "permissions">("general");
|
|
|
|
|
|
const [listTab, setListTab] = createSignal<"all" | "create" | "view" | "inactive">("all");
|
|
|
|
|
|
const [search, setSearch] = createSignal("");
|
|
|
|
|
|
const [statusFilter, setStatusFilter] = createSignal("all");
|
|
|
|
|
|
const [sortBy, setSortBy] = createSignal<
|
|
|
|
|
|
"name_asc" | "name_desc" | "employees_desc" | "employees_asc"
|
|
|
|
|
|
>("name_asc");
|
2026-03-26 20:58:39 +01:00
|
|
|
|
const [sortMenuOpen, setSortMenuOpen] = createSignal(false);
|
|
|
|
|
|
const [filterMenuOpen, setFilterMenuOpen] = createSignal(false);
|
2026-03-26 06:20:22 +01:00
|
|
|
|
const [rows, setRows] = createSignal<DepartmentRecord[]>([]);
|
|
|
|
|
|
const [openMenuId, setOpenMenuId] = createSignal<string | null>(null);
|
2026-03-30 04:48:09 +02:00
|
|
|
|
const [openMenuPos, setOpenMenuPos] = createSignal({ x: 0, y: 0 });
|
2026-03-26 06:20:22 +01:00
|
|
|
|
const [editingId, setEditingId] = createSignal<string | null>(null);
|
2026-03-27 02:05:28 +01:00
|
|
|
|
const [viewingDept, setViewingDept] = createSignal<DepartmentRecord | null>(null);
|
2026-03-30 04:48:09 +02:00
|
|
|
|
const [deleteTarget, setDeleteTarget] = createSignal<DepartmentRecord | null>(null);
|
|
|
|
|
|
const [isDeleting, setIsDeleting] = createSignal(false);
|
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
|
|
|
|
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const [name, setName] = createSignal("");
|
|
|
|
|
|
const [code, setCode] = createSignal("");
|
|
|
|
|
|
const [description, setDescription] = createSignal("");
|
|
|
|
|
|
const [departmentHead, setDepartmentHead] = createSignal("");
|
|
|
|
|
|
const [departmentEmail, setDepartmentEmail] = createSignal("");
|
|
|
|
|
|
const [status, setStatus] = createSignal<"ACTIVE" | "INACTIVE">("ACTIVE");
|
2026-03-26 20:58:39 +01:00
|
|
|
|
const [isLoading, setIsLoading] = createSignal(false);
|
|
|
|
|
|
const [isSaving, setIsSaving] = createSignal(false);
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const [error, setError] = createSignal("");
|
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-26 06:20:22 +01:00
|
|
|
|
const load = async () => {
|
2026-03-26 20:58:39 +01:00
|
|
|
|
setIsLoading(true);
|
2026-04-15 06:23:29 +02:00
|
|
|
|
setError("");
|
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
|
|
|
|
try {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const accessToken =
|
|
|
|
|
|
typeof sessionStorage !== "undefined"
|
|
|
|
|
|
? sessionStorage.getItem("nxtgauge_admin_access_token") || ""
|
|
|
|
|
|
: "";
|
2026-03-27 19:22:55 +01:00
|
|
|
|
const params = new URLSearchParams({
|
2026-04-15 06:23:29 +02:00
|
|
|
|
page: "1",
|
|
|
|
|
|
per_page: "100",
|
2026-03-27 19:22:55 +01:00
|
|
|
|
q: search().trim(),
|
|
|
|
|
|
});
|
2026-04-15 06:23:29 +02:00
|
|
|
|
if (statusFilter() !== "all") {
|
|
|
|
|
|
params.set("status", statusFilter());
|
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 21:25:00 +01:00
|
|
|
|
const res = await fetch(`${API}/api/admin/departments?${params.toString()}`, {
|
|
|
|
|
|
headers: {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
Accept: "application/json",
|
2026-03-27 21:25:00 +01:00
|
|
|
|
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
|
|
|
|
|
|
},
|
2026-04-15 06:23:29 +02:00
|
|
|
|
credentials: "include",
|
2026-03-27 21:25:00 +01:00
|
|
|
|
});
|
2026-03-27 19:22:55 +01:00
|
|
|
|
if (!res.ok) throw new Error(`Request failed (${res.status})`);
|
|
|
|
|
|
const payload = (await res.json().catch(() => null)) as DepartmentListResponse | null;
|
|
|
|
|
|
const list = Array.isArray(payload)
|
|
|
|
|
|
? payload
|
|
|
|
|
|
: Array.isArray(payload?.departments)
|
|
|
|
|
|
? payload.departments
|
|
|
|
|
|
: Array.isArray(payload?.data)
|
|
|
|
|
|
? payload.data
|
|
|
|
|
|
: Array.isArray(payload?.items)
|
|
|
|
|
|
? payload.items
|
|
|
|
|
|
: [];
|
|
|
|
|
|
setRows(list.map(normalizeDepartment));
|
|
|
|
|
|
} catch (err: any) {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
setError(err?.message || "Could not reach departments API.");
|
2026-03-27 19:22:55 +01:00
|
|
|
|
setRows([]);
|
2026-03-26 20:58:39 +01:00
|
|
|
|
} finally {
|
|
|
|
|
|
setIsLoading(false);
|
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-26 06:20:22 +01:00
|
|
|
|
onMount(() => void load());
|
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
|
|
|
|
|
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
|
|
|
|
const filteredRows = createMemo(() => {
|
|
|
|
|
|
let r = rows();
|
2026-04-15 06:23:29 +02:00
|
|
|
|
if (statusFilter() !== "all") r = r.filter((d) => d.status === statusFilter().toUpperCase());
|
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
|
|
|
|
const q = search().toLowerCase();
|
2026-03-26 20:58:39 +01:00
|
|
|
|
if (q) {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
r = r.filter(
|
|
|
|
|
|
(d) =>
|
|
|
|
|
|
d.name.toLowerCase().includes(q) ||
|
|
|
|
|
|
String(d.code ?? "")
|
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
|
.includes(q) ||
|
|
|
|
|
|
String(d.description ?? "")
|
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
|
.includes(q)
|
2026-03-26 20:58:39 +01:00
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
const sorted = [...r];
|
|
|
|
|
|
const mode = sortBy();
|
|
|
|
|
|
sorted.sort((a, b) => {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
if (mode === "name_desc") return b.name.localeCompare(a.name);
|
|
|
|
|
|
if (mode === "employees_desc")
|
|
|
|
|
|
return Number(b.totalEmployees || 0) - Number(a.totalEmployees || 0);
|
|
|
|
|
|
if (mode === "employees_asc")
|
|
|
|
|
|
return Number(a.totalEmployees || 0) - Number(b.totalEmployees || 0);
|
2026-03-26 20:58:39 +01:00
|
|
|
|
return a.name.localeCompare(b.name);
|
|
|
|
|
|
});
|
|
|
|
|
|
r = sorted;
|
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
|
|
|
|
return r;
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-03-26 06:20:22 +01:00
|
|
|
|
const resetForm = () => {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
setEditingId(null);
|
|
|
|
|
|
setName("");
|
|
|
|
|
|
setCode("");
|
|
|
|
|
|
setDescription("");
|
|
|
|
|
|
setDepartmentHead("");
|
|
|
|
|
|
setDepartmentEmail("");
|
|
|
|
|
|
setStatus("ACTIVE");
|
|
|
|
|
|
setFormTab("general");
|
|
|
|
|
|
setError("");
|
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-04-15 06:23:29 +02:00
|
|
|
|
const openCreate = () => {
|
|
|
|
|
|
resetForm();
|
|
|
|
|
|
setView("form");
|
|
|
|
|
|
};
|
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-26 06:20:22 +01:00
|
|
|
|
const openEdit = (row: DepartmentRecord) => {
|
|
|
|
|
|
setEditingId(row.id);
|
2026-04-15 06:23:29 +02:00
|
|
|
|
setName(row.name || "");
|
|
|
|
|
|
setCode(String(row.code || ""));
|
|
|
|
|
|
setDescription(String(row.description || ""));
|
|
|
|
|
|
setDepartmentHead(String(row.departmentHead || ""));
|
|
|
|
|
|
setDepartmentEmail(String(row.departmentEmail || ""));
|
|
|
|
|
|
setStatus(row.status === "INACTIVE" ? "INACTIVE" : "ACTIVE");
|
|
|
|
|
|
setFormTab("general");
|
|
|
|
|
|
setView("form");
|
|
|
|
|
|
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
|
|
|
|
};
|
|
|
|
|
|
|
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
|
|
|
|
const save = async () => {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
if (!name().trim()) {
|
|
|
|
|
|
setError("Department name is required.");
|
|
|
|
|
|
setFormTab("general");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!code().trim()) {
|
|
|
|
|
|
setError("Department code is required.");
|
|
|
|
|
|
setFormTab("general");
|
2026-03-26 20:58:39 +01:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
setIsSaving(true);
|
2026-04-15 06:23:29 +02:00
|
|
|
|
setError("");
|
2026-03-26 20:58:39 +01:00
|
|
|
|
const payload = {
|
|
|
|
|
|
name: name().trim(),
|
2026-04-15 06:23:29 +02:00
|
|
|
|
code: code().trim() || null,
|
2026-03-26 20:58:39 +01:00
|
|
|
|
description: description().trim() || null,
|
|
|
|
|
|
department_head: departmentHead().trim() || null,
|
|
|
|
|
|
department_email: departmentEmail().trim() || null,
|
|
|
|
|
|
status: status(),
|
2026-03-26 06:20:22 +01:00
|
|
|
|
};
|
2026-03-26 20:58:39 +01:00
|
|
|
|
|
|
|
|
|
|
try {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const accessToken =
|
|
|
|
|
|
typeof sessionStorage !== "undefined"
|
|
|
|
|
|
? sessionStorage.getItem("nxtgauge_admin_access_token") || ""
|
|
|
|
|
|
: "";
|
2026-03-26 20:58:39 +01:00
|
|
|
|
const endpoint = editingId()
|
|
|
|
|
|
? `${API}/api/admin/departments/${editingId()}`
|
|
|
|
|
|
: `${API}/api/admin/departments`;
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const method = editingId() ? "PATCH" : "POST";
|
2026-03-26 20:58:39 +01:00
|
|
|
|
const res = await fetch(endpoint, {
|
|
|
|
|
|
method,
|
2026-03-27 21:25:00 +01:00
|
|
|
|
headers: {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
|
|
Accept: "application/json",
|
2026-03-27 21:25:00 +01:00
|
|
|
|
...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
|
|
|
|
|
|
},
|
2026-04-15 06:23:29 +02:00
|
|
|
|
credentials: "include",
|
2026-03-26 20:58:39 +01:00
|
|
|
|
body: JSON.stringify(payload),
|
|
|
|
|
|
});
|
|
|
|
|
|
if (!res.ok) {
|
|
|
|
|
|
const body = await res.json().catch(() => ({}));
|
|
|
|
|
|
throw new Error((body as any).message || `Request failed (${res.status})`);
|
|
|
|
|
|
}
|
2026-04-15 06:23:29 +02:00
|
|
|
|
setView("list");
|
2026-03-26 20:58:39 +01:00
|
|
|
|
resetForm();
|
|
|
|
|
|
await load();
|
|
|
|
|
|
} catch (err: any) {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
setError(err?.message || "Failed to save department.");
|
2026-03-26 20:58:39 +01:00
|
|
|
|
} finally {
|
|
|
|
|
|
setIsSaving(false);
|
2026-03-26 06:20:22 +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
|
|
|
|
};
|
|
|
|
|
|
|
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
|
|
|
|
const formatDate = (v?: string) => {
|
2026-04-15 06:23:29 +02:00
|
|
|
|
const s = v || "";
|
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
|
|
|
|
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return s;
|
2026-04-15 06:23:29 +02:00
|
|
|
|
return s.slice(0, 10) || "—";
|
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 (
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<div class="w-full space-y-6 pb-8">
|
|
|
|
|
|
{/* Page header */}
|
|
|
|
|
|
<div style="margin-bottom: 1.5rem">
|
|
|
|
|
|
<h1 class="text-[28px] font-bold leading-tight text-[#111827]">Department Management</h1>
|
|
|
|
|
|
<p class="mt-1 text-[14px] text-[#6B7280]">
|
|
|
|
|
|
Manage all departments and organizational structure
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</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-04-15 06:23:29 +02:00
|
|
|
|
{/* ── LIST VIEW ── */}
|
|
|
|
|
|
<Show when={view() === "list"}>
|
|
|
|
|
|
<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
|
|
|
|
{/* Tabs */}
|
|
|
|
|
|
<div style="margin-top:24px;display:flex;align-items:center;gap:24px;border-bottom:1px solid #E5E7EB">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
{(
|
|
|
|
|
|
[
|
|
|
|
|
|
{
|
|
|
|
|
|
key: "all",
|
|
|
|
|
|
label: "All Departments",
|
|
|
|
|
|
action: () => {
|
|
|
|
|
|
setListTab("all");
|
|
|
|
|
|
setStatusFilter("all");
|
|
|
|
|
|
void load();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
key: "create",
|
|
|
|
|
|
label: "Create Department",
|
|
|
|
|
|
action: () => {
|
|
|
|
|
|
setListTab("create");
|
|
|
|
|
|
openCreate();
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
{ key: "view", label: "View Department", action: () => setListTab("view") },
|
|
|
|
|
|
] as const
|
|
|
|
|
|
).map((tab) => (
|
2026-03-26 20:58:39 +01:00
|
|
|
|
<button
|
|
|
|
|
|
type="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
|
|
|
|
onClick={tab.action}
|
2026-04-15 06:23:29 +02:00
|
|
|
|
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"}`}
|
2026-03-26 20:58:39 +01:00
|
|
|
|
>
|
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
|
|
|
|
{tab.label}
|
2026-03-26 20:58:39 +01:00
|
|
|
|
</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>
|
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:05:28 +01:00
|
|
|
|
{/* View Department panel */}
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<Show when={listTab() === "view"}>
|
|
|
|
|
|
<Show when={!viewingDept()}>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
<div style="margin-top:24px;border-radius:16px;border:1px solid #E5E7EB;background:white;padding:48px 24px;text-align:center">
|
|
|
|
|
|
<p style="font-size:15px;font-weight:600;color:#111827">No department selected</p>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<p style="margin-top:6px;font-size:13px;color:#6B7280">
|
|
|
|
|
|
Click the <strong>⋮</strong> menu on any department row and choose{" "}
|
|
|
|
|
|
<strong>View Department</strong>.
|
|
|
|
|
|
</p>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
<Show when={viewingDept()}>
|
|
|
|
|
|
<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">
|
|
|
|
|
|
{/* Header */}
|
|
|
|
|
|
<div style="padding:20px 24px;border-bottom:1px solid #E5E7EB;display:flex;align-items:center;justify-content:space-between">
|
|
|
|
|
|
<div>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<h2 style="font-size:18px;font-weight:700;color:#111827">
|
|
|
|
|
|
{viewingDept()!.name}
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
<p style="margin-top:2px;font-size:13px;color:#6B7280">
|
|
|
|
|
|
{viewingDept()!.description || "No description"}
|
|
|
|
|
|
</p>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
<StatusBadge status={viewingDept()!.status} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/* Details grid — 3 cols using flex rows */}
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<div style="display:flex;border-bottom:1px solid #F3F4F6">
|
|
|
|
|
|
<div style="flex:1;padding:16px 24px;border-right:1px solid #F3F4F6">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<p style="font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">
|
|
|
|
|
|
Department Code
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p style="margin-top:4px;font-size:14px;font-weight:600;color:#111827">
|
|
|
|
|
|
{viewingDept()!.code || "—"}
|
|
|
|
|
|
</p>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
<div style="flex:1;padding:16px 24px;border-right:1px solid #F3F4F6">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<p style="font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">
|
|
|
|
|
|
Department Head
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p style="margin-top:4px;font-size:14px;font-weight:600;color:#111827">
|
|
|
|
|
|
{viewingDept()!.departmentHead || "—"}
|
|
|
|
|
|
</p>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
<div style="flex:1;padding:16px 24px">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<p style="font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">
|
|
|
|
|
|
Department Email
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p style="margin-top:4px;font-size:14px;font-weight:600;color:#111827">
|
|
|
|
|
|
{viewingDept()!.departmentEmail || "—"}
|
|
|
|
|
|
</p>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style="display:flex;border-bottom:1px solid #F3F4F6">
|
|
|
|
|
|
<div style="flex:1;padding:16px 24px;border-right:1px solid #F3F4F6">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<p style="font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">
|
|
|
|
|
|
Total Employees
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p style="margin-top:4px;font-size:14px;font-weight:600;color:#111827">
|
|
|
|
|
|
{String(viewingDept()!.totalEmployees ?? 0)}
|
|
|
|
|
|
</p>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
|
2026-03-27 02:05:28 +01:00
|
|
|
|
<div style="flex:1;padding:16px 24px">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<p style="font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#9CA3AF">
|
|
|
|
|
|
Created Date
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p style="margin-top:4px;font-size:14px;font-weight:600;color:#111827">
|
|
|
|
|
|
{viewingDept()!.createdDate?.slice(0, 10) || "—"}
|
|
|
|
|
|
</p>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
{/* Actions */}
|
|
|
|
|
|
<div style="display:flex;align-items:center;gap:10px;padding:14px 24px;border-top:1px solid #E5E7EB">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => openEdit(viewingDept()!)}
|
|
|
|
|
|
style="height:36px;border-radius:8px;background:#0D0D2A;padding:0 16px;font-size:13px;font-weight:600;color:white;border:none;cursor:pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
Edit Department
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setViewingDept(null);
|
|
|
|
|
|
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>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
</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
|
|
|
|
{/* Table card */}
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<div style={{ display: listTab() === "view" ? "none" : "block" }}>
|
|
|
|
|
|
<div style="position:relative;margin-top:1.5rem;margin-left:-24px;margin-right:-24px;border-radius:0;border-left:none;border-right:none;overflow:visible;border-top:1px solid #E5E7EB;border-bottom:1px solid #E5E7EB;background:white;box-shadow:0 1px 3px rgba(0,0,0,0.06)">
|
|
|
|
|
|
{/* Filter bar */}
|
|
|
|
|
|
<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);
|
|
|
|
|
|
void load();
|
|
|
|
|
|
}}
|
|
|
|
|
|
placeholder="Search departments..."
|
|
|
|
|
|
style="height:34px;flex:1;border-radius:8px;border:1px solid #E5E7EB;background:white;padding:0 12px;font-size:13px;color:#111827;outline:none"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div style="position:relative">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setSortMenuOpen((v) => !v);
|
|
|
|
|
|
setFilterMenuOpen(false);
|
|
|
|
|
|
}}
|
|
|
|
|
|
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"
|
|
|
|
|
|
>
|
|
|
|
|
|
<svg
|
|
|
|
|
|
width="13"
|
|
|
|
|
|
height="13"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<path d="M7 4v13" />
|
|
|
|
|
|
<path d="m3 13 4 4 4-4" />
|
|
|
|
|
|
<path d="M17 20V7" />
|
|
|
|
|
|
<path d="m21 11-4-4-4 4" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
Sort
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<Show when={sortMenuOpen()}>
|
|
|
|
|
|
<div style="position:absolute;left:0;top:38px;z-index:30;min-width:200px;border-radius:12px;border:1px solid #E5E7EB;background:white;padding:6px;box-shadow:0 4px 16px rgba(0,0,0,0.1)">
|
|
|
|
|
|
{(["name_asc", "name_desc", "employees_desc", "employees_asc"] as const).map(
|
|
|
|
|
|
(s, i) => (
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setSortBy(s);
|
|
|
|
|
|
setSortMenuOpen(false);
|
|
|
|
|
|
}}
|
|
|
|
|
|
style={`display:block;width:100%;border-radius:8px;padding:8px 12px;text-align:left;font-size:13px;background:none;border:none;cursor:pointer;color:${sortBy() === s ? "#FF5E13" : "#374151"};background:${sortBy() === s ? "#FFF1EB" : "transparent"}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{
|
|
|
|
|
|
[
|
|
|
|
|
|
"Name (A-Z)",
|
|
|
|
|
|
"Name (Z-A)",
|
|
|
|
|
|
"Employees (High-Low)",
|
|
|
|
|
|
"Employees (Low-High)",
|
|
|
|
|
|
][i]
|
|
|
|
|
|
}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
)
|
|
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style="position:relative">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setFilterMenuOpen((v) => !v);
|
|
|
|
|
|
setSortMenuOpen(false);
|
|
|
|
|
|
}}
|
|
|
|
|
|
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"
|
|
|
|
|
|
>
|
|
|
|
|
|
<svg
|
|
|
|
|
|
width="13"
|
|
|
|
|
|
height="13"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<path d="M3 5h18M6 12h12M10 19h4" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
Filters
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<Show when={filterMenuOpen()}>
|
|
|
|
|
|
<div style="position:absolute;left:0;top:38px;z-index:30;min-width:160px;border-radius:12px;border:1px solid #E5E7EB;background:white;padding:6px;box-shadow:0 4px 16px rgba(0,0,0,0.1)">
|
|
|
|
|
|
{(["all", "active", "inactive"] as const).map((s) => (
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => {
|
|
|
|
|
|
setStatusFilter(s);
|
|
|
|
|
|
setFilterMenuOpen(false);
|
|
|
|
|
|
void load();
|
|
|
|
|
|
}}
|
|
|
|
|
|
style={`display:block;width:100%;border-radius:8px;padding:8px 12px;text-align:left;font-size:13px;background:none;border:none;cursor:pointer;color:${statusFilter() === s ? "#FF5E13" : "#374151"};background:${statusFilter() === s ? "#FFF1EB" : "transparent"}`}
|
|
|
|
|
|
>
|
|
|
|
|
|
{s === "all" ? "All Status" : s === "active" ? "Active" : "Inactive"}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
))}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
</div>
|
2026-03-26 20:58:39 +01:00
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
2026-04-15 06:23:29 +02:00
|
|
|
|
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"
|
2026-03-26 20:58:39 +01:00
|
|
|
|
>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<svg
|
|
|
|
|
|
width="13"
|
|
|
|
|
|
height="13"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
|
|
|
|
|
|
<polyline points="7 10 12 15 17 10" />
|
|
|
|
|
|
<line x1="12" y1="15" x2="12" y2="3" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
Export
|
2026-03-26 20:58:39 +01:00
|
|
|
|
</button>
|
|
|
|
|
|
</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-04-15 06:23:29 +02:00
|
|
|
|
{/* Table */}
|
|
|
|
|
|
<div class="overflow-x-auto overflow-y-visible">
|
|
|
|
|
|
<table class="min-w-full">
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr style="background:#0D0D2A;text-align:left">
|
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">
|
|
|
|
|
|
Department Name
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">
|
|
|
|
|
|
Department Code
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">
|
|
|
|
|
|
Description
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">
|
|
|
|
|
|
Total Employees
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">
|
|
|
|
|
|
Status
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">
|
|
|
|
|
|
Created Date
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th style="padding:10px 20px;font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em;color:#FFFFFF;white-space:nowrap">
|
|
|
|
|
|
Actions
|
|
|
|
|
|
</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<Show
|
|
|
|
|
|
when={filteredRows().length > 0}
|
|
|
|
|
|
fallback={
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td colspan="7" class="px-6 py-16 text-center">
|
|
|
|
|
|
<p class="text-[15px] font-semibold text-[#111827]">
|
|
|
|
|
|
No departments found
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p class="mt-1 text-[13px] text-[#6B7280]">
|
|
|
|
|
|
Create your first department to get started.
|
|
|
|
|
|
</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
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
2026-04-15 06:23:29 +02:00
|
|
|
|
onClick={openCreate}
|
|
|
|
|
|
class="mt-4 inline-flex items-center gap-2 rounded-xl bg-[#0D0D2A] px-4 py-2 text-[13px] font-semibold text-white"
|
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-04-15 06:23:29 +02:00
|
|
|
|
Create Department
|
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
|
|
|
|
</button>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
}
|
|
|
|
|
|
>
|
|
|
|
|
|
<For each={filteredRows()}>
|
|
|
|
|
|
{(row) => (
|
|
|
|
|
|
<tr
|
|
|
|
|
|
style="border-bottom:1px solid #F3F4F6"
|
|
|
|
|
|
class="hover:bg-[#FAFAFA] transition-colors"
|
|
|
|
|
|
>
|
|
|
|
|
|
<td style="padding:12px 20px">
|
|
|
|
|
|
<p style="font-size:14px;font-weight:600;color:#111827">{row.name}</p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="padding:12px 20px">
|
|
|
|
|
|
<span style="font-size:12px;font-family:monospace;color:#6B7280">
|
|
|
|
|
|
{String(row.code || "—")}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="padding:12px 20px;max-width:340px">
|
|
|
|
|
|
<p style="font-size:13px;color:#6B7280;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
|
|
|
|
|
|
{String(row.description || "—")}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="padding:12px 20px;font-size:14px;font-weight:600;color:#111827">
|
|
|
|
|
|
{Number(row.totalEmployees || 0)}
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="padding:12px 20px">
|
|
|
|
|
|
<StatusBadge status={row.status} />
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="padding:12px 20px;font-size:13px;color:#6B7280">
|
|
|
|
|
|
{formatDate(String(row.createdDate || row.updatedAt || ""))}
|
|
|
|
|
|
</td>
|
|
|
|
|
|
<td style="padding:12px 20px;position:relative">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={(e) => {
|
|
|
|
|
|
if (openMenuId() === row.id) {
|
|
|
|
|
|
setOpenMenuId(null);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
|
|
|
|
setOpenMenuPos({ x: rect.right, y: rect.top - 8 });
|
|
|
|
|
|
setOpenMenuId(row.id);
|
|
|
|
|
|
}}
|
|
|
|
|
|
class="inline-flex h-8 w-8 items-center justify-center rounded-lg text-[#9CA3AF] hover:bg-[#F3F4F6] hover:text-[#374151] transition-colors"
|
|
|
|
|
|
aria-label="More actions"
|
|
|
|
|
|
>
|
|
|
|
|
|
<svg
|
|
|
|
|
|
class="h-4 w-4"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
|
aria-hidden="true"
|
|
|
|
|
|
>
|
|
|
|
|
|
<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>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<Show when={openMenuId() === row.id}>
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={`position:fixed;left:${openMenuPos().x}px;top:${openMenuPos().y}px;transform:translate(-100%, -100%);z-index:9999;width:210px;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={() => {
|
|
|
|
|
|
setViewingDept(row);
|
|
|
|
|
|
setOpenMenuId(null);
|
|
|
|
|
|
setListTab("view");
|
|
|
|
|
|
}}
|
|
|
|
|
|
style="display:flex;width:100%;align-items:center;gap:10px;border-radius:8px;padding:10px 12px;font-size:13px;font-weight:500;color:#374151;background:none;border:none;cursor:pointer;text-align:left"
|
|
|
|
|
|
>
|
|
|
|
|
|
<svg
|
|
|
|
|
|
style="width:16px;height:16px;color:#FF5E13;flex-shrink:0"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" />
|
|
|
|
|
|
<circle cx="12" cy="12" r="3" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
View Department
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => openEdit(row)}
|
|
|
|
|
|
style="display:flex;width:100%;align-items:center;gap:10px;border-radius:8px;padding:10px 12px;font-size:13px;font-weight:500;color:#374151;background:none;border:none;cursor:pointer;text-align:left"
|
|
|
|
|
|
>
|
|
|
|
|
|
<svg
|
|
|
|
|
|
style="width:16px;height:16px;color:#FF5E13;flex-shrink:0"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<path d="M12 20h9" />
|
|
|
|
|
|
<path d="m16.5 3.5 4 4L7 21H3v-4L16.5 3.5Z" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
Edit Department
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={async () => {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await fetch(
|
|
|
|
|
|
`${API}/api/admin/departments/${row.id}`,
|
|
|
|
|
|
{
|
|
|
|
|
|
method: "PATCH",
|
|
|
|
|
|
headers: { "Content-Type": "application/json" },
|
|
|
|
|
|
body: JSON.stringify({
|
|
|
|
|
|
status:
|
|
|
|
|
|
row.status === "ACTIVE" ? "INACTIVE" : "ACTIVE",
|
|
|
|
|
|
}),
|
|
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
if (!res.ok)
|
|
|
|
|
|
throw new Error(`Request failed (${res.status})`);
|
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
|
setError(err?.message || "Failed to update status.");
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setOpenMenuId(null);
|
|
|
|
|
|
await load();
|
|
|
|
|
|
}
|
|
|
|
|
|
}}
|
|
|
|
|
|
style="display:flex;width:100%;align-items:center;gap:10px;border-radius:8px;padding:10px 12px;font-size:13px;font-weight:500;color:#374151;background:none;border:none;cursor:pointer;text-align:left"
|
|
|
|
|
|
>
|
|
|
|
|
|
<svg
|
|
|
|
|
|
style="width:16px;height:16px;color:#FF5E13;flex-shrink:0"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<circle cx="12" cy="12" r="9" />
|
|
|
|
|
|
<path d="M9 12l2 2 4-4" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
{row.status === "ACTIVE"
|
|
|
|
|
|
? "Deactivate Department"
|
|
|
|
|
|
: "Activate Department"}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<div style="height:1px;background:#F3F4F6;margin:4px 0" />
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={async () => {
|
|
|
|
|
|
setOpenMenuId(null);
|
|
|
|
|
|
setDeleteTarget(row);
|
|
|
|
|
|
}}
|
|
|
|
|
|
style="display:flex;width:100%;align-items:center;gap:10px;border-radius:8px;padding:10px 12px;font-size:13px;font-weight:500;color:#DC2626;background:none;border:none;cursor:pointer;text-align:left"
|
|
|
|
|
|
>
|
|
|
|
|
|
<svg
|
|
|
|
|
|
style="width:16px;height:16px;flex-shrink:0"
|
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
|
fill="none"
|
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
|
>
|
|
|
|
|
|
<path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v6M14 11v6" />
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
Delete Department
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</For>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
</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
|
|
|
|
|
2026-04-15 06:23:29 +02:00
|
|
|
|
{/* Pagination */}
|
|
|
|
|
|
<Show when={filteredRows().length > 0}>
|
|
|
|
|
|
<div style="display:flex;align-items:center;justify-content:space-between;border-top:1px solid #F3F4F6;padding:12px 20px">
|
|
|
|
|
|
<p style="font-size:13px;color:#6B7280">
|
|
|
|
|
|
Showing{" "}
|
|
|
|
|
|
<strong style="font-weight:600;color:#111827">1–{filteredRows().length}</strong>{" "}
|
|
|
|
|
|
of{" "}
|
|
|
|
|
|
<strong style="font-weight:600;color:#111827">{filteredRows().length}</strong>{" "}
|
|
|
|
|
|
departments
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<div style="display:flex;align-items:center;gap:4px">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
style="display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border-radius:7px;border:1px solid #E5E7EB;background:white;color:#6B7280;cursor:pointer;font-size:15px"
|
|
|
|
|
|
>
|
|
|
|
|
|
‹
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
style="display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border-radius:7px;background:#FF5E13;color:white;font-size:13px;font-weight:600;border:none;cursor:pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
1
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
style="display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border-radius:7px;border:1px solid #E5E7EB;background:white;color:#374151;font-size:13px;font-weight:500;cursor:pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
2
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
style="display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border-radius:7px;border:1px solid #E5E7EB;background:white;color:#374151;font-size:13px;font-weight:500;cursor:pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
3
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
style="display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;border-radius:7px;border:1px solid #E5E7EB;background:white;color:#6B7280;cursor:pointer;font-size:15px"
|
|
|
|
|
|
>
|
|
|
|
|
|
›
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
2026-03-26 00:01:15 +01:00
|
|
|
|
</div>
|
2026-04-15 06:23:29 +02: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
|
|
|
|
</div>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
|
|
<Show when={deleteTarget()}>
|
|
|
|
|
|
<div style="position:fixed;inset:0;z-index:10000;display:flex;align-items:center;justify-content:center;background:rgba(17,24,39,0.45);padding:16px">
|
|
|
|
|
|
<div style="width:min(92vw,480px);border-radius:16px;border:1px solid #E5E7EB;background:white;box-shadow:0 24px 48px rgba(0,0,0,0.2)">
|
|
|
|
|
|
<div style="padding:20px 22px;border-bottom:1px solid #F3F4F6">
|
|
|
|
|
|
<h3 style="font-size:18px;font-weight:700;color:#111827">Delete Department?</h3>
|
|
|
|
|
|
<p style="margin-top:8px;font-size:13px;line-height:1.5;color:#4B5563">
|
|
|
|
|
|
You are about to permanently delete
|
|
|
|
|
|
<strong style="color:#111827"> {deleteTarget()?.name}</strong>. This action cannot
|
|
|
|
|
|
be undone.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div style="display:flex;justify-content:flex-end;gap:10px;padding:14px 22px">
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => setDeleteTarget(null)}
|
|
|
|
|
|
disabled={isDeleting()}
|
|
|
|
|
|
style="height:38px;border-radius:10px;border:1px solid #E5E7EB;background:white;padding:0 14px;font-size:13px;font-weight:600;color:#374151;cursor:pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
Cancel
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
disabled={isDeleting()}
|
|
|
|
|
|
onClick={async () => {
|
|
|
|
|
|
const target = deleteTarget();
|
|
|
|
|
|
if (!target) return;
|
|
|
|
|
|
setIsDeleting(true);
|
|
|
|
|
|
try {
|
|
|
|
|
|
const res = await fetch(`${API}/api/admin/departments/${target.id}`, {
|
|
|
|
|
|
method: "DELETE",
|
|
|
|
|
|
});
|
|
|
|
|
|
if (!res.ok) throw new Error(`Request failed (${res.status})`);
|
|
|
|
|
|
setDeleteTarget(null);
|
|
|
|
|
|
await load();
|
|
|
|
|
|
} catch (err: any) {
|
|
|
|
|
|
setError(err?.message || "Failed to delete department.");
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
setIsDeleting(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
}}
|
|
|
|
|
|
style="height:38px;border-radius:10px;border:none;background:#0D0D2A;padding:0 14px;font-size:13px;font-weight:700;color:white;cursor:pointer"
|
|
|
|
|
|
>
|
|
|
|
|
|
{isDeleting() ? "Deleting..." : "Delete Department"}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
2026-03-27 02:05:28 +01:00
|
|
|
|
</div>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
|
|
|
|
|
|
{/* ── FORM VIEW (Create / Edit) ── */}
|
|
|
|
|
|
<Show when={view() === "form"}>
|
|
|
|
|
|
{/* Top tabs */}
|
|
|
|
|
|
<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 Departments
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
style="padding-bottom:12px;font-size:14px;font-weight:500;color:#FF5E13;border:none;border-bottom:2px solid #FF5E13;background:none;cursor:pointer;margin-bottom:-1px"
|
|
|
|
|
|
>
|
|
|
|
|
|
{editingId() ? "Edit Department" : "Create Department"}
|
|
|
|
|
|
</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">
|
|
|
|
|
|
{/* Sub-tabs */}
|
|
|
|
|
|
<div style="display:flex;align-items:center;gap:4px;border-bottom:1px solid #E5E7EB;padding:0 24px">
|
|
|
|
|
|
{(["general", "settings", "permissions"] as const).map((tab, i) => {
|
|
|
|
|
|
const labels = ["General Information", "Department Settings", "Permissions"];
|
|
|
|
|
|
const active = () => formTab() === tab;
|
|
|
|
|
|
return (
|
2026-03-30 04:48:09 +02:00
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
2026-04-15 06:23:29 +02:00
|
|
|
|
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"}`}
|
2026-03-30 04:48:09 +02:00
|
|
|
|
>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
{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>
|
2026-03-30 04:48:09 +02:00
|
|
|
|
</button>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
);
|
|
|
|
|
|
})}
|
2026-03-30 04:48:09 +02:00
|
|
|
|
</div>
|
2026-03-26 06:20:22 +01:00
|
|
|
|
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<div style="padding:24px">
|
|
|
|
|
|
<Show when={error()}>
|
|
|
|
|
|
<div style="margin-bottom:20px;border-radius:10px;border:1px solid #FECACA;background:#FEF2F2;padding:12px 16px;font-size:13px;color:#B91C1C">
|
|
|
|
|
|
{error()}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
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
|
|
|
|
|
2026-04-15 06:23:29 +02:00
|
|
|
|
{/* General Information */}
|
|
|
|
|
|
<Show when={formTab() === "general"}>
|
|
|
|
|
|
<div style="display:flex;flex-direction:column;gap:20px">
|
|
|
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px">
|
|
|
|
|
|
<FormInput
|
|
|
|
|
|
label="Department Name"
|
|
|
|
|
|
required
|
|
|
|
|
|
value={name()}
|
|
|
|
|
|
onInput={setName}
|
|
|
|
|
|
placeholder="e.g. Engineering"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<FormInput
|
|
|
|
|
|
label="Department Code"
|
|
|
|
|
|
required
|
|
|
|
|
|
value={code()}
|
|
|
|
|
|
onInput={setCode}
|
|
|
|
|
|
placeholder="e.g. ENG-001"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<label style="display:block">
|
|
|
|
|
|
<span style="font-size:13px;font-weight:600;color:#374151">Description</span>
|
|
|
|
|
|
<textarea
|
|
|
|
|
|
value={description()}
|
|
|
|
|
|
onInput={(e) => setDescription(e.currentTarget.value)}
|
|
|
|
|
|
placeholder="Brief description of this department's purpose..."
|
|
|
|
|
|
rows="3"
|
|
|
|
|
|
style="display:block;margin-top:6px;width:100%;border-radius:10px;border:1px solid #E5E7EB;background:white;padding:10px 14px;font-size:13px;color:#111827;outline:none;resize:none;box-sizing:border-box;font-family:inherit"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px">
|
|
|
|
|
|
<FormInput
|
|
|
|
|
|
label="Department Head"
|
|
|
|
|
|
value={departmentHead()}
|
|
|
|
|
|
onInput={setDepartmentHead}
|
|
|
|
|
|
placeholder="e.g. Arun Kumar"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<FormInput
|
|
|
|
|
|
label="Department Email"
|
|
|
|
|
|
type="email"
|
|
|
|
|
|
value={departmentEmail()}
|
|
|
|
|
|
onInput={setDepartmentEmail}
|
|
|
|
|
|
placeholder="dept@nxtgauge.com"
|
|
|
|
|
|
/>
|
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>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
</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-04-15 06:23:29 +02:00
|
|
|
|
{/* Department Settings */}
|
|
|
|
|
|
<Show when={formTab() === "settings"}>
|
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 style="display:flex;flex-direction:column;gap:32px">
|
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>
|
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
|
|
|
|
<p style="font-size:14px;font-weight:600;color:#111827">Department Status</p>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<p style="margin-top:2px;font-size:13px;color:#6B7280">
|
|
|
|
|
|
Set whether this department is currently active
|
|
|
|
|
|
</p>
|
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 style="margin-top:12px;display:flex;gap:10px">
|
2026-04-15 06:23:29 +02:00
|
|
|
|
{(["ACTIVE", "INACTIVE"] as const).map((s) => (
|
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
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => setStatus(s)}
|
2026-04-15 06:23:29 +02:00
|
|
|
|
style={`height:38px;border-radius:10px;padding:0 20px;font-size:13px;font-weight:600;cursor:pointer;border:1px solid ${status() === s ? "#FF5E13" : "#E5E7EB"};background:${status() === s ? "#FFF3EE" : "white"};color:${status() === s ? "#FF5E13" : "#6B7280"}`}
|
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-04-15 06:23:29 +02:00
|
|
|
|
{s === "ACTIVE" ? "Active" : "Inactive"}
|
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
|
|
|
|
</button>
|
|
|
|
|
|
))}
|
2026-03-26 06:20:22 +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
|
|
|
|
</div>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
</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-04-15 06:23:29 +02:00
|
|
|
|
<div>
|
|
|
|
|
|
<p style="font-size:14px;font-weight:600;color:#111827">Department Visibility</p>
|
|
|
|
|
|
<p style="margin-top:2px;font-size:13px;color:#6B7280">
|
|
|
|
|
|
Choose who can see this department
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<div style="margin-top:12px;display:grid;grid-template-columns:1fr 1fr;gap:12px">
|
|
|
|
|
|
{[
|
|
|
|
|
|
{
|
|
|
|
|
|
key: "INTERNAL",
|
|
|
|
|
|
label: "Internal",
|
|
|
|
|
|
desc: "Visible to internal employees only",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
key: "EXTERNAL",
|
|
|
|
|
|
label: "External",
|
|
|
|
|
|
desc: "Visible to external users and partners",
|
|
|
|
|
|
},
|
|
|
|
|
|
].map((opt) => (
|
|
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => setVisibility(opt.key as "INTERNAL" | "EXTERNAL")}
|
|
|
|
|
|
style={`display:flex;align-items:flex-start;gap:10px;border-radius:12px;border:1px solid ${visibility() === opt.key ? "#FF5E13" : "#E5E7EB"};background:${visibility() === opt.key ? "#FFF7ED" : "#F9FAFB"};padding:14px 16px;text-align:left;cursor:pointer`}
|
|
|
|
|
|
>
|
|
|
|
|
|
<div
|
|
|
|
|
|
style={`margin-top:2px;width:16px;height:16px;border-radius:50%;border:2px solid ${visibility() === opt.key ? "#FF5E13" : "#D1D5DB"};display:flex;align-items:center;justify-content:center;flex-shrink:0`}
|
2026-03-26 20:58:39 +01:00
|
|
|
|
>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<Show when={visibility() === opt.key}>
|
|
|
|
|
|
<div style="width:6px;height:6px;border-radius:50%;background:#FF5E13" />
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p style="font-size:13px;font-weight:600;color:#111827">{opt.label}</p>
|
|
|
|
|
|
<p style="margin-top:2px;font-size:12px;color:#6B7280">{opt.desc}</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
))}
|
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>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
</div>
|
2026-03-26 06:20:22 +01:00
|
|
|
|
|
2026-04-15 06:23:29 +02:00
|
|
|
|
<div style="display:flex;align-items:center;justify-content:space-between;border-radius:12px;border:1px solid #E5E7EB;background:#F9FAFB;padding:14px 16px">
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p style="font-size:13px;font-weight:600;color:#111827">
|
|
|
|
|
|
Allow Employee Transfers
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<p style="margin-top:2px;font-size:12px;color:#6B7280">
|
|
|
|
|
|
Employees can request to transfer into this department
|
|
|
|
|
|
</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-04-15 06:23:29 +02:00
|
|
|
|
<button
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => setTransfersEnabled((v) => !v)}
|
|
|
|
|
|
style={`position:relative;width:44px;height:24px;border-radius:12px;border:none;cursor:pointer;background:${transfersEnabled() ? "#FF5E13" : "#E5E7EB"};transition:background 0.2s;flex-shrink:0`}
|
|
|
|
|
|
>
|
|
|
|
|
|
<span
|
|
|
|
|
|
style={`position:absolute;top:2px;width:20px;height:20px;border-radius:50%;background:white;box-shadow:0 1px 3px rgba(0,0,0,0.2);transition:left 0.2s;left:${transfersEnabled() ? "22px" : "2px"}`}
|
|
|
|
|
|
/>
|
|
|
|
|
|
</button>
|
2026-03-26 06:20:22 +01:00
|
|
|
|
</div>
|
2026-04-15 06:23:29 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
2026-03-26 00:01:15 +01:00
|
|
|
|
|
2026-04-15 06:23:29 +02:00
|
|
|
|
{/* Permissions */}
|
|
|
|
|
|
<Show when={formTab() === "permissions"}>
|
|
|
|
|
|
<div style="display:flex;flex-direction:column;gap:24px">
|
|
|
|
|
|
<p style="font-size:13px;color:#6B7280">
|
|
|
|
|
|
Select the permissions available to employees in this department.
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<For each={permissionGroups}>
|
|
|
|
|
|
{(group) => (
|
|
|
|
|
|
<div>
|
|
|
|
|
|
<p style="margin-bottom:10px;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:0.08em;color:#9CA3AF">
|
|
|
|
|
|
{group.title}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px">
|
|
|
|
|
|
<For each={group.items}>
|
|
|
|
|
|
{(item) => (
|
|
|
|
|
|
<label style="display:flex;align-items:center;gap:10px;border-radius:10px;border:1px solid #E5E7EB;background:#F9FAFB;padding:10px 14px;cursor:pointer">
|
|
|
|
|
|
<input
|
|
|
|
|
|
type="checkbox"
|
|
|
|
|
|
style="width:14px;height:14px;accent-color:#FF5E13;cursor:pointer"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<span style="font-size:13px;font-weight:500;color:#374151">
|
|
|
|
|
|
{item}
|
|
|
|
|
|
</span>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</For>
|
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-04-15 06:23:29 +02:00
|
|
|
|
</div>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</For>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
2026-03-26 06:20:22 +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-04-15 06:23:29 +02:00
|
|
|
|
{/* Form actions */}
|
|
|
|
|
|
<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");
|
|
|
|
|
|
resetForm();
|
|
|
|
|
|
}}
|
|
|
|
|
|
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"
|
|
|
|
|
|
onClick={() => void save()}
|
|
|
|
|
|
disabled={isSaving()}
|
|
|
|
|
|
style="height:38px;border-radius:10px;background:#0D0D2A;padding:0 24px;font-size:13px;font-weight:600;color:white;border:none;cursor:pointer;opacity:1"
|
|
|
|
|
|
>
|
|
|
|
|
|
{isSaving() ? "Saving..." : editingId() ? "Update Department" : "Create Department"}
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</Show>
|
|
|
|
|
|
</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
|
|
|
|
);
|
|
|
|
|
|
}
|