'use client'; import { useState, useEffect } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { Shield, Check, Clock, Bike, User, Phone, MapPin, FileText, Image, DollarSign, Wrench, Battery, CheckCircle, XCircle, ArrowLeft, Save, Printer, Send, MessageSquare, Edit, UserCheck, Wallet, Store, Globe, Calendar, Briefcase, Plus, Upload } from 'lucide-react'; type ApplicationSource = 'app' | 'web' | 'walkin' | 'referral'; type KYCType = 'biker' | 'investor' | 'shop' | 'merchant' | 'general'; type RiderPlan = 'daily_rent' | 'weekly_rent' | 'monthly_rent' | 'rent_to_own' | 'share_ev'; type VerificationStage = 'application' | 'document_collection' | 'risk_check' | 'plan_selection' | 'payment' | 'agreement' | 'allocated' | 'active'; interface Document { id: string; name: string; status: 'pending' | 'uploaded' | 'approved' | 'rejected'; imageUrl?: string; rejectedReason?: string; uploadedAt?: string; } interface Request { id: string; applicationSource: ApplicationSource; sourceDetails?: string; name: string; phone: string; email: string; type: KYCType; status: 'pending' | 'documents_needed' | 'under_review' | 'risk_check' | 'approved' | 'rejected'; verificationStage: VerificationStage; submittedAt: string; location: string; address: string; requiredDocuments: Document[]; riderPlan?: RiderPlan; nomineeDetails?: { name: string; phone: string; relationship: string; nid: string }; employmentInfo?: { company: string; dailyEarning: number; whyEV: string; experience: string }; riskCheck?: { nidVerified: boolean; nomineeNidVerified: boolean; deliveryPlatformStatus: string; paymentReliability: string; notes: string }; agreement?: { dailyRentObligation: number; latePenalty: number; signedAt?: string }; evAllocation?: { evId: string; bikeModel: string; batteryId: string; hubLocation: string; gpsActivated: boolean }; securityDeposit?: number; advancePayment?: number; paymentMethod?: 'bank' | 'wallet' | 'cash'; bikeRequested?: string; scheduleDate?: string; notes: string[]; messageHistory: { date: string; message: string; from: 'admin' | 'user' }[]; } const mockRequests: Request[] = [ { id: 'REQ001', applicationSource: 'app', name: 'Rahim Ahmed', phone: '01712345678', email: 'rahim@email.com', type: 'biker', status: 'pending', verificationStage: 'application', submittedAt: '2024-03-20', location: 'Gulshan, Dhaka', address: 'House 12, Road 5, Gulshan 1', requiredDocuments: [ { id: 'd1', name: 'NID Front', status: 'uploaded', uploadedAt: '2024-03-20' }, { id: 'd2', name: 'NID Back', status: 'uploaded', uploadedAt: '2024-03-20' }, { id: 'd3', name: 'Driving License', status: 'pending' }, { id: 'd4', name: 'Profile Photo', status: 'uploaded', uploadedAt: '2024-03-20' }, ], riderPlan: 'daily_rent', employmentInfo: { company: 'Foodpanda', dailyEarning: 2500, whyEV: 'Low maintenance, good for delivery', experience: '3 years bike riding' }, nomineeDetails: { name: 'Fatema', phone: '01712345699', relationship: 'Wife', nid: '1234567890123' }, securityDeposit: 5000, advancePayment: 500, bikeRequested: 'AIMA Lightning', notes: ['Downloaded app and applied through mobile'], messageHistory: [], }, { id: 'REQ002', applicationSource: 'walkin', sourceDetails: 'Gulshan Hub', name: 'Karim Hasan', phone: '01712345679', email: 'karim@email.com', type: 'investor', status: 'documents_needed', verificationStage: 'document_collection', submittedAt: '2024-03-19', location: 'Banani, Dhaka', address: 'Flat 3B, House 22, Banani', requiredDocuments: [ { id: 'd5', name: 'NID', status: 'uploaded', uploadedAt: '2024-03-19' }, { id: 'd6', name: 'TIN Certificate', status: 'pending' }, { id: 'd7', name: 'Bank Statement', status: 'pending' }, ], notes: ['Walked in at Gulshan office - referred by current biker'], messageHistory: [], }, ]; const statusColors: Record = { pending: 'bg-amber-100 text-amber-700', documents_needed: 'bg-orange-100 text-orange-700', under_review: 'bg-blue-100 text-blue-700', risk_check: 'bg-purple-100 text-purple-700', approved: 'bg-green-100 text-green-700', rejected: 'bg-red-100 text-red-700', }; const stageLabels: Record = { application: 'Application', document_collection: 'Documents', risk_check: 'Risk Check', plan_selection: 'Plan Selection', payment: 'Payment', agreement: 'Agreement', allocated: 'EV Allocated', active: 'Active', }; const sourceLabels: Record = { app: 'Mobile App', web: 'Website', walkin: 'Walk-in', referral: 'Referral', }; const planLabels: Record = { daily_rent: 'Daily Rent', weekly_rent: 'Weekly Rent', monthly_rent: 'Monthly Rent', rent_to_own: 'Rent-to-Own', share_ev: 'Share EV', }; const typeIcons: Record = { biker: Bike, investor: DollarSign, shop: Store, merchant: User, }; export default function KYCDetailPage() { const params = useParams(); const router = useRouter(); const id = params.id as string; const [request, setRequest] = useState(null); const [editMode, setEditMode] = useState(false); const [editForm, setEditForm] = useState>({}); const [showMessageModal, setShowMessageModal] = useState(false); const [showAddNoteModal, setShowAddNoteModal] = useState(false); const [newNoteText, setNewNoteText] = useState(''); const [newMessageText, setNewMessageText] = useState(''); const [showAddDocModal, setShowAddDocModal] = useState(false); const [newDocName, setNewDocName] = useState(''); const [showUploadDocModal, setShowUploadDocModal] = useState(false); const [uploadDocId, setUploadDocId] = useState(null); useEffect(() => { const found = mockRequests.find(r => r.id === id); if (found) { setRequest(found); setEditForm(found); } }, [id]); if (!request) { return (

Request not found

); } const handleSaveEdit = () => { setRequest(prev => prev ? { ...prev, ...editForm } : null); setEditMode(false); }; const handleAddNote = () => { if (!request || !newNoteText.trim()) return; setRequest(prev => prev ? { ...prev, notes: [...prev.notes, newNoteText] } : null); setNewNoteText(''); setShowAddNoteModal(false); }; const handleSendMessage = () => { if (!request || !newMessageText.trim()) return; setRequest(prev => prev ? { ...prev, messageHistory: [...prev.messageHistory, { date: new Date().toISOString().split('T')[0], message: newMessageText, from: 'admin' as const }] } : null); setNewMessageText(''); setShowMessageModal(false); }; const handleAddDocument = () => { if (!request || !newDocName.trim()) return; setRequest(prev => prev ? { ...prev, requiredDocuments: [...prev.requiredDocuments, { id: `doc-${Date.now()}`, name: newDocName, status: 'pending' as const }] } : null); setNewDocName(''); setShowAddDocModal(false); }; const handleApproveDocument = (docId: string) => { if (!request) return; setRequest(prev => prev ? { ...prev, requiredDocuments: prev.requiredDocuments.map(doc => doc.id === docId ? { ...doc, status: 'approved' as const } : doc ) } : null); }; const handleRejectDocument = (docId: string) => { const reason = prompt('Enter rejection reason:'); if (reason) { setRequest(prev => prev ? { ...prev, requiredDocuments: prev.requiredDocuments.map(doc => doc.id === docId ? { ...doc, status: 'rejected' as const, rejectedReason: reason } : doc ) } : null); } }; const handleUploadDocument = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file || !uploadDocId || !request) return; const imageUrl = URL.createObjectURL(file); setRequest(prev => prev ? { ...prev, requiredDocuments: prev.requiredDocuments.map(doc => doc.id === uploadDocId ? { ...doc, status: 'uploaded' as const, imageUrl, uploadedAt: new Date().toISOString() } : doc ) } : null); setShowUploadDocModal(false); }; const openUploadModal = (docId: string) => { setUploadDocId(docId); setShowUploadDocModal(true); }; const TypeIcon = typeIcons[request.type]; return (

{request.id}

{request.status.replace('_', ' ')} {request.type === 'biker' && request.verificationStage && ( {stageLabels[request.verificationStage]} )}

{request.name} • {request.submittedAt}

{editMode ? ( <> ) : ( <> {request.type === 'biker' && request.status !== 'approved' && ( )} {request.type === 'investor' && request.status !== 'approved' && ( )} {request.type === 'shop' && request.status !== 'approved' && ( )} {request.type === 'merchant' && request.status !== 'approved' && ( )} )}

Personal Info

{editMode ? (
setEditForm({ ...editForm, name: e.target.value })} placeholder="Full Name" className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" /> setEditForm({ ...editForm, phone: e.target.value })} placeholder="Phone" className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" /> setEditForm({ ...editForm, email: e.target.value })} placeholder="Email" className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" /> setEditForm({ ...editForm, location: e.target.value })} placeholder="Location" className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm" />
) : (
Name{request.name}
Phone{request.phone}
Email{request.email || '-'}
Location{request.location}
)}

Source

Source{sourceLabels[request.applicationSource]}
{request.sourceDetails &&
Details{request.sourceDetails}
}
Type {request.type}
{request.type === 'biker' && (

Plan Selection

{editMode ? (
setEditForm({ ...editForm, bikeRequested: e.target.value })} placeholder="Bike Model" className="w-full px-3 py-2 border border-purple-200 rounded-lg text-sm" />
) : (
Plan{request.riderPlan ? planLabels[request.riderPlan] : '-'}
Bike{request.bikeRequested || '-'}
{request.scheduleDate &&
Schedule{request.scheduleDate}
}
)}
)} {request.type === 'biker' && request.nomineeDetails && (

Nominee Details

{editMode ? (
setEditForm({ ...editForm, nomineeDetails: { ...editForm.nomineeDetails!, name: e.target.value } })} placeholder="Nominee Name" className="w-full px-3 py-2 border border-pink-200 rounded-lg text-sm" /> setEditForm({ ...editForm, nomineeDetails: { ...editForm.nomineeDetails!, phone: e.target.value } })} placeholder="Phone" className="w-full px-3 py-2 border border-pink-200 rounded-lg text-sm" /> setEditForm({ ...editForm, nomineeDetails: { ...editForm.nomineeDetails!, relationship: e.target.value } })} placeholder="Relationship" className="w-full px-3 py-2 border border-pink-200 rounded-lg text-sm" />
) : (
Name{request.nomineeDetails.name}
Phone{request.nomineeDetails.phone}
Relationship{request.nomineeDetails.relationship}
NID{request.nomineeDetails.nid}
)}
)}

Documents ({request.requiredDocuments.length})

{request.requiredDocuments.map((doc) => (
{doc.status === 'pending' && } {doc.status === 'uploaded' && } {doc.status === 'approved' && } {doc.status === 'rejected' && } {doc.name}
{doc.status === 'pending' && ( )} {(doc.status === 'uploaded' || doc.status === 'approved') && doc.imageUrl && ( )} {doc.status === 'uploaded' && ( <> )} {doc.status === 'approved' && Approved} {doc.status === 'rejected' && Rejected} {doc.status === 'pending' && Pending}
))}
{request.type === 'biker' && request.employmentInfo && (

Employment

Company{request.employmentInfo.company}
Daily Earning৳{request.employmentInfo.dailyEarning}
Experience{request.employmentInfo.experience}
)}

Notes ({request.notes.length})

{request.notes.length > 0 ? (
{request.notes.map((note, idx) => (
• {note}
))}
) : (

No notes yet

)}

Messages ({request.messageHistory.length})

{request.messageHistory.length > 0 ? (
{request.messageHistory.map((msg, idx) => (
{msg.from === 'admin' ? 'Admin' : 'User'}: {msg.message} {msg.date}
))}
) : (

No messages yet

)}
{showMessageModal && (

Send Message