2026-05-17 23:45:38 +06:00
'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
2026-04-22 01:02:45 +06:00
} from 'lucide-react' ;
2026-05-17 23:45:38 +06:00
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 ;
}
2026-04-22 01:02:45 +06:00
2026-05-17 23:45:38 +06:00
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)' }
2026-04-22 01:02:45 +06:00
] ;
2026-05-17 23:45:38 +06:00
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' }
] ;
2026-04-22 01:02:45 +06:00
export default function AdminDashboard() {
2026-05-17 23:45:38 +06:00
// 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 ) ;
} ) ;
2026-04-22 01:02:45 +06:00
return (
2026-05-17 23:45:38 +06:00
< div className = "p-4 lg:p-6 max-w-8xl mx-auto space-y-6" >
{ /* 👑 SUPER ADMIN SECURITY HEADER BANNER */ }
< div className = "bg-white text-slate-800 rounded-2xl p-5 border border-slate-200 shadow-sm relative overflow-hidden" >
< 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 flex-wrap" >
< 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 >
{ /* System Telemetry Metadata */ }
< 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 >
2026-04-22 01:02:45 +06:00
< / div >
< / div >
2026-05-17 23:45:38 +06:00
{ /* 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 ) = > {
2026-04-22 01:02:45 +06:00
const Icon = stat . icon ;
return (
2026-05-17 23:45:38 +06:00
< 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 justify-between items-start" >
< div className = { ` w-10 h-10 rounded-lg flex items-center justify-center border ${ stat . color } ` } >
< Icon className = "w-5 h-5" / >
2026-04-22 01:02:45 +06:00
< / div >
2026-05-17 23:45:38 +06:00
< 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'
} ` }>
2026-04-22 01:02:45 +06:00
{ stat . trend === 'up' ? < ArrowUpRight className = "w-3 h-3" / > : < ArrowDownRight className = "w-3 h-3" / > }
{ stat . change }
< / span >
< / div >
2026-05-17 23:45:38 +06:00
< div className = "mt-4" >
< 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 >
2026-04-22 01:02:45 +06:00
< / div >
) ;
} ) }
< / div >
2026-05-17 23:45:38 +06:00
{ /* CORE TELEMETRY ANALYTICS: CUSTOM INTERACTIVE VECTOR SVG CHARTS */ }
< div className = "grid lg:grid-cols-3 gap-6" >
{ /* SVG High-Fidelity Chart */ }
< 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 className = "flex gap-1.5 p-1 bg-slate-50 border border-slate-200 rounded-lg self-start" >
{ [
{ 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 : 17 th 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 >
2026-04-22 01:02:45 +06:00
< / div >
2026-05-17 23:45:38 +06:00
< / 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" >
2026-04-22 01:02:45 +06:00
< tr >
2026-05-17 23:45:38 +06:00
< 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 font-bold text-slate-500 uppercase tracking-wider" > Charge status < / 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 font-bold text-slate-500 uppercase tracking-wider" > OTA Lock Override < / th >
< th className = "px-4 py-3 text-right font-bold text-slate-500 uppercase tracking-wider" > Siren Warning < / th >
2026-04-22 01:02:45 +06:00
< / tr >
< / thead >
< tbody className = "divide-y divide-slate-50" >
2026-05-17 23:45:38 +06:00
{ filteredFleet . map ( bike = > {
const isRented = bike . status === 'rented' ;
2026-04-22 01:02:45 +06:00
return (
2026-05-17 23:45:38 +06:00
< tr key = { bike . id } className = "hover:bg-slate-50/40 transition-colors" >
2026-04-22 01:02:45 +06:00
< td className = "px-4 py-3" >
2026-05-17 23:45:38 +06:00
< p className = "font-extrabold text-slate-800" > { bike . model } < / p >
< span className = "text-[10px] text-slate-400 font-mono tracking-tight" > { bike . plateNumber } < / span >
2026-04-22 01:02:45 +06:00
< / td >
< td className = "px-4 py-3" >
2026-05-17 23:45:38 +06:00
< div className = "flex items-center gap-1.5" >
< 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 >
2026-04-22 01:02:45 +06:00
< / td >
2026-05-17 23:45:38 +06:00
< td className = "px-4 py-3 font-semibold text-slate-500" >
{ bike . location }
2026-04-22 01:02:45 +06:00
< / td >
< td className = "px-4 py-3" >
2026-05-17 23:45:38 +06:00
< 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 >
2026-04-22 01:02:45 +06:00
< / td >
2026-05-17 23:45:38 +06:00
< td className = "px-4 py-3 text-right" >
< button
onClick = { ( ) = > handleTriggerSiren ( bike . plateNumber ) }
className = "p-1.5 hover:bg-red-50 rounded-lg text-slate-400 hover:text-red-600 transition-colors cursor-pointer"
title = "Trigger Anti-theft Audio Warning Beacon"
>
< Volume2 className = "w-4 h-4" / >
< / button >
2026-04-22 01:02:45 +06:00
< / td >
< / tr >
) ;
} ) }
< / tbody >
< / table >
< / div >
2026-05-17 23:45:38 +06:00
{ /* Mobile Card Layout */ }
< 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" >
{ filteredFleet . map ( bike = > {
const isRented = bike . status === 'rented' ;
return (
< div key = { bike . id } className = "bg-white p-4 rounded-xl border border-slate-100 shadow-sm space-y-3" >
< div className = "flex justify-between items-start" >
< div >
< h4 className = "font-extrabold text-slate-800 text-sm" > { bike . model } < / h4 >
< p className = "text-[10px] text-slate-400 font-mono mt-0.5" > { bike . plateNumber } < / p >
< / div >
< div className = "flex items-center gap-1 bg-slate-50 border border-slate-100 rounded-lg px-2 py-0.5" >
< span className = { ` w-2 h-2 rounded-full ${ bike . batteryLevel > 70 ? 'bg-green-500' : bike . batteryLevel > 30 ? 'bg-amber-500' : 'bg-red-500'
} ` } />
< span className = "font-mono text-slate-700 font-bold text-[10px]" > { bike . batteryLevel } % < / span >
< / div >
< / div >
< div className = "flex justify-between items-center text-xs font-bold text-slate-500" >
< span > Audit Location : < / span >
< span className = "text-slate-800" > { bike . location } < / span >
< / 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 < / >
) }
< / button >
< button
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 >
2026-04-22 01:02:45 +06:00
< / div >
< / div >
2026-05-17 23:45:38 +06:00
) ;
} ) }
2026-04-22 01:02:45 +06:00
< / div >
< / div >
< / div >
2026-05-17 23:45:38 +06:00
{ /* QUICK OPERATIONS CONSOLE & CENTRAL UTILITIES */ }
2026-04-22 01:02:45 +06:00
< div className = "grid lg:grid-cols-2 gap-6" >
2026-05-17 23:45:38 +06:00
{ /* 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 >
) ) }
2026-04-22 01:02:45 +06:00
< / div >
< / div >
2026-05-17 23:45:38 +06:00
{ /* 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 >
2026-04-22 01:02:45 +06:00
< div className = "space-y-3" >
2026-05-17 23:45:38 +06:00
< 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 30 km / h for Yadea fleet elements inside high rainfall areas . < / p >
2026-04-22 01:02:45 +06:00
< / div >
2026-05-17 23:45:38 +06:00
< 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 >
2026-04-22 01:02:45 +06:00
< / div >
2026-05-17 23:45:38 +06:00
< div className = "flex items-center gap-3 p-3 bg-amber-50 rounded-xl border border-amber-100" >
2026-04-22 01:02:45 +06:00
< Clock className = "w-5 h-5 text-amber-500" / >
2026-05-17 23:45:38 +06:00
< 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 >
2026-04-22 01:02:45 +06:00
< / div >
2026-05-17 23:45:38 +06:00
< button
onClick = { ( ) = > setShowToolsDrawer ( false ) }
className = "p-1 hover:bg-white/10 rounded-lg transition-colors text-white"
>
< XCircle className = "w-5 h-5" / >
< / button >
2026-04-22 01:02:45 +06:00
< / div >
2026-05-17 23:45:38 +06:00
< 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 30 km / 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 >
2026-04-22 01:02:45 +06:00
< / div >
< / div >
2026-05-17 23:45:38 +06:00
< 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 >
2026-04-22 01:02:45 +06:00
< / div >
< / div >
2026-05-17 23:45:38 +06:00
) }
2026-04-22 01:02:45 +06:00
< / div >
) ;
}