nxtgauge-admin-solid/src/routes/admin/index.tsx

206 lines
11 KiB
TypeScript
Raw Normal View History

import { A } from '@solidjs/router';
import AdminShell from '~/components/AdminShell';
import {
Users, Building2, Briefcase, Clock, Ticket, Receipt,
Package, Megaphone, Shield, UserCog, FormInput, LayoutDashboard,
BadgeCheck, ArrowRight,
} from 'lucide-solid';
import type { Component } from 'solid-js';
type KpiCard = {
label: string;
value: string;
badge?: string;
badgeColor: string;
href: string;
icon: Component<any>;
};
const KPI: KpiCard[] = [
{ label: 'Total Users', value: '—', badge: '+0%', badgeColor: 'text-emerald-600 bg-emerald-50', href: '/admin/users', icon: Users },
{ label: 'Total Revenue', value: '—', badge: 'Weekly', badgeColor: 'text-[#0a1d37] bg-slate-100', href: '/admin/invoice', icon: Receipt },
{ label: 'Active Roles', value: '—', badge: 'Live', badgeColor: 'text-amber-600 bg-amber-50', href: '/admin/runtime-roles', icon: Briefcase},
{ label: 'Pending Approvals', value: '—', badge: 'Action Required', badgeColor: 'text-white bg-red-500', href: '/admin/approval', icon: Clock },
];
const ACTIVITY = [
{ day: 'MON', h: 40 }, { day: 'TUE', h: 65 }, { day: 'WED', h: 95 },
{ day: 'THU', h: 70 }, { day: 'FRI', h: 55 }, { day: 'SAT', h: 30 }, { day: 'SUN', h: 45 },
];
const QUICK_ACTIONS = [
{ label: 'Create New Role', href: '/admin/roles/create', icon: Shield },
{ label: 'Configure Dashboard', href: '/admin/external-dashboard-management', icon: LayoutDashboard },
{ label: 'Add Employee', href: '/admin/employees', icon: Users },
];
const PIPELINE = [
{ name: 'Candidate Roles', type: 'External Role', status: 'Active', statusColor: 'text-emerald-600 bg-emerald-50', progress: 85, barColor: 'bg-[#fd6216]' },
{ name: 'Onboarding Flows', type: 'Schema Builder', status: 'Pending', statusColor: 'text-amber-600 bg-amber-50', progress: 42, barColor: 'bg-amber-400' },
{ name: 'Dashboard Config', type: 'UI Config', status: 'Draft', statusColor: 'text-slate-500 bg-slate-100', progress: 12, barColor: 'bg-slate-300' },
];
const CONTROL: Array<{ label: string; href: string; desc: string; icon: Component<any>; iconBg: string; iconFg: string }> = [
{ label: 'Internal Roles', href: '/admin/roles', desc: 'Permissions & access levels for internal staff.', icon: Shield, iconBg: 'bg-blue-50', iconFg: 'text-blue-600' },
{ label: 'External Roles', href: '/admin/runtime-roles', desc: 'Modules, credits & capabilities per external role.', icon: UserCog, iconBg: 'bg-violet-50', iconFg: 'text-violet-600' },
{ label: 'Onboarding Flows', href: '/admin/onboarding-schemas', desc: 'Schema-driven onboarding forms per external role.', icon: FormInput, iconBg: 'bg-amber-50', iconFg: 'text-amber-600' },
{ label: 'External Dashboards', href: '/admin/external-dashboard-management', desc: 'Sidebar, widgets & runtimeConfig per role.', icon: LayoutDashboard, iconBg: 'bg-teal-50', iconFg: 'text-teal-600' },
{ label: 'Internal Dashboards', href: '/admin/internal-dashboard-management', desc: 'Home widgets & KPI panels for internal staff.', icon: LayoutDashboard, iconBg: 'bg-orange-50', iconFg: 'text-orange-600' },
{ label: 'Approval Queue', href: '/admin/approval', desc: 'Review, approve or reject pending action requests.', icon: BadgeCheck, iconBg: 'bg-rose-50', iconFg: 'text-rose-600' },
];
export default function AdminDashboard() {
return (
<AdminShell>
<div class="space-y-6">
{/* ── KPI Cards ── */}
<div class="grid grid-cols-2 gap-4 lg:grid-cols-4">
{KPI.map((kpi) => {
const Icon = kpi.icon;
return (
<A
href={kpi.href}
class="relative overflow-hidden rounded-xl bg-white p-5 shadow-[0_4px_20px_rgba(10,29,55,0.06)] transition-all duration-200 hover:-translate-y-px hover:shadow-[0_8px_28px_rgba(10,29,55,0.10)]"
>
{/* Left navy accent bar */}
<div class="absolute left-0 top-0 h-full w-1.5 rounded-l-xl bg-[#0a1d37]" />
<div class="flex items-start justify-between pl-1">
<div class="flex h-10 w-10 items-center justify-center rounded-lg bg-[#0a1d37]/6">
<Icon class="h-5 w-5 text-[#0a1d37]" />
</div>
{kpi.badge && (
<span class={`rounded-md px-2 py-0.5 text-[10px] font-bold ${kpi.badgeColor}`}>
{kpi.badge}
</span>
)}
</div>
<div class="mt-4 pl-1">
<h3 class="text-[10px] font-bold uppercase tracking-widest text-slate-400">
{kpi.label}
</h3>
<p class="mt-1 text-3xl font-black tracking-tight text-[#0a1d37]">
{kpi.value}
</p>
</div>
</A>
);
})}
</div>
{/* ── Activity + Intelligence Hub ── */}
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
{/* Activity Chart */}
<div class="lg:col-span-2 rounded-xl bg-white p-6 shadow-[0_4px_20px_rgba(10,29,55,0.06)]">
<div class="mb-6 flex items-end justify-between">
<div>
<h2 class="text-lg font-black tracking-tight text-[#0a1d37]">System Activity</h2>
<p class="mt-0.5 text-sm text-slate-400">Platform traffic & Tracecoin velocity</p>
</div>
<select class="rounded-lg border border-slate-200 bg-white py-1.5 pl-3 pr-8 text-xs font-semibold text-[#0a1d37] focus:outline-none focus:ring-2 focus:ring-[#0a1d37]/10">
<option>Last 7 Days</option>
<option>Last 30 Days</option>
</select>
</div>
<div class="flex h-44 items-end justify-between gap-2">
{ACTIVITY.map((d) => (
<div class="group flex flex-1 flex-col items-center gap-1.5">
<div
class={`w-full rounded-t-md transition-all duration-200 ${d.day === 'WED' ? 'bg-[#0a1d37] shadow-lg shadow-[#0a1d37]/20' : 'bg-slate-100 group-hover:bg-slate-300'}`}
style={`height: ${d.h}%`}
/>
<span class={`text-[10px] font-bold ${d.day === 'WED' ? 'text-[#0a1d37]' : 'text-slate-400'}`}>
{d.day}
</span>
</div>
))}
</div>
</div>
{/* Intelligence Hub + Pipeline */}
<div class="space-y-4">
{/* Intelligence Hub */}
<div class="relative overflow-hidden rounded-xl bg-[#0a1d37] p-5 text-white">
<div class="absolute -right-4 -top-4 h-20 w-20 rounded-full bg-white/5 blur-2xl" />
<h2 class="mb-3 text-base font-black">Intelligence Hub</h2>
<div class="space-y-2">
{QUICK_ACTIONS.map((a) => {
const Icon = a.icon;
return (
<A
href={a.href}
class="group flex w-full items-center justify-between rounded-lg bg-white/10 px-3.5 py-3 transition-all hover:bg-white/15"
>
<span class="text-[13px] font-semibold">{a.label}</span>
<Icon class="h-4 w-4 text-[#fd6216] transition-transform group-hover:translate-x-0.5" />
</A>
);
})}
</div>
</div>
{/* Pipeline Status */}
<div class="rounded-xl bg-white p-5 shadow-[0_4px_20px_rgba(10,29,55,0.06)]">
<h2 class="mb-4 text-[10px] font-bold uppercase tracking-widest text-[#0a1d37]">
Pipeline Status
</h2>
<div class="space-y-4">
{PIPELINE.map((p) => (
<div>
<div class="mb-1.5 flex items-center justify-between gap-2">
<div class="min-w-0">
<p class="truncate text-[13px] font-bold text-[#0a1d37]">{p.name}</p>
<p class="text-[10px] text-slate-400">{p.type}</p>
</div>
<span class={`shrink-0 rounded-md px-2 py-0.5 text-[10px] font-bold uppercase ${p.statusColor}`}>
{p.status}
</span>
</div>
<div class="h-1.5 w-full overflow-hidden rounded-full bg-slate-100">
<div class={`h-full rounded-full ${p.barColor}`} style={`width: ${p.progress}%`} />
</div>
</div>
))}
</div>
</div>
</div>
</div>
{/* ── Control Plane ── */}
<div>
<div class="mb-4 flex items-center justify-between">
<h2 class="text-lg font-black tracking-tight text-[#0a1d37]">Control Plane</h2>
<span class="rounded-md border border-slate-200 bg-white px-2.5 py-1 text-[10px] font-bold uppercase tracking-widest text-slate-400">
{CONTROL.length} modules
</span>
</div>
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
{CONTROL.map((item) => {
const Icon = item.icon;
return (
<A
href={item.href}
class="group flex items-start gap-3.5 rounded-xl border border-slate-100 bg-white p-4 shadow-[0_4px_20px_rgba(10,29,55,0.04)] transition-all duration-200 hover:-translate-y-px hover:border-[#0a1d37]/10 hover:shadow-[0_8px_28px_rgba(10,29,55,0.08)]"
>
<div class={`mt-0.5 flex h-8 w-8 shrink-0 items-center justify-center rounded-lg ${item.iconBg}`}>
<Icon class={`h-4 w-4 ${item.iconFg}`} />
</div>
<div class="min-w-0 flex-1">
<p class="truncate text-[13px] font-bold text-[#0a1d37] transition-colors group-hover:text-[#fd6216]">{item.label}</p>
<p class="mt-0.5 text-[11px] leading-relaxed text-slate-400">{item.desc}</p>
</div>
<ArrowRight class="mt-0.5 h-3.5 w-3.5 shrink-0 text-slate-200 transition-all group-hover:translate-x-0.5 group-hover:text-[#0a1d37]" />
</A>
);
})}
</div>
</div>
</div>
</AdminShell>
);
}