diff --git a/src/app/admin/page.tsx b/src/app/admin/page.tsx index 8259907..ee9d37a 100644 --- a/src/app/admin/page.tsx +++ b/src/app/admin/page.tsx @@ -1,114 +1,623 @@ -import { - Users, - Bike, - DollarSign, - TrendingUp, - Activity, - ArrowUpRight, - ArrowDownRight, - Clock, - Shield, - AlertTriangle, - CheckCircle, - XCircle -} from 'lucide-react'; -import { kycRequests, bikes, rentals, transactions } from '@/data/mockData'; +'use client'; -const stats = [ - { label: 'Total Bikers', value: '156', change: '+12%', trend: 'up', icon: Users, color: 'text-blue-600', bg: 'bg-blue-50' }, - { label: 'Active Rentals', value: '89', change: '+8%', trend: 'up', icon: Bike, color: 'text-green-600', bg: 'bg-green-50' }, - { label: 'Daily Revenue', value: '৳45.6k', change: '+23%', trend: 'up', icon: DollarSign, color: 'text-purple-600', bg: 'bg-purple-50' }, - { label: 'Fleet Utilization', value: '78%', change: '-2%', trend: 'down', icon: TrendingUp, color: 'text-amber-600', bg: 'bg-amber-50' }, +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 +} 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 activeRentals = rentals.filter(r => r.status === 'active'); +const mockLiveMessages = [ + { 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() { + // 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(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 ( -
-
-
-

Admin Dashboard

-

Manage fleet, users, and operations

-
-
- Last updated: - Just now +
+ + {/* 👑 SUPER ADMIN SECURITY HEADER BANNER */} +
+
+
+
+
+ +
+
+
+

JAIBEN Operations Command Center

+ + 👑 SUPER ADMIN ACCESS + + {sandboxMode && ( + + Sandbox Active + + )} +
+

Real-time telemetry, OTA secure triggers, and accounting ledger supervisor node

+
+
+ + {/* System Telemetry Metadata */} +
+
+ Telemetry Time + + {systemTime || 'Loading...'} + +
+
+ Server status + + ONLINE + +
+ +
-
- {stats.map((stat, index) => { + {/* 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}

+
+

{stat.value}

+

{stat.label}

+
); })}
-
-
-
-

Recent Rentals

- + {/* 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' + }; + return ( +
+
+ [{log.timestamp}] source: {log.source} + + {log.level} + +
+

{log.message}

+
+ ); + })} +
+ +
+ Telemetry stream synchronized + +
+
+ + + {/* DUAL WORKSPACE: INTERACTIVE KYC DESK & HARDWARE FLEET TELEMETRY */} +
+ + {/* Interactive KYC Pending Table / List */} +
+
+
+

KYC Pending Desk

+

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

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

{kyc.userName}

+

{kyc.phone}

+
+ TIN Files Verified + License Valid +
+
+ {kyc.submittedAt} +
+ +
+ + +
+
+ ))} + + {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" + /> +
+
+ + {/* Desktop Table View */} +
+
+ - - - - - - + + + + + - {activeRentals.map(rental => { - const bike = bikes.find(b => b.id === rental.bikeId); + {filteredFleet.map(bike => { + const isRented = bike.status === 'rented'; return ( - + + - - - ); @@ -116,96 +625,187 @@ export default function AdminDashboard() {
Rental IDBikeUserTypeStatusDaily RateEV InfoCharge statusAudit locationOTA Lock OverrideSiren Warning
- {rental.id} +

{bike.model}

+ {bike.plateNumber}
- {bike?.model} - {bike?.plateNumber} +
+ 70 ? 'bg-green-500' : bike.batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500' + }`} /> + {bike.batteryLevel}% +
+
+ {bike.location} - {rental.userId} + - {rental.type} - - - - {rental.status} - - - ৳{rental.dailyRate} + +
-
-
-
-

KYC Requests

- - {pendingKYCs.length} pending - -
-
- {pendingKYCs.map(kyc => ( -
-
-
-

{kyc.userName}

-

{kyc.phone}

-

- {kyc.submittedAt} -

+ {/* 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}% +
- - +
+ Audit Location: + {bike.location} +
+
+ + +
+
+ ); + })} +
+
+
+ + {/* QUICK OPERATIONS CONSOLE & CENTRAL UTILITIES */} +
+ + {/* Super Admin Quick tools */} +
+
+

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) => ( + - -
-
+ ))} - {pendingKYCs.length === 0 && ( -
- -

No pending KYC requests

-
- )} -
-
-
- -
-
-

Quick Actions

-
- - - -
-
-

System Alerts

+ {/* Global Security Alerts Panel */} +
+
+

Live Security & Maintenance Telemetry

+

Critical operating limit warnings pushed from connected swap hardware nodes

+
+
-
- -
-

3 bikes overdue maintenance

-

Action required

+
+ +
+

Monsoon Load Warning active

+

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

+
-
+ +
-
-

5 pending KYC verifications

-

Review needed

-
-
-
- -
-

System running smoothly

-

All services operational

+
+

Battery inventory warnings at Gulshan station

+

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

+ + Dispatch Hub +
+ + {/* ========================================= MONSOON / GLOBAL OVERRIDE SIMULATOR PANEL DRAWER ========================================= */} + {showToolsDrawer && ( +
+
+
+
+ +

Run Environment Simulation

+
+ +
+ +
+

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

+ +
+ + +
+
+ +
+ +
+
+
+ )}
); } \ No newline at end of file