diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index ee9d37a..dc8532f 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,10 +1,11 @@ 'use client'; -import { useState, useEffect, useRef } from 'react'; -import { - Users, Bike, DollarSign, TrendingUp, Activity, ArrowUpRight, ArrowDownRight, - Clock, Shield, AlertTriangle, CheckCircle, XCircle, Play, Sparkles, RefreshCw, - Search, Lock, Unlock, Volume2, ShieldAlert, Cpu, Terminal, Database, Settings, HelpCircle, ChevronRight +import { useState, useEffect } from 'react'; +import { + Users, Bike, DollarSign, TrendingUp, Activity, ArrowUpRight, ArrowDownRight, + Clock, Shield, AlertTriangle, CheckCircle, XCircle, RefreshCw, + Search, Lock, Unlock, Volume2, ShieldAlert, Cpu, Terminal, Settings, ChevronRight, + Database, PlusCircle, Wrench, BatteryCharging, CreditCard, FileText, Check, ArrowDownUp, Ticket, UserCheck, Eye, Trash2 } 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'; @@ -37,33 +38,72 @@ const mockLiveMessages = [ ]; export default function AdminDashboard() { - // Live State + // Simulated Roles: super_admin | hub_manager | accountant | front_desk + const [activeRole, setActiveRole] = useState<'super_admin' | 'hub_manager' | 'accountant' | 'front_desk'>('super_admin'); + + // Live Dynamic 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 + { id: 'tel-1', model: 'Etron ET50', plateNumber: 'Dhaka Metro Cha-1234', batteryLevel: 78, location: 'Gulshan 1', status: 'rented' }, + { id: 'tel-2', model: 'Yadea DT3', plateNumber: 'Dhaka Metro Cha-5678', batteryLevel: 95, location: 'Banani', status: 'available' }, + { id: 'tel-3', model: 'AIMA Lightning', plateNumber: 'Dhaka Metro Cha-9012', batteryLevel: 62, location: 'Uttara', status: 'rented' }, + { id: 'tel-4', model: 'TVS iQube', plateNumber: 'Dhaka Metro Cha-3456', batteryLevel: 45, location: 'Workshop', status: 'available' } ]); const [rentalsList, setRentalsList] = useState(mockRentals); const [auditLogs, setAuditLogs] = useState(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); + // Hub Manager Interactive battery cabinet states + const [cabinetSlots, setCabinetSlots] = useState([ + { slot: 1, charge: 98, status: 'fully_charged', temp: 31 }, + { slot: 2, charge: 95, status: 'fully_charged', temp: 32 }, + { slot: 3, charge: 15, status: 'charging', temp: 38 }, + { slot: 4, charge: 88, status: 'ready', temp: 33 }, + { slot: 5, charge: 5, status: 'discharged', temp: 42 }, + { slot: 6, charge: 96, status: 'fully_charged', temp: 30 }, + { slot: 7, charge: 0, status: 'empty', temp: 25 }, + { slot: 8, charge: 91, status: 'ready', temp: 34 } + ]); + + // Hub Manager Service Tickets + const [serviceTickets, setServiceTickets] = useState([ + { id: 'tkt-01', model: 'Yadea DT3', issue: 'Rear Brake Pad friction replacement', urgency: 'high', hub: 'Gulshan Hub' }, + { id: 'tkt-02', model: 'TVS iQube', issue: 'Front Left LED replacement', urgency: 'medium', hub: 'Gulshan Hub' }, + { id: 'tkt-03', model: 'Etron ET50', issue: 'Throttle wire connectivity check', urgency: 'low', hub: 'Banani Hub' } + ]); + + // Accountant Interactive vouchers + const [journalVouchers, setJournalVouchers] = useState([ + { id: 'JV-2026-004', desc: 'Accrued Biker Rental fees single pay', debit: 45600, credit: 45600, date: '17 May', status: 'draft' }, + { id: 'JV-2026-003', desc: 'Swap cabinet electricity amortization', debit: 12000, credit: 12000, date: '16 May', status: 'posted' }, + { id: 'JV-2026-002', desc: 'Disbursed Investor returns Gold tier share', debit: 62100, credit: 62100, date: '15 May', status: 'posted' } + ]); + + // Accountant past due bikers + const [pastDueBikers, setPastDueBikers] = useState([ + { id: 'usr-09', name: 'Farid Ahmed', pastDueAmount: 1200, lastAttempt: '14 May', mobile: '+8801700000001' }, + { id: 'usr-11', name: 'Tariqul Islam', pastDueAmount: 850, lastAttempt: '15 May', mobile: '+8801700000002' } + ]); + + // Front Desk walk-in check-in bikers queue + const [walkinQueue, setWalkinQueue] = useState([ + { id: 'q-1', name: 'Zahid Hasan', purpose: 'EV Assignment check-in', regDate: '17:42' }, + { id: 'q-2', name: 'Mahbub Alam', purpose: 'Physical document KYC file check', regDate: '17:45' } + ]); + + // Front Desk Ready Plates + const [assignedPlateVal, setAssignedPlateVal] = useState('Dhaka Metro Cha-5678'); + + // Real-time ticking Clock & Live WebSocket Telemetry Simulation useEffect(() => { - // Clock update const updateTime = () => { const now = new Date(); setSystemTime(now.toLocaleTimeString()); @@ -71,14 +111,13 @@ export default function AdminDashboard() { 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, @@ -88,7 +127,7 @@ export default function AdminDashboard() { }; setAuditLogs(prev => [newLog, ...prev.slice(0, 7)]); - }, 4000); + }, 4500); } return () => { @@ -97,15 +136,14 @@ export default function AdminDashboard() { }; }, [liveStreamActive]); - // KYC Quick Actions + // Dynamic state 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 + toast.success(`Applicant ${name} successfully approved. Role updated to Biker!`); + 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}` }, + { id: `audit-${Date.now()}`, timestamp: now, source: 'KYC', level: 'success', message: `Admin approved KYC document verification for Biker ${name}` }, ...prev ]); }; @@ -113,18 +151,17 @@ export default function AdminDashboard() { 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)` }, + { id: `audit-${Date.now()}`, timestamp: now, source: 'KYC', level: 'warning', message: `Admin rejected KYC files for Biker ${name} (Blurry images)` }, ...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) { @@ -144,59 +181,116 @@ export default function AdminDashboard() { }; const handleTriggerSiren = (plateNumber: string) => { - toast.success(`Siren / Audio Warning beacon triggered remotely on ${plateNumber}!`, { icon: '🔊' }); + toast.success(`Siren audio warning 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}` }, + { id: `audit-${Date.now()}`, timestamp: now, source: 'FLEET', level: 'warning', message: `Admin triggered audio warning beacon on vehicle ${plateNumber}` }, ...prev ]); }; - // Simulator Utilities + // Hub Manager remote opening + const handleOpenCabinetSlot = (slot: number) => { + toast.loading(`Issuing remote release command for swap slot #${slot}...`, { duration: 1200 }); + setTimeout(() => { + setCabinetSlots(prev => prev.map(s => s.slot === slot ? { ...s, status: 'empty', charge: 0 } : s)); + toast.success(`Cabinet Slot #${slot} released successfully! Door opened.`, { icon: '🔓' }); + + const now = new Date().toLocaleTimeString(); + setAuditLogs(prev => [ + { id: `audit-${Date.now()}`, timestamp: now, source: 'SWAP', level: 'success', message: `Hub Manager remotely opened lock for charging slot Cabinet #${slot}` }, + ...prev + ]); + }, 1200); + }; + + // Dispatch mechanics + const handleDispatchTicket = (id: string, issue: string) => { + toast.success(`Mechanics team dispatched for ticket ${id}!`); + setServiceTickets(prev => prev.filter(t => t.id !== id)); + + const now = new Date().toLocaleTimeString(); + setAuditLogs(prev => [ + { id: `audit-${Date.now()}`, timestamp: now, source: 'FLEET', level: 'info', message: `Service Ticket ${id} dispatched: ${issue}` }, + ...prev + ]); + }; + + // Accountant post voucher + const handlePostVoucher = (id: string) => { + setJournalVouchers(prev => prev.map(v => v.id === id ? { ...v, status: 'posted' } : v)); + toast.success(`Journal Voucher ${id} posted successfully to double-entry ledger!`, { icon: '📝' }); + + const now = new Date().toLocaleTimeString(); + setAuditLogs(prev => [ + { id: `audit-${Date.now()}`, timestamp: now, source: 'ACCOUNTING', level: 'success', message: `Accountant posted Journal Entry ${id} to active books` }, + ...prev + ]); + }; + + // Accountant trigger warning SMS + const handleSendBillWarning = (name: string, amt: number) => { + toast.success(`Past due payment reminder of ৳${amt} sent to ${name}!`, { icon: '💬' }); + const now = new Date().toLocaleTimeString(); + setAuditLogs(prev => [ + { id: `audit-${Date.now()}`, timestamp: now, source: 'USER', level: 'warning', message: `SMS payment collection reminder dispatched to ${name} (৳${amt})` }, + ...prev + ]); + }; + + // Front Desk Check-in biker Walk-in assignment + const handleAssignBikerWalkin = (qId: string, name: string) => { + toast.success(`EV plate ${assignedPlateVal} successfully assigned to Checked-in biker ${name}!`, { icon: '🏍️' }); + setWalkinQueue(prev => prev.filter(q => q.id !== qId)); + + // Add Yadea/TVS assignment update + const now = new Date().toLocaleTimeString(); + setAuditLogs(prev => [ + { id: `audit-${Date.now()}`, timestamp: now, source: 'USER', level: 'success', message: `Front Desk checked-in walk-in Biker ${name} to vehicle ${assignedPlateVal}` }, + ...prev + ]); + }; + + // Environmental load simulations const runSimulatorTool = (type: string) => { setShowToolsDrawer(false); - toast.loading(`Applying global load simulation...`, { duration: 1200 }); + toast.loading(`Applying simulation conditions...`, { duration: 1000 }); 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.'); + toast.success('Simulation active: Monsoon load applied! Restricting speed limit.'); 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.' }, + { id: `sim-${Date.now()}`, timestamp: now, source: 'FLEET', level: 'warning', message: 'Load rules: Monsoon weather limits active. Battery cell lock set to 45°C.' }, ...prev ]); break; case 'swaps': - toast.success('Simulation: Toggled peak hour swap station fast loads. Grid stress active.'); + toast.success('Simulation: Grid peak loading limits 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%.' }, + { id: `sim-${Date.now()}`, timestamp: now, source: 'SWAP', level: 'info', message: 'Power stress: Grid swap balancer activated. Fast charge locked.' }, ...prev ]); break; case 'backup': - toast.success('System audit databases successfully compressed and pushed to backup secure drive.'); + toast.success('Ledger journals compressed and backed up.'); setAuditLogs(prev => [ - { id: `sim-${Date.now()}`, timestamp: now, source: 'ACCOUNTING', level: 'success', message: 'Secure system database checkpoint recorded. Uptime: 99.98%' }, + { id: `sim-${Date.now()}`, timestamp: now, source: 'ACCOUNTING', level: 'success', message: 'Secure ledger checkpoint drafted and saved to backup servers' }, ...prev ]); break; default: return; } - }, 1200); + }, 1000); }; - // Calculations for dynamic stats + // Filter calculations const pendingKYCList = kycRequests.filter(k => k.status === 'pending'); const activeRentalsCount = rentalsList.filter(r => r.status === 'active').length; - const totalBikersCount = mockUsersListCount(); + const totalBikersCount = 156 + (kycRequests.filter(k => k.status === 'approved').length); - 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); @@ -209,8 +303,8 @@ export default function AdminDashboard() { return (
- - {/* 👑 SUPER ADMIN SECURITY HEADER BANNER */} + + {/* 👑 SUPER ADMIN SECURITY HEADER BANNER WITH DYNAMIC ROLE SWITCHER */}
@@ -234,527 +328,1039 @@ export default function AdminDashboard() {
- {/* System Telemetry Metadata */} -
-
- Telemetry Time - - {systemTime || 'Loading...'} - -
-
- Server status - - ONLINE - -
-
- {/* COMMAND CENTER OPERATIONS STATISTICS */} -
- {[ - { 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; - return ( -
-
-
- -
- - {stat.trend === 'up' ? : } - {stat.change} - -
-
-

{stat.value}

-

{stat.label}

-
-
- ); - })} -
- - {/* CORE TELEMETRY ANALYTICS: CUSTOM INTERACTIVE VECTOR SVG CHARTS */} -
- - {/* SVG High-Fidelity Chart */} -
-
-
-

Telemetry Analytics

-

Live operational ledger logs plotted against target performance guidelines

-
-
- {[ - { id: 'revenue', label: 'Revenue Curve' }, - { id: 'utilization', label: 'Utilization' }, - { id: 'swaps', label: 'Cabinet stress' } - ].map(opt => ( - - ))} -
-
- - {/* Hand-Crafted Interactive Vector Graph */} -
-
- Active Operations - Target Projection -
- - {activeChartMetric === 'revenue' && ( - - - - - - - - {/* Grid Lines */} - - - - - {/* Projections dashed */} - - - {/* Active curve gradient */} - - - {/* Active curve line */} - - - {/* Interactive Points */} - - - - {/* Custom Tooltip Box */} - - - Date: 17th May - ৳45,600 Daily - - - {/* X Axis Labels */} - Mon - Tue - Wed - Thu - Fri - - )} - - {activeChartMetric === 'utilization' && ( - - - - - - - - - - - - - - - - - - - - Utilization rate - 78% capacity - - - Mon - Tue - Wed - Thu - Fri - - )} - - {activeChartMetric === 'swaps' && ( - - - - - - - - - - - - - - - - - - - - Swaps volume - 254 completed - - - Mon - Tue - Wed - Thu - Fri - - )} -
-
- - {/* 🔴 LIVE Audit Audit & Log terminal Stream */} -
-
-

- Live Telemetry Feed -

- -
- -
- {auditLogs.map(log => { - const colors = { - info: 'text-blue-400', - warning: 'text-amber-400', - critical: 'text-red-400 font-bold', - success: 'text-emerald-400' - }; + {/* ========================================================================================================= */} + {/* 1. 👑 SUPER ADMIN VIEW / STATS / WORKSPACES */} + {/* ========================================================================================================= */} + {activeRole === 'super_admin' && ( + <> + {/* STATS */} +
+ {[ + { 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; return ( -
-
- [{log.timestamp}] source: {log.source} - - {log.level} +
+
+
+ +
+ + {stat.trend === 'up' ? : } + {stat.change}
-

{log.message}

+
+

{stat.value}

+

{stat.label}

+
); })}
-
- Telemetry stream synchronized - -
-
-
+ {/* TELEMETRY CHARTS & LOG TERMINAL */} +
+
+
+
+

Telemetry Analytics

+

Live operational ledger logs plotted against target performance guidelines

+
+
+ {[ + { id: 'revenue', label: 'Revenue Curve' }, + { id: 'utilization', label: 'Utilization' }, + { id: 'swaps', label: 'Cabinet stress' } + ].map(opt => ( + + ))} +
+
- {/* DUAL WORKSPACE: INTERACTIVE KYC DESK & HARDWARE FLEET TELEMETRY */} -
+ {/* Hand-Crafted Interactive Vector Graph */} +
+
+ Active Operations + Target Projection +
- {/* Interactive KYC Pending Table / List */} -
-
-
-

KYC Pending Desk

-

{pendingKYCList.length} requests await secure super-admin sign-off

+ {activeChartMetric === 'revenue' && ( + + + + + + + + + + + + + + + + + + Date: 17th May + ৳45,600 Daily + + Mon + Tue + Wed + Thu + Fri + + )} + + {activeChartMetric === 'utilization' && ( + + + + + + + + + + + + + + + + + Utilization rate + 78% capacity + + Mon + Tue + Wed + Thu + Fri + + )} + + {activeChartMetric === 'swaps' && ( + + + + + + + + + + + + + + + + + Swaps volume + 254 completed + + Mon + Tue + Wed + Thu + Fri + + )} +
- {/* Search inputs */} -
- - 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" - /> + {/* LIVE TELEMETRY BLACK FEED TERMINAL */} +
+
+

+ Live Telemetry Feed +

+ +
+ +
+ {auditLogs.map(log => { + const colors = { + info: 'text-blue-400', + warning: 'text-amber-400', + critical: 'text-red-400 font-bold', + success: 'text-emerald-400' + }; + return ( +
+
+ [{log.timestamp}] source: {log.source} + + {log.level} + +
+

{log.message}

+
+ ); + })} +
+ +
+ Telemetry synchronized + +
-
- {filteredKYCs.map(kyc => ( -
-
-
-

{kyc.userName}

-

{kyc.phone}

-
- TIN Files Verified - License Valid + {/* DUAL WORKSPACE: INTERACTIVE KYC DESK & TELEMATICS FLEET CONTROL */} +
+ {/* KYC Pending Desk */} +
+
+
+

KYC Pending Desk

+

{pendingKYCList.length} requests await secure super-admin sign-off

+
+
+ + 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" + /> +
+
+ +
+ {filteredKYCs.map(kyc => ( +
+
+
+

{kyc.userName}

+

{kyc.phone}

+
+ TIN Verified + NID Match +
+
+ {kyc.submittedAt} +
+ +
+ +
- {kyc.submittedAt} -
+ ))} -
- - -
+ {filteredKYCs.length === 0 && ( +
+ +

No pending KYC files.

+
+ )}
- ))} - - {filteredKYCs.length === 0 && ( -
- -

No pending KYC files match your filter.

-
- )} -
-
- - {/* Live Hardware EV Fleet lock controller dashboard */} -
-
-
-

OTA Vehicle Telematics Dashboard

-

Direct OTA remote control node to override vehicle immobilizers or warn operators

-
- - 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" - /> -
-
+ {/* Live Hardware EV Fleet lock controller dashboard */} +
+
+
+

OTA Vehicle Telematics Dashboard

+

Direct OTA remote control node to override vehicle immobilizers or warn operators

+
+ +
+ + 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" + /> +
+
- {/* Desktop Table View */} -
- - - - - - - - - - - + {/* Desktop Table View */} +
+
EV InfoCharge statusAudit locationOTA Lock OverrideSiren Warning
+ + + + + + + + + + + {filteredFleet.map(bike => { + const isRented = bike.status === 'rented'; + return ( + + + + + + + + ); + })} + +
EV InfoCharge statusAudit locationOTA Lock OverrideSiren Warning
+

{bike.model}

+ {bike.plateNumber} +
+
+ 70 ? 'bg-green-500' : bike.batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500' + }`} /> + {bike.batteryLevel}% +
+
+ {bike.location} + + + + +
+
+ + {/* Mobile Card Layout */} +
{filteredFleet.map(bike => { const isRented = bike.status === 'rented'; return ( - - -

{bike.model}

- {bike.plateNumber} - - -
- 70 ? 'bg-green-500' : bike.batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500' - }`} /> - {bike.batteryLevel}% +
+
+
+

{bike.model}

+

{bike.plateNumber}

- - - {bike.location} - - +
+ 70 ? 'bg-green-500' : bike.batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500' + }`} /> + {bike.batteryLevel}% +
+
+
+ Audit Location: + {bike.location} +
+
- - - - +
+
); })} - - +
+
+ + )} - {/* Mobile Card Layout */} -
- {filteredFleet.map(bike => { - const isRented = bike.status === 'rented'; + {/* ========================================================================================================= */} + {/* 2. 🏢 HUB MANAGER VIEW / STATS / WORKSPACES */} + {/* ========================================================================================================= */} + {activeRole === 'hub_manager' && ( + <> + {/* STATS */} +
+ {[ + { label: 'Total EV Hub Inventory', value: '28 Bikes', change: '100% capacity', icon: Bike, color: 'text-blue-600 border-blue-100 bg-blue-50/30' }, + { label: 'Swappable Battery Cells', value: '84 Cells', change: 'Gulshan Hub', icon: BatteryCharging, color: 'text-emerald-600 border-emerald-100 bg-emerald-50/30' }, + { label: 'Active Charging Cabinets', value: '16 Slots', change: '8 empty slots', icon: Cpu, color: 'text-purple-600 border-purple-100 bg-purple-50/30' }, + { label: 'Pending Service Tickets', value: serviceTickets.length, change: '2 critical dispatches', icon: Wrench, color: 'text-amber-600 border-amber-100 bg-amber-50/30' } + ].map((stat, i) => { + const Icon = stat.icon; return ( -
+
-
-

{bike.model}

-

{bike.plateNumber}

-
-
- 70 ? 'bg-green-500' : bike.batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500' - }`} /> - {bike.batteryLevel}% +
+
+ + {stat.change} +
-
- Audit Location: - {bike.location} -
-
- - +
+

{stat.value}

+

{stat.label}

); })}
-
-
- {/* QUICK OPERATIONS CONSOLE & CENTRAL UTILITIES */} -
+ {/* TELEMETRY CHARTS & THERMAL SPECTRUMS */} +
+
+
+

Hub Grid Thermal Balancing Curve

+

Gulshan Cabinet battery temperature levels monitored during concurrent quick swap balancing

+
+ +
+ + + + + + {/* Temp Curve (Normal limits: 30-45 deg C) */} + + + + + + Cell Temp + 38°C Balanced + + 08:00 + 12:00 + 16:00 + 20:00 + 23:00 + +
+
- {/* Super Admin Quick tools */} -
-
-

Super-Admin Commands Console

-

Rapid access control widgets to configure environment variables or databases

+ {/* LIVE TELEMETRY BLACK FEED TERMINAL */} +
+
+

+ Live Telemetry Feed +

+ +
+ +
+ {auditLogs.filter(l => l.source === 'SWAP' || l.source === 'FLEET').map(log => ( +
+
+ [{log.timestamp}] source: {log.source} +
+

{log.message}

+
+ ))} +
+ +
+ Hub Telemetry synced +
+
-
+ {/* DUAL WORKSPACE: INTERACTIVE CABINET DOOR RELEASER & SERVICE TICKETS */} +
+ + {/* Interactive Cabinet Slots Releaser */} +
+
+

Gulshan Swap Cabinet #1

+

Click to remotely release slot electromagnet lock during hardware issues

+
+ +
+ {cabinetSlots.map(cab => { + const isEmpty = cab.status === 'empty'; + const isCharging = cab.status === 'charging'; + return ( + + ); + })} +
+
+ + {/* Service / Maintenance Tickets Desk */} +
+
+

Active Maintenance Ticket queue

+

Authorize physical mechanics team dispatchments to handle bike failures

+
+ +
+ {serviceTickets.map(tkt => ( +
+
+
+ {tkt.model} + {tkt.id} + + {tkt.urgency} Urgency + +
+

{tkt.issue}

+
+ + +
+ ))} + + {serviceTickets.length === 0 && ( +
+ +

All service tickets resolved! Hub operational.

+
+ )} +
+
+
+ + )} + + {/* ========================================================================================================= */} + {/* 3. 💼 ACCOUNTANT VIEW / STATS / WORKSPACES */} + {/* ========================================================================================================= */} + {activeRole === 'accountant' && ( + <> + {/* STATS */} +
{[ - { 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) => ( - - ))} -
-
- - {/* Global Security Alerts Panel */} -
-
-

Live Security & Maintenance Telemetry

-

Critical operating limit warnings pushed from connected swap hardware nodes

+ ); + })}
-
-
- -
-

Monsoon Load Warning active

-

Speed limited to 30km/h for Yadea fleet elements inside high rainfall areas.

+ {/* TELEMETRY CHARTS & ACCOUNTING BALANCES */} +
+
+
+

Weekly Corporate Cash Ledger curve

+

Rental receivables collection compared with investor yield payouts

+
+ +
+ + + + + + {/* Ledger Curve */} + + + + + + + Ledger Flow + ৳128,400 Pay + + Mon + Tue + Wed + Thu + Fri +
-
-
- -
-

Battery inventory warnings at Gulshan station

-

Station has only 1 fully charged cabinet remaining. Restock is required immediately.

+ {/* LIVE TELEMETRY BLACK FEED TERMINAL */} +
+
+

+ Live Telemetry Feed +

+ +
+ +
+ {auditLogs.filter(l => l.source === 'ACCOUNTING' || l.source === 'USER').map(log => ( +
+
+ [{log.timestamp}] source: {log.source} +
+

{log.message}

+
+ ))} +
+ +
+ Ledger Node synced +
+
+
+ + {/* DUAL WORKSPACE: JOURNAL ENTRIES DRAFTS & OVERDUE COLLECTIONS */} +
+ + {/* Journal Entry Drafts Desk */} +
+
+

Active Journal Voucher drafts

+

Post auto-accrued billing vouchers to Active Corporate books

+
+ +
+ {journalVouchers.map(jv => ( +
+
+
+ {jv.id} + {jv.date} + + {jv.status} + +
+

{jv.desc}

+
+ +
+
+

Debit / Credit

+

৳{jv.debit}

+
+ {jv.status === 'draft' ? ( + + ) : ( +
+ Posted +
+ )} +
+
+ ))} +
+
+ + {/* Overdue Biker Collections desk */} +
+
+

Overdue Biker Ledgers

+

Collect due balances or issue instant remote SMS payment warnings

+
+ +
+ {pastDueBikers.map(bkr => ( +
+
+
+

{bkr.name}

+

{bkr.mobile}

+
+
+

Past Due

+

৳{bkr.pastDueAmount}

+
+
+ +
+ + +
+
+ ))} +
+
+
+ + )} + + {/* ========================================================================================================= */} + {/* 4. 🙋 FRONT DESK OFFICER VIEW / STATS / WORKSPACES */} + {/* ========================================================================================================= */} + {activeRole === 'front_desk' && ( + <> + {/* STATS */} +
+ {[ + { label: 'Bikers Waiting in Queue', value: `${walkinQueue.length} Bikers`, change: 'Walk-in lobby', icon: Users, color: 'text-blue-600 border-blue-100 bg-blue-50/30' }, + { label: 'Ready EV Plates in parking', value: '8 Bikes', change: 'Assigned available', icon: Bike, color: 'text-emerald-600 border-emerald-100 bg-emerald-50/30' }, + { label: 'Incomplete KYC Files', value: `${kycRequests.filter(k => k.status === 'pending').length} Files`, change: 'Awaiting doc upload', icon: Shield, color: 'text-purple-600 border-purple-100 bg-purple-50/30' }, + { label: 'Swaps Processed Today', value: '42 Swaps', change: 'Manual tokens issued', icon: BatteryCharging, color: 'text-amber-600 border-amber-100 bg-amber-50/30' } + ].map((stat, i) => { + const Icon = stat.icon; + return ( +
+
+
+ +
+ + {stat.change} + +
+
+

{stat.value}

+

{stat.label}

+
+
+ ); + })} +
+ + {/* TELEMETRY CHARTS & WALK-IN LOG TELEMETRY */} +
+
+
+

Walk-in Swaps Queue density

+

Average wait times mapped against support hours throughout today

+
+ +
+ + + + + + {/* Wait times Bar Chart SVG */} + + + + + + + + 09:00 + 11:00 + 13:00 + 15:00 + 17:00 + 19:00 + +
+
+ + {/* LIVE TELEMETRY BLACK FEED TERMINAL */} +
+
+

+ Live Telemetry Feed +

+ +
+ +
+ {auditLogs.filter(l => l.source === 'USER' || l.source === 'KYC').map(log => ( +
+
+ [{log.timestamp}] source: {log.source} +
+

{log.message}

+
+ ))} +
+ +
+ Front Desk synced +
+
+
+ + {/* DUAL WORKSPACE: WALK-IN BIKE ASSIGNMENTS & KYC PHYSICAL DOCUMENTS DESK */} +
+ + {/* Walk-in Biker check-in desk */} +
+
+

Walk-in Biker Assignment desk

+

Assign ready EV plate numbers directly to lobby checked-in bikers

+
+ +
+ {walkinQueue.map(qBkr => ( +
+
+
+

{qBkr.name}

+

{qBkr.purpose}

+
+ {qBkr.regDate} check-in +
+ +
+ + +
+
+ ))} + + {walkinQueue.length === 0 && ( +
+ +

All checked-in walkins assigned! Lobby empty.

+
+ )} +
+
+ + {/* Incomplete KYC physical document uploads */} +
+
+
+

Walk-in KYC Upload Queue

+

{pendingKYCList.length} bikers require physical document scan uploads

+
+
+ +
+ {pendingKYCList.slice(0, 3).map(kyc => ( +
+
+

{kyc.userName}

+

{kyc.phone} • Submitted: {kyc.submittedAt}

+
+ +
+ + +
+
+ ))} +
+
+
+ + )} + + {/* COMMAND COMMANDS Drawer triggers */} + {activeRole === 'super_admin' && ( +
+
+
+

Super-Admin Commands Console

+

Rapid access control widgets to configure environment variables or databases

+
+ +
+ {[ + { 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) => ( + + ))} +
+
+ + {/* Global Security Alerts Panel */} +
+
+

Live Security & Telemetry alerts

+

Critical operating limit warnings pushed from connected swap hardware nodes

+
+ +
+
+ +
+

Monsoon Load Warning active

+

Speed limited to 30km/h for Yadea fleet elements inside high rainfall areas.

+
+ +
+ +
+ +
+

Battery inventory warnings at Gulshan station

+

Station has only 1 fully charged cabinet remaining. Restock is required immediately.

+
+ + Dispatch Hub +
- - Dispatch Hub -
-
+ )} - {/* ========================================= MONSOON / GLOBAL OVERRIDE SIMULATOR PANEL DRAWER ========================================= */} + {/* Global Simulator modal */} {showToolsDrawer && (
-
+
@@ -767,10 +1373,10 @@ export default function AdminDashboard() {
- +
-

Select global environment load override conditions. These parameters immediately scale system-wide biker limitations, accounting calculations, and thermal thresholds.

- +

Select global environment load override conditions.

+
@@ -787,8 +1393,8 @@ export default function AdminDashboard() { 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" >
-

Peak Hour Swaps load

-

cabinet reserves restricted, grid loading warnings active.

+

Peak Grid load

+

cabinet reserves restricted.