'use client'; import { useState, useEffect } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { AlertTriangle, Search, Plus, X, Check, Clock, Bike, User, Phone, MapPin, FileText, Image, DollarSign, Wrench, Battery, Key, CheckCircle, XCircle, ChevronLeft, Save, Printer, Send, QrCode, Wallet, Building, Edit, MessageSquare, Calendar, ArrowLeft } from 'lucide-react'; type TransactionType = 'deposit' | 'rent_income' | 'investor_funding' | 'investor_withdraw' | 'salary' | 'rent_expense' | 'utility' | 'maintenance' | 'bike_purchase' | 'bike_sale' | 'other_income' | 'other_expense'; type MaintenanceType = 'damage' | 'repair' | 'service' | 'battery_swap' | 'inspection' | 'other'; type DamageSeverity = 'critical' | 'major' | 'minor' | 'cosmetic'; type MaintenanceStatus = 'reported' | 'in_progress' | 'parts_ordered' | 'completed' | 'cancelled'; type PaymentStatus = 'pending' | 'approved' | 'paid' | 'rejected'; interface MaintenanceRecord { id: string; date: string; type: MaintenanceType; severity: DamageSeverity; status: MaintenanceStatus; paymentStatus: PaymentStatus; bikeId: string; bikeModel: string; bikePlate: string; batteryId?: string; reporterId: string; reporterName: string; reporterPhone: string; reporterRole: 'biker' | 'staff' | 'hub'; description: string; location: string; estimatedCost: number; actualCost?: number; partsUsed?: string[]; images: { id: string; name: string; url: string; uploadedAt: string }[]; assignedTo?: string; notes: string[]; resolvedAt?: string; createdAt: string; createdBy: string; } const mockMaintenance: MaintenanceRecord[] = [ { id: 'MNT-001', date: '2024-03-21', type: 'damage', severity: 'major', status: 'in_progress', paymentStatus: 'approved', bikeId: 'EV-004', bikeModel: 'AIMA Lightning', bikePlate: 'Dhaka Metro Cha-5679', batteryId: 'BAT-044', reporterId: 'BIKER-004', reporterName: 'Sofiq Rahman', reporterPhone: '01712345681', reporterRole: 'biker', description: 'Front fender damaged in accident at Gulshan signal', location: 'Gulshan, Dhaka', estimatedCost: 3500, actualCost: 3200, partsUsed: ['Front fender', 'Mounting brackets'], images: [ { id: 'img1', name: 'Damage Front', url: '', uploadedAt: '2024-03-21' }, { id: 'img2', name: 'Damage Side', url: '', uploadedAt: '2024-03-21' }, ], assignedTo: 'Service Center A', notes: ['Parts ordered from supplier'], createdAt: '2024-03-21T10:00:00', createdBy: 'Admin', }, { id: 'MNT-002', date: '2024-03-20', type: 'service', severity: 'minor', status: 'completed', paymentStatus: 'paid', bikeId: 'EV-002', bikeModel: 'Yadea DT3', bikePlate: 'Dhaka Metro Ba-1234', batteryId: 'BAT-021', reporterId: 'BIKER-002', reporterName: 'Karim Hasan', reporterPhone: '01712345679', reporterRole: 'biker', description: 'Routine service - brake adjustment and chain lubrication', location: 'Banani Hub', estimatedCost: 500, actualCost: 450, images: [], notes: ['Service completed'], resolvedAt: '2024-03-20T14:00:00', createdAt: '2024-03-20T08:00:00', createdBy: 'Hub Staff', }, { id: 'MNT-003', date: '2024-03-19', type: 'battery_swap', severity: 'minor', status: 'completed', paymentStatus: 'pending', bikeId: 'EV-007', bikeModel: 'Etron ET50', bikePlate: 'Dhaka Metro Ca-8901', reporterId: 'BIKER-007', reporterName: 'Jamal', reporterPhone: '01712345687', reporterRole: 'biker', description: 'Battery not holding charge properly - need replacement', location: 'Dhanmondi, Dhaka', estimatedCost: 0, images: [], notes: ['Battery replaced under warranty'], resolvedAt: '2024-03-19T16:00:00', createdAt: '2024-03-19T12:00:00', createdBy: 'Admin', }, { id: 'MNT-004', date: '2024-03-18', type: 'repair', severity: 'critical', status: 'in_progress', paymentStatus: 'pending', bikeId: 'EV-010', bikeModel: 'TVS iQube', bikePlate: 'Dhaka Metro Da-4567', reporterId: 'BIKER-010', reporterName: 'Ripon', reporterPhone: '01712345690', reporterRole: 'biker', description: 'Motor issue - bike not moving properly', location: 'Mirpur, Dhaka', estimatedCost: 8000, images: [ { id: 'img3', name: 'Motor Damage', url: '', uploadedAt: '2024-03-18' }, ], assignedTo: 'Authorized Service Center', notes: ['Motor needs replacement - ordered', 'Waiting for parts'], createdAt: '2024-03-18T09:00:00', createdBy: 'Admin', }, { id: 'MNT-005', date: '2024-03-17', type: 'inspection', severity: 'minor', status: 'completed', paymentStatus: 'paid', bikeId: 'EV-001', bikeModel: 'AIMA Lightning', bikePlate: 'Dhaka Metro Aa-1111', reporterId: 'Hub-01', reporterName: 'Gulshan Hub', reporterPhone: '02-1234567', reporterRole: 'hub', description: 'Monthly inspection completed', location: 'Gulshan Hub', estimatedCost: 300, actualCost: 250, images: [], notes: ['All checks passed'], resolvedAt: '2024-03-17T15:00:00', createdAt: '2024-03-17T10:00:00', createdBy: 'Hub Staff', }, { id: 'MNT-006', date: '2024-03-15', type: 'damage', severity: 'cosmetic', status: 'completed', paymentStatus: 'rejected', bikeId: 'EV-005', bikeModel: 'Yadea DT3', bikePlate: 'Dhaka Metro Ba-5678', reporterId: 'BIKER-005', reporterName: 'Rahim', reporterPhone: '01712345685', reporterRole: 'biker', description: 'Minor scratch on mirror - customer dropped bike slowly', location: 'Uttara, Dhaka', estimatedCost: 500, images: [], notes: ['Denied - user responsibility'], createdAt: '2024-03-15T14:00:00', createdBy: 'Admin', }, ]; const statusColors: Record = { reported: 'bg-amber-100 text-amber-700', in_progress: 'bg-blue-100 text-blue-700', parts_ordered: 'bg-purple-100 text-purple-700', completed: 'bg-green-100 text-green-700', cancelled: 'bg-red-100 text-red-700', }; const severityColors: Record = { critical: 'bg-red-100 text-red-700', major: 'bg-orange-100 text-orange-700', minor: 'bg-amber-100 text-amber-700', cosmetic: 'bg-slate-100 text-slate-700', }; const paymentColors: Record = { pending: 'bg-amber-100 text-amber-700', approved: 'bg-blue-100 text-blue-700', paid: 'bg-green-100 text-green-700', rejected: 'bg-red-100 text-red-700', }; const typeLabels: Record = { damage: 'Damage', repair: 'Repair', service: 'Service', battery_swap: 'Battery Swap', inspection: 'Inspection', other: 'Other', }; export default function MaintenanceDetailPage() { const params = useParams(); const router = useRouter(); const id = params.id as string; const [record, setRecord] = useState(null); const [editMode, setEditMode] = useState(false); const [showCompleteModal, setShowCompleteModal] = useState(false); const [showPaymentModal, setShowPaymentModal] = useState(false); const [showInvoiceModal, setShowInvoiceModal] = useState(false); const [showAddNoteModal, setShowAddNoteModal] = useState(false); const [editForm, setEditForm] = useState>({}); const [newNoteText, setNewNoteText] = useState(''); const [actualCost, setActualCost] = useState(''); useEffect(() => { const found = mockMaintenance.find(r => r.id === id); if (found) { setRecord(found); setEditForm(found); setActualCost(found.actualCost?.toString() || found.estimatedCost.toString()); } }, [id]); if (!record) { return (

Record not found

); } const handleSaveEdit = () => { setRecord(prev => prev ? { ...prev, ...editForm } : null); setEditMode(false); }; const handleComplete = () => { if (!record) return; const cost = parseInt(actualCost) || record.estimatedCost; setRecord(prev => prev ? { ...prev, status: 'completed', resolvedAt: new Date().toISOString().split('T')[0], actualCost: cost } : null); setShowCompleteModal(false); }; const handlePayment = (source: 'bank' | 'cash' | 'biker') => { if (!record) return; const cost = record.actualCost || record.estimatedCost; setRecord(prev => prev ? { ...prev, paymentStatus: 'paid' } : null); setShowPaymentModal(false); setShowInvoiceModal(true); }; const handleGenerateInvoice = () => { if (!record) return; import('jspdf').then(jsPDF => { const doc = new jsPDF.default(); const cost = record.actualCost || record.estimatedCost; const qrData = `INV-${record.id}|${record.bikePlate}|${record.type}|${cost}|${new Date().toISOString().split('T')[0]}`; doc.setFontSize(20); doc.setTextColor(6, 95, 70); doc.text('JAIBEN Mobility Ltd', 20, 20); doc.setFontSize(14); doc.setTextColor(0); doc.text('Maintenance Invoice', 20, 32); doc.setFontSize(10); doc.setTextColor(100); doc.text(`Invoice No: INV-${record.id}`, 20, 42); doc.text(`Date: ${record.date}`, 20, 48); doc.text(`Issue Type: ${typeLabels[record.type]}`, 20, 54); doc.text(`Severity: ${record.severity}`, 20, 60); doc.text(`Status: ${record.status}`, 20, 66); doc.setFontSize(11); doc.setTextColor(0); doc.text('Bike Details', 20, 80); doc.setFontSize(10); doc.text(`Bike ID: ${record.bikeId}`, 20, 86); doc.text(`Model: ${record.bikeModel}`, 20, 92); doc.text(`License Plate: ${record.bikePlate}`, 20, 98); if (record.batteryId) doc.text(`Battery ID: ${record.batteryId}`, 20, 104); doc.setFontSize(11); doc.text('Reporter', 20, 118); doc.setFontSize(10); doc.text(`Name: ${record.reporterName}`, 20, 124); doc.text(`Phone: ${record.reporterPhone}`, 20, 130); doc.text(`Role: ${record.reporterRole}`, 20, 136); doc.setFontSize(11); doc.text('Description', 20, 150); doc.setFontSize(10); const descLines = doc.splitTextToSize(record.description, 170); doc.text(descLines, 20, 156); doc.setFontSize(11); doc.text('Service Details', 120, 80); doc.setFontSize(10); doc.text(`Location: ${record.location}`, 120, 86); if (record.assignedTo) doc.text(`Assigned: ${record.assignedTo}`, 120, 92); if (record.resolvedAt) doc.text(`Resolved: ${record.resolvedAt}`, 120, 98); doc.setFontSize(11); doc.text('Cost Breakdown', 20, 175); doc.setFontSize(10); doc.text(`Estimated Cost: ৳${record.estimatedCost}`, 20, 181); if (record.actualCost) doc.text(`Actual Cost: ৳${record.actualCost}`, 20, 187); if (record.partsUsed && record.partsUsed.length > 0) { doc.text(`Parts: ${record.partsUsed.join(', ')}`, 20, 193); } doc.setFontSize(14); doc.setTextColor(6, 95, 70); doc.text(`Total: ৳${cost}`, 20, 205); doc.setFontSize(9); doc.setTextColor(150); doc.text('Generated from JAIBEN Maintenance System', 20, 280); doc.text(`QR: ${qrData}`, 20, 286); doc.save(`maintenance-invoice-${record.id}.pdf`); }); setShowInvoiceModal(false); }; const handleAddNote = () => { if (!record || !newNoteText.trim()) return; setRecord(prev => prev ? { ...prev, notes: [...prev.notes, newNoteText] } : null); setNewNoteText(''); setShowAddNoteModal(false); }; return (

{record.id}

{record.severity} {record.status.replace('_', ' ')} {record.paymentStatus}

{typeLabels[record.type]} • {record.date}

{editMode ? ( <> ) : ( <> {record.status !== 'completed' && ( )} {record.status === 'completed' && record.paymentStatus !== 'paid' && ( )} {record.paymentStatus === 'paid' && ( )} )}

Bike Information

{editMode ? (
setEditForm({ ...editForm, bikeId: e.target.value })} className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" />
setEditForm({ ...editForm, bikePlate: e.target.value })} className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" />
setEditForm({ ...editForm, bikeModel: e.target.value })} className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" />
setEditForm({ ...editForm, batteryId: e.target.value })} className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" />
) : (
Bike ID {record.bikeId}
Model {record.bikeModel}
License Plate {record.bikePlate}
{record.batteryId && (
Battery ID {record.batteryId}
)}
)}

Reporter

Name {record.reporterName}
Phone {record.reporterPhone}
Role {record.reporterRole}

Description

{editMode ? (