feat: enhance admin dashboard with real-time telematics, audit logs, and interactive management tools

This commit is contained in:
sazzadulalambd
2026-05-17 23:45:38 +06:00
parent 6870ca6b0f
commit f8a745ad42

View File

@@ -1,114 +1,623 @@
import { 'use client';
Users,
Bike,
DollarSign,
TrendingUp,
Activity,
ArrowUpRight,
ArrowDownRight,
Clock,
Shield,
AlertTriangle,
CheckCircle,
XCircle
} from 'lucide-react';
import { kycRequests, bikes, rentals, transactions } from '@/data/mockData';
const stats = [ import { useState, useEffect, useRef } from 'react';
{ label: 'Total Bikers', value: '156', change: '+12%', trend: 'up', icon: Users, color: 'text-blue-600', bg: 'bg-blue-50' }, import {
{ label: 'Active Rentals', value: '89', change: '+8%', trend: 'up', icon: Bike, color: 'text-green-600', bg: 'bg-green-50' }, Users, Bike, DollarSign, TrendingUp, Activity, ArrowUpRight, ArrowDownRight,
{ label: 'Daily Revenue', value: '৳45.6k', change: '+23%', trend: 'up', icon: DollarSign, color: 'text-purple-600', bg: 'bg-purple-50' }, Clock, Shield, AlertTriangle, CheckCircle, XCircle, Play, Sparkles, RefreshCw,
{ label: 'Fleet Utilization', value: '78%', change: '-2%', trend: 'down', icon: TrendingUp, color: 'text-amber-600', bg: 'bg-amber-50' }, Search, Lock, Unlock, Volume2, ShieldAlert, Cpu, Terminal, Database, Settings, HelpCircle, ChevronRight
} from 'lucide-react';
import { kycRequests as mockKycRequests, bikes as mockBikes, rentals as mockRentals, transactions as mockTransactions } from '@/data/mockData';
import toast from 'react-hot-toast';
import Link from 'next/link';
interface AuditLog {
id: string;
timestamp: string;
source: 'FLEET' | 'KYC' | 'SWAP' | 'ACCOUNTING' | 'USER';
level: 'info' | 'warning' | 'critical' | 'success';
message: string;
}
const initialAuditLogs: AuditLog[] = [
{ id: 'log-1', timestamp: '23:25:12', source: 'FLEET', level: 'info', message: 'EV Bike Plate Dhaka Metro-1290 reported battery status at 88%' },
{ id: 'log-2', timestamp: '23:24:45', source: 'KYC', level: 'success', message: 'Front Desk submitted TIN verification for Biker USR-009' },
{ id: 'log-3', timestamp: '23:22:10', source: 'SWAP', level: 'warning', message: 'Gulshan Swap Station Cabinet #5 reported abnormal temperature cell rise (48°C)' },
{ id: 'log-4', timestamp: '23:20:05', source: 'ACCOUNTING', level: 'info', message: 'Journal Draft JV-2026-004 auto-posted for Biker rental fee payment' },
{ id: 'log-5', timestamp: '23:18:15', source: 'USER', level: 'critical', message: 'Overdue Lock Pending for Bike Plate Dhaka Metro-5621 (Farid Ahmed)' }
]; ];
const pendingKYCs = kycRequests.filter(k => k.status === 'pending'); const mockLiveMessages = [
const activeRentals = rentals.filter(r => r.status === 'active'); { source: 'FLEET' as const, level: 'info' as const, message: 'GPS coordinates synced for Yadea DT3 (Dhaka Metro-004)' },
{ source: 'SWAP' as const, level: 'success' as const, message: 'Biker Rahim Ahmed completed battery swap in 18 seconds (Cabinet #2)' },
{ source: 'ACCOUNTING' as const, level: 'success' as const, message: 'Payment gateway captured ৳300 auto-inflow for single rent' },
{ source: 'FLEET' as const, level: 'warning' as const, message: 'Speed alert triggered: EV Dhaka Metro-1290 exceeded 55 km/h in urban zone' },
{ source: 'KYC' as const, level: 'info' as const, message: 'Biker Jamal Uddin completed verification of email address' },
{ source: 'SWAP' as const, level: 'critical' as const, message: 'Cabinet #8 in Banani Station reported battery lock failure' },
{ source: 'ACCOUNTING' as const, level: 'info' as const, message: 'Investor return ledger recalculated for gold plan tier' }
];
export default function AdminDashboard() { export default function AdminDashboard() {
// Live State
const [kycRequests, setKycRequests] = useState(mockKycRequests);
const [bikesList, setBikesList] = useState(mockBikes);
const [telematicsBikes, setTelematicsBikes] = useState([
{ id: 'tel-1', model: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', batteryLevel: 78, location: 'Gulshan 1', status: 'rented' }, // secure locked
{ id: 'tel-2', model: 'Yadea DT3', plateNumber: 'Dhaka Metro Cha-5678', batteryLevel: 95, location: 'Banani', status: 'available' }, // active unlocked
{ id: 'tel-3', model: 'AIMA Lightning', plateNumber: 'Dhaka Metro Cha-9012', batteryLevel: 62, location: 'Uttara', status: 'rented' }, // secure locked
{ id: 'tel-4', model: 'TVS iQube', plateNumber: 'Dhaka Metro Cha-3456', batteryLevel: 45, location: 'Workshop', status: 'available' } // active unlocked
]);
const [rentalsList, setRentalsList] = useState(mockRentals);
const [auditLogs, setAuditLogs] = useState<AuditLog[]>(initialAuditLogs);
const [activeChartMetric, setActiveChartMetric] = useState<'revenue' | 'utilization' | 'swaps'>('revenue');
// Interactive Filters & Searches
const [kycSearch, setKycSearch] = useState('');
const [fleetSearch, setFleetSearch] = useState('');
const [sandboxMode, setSandboxMode] = useState(true);
const [liveStreamActive, setLiveStreamActive] = useState(true);
// Real-time ticking time counter
const [systemTime, setSystemTime] = useState('');
// Controls drawer
const [showToolsDrawer, setShowToolsDrawer] = useState(false);
useEffect(() => {
// Clock update
const updateTime = () => {
const now = new Date();
setSystemTime(now.toLocaleTimeString());
};
updateTime();
const clockInterval = setInterval(updateTime, 1000);
// Live WebSocket simulator for Activity Log
let liveLogInterval: NodeJS.Timeout;
if (liveStreamActive) {
liveLogInterval = setInterval(() => {
const randMsg = mockLiveMessages[Math.floor(Math.random() * mockLiveMessages.length)];
const now = new Date();
const timestampStr = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
const newLog: AuditLog = {
id: `sim-log-${Date.now()}`,
timestamp: timestampStr,
source: randMsg.source,
level: randMsg.level,
message: randMsg.message
};
setAuditLogs(prev => [newLog, ...prev.slice(0, 7)]);
}, 4000);
}
return () => {
clearInterval(clockInterval);
if (liveLogInterval) clearInterval(liveLogInterval);
};
}, [liveStreamActive]);
// KYC Quick Actions
const handleApproveKYC = (id: string, name: string) => {
setKycRequests(prev => prev.map(k => k.id === id ? { ...k, status: 'approved' } : k));
toast.success(`Applicant ${name} successfully approved. Role set to Biker!`);
// Add to audit logs
const now = new Date().toLocaleTimeString();
setAuditLogs(prev => [
{ id: `audit-${Date.now()}`, timestamp: now, source: 'KYC', level: 'success', message: `Super Admin approved KYC document verification for ${name}` },
...prev
]);
};
const handleRejectKYC = (id: string, name: string) => {
setKycRequests(prev => prev.map(k => k.id === id ? { ...k, status: 'rejected' } : k));
toast.error(`Applicant ${name} KYC documents rejected.`);
const now = new Date().toLocaleTimeString();
setAuditLogs(prev => [
{ id: `audit-${Date.now()}`, timestamp: now, source: 'KYC', level: 'warning', message: `Super Admin rejected KYC files for ${name} (模糊不清 note)` },
...prev
]);
};
// Fleet Actions
const handleToggleLock = (bikeId: string, model: string, currentStatus: string) => {
toast.loading(`Sending OTA secure immobilization package to EV...`, { duration: 1000 });
setTimeout(() => {
setTelematicsBikes(prev => prev.map(b => {
if (b.id === bikeId) {
const nextStatus = b.status === 'rented' ? 'available' : 'rented';
toast.success(`Vehicle ${b.plateNumber} remote status set to: ${nextStatus === 'rented' ? 'LOCKED' : 'UNLOCKED'}`);
return { ...b, status: nextStatus };
}
return b;
}));
const now = new Date().toLocaleTimeString();
setAuditLogs(prev => [
{ id: `audit-${Date.now()}`, timestamp: now, source: 'FLEET', level: 'critical', message: `OTA secure signal sent: Toggled lock state for vehicle ${model}` },
...prev
]);
}, 1000);
};
const handleTriggerSiren = (plateNumber: string) => {
toast.success(`Siren / Audio Warning beacon triggered remotely on ${plateNumber}!`, { icon: '🔊' });
const now = new Date().toLocaleTimeString();
setAuditLogs(prev => [
{ id: `audit-${Date.now()}`, timestamp: now, source: 'FLEET', level: 'warning', message: `Super Admin triggered anti-theft audio warning on vehicle ${plateNumber}` },
...prev
]);
};
// Simulator Utilities
const runSimulatorTool = (type: string) => {
setShowToolsDrawer(false);
toast.loading(`Applying global load simulation...`, { duration: 1200 });
setTimeout(() => {
const now = new Date().toLocaleTimeString();
switch (type) {
case 'rain':
toast.success('Simulation active: heavy monsoon load rules applied! Fleet limits restricted to 30km/h.');
setAuditLogs(prev => [
{ id: `sim-${Date.now()}`, timestamp: now, source: 'FLEET', level: 'warning', message: 'Global Load Rules Override: Monsoon active. Battery thermal limit set to 45°C.' },
...prev
]);
break;
case 'swaps':
toast.success('Simulation: Toggled peak hour swap station fast loads. Grid stress active.');
setAuditLogs(prev => [
{ id: `sim-${Date.now()}`, timestamp: now, source: 'SWAP', level: 'info', message: 'Swap station rules override: High stress swap active. Buffer reserve locked at 15%.' },
...prev
]);
break;
case 'backup':
toast.success('System audit databases successfully compressed and pushed to backup secure drive.');
setAuditLogs(prev => [
{ id: `sim-${Date.now()}`, timestamp: now, source: 'ACCOUNTING', level: 'success', message: 'Secure system database checkpoint recorded. Uptime: 99.98%' },
...prev
]);
break;
default:
return;
}
}, 1200);
};
// Calculations for dynamic stats
const pendingKYCList = kycRequests.filter(k => k.status === 'pending');
const activeRentalsCount = rentalsList.filter(r => r.status === 'active').length;
const totalBikersCount = mockUsersListCount();
function mockUsersListCount() {
return 156 + (kycRequests.filter(k => k.status === 'approved').length);
}
// Filtered lists for view
const filteredKYCs = pendingKYCList.filter(k => {
const q = kycSearch.toLowerCase();
return k.userName.toLowerCase().includes(q) || k.phone.includes(q);
});
const filteredFleet = telematicsBikes.filter(b => {
const q = fleetSearch.toLowerCase();
return b.model.toLowerCase().includes(q) || b.plateNumber.toLowerCase().includes(q) || b.location.toLowerCase().includes(q);
});
return ( return (
<div className="p-4 lg:p-6"> <div className="p-4 lg:p-6 max-w-8xl mx-auto space-y-6">
<div className="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 mb-6">
<div> {/* 👑 SUPER ADMIN SECURITY HEADER BANNER */}
<h1 className="text-2xl lg:text-3xl font-extrabold text-slate-800">Admin Dashboard</h1> <div className="bg-white text-slate-800 rounded-2xl p-5 border border-slate-200 shadow-sm relative overflow-hidden">
<p className="text-sm text-slate-500 mt-1">Manage fleet, users, and operations</p> <div className="absolute right-0 top-0 translate-x-12 -translate-y-12 w-64 h-64 bg-accent/5 rounded-full blur-3xl" />
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-4 relative z-10">
<div className="flex items-center gap-4">
<div className="w-12 h-12 rounded-xl bg-accent/5 border border-accent/20 flex items-center justify-center text-accent shrink-0 shadow-sm">
<Shield className="w-6 h-6" />
</div> </div>
<div className="flex items-center gap-2"> <div>
<span className="text-sm text-slate-500">Last updated:</span> <div className="flex items-center gap-2 flex-wrap">
<span className="text-sm font-medium text-slate-700">Just now</span> <h1 className="text-xl lg:text-2xl font-black tracking-tight text-slate-800">JAIBEN Operations Command Center</h1>
<span className="px-2.5 py-0.5 bg-amber-100 border border-amber-200 text-amber-800 rounded-full text-[10px] font-extrabold uppercase tracking-wider flex items-center gap-1">
👑 SUPER ADMIN ACCESS
</span>
{sandboxMode && (
<span className="px-2 py-0.5 bg-emerald-100 border border-emerald-250 text-emerald-800 rounded-full text-[10px] font-bold">
Sandbox Active
</span>
)}
</div>
<p className="text-xs text-slate-500 mt-1">Real-time telemetry, OTA secure triggers, and accounting ledger supervisor node</p>
</div> </div>
</div> </div>
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 mb-8"> {/* System Telemetry Metadata */}
{stats.map((stat, index) => { <div className="flex items-center gap-4 text-xs font-semibold self-start lg:self-center bg-slate-50 p-3 rounded-xl border border-slate-200">
<div className="space-y-1">
<span className="text-slate-400 block uppercase text-[9px]">Telemetry Time</span>
<span className="text-accent font-mono tracking-wider flex items-center gap-1.5 font-bold">
<Clock className="w-3.5 h-3.5" /> {systemTime || 'Loading...'}
</span>
</div>
<div className="border-l border-slate-200 pl-4 space-y-1">
<span className="text-slate-400 block uppercase text-[9px]">Server status</span>
<span className="text-accent flex items-center gap-1 font-bold">
<Cpu className="w-3.5 h-3.5" /> ONLINE
</span>
</div>
<button
onClick={() => { setLiveStreamActive(!liveStreamActive); toast.success(liveStreamActive ? 'Live Stream paused' : 'Live stream active'); }}
className="border-l border-slate-200 pl-4 text-slate-450 hover:text-slate-750 transition-colors cursor-pointer"
title="Toggle Live Stream Feed"
>
<RefreshCw className={`w-4 h-4 ${liveStreamActive ? 'animate-spin' : ''}`} />
</button>
</div>
</div>
</div>
{/* COMMAND CENTER OPERATIONS STATISTICS */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4">
{[
{ label: 'Total active Bikers', value: totalBikersCount, change: '+14%', trend: 'up', icon: Users, color: 'text-blue-600 border-blue-100 bg-blue-50/30' },
{ label: 'Live Active Rentals', value: activeRentalsCount, change: '+18%', trend: 'up', icon: Bike, color: 'text-emerald-600 border-emerald-100 bg-emerald-50/30' },
{ label: 'Aggregate Cash Flow', value: '৳984.6k', change: '+28%', trend: 'up', icon: DollarSign, color: 'text-purple-600 border-purple-100 bg-purple-50/30' },
{ label: 'Cabinet Swaps (24h)', value: '254', change: '-4%', trend: 'down', icon: TrendingUp, color: 'text-amber-600 border-amber-100 bg-amber-50/30' }
].map((stat, i) => {
const Icon = stat.icon; const Icon = stat.icon;
return ( return (
<div key={index} className="bg-white rounded-xl p-5 shadow-sm border border-slate-100 hover:shadow-md transition-shadow"> <div key={i} className="bg-white rounded-xl p-4 shadow-sm border border-slate-100 flex flex-col justify-between hover:shadow-md transition-shadow relative overflow-hidden">
<div className="flex items-start justify-between mb-3"> <div className="flex justify-between items-start">
<div className={`w-12 h-12 rounded-xl ${stat.bg} flex items-center justify-center`}> <div className={`w-10 h-10 rounded-lg flex items-center justify-center border ${stat.color}`}>
<Icon className={`w-6 h-6 ${stat.color}`} /> <Icon className="w-5 h-5" />
</div> </div>
<span className={`text-xs font-semibold px-2 py-1 rounded-full flex items-center gap-1 ${ <span className={`text-[10px] font-bold px-2 py-0.5 rounded-full flex items-center gap-0.5 ${stat.trend === 'up' ? 'bg-green-50 border border-green-200 text-green-700' : 'bg-red-50 border border-red-200 text-red-700'
stat.trend === 'up' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'
}`}> }`}>
{stat.trend === 'up' ? <ArrowUpRight className="w-3 h-3" /> : <ArrowDownRight className="w-3 h-3" />} {stat.trend === 'up' ? <ArrowUpRight className="w-3 h-3" /> : <ArrowDownRight className="w-3 h-3" />}
{stat.change} {stat.change}
</span> </span>
</div> </div>
<p className="text-2xl font-extrabold text-slate-800">{stat.value}</p> <div className="mt-4">
<p className="text-sm text-slate-500 mt-1">{stat.label}</p> <p className="text-2xl font-black text-slate-800 tracking-tight">{stat.value}</p>
<p className="text-xs text-slate-400 font-semibold uppercase mt-0.5">{stat.label}</p>
</div>
</div> </div>
); );
})} })}
</div> </div>
<div className="grid lg:grid-cols-3 gap-6 mb-8"> {/* CORE TELEMETRY ANALYTICS: CUSTOM INTERACTIVE VECTOR SVG CHARTS */}
<div className="lg:col-span-2 bg-white rounded-xl shadow-sm border border-slate-100 overflow-hidden"> <div className="grid lg:grid-cols-3 gap-6">
<div className="px-5 py-4 border-b border-slate-100 flex items-center justify-between">
<h2 className="font-bold text-slate-800">Recent Rentals</h2> {/* SVG High-Fidelity Chart */}
<button className="text-sm text-blue-600 font-medium hover:underline">View All</button> <div className="lg:col-span-2 bg-white rounded-xl shadow-sm border border-slate-100 p-5 space-y-4">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 border-b border-slate-100 pb-4">
<div>
<h2 className="font-extrabold text-slate-800 flex items-center gap-1.5"><Activity className="w-4 h-4 text-accent" /> Telemetry Analytics</h2>
<p className="text-xs text-slate-400">Live operational ledger logs plotted against target performance guidelines</p>
</div> </div>
<div className="overflow-x-auto"> <div className="flex gap-1.5 p-1 bg-slate-50 border border-slate-200 rounded-lg self-start">
<table className="w-full"> {[
<thead className="bg-slate-50"> { id: 'revenue', label: 'Revenue Curve' },
{ id: 'utilization', label: 'Utilization' },
{ id: 'swaps', label: 'Cabinet stress' }
].map(opt => (
<button
key={opt.id}
onClick={() => { setActiveChartMetric(opt.id as any); toast.success(`Loaded ${opt.label}`); }}
className={`px-3 py-1 text-xs font-bold rounded-md transition-all cursor-pointer ${activeChartMetric === opt.id ? 'bg-accent text-white shadow' : 'text-accent-500 hover:text-slate-850'
}`}
>
{opt.label}
</button>
))}
</div>
</div>
{/* Hand-Crafted Interactive Vector Graph */}
<div className="bg-slate-100 p-4 rounded-xl border border-slate-50 relative overflow-hidden shadow-inner">
<div className="absolute top-3 right-3 flex items-center gap-1.5 text-[9px] text-slate-400 font-mono">
<span className="w-2.5 h-2.5 bg-accent rounded-full inline-block" /> Active Operations
<span className="w-2.5 h-2.5 bg-slate-650 rounded-full inline-block ml-2" /> Target Projection
</div>
{activeChartMetric === 'revenue' && (
<svg viewBox="0 0 500 200" className="w-full h-auto text-accent select-none overflow-visible">
<defs>
<linearGradient id="chartGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="var(--color-accent, #10b981)" stopOpacity="0.25" />
<stop offset="100%" stopColor="var(--color-accent, #10b981)" stopOpacity="0.0" />
</linearGradient>
</defs>
{/* Grid Lines */}
<line x1="0" y1="50" x2="500" y2="50" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<line x1="0" y1="100" x2="500" y2="100" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<line x1="0" y1="150" x2="500" y2="150" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
{/* Projections dashed */}
<path d="M 0,160 Q 120,130 250,90 T 500,40" fill="none" stroke="#475569" strokeWidth="2" strokeDasharray="4" />
{/* Active curve gradient */}
<path d="M 0,170 C 80,180 150,110 250,120 C 350,130 400,60 500,50 L 500,200 L 0,200 Z" fill="url(#chartGrad)" />
{/* Active curve line */}
<path d="M 0,170 C 80,180 150,110 250,120 C 350,130 400,60 500,50" fill="none" stroke="currentColor" strokeWidth="3" className="stroke-accent" />
{/* Interactive Points */}
<circle cx="250" cy="120" r="5" fill="#ffffff" className="stroke-accent" strokeWidth="3" />
<circle cx="500" cy="50" r="5" fill="#ffffff" className="stroke-accent" strokeWidth="3" />
{/* Custom Tooltip Box */}
<g transform="translate(265, 105)" className="opacity-95">
<rect width="90" height="35" rx="5" fill="#0f172a" stroke="#334155" strokeWidth="1" />
<text x="8" y="15" fill="#94a3b8" fontSize="8" fontWeight="bold" fontFamily="monospace">Date: 17th May</text>
<text x="8" y="27" fill="#ffffff" fontSize="9" fontWeight="bold" fontFamily="sans-serif">45,600 Daily</text>
</g>
{/* X Axis Labels */}
<text x="5" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Mon</text>
<text x="125" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Tue</text>
<text x="245" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Wed</text>
<text x="365" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Thu</text>
<text x="475" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Fri</text>
</svg>
)}
{activeChartMetric === 'utilization' && (
<svg viewBox="0 0 500 200" className="w-full h-auto text-blue-500 select-none overflow-visible">
<defs>
<linearGradient id="chartGradBlue" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#3b82f6" stopOpacity="0.25" />
<stop offset="100%" stopColor="#3b82f6" stopOpacity="0.0" />
</linearGradient>
</defs>
<line x1="0" y1="50" x2="500" y2="50" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<line x1="0" y1="100" x2="500" y2="100" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<line x1="0" y1="150" x2="500" y2="150" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<path d="M 0,140 Q 150,140 250,70 T 500,60" fill="none" stroke="#475569" strokeWidth="2" strokeDasharray="4" />
<path d="M 0,150 C 90,130 180,160 250,90 C 320,20 410,95 500,40 L 500,200 L 0,200 Z" fill="url(#chartGradBlue)" />
<path d="M 0,150 C 90,130 180,160 250,90 C 320,20 410,95 500,40" fill="none" stroke="#3b82f6" strokeWidth="3" />
<circle cx="250" cy="90" r="5" fill="#ffffff" stroke="#3b82f6" strokeWidth="3" />
<g transform="translate(265, 75)">
<rect width="90" height="35" rx="5" fill="#0f172a" stroke="#334155" strokeWidth="1" />
<text x="8" y="15" fill="#94a3b8" fontSize="8" fontWeight="bold" fontFamily="monospace">Utilization rate</text>
<text x="8" y="27" fill="#3b82f6" fontSize="10" fontWeight="bold" fontFamily="sans-serif">78% capacity</text>
</g>
<text x="5" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Mon</text>
<text x="125" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Tue</text>
<text x="245" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Wed</text>
<text x="365" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Thu</text>
<text x="475" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Fri</text>
</svg>
)}
{activeChartMetric === 'swaps' && (
<svg viewBox="0 0 500 200" className="w-full h-auto text-purple-500 select-none overflow-visible">
<defs>
<linearGradient id="chartGradPurple" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#a855f7" stopOpacity="0.25" />
<stop offset="100%" stopColor="#a855f7" stopOpacity="0.0" />
</linearGradient>
</defs>
<line x1="0" y1="50" x2="500" y2="50" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<line x1="0" y1="100" x2="500" y2="100" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<line x1="0" y1="150" x2="500" y2="150" stroke="#1e293b" strokeDasharray="3" strokeWidth="0.5" />
<path d="M 0,160 Q 150,110 250,100 T 500,80" fill="none" stroke="#475569" strokeWidth="2" strokeDasharray="4" />
<path d="M 0,180 C 100,140 120,70 250,90 C 350,110 390,40 500,70 L 500,200 L 0,200 Z" fill="url(#chartGradPurple)" />
<path d="M 0,180 C 100,140 120,70 250,90 C 350,110 390,40 500,70" fill="none" stroke="#a855f7" strokeWidth="3" />
<circle cx="250" cy="90" r="5" fill="#ffffff" stroke="#a855f7" strokeWidth="3" />
<g transform="translate(265, 75)">
<rect width="90" height="35" rx="5" fill="#0f172a" stroke="#334155" strokeWidth="1" />
<text x="8" y="15" fill="#94a3b8" fontSize="8" fontWeight="bold" fontFamily="monospace">Swaps volume</text>
<text x="8" y="27" fill="#a855f7" fontSize="10" fontWeight="bold" fontFamily="sans-serif">254 completed</text>
</g>
<text x="5" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Mon</text>
<text x="125" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Tue</text>
<text x="245" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Wed</text>
<text x="365" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Thu</text>
<text x="475" y="195" fill="#64748b" fontSize="8" fontFamily="monospace">Fri</text>
</svg>
)}
</div>
</div>
{/* 🔴 LIVE Audit Audit & Log terminal Stream */}
<div className="bg-slate-900 border border-slate-800 rounded-xl overflow-hidden shadow-lg flex flex-col justify-between">
<div className="px-5 py-4 border-b border-slate-800 flex items-center justify-between bg-slate-950/60">
<h2 className="font-extrabold text-sm text-slate-200 flex items-center gap-2">
<Terminal className="w-4 h-4 text-emerald-400 animate-pulse" /> Live Telemetry Feed
</h2>
<span className="w-2.5 h-2.5 bg-emerald-500 rounded-full inline-block animate-ping" />
</div>
<div className="p-4 font-mono text-[11px] text-slate-300 space-y-3 flex-1 overflow-y-auto max-h-[220px] lg:max-h-[300px]">
{auditLogs.map(log => {
const colors = {
info: 'text-blue-400',
warning: 'text-amber-400',
critical: 'text-red-400 font-bold',
success: 'text-emerald-400'
};
return (
<div key={log.id} className="space-y-0.5 border-b border-slate-800/40 pb-2">
<div className="flex justify-between items-center text-[10px] text-slate-500">
<span>[{log.timestamp}] source: <strong className="text-slate-400">{log.source}</strong></span>
<span className={`uppercase font-bold text-[8px] px-1 py-0.2 rounded bg-slate-800/50 ${colors[log.level]}`}>
{log.level}
</span>
</div>
<p className="leading-relaxed text-slate-350">{log.message}</p>
</div>
);
})}
</div>
<div className="p-3 border-t border-slate-800 bg-slate-950/60 flex justify-between items-center">
<span className="text-[10px] text-slate-500 font-mono">Telemetry stream synchronized</span>
<button
onClick={() => { setAuditLogs(initialAuditLogs); toast.success('Telemetry console logs reset'); }}
className="text-[10px] font-bold text-accent hover:underline cursor-pointer"
>
Reset Logs
</button>
</div>
</div>
</div>
{/* DUAL WORKSPACE: INTERACTIVE KYC DESK & HARDWARE FLEET TELEMETRY */}
<div className="grid lg:grid-cols-3 gap-6">
{/* Interactive KYC Pending Table / List */}
<div className="bg-white rounded-xl border border-slate-100 shadow-sm overflow-hidden flex flex-col justify-between">
<div className="px-5 py-4 border-b border-slate-100 flex items-center justify-between flex-wrap gap-2">
<div>
<h2 className="font-extrabold text-slate-800 flex items-center gap-1.5"><Shield className="w-4 h-4 text-amber-500" /> KYC Pending Desk</h2>
<p className="text-xs text-slate-400 mt-0.5">{pendingKYCList.length} requests await secure super-admin sign-off</p>
</div>
{/* Search inputs */}
<div className="relative w-full sm:w-auto">
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-slate-400" />
<input
type="text"
placeholder="Filter applicant..."
value={kycSearch}
onChange={(e) => setKycSearch(e.target.value)}
className="pl-8 pr-3 py-1 border border-slate-200 rounded-lg text-xs bg-white text-slate-700 focus:outline-none focus:ring-1 focus:ring-accent"
/>
</div>
</div>
<div className="divide-y divide-slate-100 flex-1 overflow-y-auto max-h-[350px]">
{filteredKYCs.map(kyc => (
<div key={kyc.id} className="p-4 hover:bg-slate-50/50 transition-colors space-y-3">
<div className="flex items-start justify-between">
<div>
<h4 className="font-bold text-slate-800 text-sm">{kyc.userName}</h4>
<p className="text-xs text-slate-500 mt-0.5">{kyc.phone}</p>
<div className="flex gap-1.5 mt-2">
<span className="px-2 py-0.5 bg-slate-100 text-slate-650 rounded text-[9px] font-semibold">TIN Files Verified</span>
<span className="px-2 py-0.5 bg-slate-100 text-slate-650 rounded text-[9px] font-semibold">License Valid</span>
</div>
</div>
<span className="text-[10px] text-slate-400 font-semibold">{kyc.submittedAt}</span>
</div>
<div className="flex gap-2">
<button
onClick={() => handleApproveKYC(kyc.id, kyc.userName)}
className="flex-1 py-1.5 bg-emerald-600 hover:bg-emerald-700 text-white text-xs font-bold rounded-lg transition-colors flex items-center justify-center gap-1 cursor-pointer"
>
<CheckCircle className="w-3.5 h-3.5" /> Approve
</button>
<button
onClick={() => handleRejectKYC(kyc.id, kyc.userName)}
className="flex-1 py-1.5 border border-red-200 text-red-600 hover:bg-red-50 text-xs font-bold rounded-lg transition-colors flex items-center justify-center gap-1 cursor-pointer"
>
<XCircle className="w-3.5 h-3.5" /> Reject
</button>
</div>
</div>
))}
{filteredKYCs.length === 0 && (
<div className="p-12 text-center text-slate-400 space-y-2">
<CheckCircle className="w-12 h-12 text-slate-200 mx-auto" />
<p className="text-xs font-semibold">No pending KYC files match your filter.</p>
</div>
)}
</div>
</div>
{/* Live Hardware EV Fleet lock controller dashboard */}
<div className="lg:col-span-2 bg-white rounded-xl border border-slate-100 shadow-sm overflow-hidden flex flex-col justify-between">
<div className="px-5 py-4 border-b border-slate-100 flex items-center justify-between flex-wrap gap-2">
<div>
<h2 className="font-extrabold text-slate-800 flex items-center gap-1.5"><Bike className="w-4 h-4 text-accent" /> OTA Vehicle Telematics Dashboard</h2>
<p className="text-xs text-slate-400 mt-0.5">Direct OTA remote control node to override vehicle immobilizers or warn operators</p>
</div>
<div className="relative w-full sm:w-auto">
<Search className="absolute left-2.5 top-1/2 -translate-y-1/2 w-3.5 h-3.5 text-slate-400" />
<input
type="text"
placeholder="Filter EV plate number..."
value={fleetSearch}
onChange={(e) => setFleetSearch(e.target.value)}
className="pl-8 pr-3 py-1 border border-slate-200 rounded-lg text-xs bg-white text-slate-700 focus:outline-none focus:ring-1 focus:ring-accent"
/>
</div>
</div>
{/* Desktop Table View */}
<div className="hidden md:block overflow-x-auto flex-1">
<table className="w-full text-xs">
<thead className="bg-slate-50/50 border-b border-slate-100">
<tr> <tr>
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Rental ID</th> <th className="px-4 py-3 text-left font-bold text-slate-500 uppercase tracking-wider">EV Info</th>
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Bike</th> <th className="px-4 py-3 text-left font-bold text-slate-500 uppercase tracking-wider">Charge status</th>
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">User</th> <th className="px-4 py-3 text-left font-bold text-slate-500 uppercase tracking-wider">Audit location</th>
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Type</th> <th className="px-4 py-3 text-left font-bold text-slate-500 uppercase tracking-wider">OTA Lock Override</th>
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Status</th> <th className="px-4 py-3 text-right font-bold text-slate-500 uppercase tracking-wider">Siren Warning</th>
<th className="px-4 py-3 text-left text-xs font-semibold text-slate-500 uppercase tracking-wider">Daily Rate</th>
</tr> </tr>
</thead> </thead>
<tbody className="divide-y divide-slate-50"> <tbody className="divide-y divide-slate-50">
{activeRentals.map(rental => { {filteredFleet.map(bike => {
const bike = bikes.find(b => b.id === rental.bikeId); const isRented = bike.status === 'rented';
return ( return (
<tr key={rental.id} className="hover:bg-slate-50 transition-colors"> <tr key={bike.id} className="hover:bg-slate-50/40 transition-colors">
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm font-medium text-slate-700">{rental.id}</span> <p className="font-extrabold text-slate-800">{bike.model}</p>
<span className="text-[10px] text-slate-400 font-mono tracking-tight">{bike.plateNumber}</span>
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm text-slate-600">{bike?.model}</span> <div className="flex items-center gap-1.5">
<span className="text-xs text-slate-400 block">{bike?.plateNumber}</span> <span className={`w-2.5 h-2.5 rounded-full inline-block ${bike.batteryLevel > 70 ? 'bg-green-500' : bike.batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500'
}`} />
<span className="font-mono font-bold text-slate-700">{bike.batteryLevel}%</span>
</div>
</td>
<td className="px-4 py-3 font-semibold text-slate-500">
{bike.location}
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3">
<span className="text-sm text-slate-600">{rental.userId}</span> <button
onClick={() => handleToggleLock(bike.id, bike.model, bike.status)}
className={`py-1 px-3 rounded-lg text-[10px] font-extrabold tracking-wider uppercase transition-all flex items-center gap-1 shadow-sm cursor-pointer ${isRented
? 'bg-slate-900 border border-slate-900 text-white hover:bg-slate-800'
: 'bg-emerald-50 border border-emerald-250 text-emerald-700 hover:bg-emerald-100'
}`}
>
{isRented ? (
<>
<Lock className="w-3.5 h-3.5" /> Secure locked
</>
) : (
<>
<Unlock className="w-3.5 h-3.5" /> Active unlocked
</>
)}
</button>
</td> </td>
<td className="px-4 py-3"> <td className="px-4 py-3 text-right">
<span className="text-sm text-slate-600 capitalize">{rental.type}</span> <button
</td> onClick={() => handleTriggerSiren(bike.plateNumber)}
<td className="px-4 py-3"> className="p-1.5 hover:bg-red-50 rounded-lg text-slate-400 hover:text-red-600 transition-colors cursor-pointer"
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${ title="Trigger Anti-theft Audio Warning Beacon"
rental.status === 'active' ? 'bg-green-100 text-green-700' : >
rental.status === 'pending' ? 'bg-amber-100 text-amber-700' : <Volume2 className="w-4 h-4" />
'bg-slate-100 text-slate-500' </button>
}`}>
<Activity className="w-3 h-3" />
{rental.status}
</span>
</td>
<td className="px-4 py-3">
<span className="text-sm font-semibold text-slate-700">{rental.dailyRate}</span>
</td> </td>
</tr> </tr>
); );
@@ -116,96 +625,187 @@ export default function AdminDashboard() {
</tbody> </tbody>
</table> </table>
</div> </div>
</div>
<div className="bg-white rounded-xl shadow-sm border border-slate-100 overflow-hidden"> {/* Mobile Card Layout */}
<div className="px-5 py-4 border-b border-slate-100 flex items-center justify-between"> <div className="block md:hidden p-4 space-y-3 overflow-y-auto max-h-[350px] bg-slate-50/30 border-t border-slate-100">
<h2 className="font-bold text-slate-800">KYC Requests</h2> {filteredFleet.map(bike => {
<span className="text-xs font-semibold px-2 py-1 bg-amber-100 text-amber-700 rounded-full"> const isRented = bike.status === 'rented';
{pendingKYCs.length} pending return (
</span> <div key={bike.id} className="bg-white p-4 rounded-xl border border-slate-100 shadow-sm space-y-3">
</div> <div className="flex justify-between items-start">
<div className="divide-y divide-slate-50">
{pendingKYCs.map(kyc => (
<div key={kyc.id} className="p-4 hover:bg-slate-50 transition-colors">
<div className="flex items-start justify-between mb-3">
<div> <div>
<p className="font-medium text-slate-700">{kyc.userName}</p> <h4 className="font-extrabold text-slate-800 text-sm">{bike.model}</h4>
<p className="text-sm text-slate-400">{kyc.phone}</p> <p className="text-[10px] text-slate-400 font-mono mt-0.5">{bike.plateNumber}</p>
<p className="text-xs text-slate-400 mt-1 flex items-center gap-1">
<Clock className="w-3 h-3" /> {kyc.submittedAt}
</p>
</div> </div>
<span className="p-1.5 bg-amber-100 rounded-lg"> <div className="flex items-center gap-1 bg-slate-50 border border-slate-100 rounded-lg px-2 py-0.5">
<Shield className="w-4 h-4 text-amber-600" /> <span className={`w-2 h-2 rounded-full ${bike.batteryLevel > 70 ? 'bg-green-500' : bike.batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500'
</span> }`} />
</div> <span className="font-mono text-slate-700 font-bold text-[10px]">{bike.batteryLevel}%</span>
<div className="flex gap-2">
<button className="flex-1 py-2 bg-green-600 text-white text-sm font-semibold rounded-lg hover:bg-green-700 flex items-center justify-center gap-1">
<CheckCircle className="w-4 h-4" /> Approve
</button>
<button className="flex-1 py-2 border border-red-200 text-red-600 text-sm font-semibold rounded-lg hover:bg-red-50 flex items-center justify-center gap-1">
<XCircle className="w-4 h-4" /> Reject
</button>
</div> </div>
</div> </div>
))} <div className="flex justify-between items-center text-xs font-bold text-slate-500">
{pendingKYCs.length === 0 && ( <span>Audit Location:</span>
<div className="p-8 text-center"> <span className="text-slate-800">{bike.location}</span>
<CheckCircle className="w-12 h-12 text-green-500 mx-auto mb-2" />
<p className="text-sm text-slate-500">No pending KYC requests</p>
</div> </div>
<div className="flex gap-2 pt-1 border-t border-slate-50">
<button
onClick={() => handleToggleLock(bike.id, bike.model, bike.status)}
className={`flex-1 py-1.5 rounded-lg text-[10px] font-extrabold tracking-wider uppercase flex items-center justify-center gap-1 shadow-sm cursor-pointer ${isRented
? 'bg-slate-900 border border-slate-900 text-white hover:bg-slate-800'
: 'bg-emerald-50 border border-emerald-250 text-emerald-700 hover:bg-emerald-100'
}`}
>
{isRented ? (
<><Lock className="w-3 h-3" /> Secure locked</>
) : (
<><Unlock className="w-3 h-3" /> Active unlocked</>
)} )}
</div>
</div>
</div>
<div className="grid lg:grid-cols-2 gap-6">
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-5">
<h2 className="font-bold text-slate-800 mb-4">Quick Actions</h2>
<div className="grid grid-cols-2 gap-3">
<button className="py-3 px-4 bg-accent text-white rounded-lg font-semibold text-sm hover:bg-accent-dark transition-colors">
+ Add New Bike
</button> </button>
<button className="py-3 px-4 bg-blue-600 text-white rounded-lg font-semibold text-sm hover:bg-blue-700 transition-colors"> <button
Manage Users onClick={() => handleTriggerSiren(bike.plateNumber)}
className="px-3 py-1.5 border border-slate-200 hover:bg-red-50 text-slate-400 hover:text-red-650 rounded-lg transition-colors flex items-center justify-center cursor-pointer"
>
<Volume2 className="w-4 h-4" />
</button> </button>
<button className="py-3 px-4 bg-purple-600 text-white rounded-lg font-semibold text-sm hover:bg-purple-700 transition-colors">
View Reports
</button>
<button className="py-3 px-4 border border-slate-200 text-slate-600 rounded-lg font-semibold text-sm hover:bg-slate-50 transition-colors">
Settings
</button>
</div>
</div>
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-5">
<h2 className="font-bold text-slate-800 mb-4">System Alerts</h2>
<div className="space-y-3">
<div className="flex items-center gap-3 p-3 bg-red-50 rounded-lg border border-red-100">
<AlertTriangle className="w-5 h-5 text-red-500" />
<div>
<p className="text-sm font-medium text-red-700">3 bikes overdue maintenance</p>
<p className="text-xs text-red-500">Action required</p>
</div>
</div>
<div className="flex items-center gap-3 p-3 bg-amber-50 rounded-lg border border-amber-100">
<Clock className="w-5 h-5 text-amber-500" />
<div>
<p className="text-sm font-medium text-amber-700">5 pending KYC verifications</p>
<p className="text-xs text-amber-500">Review needed</p>
</div>
</div>
<div className="flex items-center gap-3 p-3 bg-green-50 rounded-lg border border-green-100">
<CheckCircle className="w-5 h-5 text-green-500" />
<div>
<p className="text-sm font-medium text-green-700">System running smoothly</p>
<p className="text-xs text-green-500">All services operational</p>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
); );
})}
</div>
</div>
</div>
{/* QUICK OPERATIONS CONSOLE & CENTRAL UTILITIES */}
<div className="grid lg:grid-cols-2 gap-6">
{/* Super Admin Quick tools */}
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-5 space-y-4">
<div>
<h2 className="font-extrabold text-slate-800 flex items-center gap-1.5"><Settings className="w-4 h-4 text-purple-600" /> Super-Admin Commands Console</h2>
<p className="text-xs text-slate-400 mt-0.5">Rapid access control widgets to configure environment variables or databases</p>
</div>
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
{[
{ label: 'Sandbox Payments', active: sandboxMode, onClick: () => { setSandboxMode(!sandboxMode); toast.success(sandboxMode ? 'Sandbox payments deactivated' : 'Sandbox active'); } },
{ label: 'Live Events Logs', active: liveStreamActive, onClick: () => setLiveStreamActive(!liveStreamActive) },
{ label: 'Run global Load', active: false, onClick: () => setShowToolsDrawer(true) },
{ label: 'Database Backup', active: false, onClick: () => runSimulatorTool('backup') }
].map((tool, i) => (
<button
key={i}
onClick={tool.onClick}
className={`p-3 rounded-xl border flex flex-col justify-between text-left h-24 transition-all cursor-pointer ${tool.active
? 'border-accent bg-accent/5 text-accent shadow-sm'
: 'border-slate-200 text-slate-655 bg-white hover:border-slate-350 hover:bg-slate-50/50'
}`}
>
<span className="text-[10px] font-bold uppercase tracking-wider text-slate-400">Environment Node</span>
<div>
<p className="text-xs font-black text-slate-850 leading-tight">{tool.label}</p>
<span className="text-[9px] font-bold text-slate-400 uppercase mt-0.5 block">
{tool.active ? 'active / enabled' : 'click to run'}
</span>
</div>
</button>
))}
</div>
</div>
{/* Global Security Alerts Panel */}
<div className="bg-white rounded-xl shadow-sm border border-slate-100 p-5 space-y-4">
<div>
<h2 className="font-extrabold text-slate-800 flex items-center gap-1.5"><ShieldAlert className="w-4 h-4 text-red-500 animate-bounce" /> Live Security & Maintenance Telemetry</h2>
<p className="text-xs text-slate-400 mt-0.5">Critical operating limit warnings pushed from connected swap hardware nodes</p>
</div>
<div className="space-y-3">
<div className="flex items-center gap-3 p-3 bg-red-50 rounded-xl border border-red-100">
<AlertTriangle className="w-5 h-5 text-red-500 animate-pulse" />
<div className="min-w-0 flex-1">
<p className="text-xs font-bold text-red-800 leading-tight">Monsoon Load Warning active</p>
<p className="text-[10px] text-red-500 mt-0.5">Speed limited to 30km/h for Yadea fleet elements inside high rainfall areas.</p>
</div>
<button
onClick={() => toast.success('Override monsoons restrictions: Secure sign-off accepted')}
className="text-[9px] font-extrabold uppercase text-red-700 bg-red-100 hover:bg-red-200 px-2 py-1 rounded transition-colors shrink-0 cursor-pointer"
>
Override Rules
</button>
</div>
<div className="flex items-center gap-3 p-3 bg-amber-50 rounded-xl border border-amber-100">
<Clock className="w-5 h-5 text-amber-500" />
<div className="min-w-0 flex-1">
<p className="text-xs font-bold text-amber-800 leading-tight">Battery inventory warnings at Gulshan station</p>
<p className="text-[10px] text-amber-500 mt-0.5">Station has only 1 fully charged cabinet remaining. Restock is required immediately.</p>
</div>
<Link
href="/admin/swap-stations"
className="text-[9px] font-extrabold uppercase text-amber-700 bg-amber-100 hover:bg-amber-200 px-2 py-1 rounded transition-colors shrink-0"
>
Dispatch Hub
</Link>
</div>
</div>
</div>
</div>
{/* ========================================= MONSOON / GLOBAL OVERRIDE SIMULATOR PANEL DRAWER ========================================= */}
{showToolsDrawer && (
<div className="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-white rounded-2xl shadow-2xl w-full max-w-sm overflow-hidden border border-slate-100 flex flex-col animate-scaleIn">
<div className="p-4 bg-slate-900 text-white flex items-center justify-between">
<div className="flex items-center gap-2">
<Cpu className="w-5 h-5 text-amber-400" />
<h3 className="font-extrabold text-sm uppercase tracking-wider">Run Environment Simulation</h3>
</div>
<button
onClick={() => setShowToolsDrawer(false)}
className="p-1 hover:bg-white/10 rounded-lg transition-colors text-white"
>
<XCircle className="w-5 h-5" />
</button>
</div>
<div className="p-5 space-y-4">
<p className="text-xs text-slate-500 leading-relaxed">Select global environment load override conditions. These parameters immediately scale system-wide biker limitations, accounting calculations, and thermal thresholds.</p>
<div className="space-y-2">
<button
onClick={() => runSimulatorTool('rain')}
className="w-full flex items-center justify-between p-3 border border-slate-200 rounded-xl hover:border-amber-300 hover:bg-amber-50/20 text-left transition-all group cursor-pointer"
>
<div>
<h4 className="text-xs font-bold text-slate-800">Monsoon Heavy Rain load</h4>
<p className="text-[10px] text-slate-400 mt-0.5">Speed restricted to 30km/h, thermal thresholds forced.</p>
</div>
<ChevronRight className="w-4 h-4 text-slate-400 group-hover:translate-x-1 transition-transform" />
</button>
<button
onClick={() => runSimulatorTool('swaps')}
className="w-full flex items-center justify-between p-3 border border-slate-200 rounded-xl hover:border-purple-300 hover:bg-purple-50/20 text-left transition-all group cursor-pointer"
>
<div>
<h4 className="text-xs font-bold text-slate-800">Peak Hour Swaps load</h4>
<p className="text-[10px] text-slate-400 mt-0.5"> cabinet reserves restricted, grid loading warnings active.</p>
</div>
<ChevronRight className="w-4 h-4 text-slate-400 group-hover:translate-x-1 transition-transform" />
</button>
</div>
</div>
<div className="p-4 bg-slate-50 border-t border-slate-100 flex justify-end">
<button
onClick={() => setShowToolsDrawer(false)}
className="py-1.5 px-4 bg-white border border-slate-200 text-slate-600 rounded-lg text-xs font-bold hover:bg-slate-50 transition-colors"
>
Cancel / Close
</button>
</div>
</div>
</div>
)}
</div>
);
} }