nxtgauge-admin-solid/src/components/AdminSidebar.tsx
Ashwin Kumar 2409d85b3c feat(admin): add email management page with preview and test functionality
- Add email management page with template listing

- Add email preview with iframe

- Add test email sending functionality

- Add Email Management to sidebar navigation
2026-04-10 04:50:00 +02:00

483 lines
13 KiB
TypeScript

import { A, useLocation } from "@solidjs/router";
import { For, Show, createMemo } from "solid-js";
import {
LayoutGrid,
Building2,
Briefcase,
Users,
ShieldCheck,
FileText,
LayoutDashboard,
ClipboardList,
UserRoundSearch,
UserCircle,
Camera,
Palette,
BookOpen,
Code2,
BriefcaseBusiness,
HandHelping,
WalletCards,
CreditCard,
Tag,
Percent,
Receipt,
ShoppingCart,
FileCheck,
Star,
HeadphonesIcon,
BarChart3,
ChevronLeft,
BadgeCheck,
Activity,
Film,
Utensils,
PenTool,
Mail,
Megaphone,
Bell,
Video,
} from "lucide-solid";
type NavItem = {
href: string;
label: string;
icon: any;
aliasPrefix?: string;
moduleKeys?: string[];
};
const GROUPS: NavItem[][] = [
[
{
href: "/admin",
label: "Dashboard",
icon: LayoutGrid,
moduleKeys: ["ADMIN_DASHBOARD", "DASHBOARD"],
},
],
[
{
href: "/admin/department",
label: "Department Management",
icon: Building2,
moduleKeys: ["DEPARTMENT_MANAGEMENT", "DEPARTMENTS"],
},
{
href: "/admin/designation",
label: "Designation Management",
icon: Briefcase,
moduleKeys: ["DESIGNATION_MANAGEMENT", "DESIGNATIONS"],
},
{
href: "/admin/roles",
label: "Internal Role Management",
icon: ShieldCheck,
moduleKeys: ["INTERNAL_ROLE_MANAGEMENT", "ROLES"],
},
{
href: "/admin/employees",
label: "Employee Management",
icon: Users,
moduleKeys: ["EMPLOYEE_MANAGEMENT", "EMPLOYEES"],
},
],
[
{
href: "/admin/external-roles",
label: "External Role Management",
icon: ShieldCheck,
moduleKeys: ["EXTERNAL_ROLE_MANAGEMENT", "EXTERNAL_ROLES"],
},
{
href: "/admin/internal-dashboard-management",
label: "Internal Dashboard Management",
icon: LayoutDashboard,
moduleKeys: [
"INTERNAL_DASHBOARD_MANAGEMENT",
"INTERNAL_DASHBOARDS",
"INTERNAL_DASHBOARD_CONFIG",
],
},
{
href: "/admin/external-dashboard-management",
label: "External Dashboard Management",
icon: LayoutDashboard,
aliasPrefix: "/admin/role-ui-configs",
moduleKeys: [
"DASHBOARD_CONFIG_MANAGEMENT",
"EXTERNAL_DASHBOARD_MANAGEMENT",
"EXTERNAL_DASHBOARDS",
"EXTERNAL_DASHBOARD_CONFIG",
"RUNTIME_ROLES",
],
},
],
[
{
href: "/admin/verification",
label: "Verification Management",
icon: BadgeCheck,
moduleKeys: ["VERIFICATION_MANAGEMENT", "VERIFICATIONS"],
},
{
href: "/admin/approval",
label: "Approval Management",
icon: ClipboardList,
moduleKeys: ["APPROVAL_MANAGEMENT", "APPROVALS"],
},
],
[
{
href: "/admin/users",
label: "Users Management",
icon: UserRoundSearch,
moduleKeys: ["USER_MANAGEMENT", "USERS"],
},
{
href: "/admin/company",
label: "Company Management",
icon: Building2,
moduleKeys: ["COMPANY_MANAGEMENT", "COMPANIES"],
},
{
href: "/admin/candidate",
label: "Candidate Management",
icon: UserCircle,
moduleKeys: ["CANDIDATE_MANAGEMENT", "CANDIDATES"],
},
{
href: "/admin/customer",
label: "Customer Management",
icon: UserCircle,
moduleKeys: ["CUSTOMER_MANAGEMENT", "CUSTOMERS"],
},
],
[
{
href: "/admin/photographer",
label: "Photographer Management",
icon: Camera,
moduleKeys: ["PHOTOGRAPHER_MANAGEMENT", "PHOTOGRAPHERS"],
},
{
href: "/admin/makeup-artist",
label: "Makeup Artist Management",
icon: Palette,
moduleKeys: ["MAKEUP_ARTIST_MANAGEMENT", "MAKEUP_ARTISTS"],
},
{
href: "/admin/tutors",
label: "Tutors Management",
icon: BookOpen,
moduleKeys: ["TUTOR_MANAGEMENT", "TUTORS"],
},
{
href: "/admin/developers",
label: "Developers Management",
icon: Code2,
moduleKeys: ["DEVELOPER_MANAGEMENT", "DEVELOPERS"],
},
{
href: "/admin/video-editors",
label: "Video Editor Management",
icon: Film,
moduleKeys: ["VIDEO_EDITOR_MANAGEMENT", "VIDEO_EDITORS"],
},
{
href: "/admin/fitness-trainers",
label: "Fitness Trainer Management",
icon: Activity,
moduleKeys: ["FITNESS_TRAINER_MANAGEMENT", "FITNESS_TRAINERS"],
},
{
href: "/admin/catering-services",
label: "Catering Services Management",
icon: Utensils,
moduleKeys: ["CATERING_SERVICES_MANAGEMENT", "CATERING_SERVICES"],
},
{
href: "/admin/graphic-designers",
label: "Graphics Designer Management",
icon: PenTool,
moduleKeys: ["GRAPHIC_DESIGNER_MANAGEMENT", "GRAPHIC_DESIGNERS"],
},
{
href: "/admin/social-media-managers",
label: "Social Media Manager Management",
icon: Megaphone,
moduleKeys: [
"SOCIAL_MEDIA_MANAGEMENT",
"SOCIAL_MEDIA_MANAGER_MANAGEMENT",
"SOCIAL_MEDIA_MANAGERS",
],
},
{
href: "/admin/ugc-content-creator",
label: "UGC Content Creator Management",
icon: Video,
moduleKeys: ["UGC_CONTENT_CREATOR_MANAGEMENT", "UGC_CONTENT_CREATOR"],
},
],
[
{
href: "/admin/jobs",
label: "Jobs Management",
icon: BriefcaseBusiness,
moduleKeys: ["JOBS_MANAGEMENT", "JOBS"],
},
{
href: "/admin/leads",
label: "Leads Management",
icon: HandHelping,
moduleKeys: ["LEADS_MANAGEMENT", "LEADS", "REQUIREMENTS_MANAGEMENT", "REQUIREMENTS"],
},
],
[
{
href: "/admin/pricing",
label: "Pricing Management",
icon: WalletCards,
moduleKeys: ["PRICING_MANAGEMENT", "PRICING"],
},
{
href: "/admin/credit",
label: "Credit Management",
icon: CreditCard,
moduleKeys: ["CREDIT_MANAGEMENT", "CREDITS"],
},
{
href: "/admin/coupon",
label: "Coupon Management",
icon: Tag,
moduleKeys: ["COUPON_MANAGEMENT", "COUPONS"],
},
{
href: "/admin/discount",
label: "Discount Management",
icon: Percent,
moduleKeys: ["DISCOUNT_MANAGEMENT", "DISCOUNTS"],
},
{
href: "/admin/tax",
label: "Tax Management",
icon: Receipt,
moduleKeys: ["TAX_MANAGEMENT", "TAXES"],
},
{
href: "/admin/order",
label: "Order Management",
icon: ShoppingCart,
moduleKeys: ["ORDER_MANAGEMENT", "ORDERS"],
},
{
href: "/admin/invoice",
label: "Invoice Management",
icon: FileCheck,
moduleKeys: ["INVOICE_MANAGEMENT", "INVOICES"],
},
{
href: "/admin/payment-gateway",
label: "Payment Gateway Management",
icon: CreditCard,
moduleKeys: ["PAYMENT_GATEWAY_MANAGEMENT", "PAYMENT_GATEWAY"],
},
{
href: "/admin/smtp",
label: "SMTP Management",
icon: Mail,
moduleKeys: ["SMTP_MANAGEMENT", "SMTP"],
},
{
href: "/admin/email-management",
label: "Email Management",
icon: Mail,
moduleKeys: ["EMAIL_MANAGEMENT", "EMAILS", "EMAIL_TEMPLATES"],
},
],
[
{
href: "/admin/kb",
label: "Knowledge Base Management",
icon: BookOpen,
moduleKeys: ["KNOWLEDGE_BASE_MANAGEMENT", "KNOWLEDGE_BASE", "KB"],
},
{
href: "/admin/notifications",
label: "Notifications",
icon: Bell,
moduleKeys: ["NOTIFICATIONS_MANAGEMENT", "NOTIFICATIONS"],
},
{
href: "/admin/review",
label: "Review Management",
icon: Star,
moduleKeys: ["REVIEW_MANAGEMENT", "REVIEWS"],
},
{
href: "/admin/support",
label: "Support Management",
icon: HeadphonesIcon,
moduleKeys: ["SUPPORT_MANAGEMENT", "SUPPORT"],
},
{
href: "/admin/report",
label: "Report Management",
icon: BarChart3,
moduleKeys: ["REPORT_MANAGEMENT", "REPORTS"],
},
{
href: "/admin/ledger",
label: "Ledger Management",
icon: Receipt,
moduleKeys: ["LEDGER", "LEDGER_MANAGEMENT"],
},
],
];
export default function AdminSidebar(props: {
collapsed: boolean;
onToggle: () => void;
onNavigate?: () => void;
adminName: string;
adminInitials: string;
theme?: "light" | "dark";
allowedModules?: string[] | null;
isSuperAdmin?: boolean;
}) {
const location = useLocation();
const allowed = createMemo(
() =>
new Set(
(props.allowedModules || [])
.map((m) =>
String(m || "")
.trim()
.toUpperCase()
)
.filter(Boolean)
)
);
const canShowItem = (item: NavItem) => {
if (props.isSuperAdmin) return true;
if (!props.allowedModules || props.allowedModules.length === 0) return true;
if (item.href === "/admin") return true;
const keys = item.moduleKeys || [];
for (const k of keys) if (allowed().has(String(k).toUpperCase())) return true;
return false;
};
const visibleGroups = createMemo(() =>
GROUPS.map((group) => group.filter((item) => canShowItem(item))).filter(
(group) => group.length > 0
)
);
const isActive = (item: NavItem) => {
if (location.pathname === "/admin") return item.href === "/admin";
if (item.href === "/admin") return false;
if (item.aliasPrefix && location.pathname.startsWith(item.aliasPrefix)) return true;
return location.pathname === item.href || location.pathname.startsWith(`${item.href}/`);
};
const isDark = () => props.theme === "dark";
return (
<aside
style={{
overflow: "hidden",
display: "flex",
"flex-direction": "column",
height: "100%",
background: isDark() ? "#0F172A" : "white",
"border-right": `1px solid ${isDark() ? "#1F2937" : "#E5E7EB"}`,
transition: "width 0.3s",
"flex-shrink": 0,
width: props.collapsed ? "64px" : "220px",
}}
>
{/* Logo area */}
<div
style={`position:relative;height:64px;display:flex;align-items:center;border-bottom:1px solid ${isDark() ? "#1F2937" : "#E5E7EB"};flex-shrink:0;padding:0 14px`}
>
<A
href="/admin"
onClick={props.onNavigate}
style="display:flex;align-items:center;gap:10px;text-decoration:none;overflow:hidden"
>
<Show
when={!props.collapsed}
fallback={
<img
src="/nxtgauge-icon.png"
alt="Nxtgauge"
style="width:32px;height:32px;object-fit:contain;flex-shrink:0"
/>
}
>
<img
src="/nxtgauge-logo.png"
alt="Nxtgauge"
style="height:44px;object-fit:contain;flex-shrink:0;max-width:180px"
/>
</Show>
</A>
<button
type="button"
onClick={props.onToggle}
style={`position:absolute;right:-10px;top:50%;transform:translateY(-50%);width:20px;height:20px;border-radius:50%;border:1px solid ${isDark() ? "#1F2937" : "#E5E7EB"};background:${isDark() ? "#111827" : "white"};box-shadow:0 1px 4px rgba(0,0,0,0.1);display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:10;color:${isDark() ? "#CBD5E1" : "#6B7280"}`}
aria-label={props.collapsed ? "Expand sidebar" : "Collapse sidebar"}
>
<ChevronLeft
size={11}
style={`transition:transform 0.3s;${props.collapsed ? "transform:rotate(180deg)" : ""}`}
/>
</button>
</div>
{/* Navigation */}
<nav style="flex:1;min-height:0;overflow-y:auto;padding:10px 8px">
<For each={visibleGroups()}>
{(group, gi) => (
<>
<Show when={gi() > 0}>
<div
style={`height:1px;background:${isDark() ? "#1F2937" : "#F3F4F6"};margin:6px 4px`}
/>
</Show>
<div style="display:flex;flex-direction:column;gap:1px">
<For each={group}>
{(item) => {
const active = () => isActive(item);
const Icon = item.icon;
return (
<A
href={item.href}
onClick={props.onNavigate}
title={props.collapsed ? item.label : undefined}
style={`display:flex;align-items:center;height:36px;border-radius:8px;text-decoration:none;padding:0 ${props.collapsed ? "0" : "10px"};transition:background 140ms ease,color 140ms ease;${props.collapsed ? "justify-content:center;" : ""}${active() ? "background:#FFF3EE;color:#FF5E13;" : `color:${isDark() ? "#CBD5E1" : "#6B7280"};`}`}
aria-current={active() ? "page" : undefined}
>
<Icon
size={16}
style={`flex-shrink:0;${active() ? "color:#FF5E13" : `color:${isDark() ? "#94A3B8" : "#9CA3AF"}`}`}
strokeWidth={active() ? 2.5 : 2}
/>
<Show when={!props.collapsed}>
<span style="margin-left:9px;font-size:12.5px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">
{item.label}
</span>
</Show>
</A>
);
}}
</For>
</div>
</>
)}
</For>
</nav>
</aside>
);
}