- Add email management page with template listing - Add email preview with iframe - Add test email sending functionality - Add Email Management to sidebar navigation
483 lines
13 KiB
TypeScript
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>
|
|
);
|
|
}
|