Files
JML/src/app/admin/kyc/[id]/page.tsx

695 lines
34 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'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<string, string> = {
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<string, string> = {
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<string, string> = {
app: 'Mobile App',
web: 'Website',
walkin: 'Walk-in',
referral: 'Referral',
};
const planLabels: Record<string, string> = {
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<string, any> = {
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<Request | null>(null);
const [editMode, setEditMode] = useState(false);
const [editForm, setEditForm] = useState<Partial<Request>>({});
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<string | null>(null);
useEffect(() => {
const found = mockRequests.find(r => r.id === id);
if (found) {
setRequest(found);
setEditForm(found);
}
}, [id]);
if (!request) {
return (
<div className="p-6 flex items-center justify-center min-h-[50vh]">
<div className="text-center">
<Shield className="w-16 h-16 text-slate-300 mx-auto mb-4" />
<p className="text-slate-500">Request not found</p>
<button
onClick={() => router.push('/admin/kyc')}
className="mt-4 px-4 py-2 bg-accent text-white rounded-lg text-sm"
>
Back to KYC
</button>
</div>
</div>
);
}
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<HTMLInputElement>) => {
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 (
<div className="p-4 lg:p-6 max-w-8xl mx-auto">
<button
onClick={() => router.push('/admin/kyc')}
className="flex items-center gap-2 text-slate-600 hover:text-slate-800 mb-4"
>
<ArrowLeft className="w-4 h-4" /> Back to KYC
</button>
<div className="bg-white rounded-xl shadow-sm border border-slate-100 overflow-hidden">
<div className="p-6 border-b border-slate-100">
<div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-4">
<div>
<div className="flex items-center gap-3">
<h1 className="text-2xl font-extrabold text-slate-800">{request.id}</h1>
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full ${statusColors[request.status]}`}>
{request.status.replace('_', ' ')}
</span>
{request.type === 'biker' && request.verificationStage && (
<span className="inline-flex items-center gap-1 text-xs font-medium px-2.5 py-1 rounded-full bg-cyan-100 text-cyan-700">
{stageLabels[request.verificationStage]}
</span>
)}
</div>
<p className="text-slate-500 mt-1">{request.name} {request.submittedAt}</p>
</div>
<div className="flex gap-2">
{editMode ? (
<>
<button onClick={handleSaveEdit} className="px-4 py-2 bg-green-600 text-white rounded-lg text-sm hover:bg-green-700 flex items-center gap-2">
<Save className="w-4 h-4" /> Save
</button>
<button onClick={() => { setEditForm(request); setEditMode(false); }} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50">
Cancel
</button>
</>
) : (
<>
{request.type === 'biker' && request.status !== 'approved' && (
<button
onClick={() => {
if (confirm('Approve this request and create biker profile?')) {
setRequest(prev => prev ? { ...prev, status: 'approved', verificationStage: 'active' } : null);
alert('Biker created successfully!');
}
}}
className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm hover:bg-blue-700 flex items-center gap-2"
>
<Bike className="w-4 h-4" /> Make Biker
</button>
)}
{request.type === 'investor' && request.status !== 'approved' && (
<button
onClick={() => {
if (confirm('Approve this request and create investor profile?')) {
setRequest(prev => prev ? { ...prev, status: 'approved' } : null);
alert('Investor created successfully!');
}
}}
className="px-4 py-2 bg-purple-600 text-white rounded-lg text-sm hover:bg-purple-700 flex items-center gap-2"
>
<DollarSign className="w-4 h-4" /> Make Investor
</button>
)}
{request.type === 'shop' && request.status !== 'approved' && (
<button
onClick={() => {
if (confirm('Approve this request and create shop profile?')) {
setRequest(prev => prev ? { ...prev, status: 'approved' } : null);
alert('Shop created successfully!');
}
}}
className="px-4 py-2 bg-green-600 text-white rounded-lg text-sm hover:bg-green-700 flex items-center gap-2"
>
<Store className="w-4 h-4" /> Make Shop
</button>
)}
{request.type === 'merchant' && request.status !== 'approved' && (
<button
onClick={() => {
if (confirm('Approve this request and create merchant profile?')) {
setRequest(prev => prev ? { ...prev, status: 'approved' } : null);
alert('Merchant created successfully!');
}
}}
className="px-4 py-2 bg-orange-600 text-white rounded-lg text-sm hover:bg-orange-700 flex items-center gap-2"
>
<User className="w-4 h-4" /> Make Merchant
</button>
)}
<button onClick={() => setEditMode(true)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50 flex items-center gap-2">
<Edit className="w-4 h-4" /> Edit
</button>
<button onClick={() => setShowAddNoteModal(true)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50 flex items-center gap-2">
<MessageSquare className="w-4 h-4" /> Note
</button>
<button onClick={() => setShowMessageModal(true)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50 flex items-center gap-2">
<Send className="w-4 h-4" /> Message
</button>
</>
)}
</div>
</div>
</div>
<div className="p-6 grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="space-y-4">
<div className="bg-blue-50 p-4 rounded-xl border border-blue-100">
<h3 className="font-semibold text-blue-800 mb-3 flex items-center gap-2">
<User className="w-5 h-5" /> Personal Info
</h3>
{editMode ? (
<div className="space-y-3">
<input
type="text"
value={editForm.name || ''}
onChange={(e) => setEditForm({ ...editForm, name: e.target.value })}
placeholder="Full Name"
className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm"
/>
<input
type="text"
value={editForm.phone || ''}
onChange={(e) => setEditForm({ ...editForm, phone: e.target.value })}
placeholder="Phone"
className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm"
/>
<input
type="email"
value={editForm.email || ''}
onChange={(e) => setEditForm({ ...editForm, email: e.target.value })}
placeholder="Email"
className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm"
/>
<input
type="text"
value={editForm.location || ''}
onChange={(e) => setEditForm({ ...editForm, location: e.target.value })}
placeholder="Location"
className="w-full px-3 py-2 border border-blue-200 rounded-lg text-sm"
/>
</div>
) : (
<div className="space-y-2">
<div className="flex justify-between"><span className="text-sm text-blue-600">Name</span><span className="text-sm font-medium text-blue-800">{request.name}</span></div>
<div className="flex justify-between"><span className="text-sm text-blue-600">Phone</span><span className="text-sm font-medium text-blue-800">{request.phone}</span></div>
<div className="flex justify-between"><span className="text-sm text-blue-600">Email</span><span className="text-sm font-medium text-blue-800">{request.email || '-'}</span></div>
<div className="flex justify-between"><span className="text-sm text-blue-600">Location</span><span className="text-sm font-medium text-blue-800">{request.location}</span></div>
</div>
)}
</div>
<div className="bg-green-50 p-4 rounded-xl border border-green-100">
<h3 className="font-semibold text-green-800 mb-3 flex items-center gap-2">
<Globe className="w-5 h-5" /> Source
</h3>
<div className="space-y-2">
<div className="flex justify-between"><span className="text-sm text-green-600">Source</span><span className="text-sm font-medium text-green-800">{sourceLabels[request.applicationSource]}</span></div>
{request.sourceDetails && <div className="flex justify-between"><span className="text-sm text-green-600">Details</span><span className="text-sm font-medium text-green-800">{request.sourceDetails}</span></div>}
<div className="flex justify-between"><span className="text-sm text-green-600">Type</span><span className="text-sm font-medium text-green-800 capitalize flex items-center gap-1"><TypeIcon className="w-4 h-4" /> {request.type}</span></div>
</div>
</div>
{request.type === 'biker' && (
<div className="bg-purple-50 p-4 rounded-xl border border-purple-100">
<h3 className="font-semibold text-purple-800 mb-3 flex items-center gap-2">
<Calendar className="w-5 h-5" /> Plan Selection
</h3>
{editMode ? (
<div className="space-y-3">
<select
value={editForm.riderPlan || ''}
onChange={(e) => setEditForm({ ...editForm, riderPlan: e.target.value as RiderPlan })}
className="w-full px-3 py-2 border border-purple-200 rounded-lg text-sm"
>
<option value="">Select Plan</option>
<option value="daily_rent">Daily Rent</option>
<option value="weekly_rent">Weekly Rent</option>
<option value="monthly_rent">Monthly Rent</option>
<option value="rent_to_own">Rent-to-Own</option>
<option value="share_ev">Share EV</option>
</select>
<input
type="text"
value={editForm.bikeRequested || ''}
onChange={(e) => setEditForm({ ...editForm, bikeRequested: e.target.value })}
placeholder="Bike Model"
className="w-full px-3 py-2 border border-purple-200 rounded-lg text-sm"
/>
</div>
) : (
<div className="space-y-2">
<div className="flex justify-between"><span className="text-sm text-purple-600">Plan</span><span className="text-sm font-medium text-purple-800">{request.riderPlan ? planLabels[request.riderPlan] : '-'}</span></div>
<div className="flex justify-between"><span className="text-sm text-purple-600">Bike</span><span className="text-sm font-medium text-purple-800">{request.bikeRequested || '-'}</span></div>
{request.scheduleDate && <div className="flex justify-between"><span className="text-sm text-purple-600">Schedule</span><span className="text-sm font-medium text-purple-800">{request.scheduleDate}</span></div>}
</div>
)}
</div>
)}
{request.type === 'biker' && request.nomineeDetails && (
<div className="bg-pink-50 p-4 rounded-xl border border-pink-100">
<h3 className="font-semibold text-pink-800 mb-3 flex items-center gap-2">
<User className="w-5 h-5" /> Nominee Details
</h3>
{editMode ? (
<div className="space-y-3">
<input
type="text"
value={editForm.nomineeDetails?.name || ''}
onChange={(e) => 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"
/>
<input
type="text"
value={editForm.nomineeDetails?.phone || ''}
onChange={(e) => 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"
/>
<input
type="text"
value={editForm.nomineeDetails?.relationship || ''}
onChange={(e) => 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"
/>
</div>
) : (
<div className="space-y-2">
<div className="flex justify-between"><span className="text-sm text-pink-600">Name</span><span className="text-sm font-medium text-pink-800">{request.nomineeDetails.name}</span></div>
<div className="flex justify-between"><span className="text-sm text-pink-600">Phone</span><span className="text-sm font-medium text-pink-800">{request.nomineeDetails.phone}</span></div>
<div className="flex justify-between"><span className="text-sm text-pink-600">Relationship</span><span className="text-sm font-medium text-pink-800">{request.nomineeDetails.relationship}</span></div>
<div className="flex justify-between"><span className="text-sm text-pink-600">NID</span><span className="text-sm font-medium text-pink-800">{request.nomineeDetails.nid}</span></div>
</div>
)}
</div>
)}
</div>
<div className="space-y-4">
<div className="bg-amber-50 p-4 rounded-xl border border-amber-100">
<div className="flex items-center justify-between mb-3">
<h3 className="font-semibold text-amber-800 flex items-center gap-2">
<FileText className="w-5 h-5" /> Documents ({request.requiredDocuments.length})
</h3>
<button
onClick={() => setShowAddDocModal(true)}
className="text-xs px-2 py-1 bg-white rounded border border-amber-200 text-amber-700 hover:bg-amber-100 flex items-center gap-1"
>
<Plus className="w-3 h-3" /> Add
</button>
</div>
<div className="space-y-2">
{request.requiredDocuments.map((doc) => (
<div key={doc.id} className="flex items-center justify-between p-2 bg-white rounded-lg">
<div className="flex items-center gap-2">
{doc.status === 'pending' && <Clock className="w-4 h-4 text-amber-400" />}
{doc.status === 'uploaded' && <FileText className="w-4 h-4 text-blue-400" />}
{doc.status === 'approved' && <CheckCircle className="w-4 h-4 text-green-500" />}
{doc.status === 'rejected' && <XCircle className="w-4 h-4 text-red-500" />}
<span className="text-sm text-slate-700">{doc.name}</span>
</div>
<div className="flex items-center gap-1">
{doc.status === 'pending' && (
<button onClick={() => openUploadModal(doc.id)} className="p-1 bg-amber-100 text-amber-600 rounded hover:bg-amber-200" title="Upload"><Upload className="w-4 h-4" /></button>
)}
{(doc.status === 'uploaded' || doc.status === 'approved') && doc.imageUrl && (
<button onClick={() => window.open(doc.imageUrl, '_blank')} className="p-1 bg-blue-100 text-blue-600 rounded hover:bg-blue-200" title="View"><Image className="w-4 h-4" /></button>
)}
{doc.status === 'uploaded' && (
<>
<button onClick={() => handleApproveDocument(doc.id)} className="p-1 bg-green-100 text-green-600 rounded hover:bg-green-200" title="Approve"><CheckCircle className="w-4 h-4" /></button>
<button onClick={() => handleRejectDocument(doc.id)} className="p-1 bg-red-100 text-red-600 rounded hover:bg-red-200" title="Reject"><XCircle className="w-4 h-4" /></button>
</>
)}
{doc.status === 'approved' && <span className="text-xs px-2 py-1 bg-green-100 text-green-700 rounded-full">Approved</span>}
{doc.status === 'rejected' && <span className="text-xs px-2 py-1 bg-red-100 text-red-700 rounded-full">Rejected</span>}
{doc.status === 'pending' && <span className="text-xs px-2 py-1 bg-amber-100 text-amber-700 rounded-full">Pending</span>}
</div>
</div>
))}
</div>
</div>
{request.type === 'biker' && request.employmentInfo && (
<div className="bg-slate-50 p-4 rounded-xl border border-slate-100">
<h3 className="font-semibold text-slate-800 mb-3 flex items-center gap-2">
<Briefcase className="w-5 h-5" /> Employment
</h3>
<div className="space-y-2">
<div className="flex justify-between"><span className="text-sm text-slate-600">Company</span><span className="text-sm font-medium text-slate-800">{request.employmentInfo.company}</span></div>
<div className="flex justify-between"><span className="text-sm text-slate-600">Daily Earning</span><span className="text-sm font-medium text-slate-800">{request.employmentInfo.dailyEarning}</span></div>
<div className="flex justify-between"><span className="text-sm text-slate-600">Experience</span><span className="text-sm font-medium text-slate-800">{request.employmentInfo.experience}</span></div>
</div>
</div>
)}
<div className="bg-slate-50 p-4 rounded-xl border border-slate-100">
<h3 className="font-semibold text-slate-800 mb-3 flex items-center gap-2">
<MessageSquare className="w-5 h-5" /> Notes ({request.notes.length})
</h3>
{request.notes.length > 0 ? (
<div className="space-y-2">
{request.notes.map((note, idx) => (
<div key={idx} className="text-sm text-slate-600 p-2 bg-white rounded-lg"> {note}</div>
))}
</div>
) : (
<p className="text-sm text-slate-400">No notes yet</p>
)}
</div>
<div className="bg-indigo-50 p-4 rounded-xl border border-indigo-100">
<h3 className="font-semibold text-indigo-800 mb-3 flex items-center gap-2">
<Send className="w-5 h-5" /> Messages ({request.messageHistory.length})
</h3>
{request.messageHistory.length > 0 ? (
<div className="space-y-2 max-h-40 overflow-y-auto">
{request.messageHistory.map((msg, idx) => (
<div key={idx} className={`text-sm p-2 rounded-lg ${msg.from === 'admin' ? 'bg-blue-100 text-blue-800' : 'bg-white text-slate-600'}`}>
<span className="font-medium">{msg.from === 'admin' ? 'Admin' : 'User'}:</span> {msg.message}
<span className="text-xs text-slate-400 ml-2">{msg.date}</span>
</div>
))}
</div>
) : (
<p className="text-sm text-indigo-400">No messages yet</p>
)}
</div>
</div>
</div>
</div>
{showMessageModal && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md">
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
<h3 className="font-semibold text-slate-800">Send Message</h3>
<button onClick={() => setShowMessageModal(false)} className="text-slate-400 hover:text-slate-600">×</button>
</div>
<div className="p-4">
<textarea
value={newMessageText}
onChange={(e) => setNewMessageText(e.target.value)}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
rows={4}
placeholder="Type message to send to user..."
/>
</div>
<div className="p-4 border-t border-slate-100 flex justify-end gap-2">
<button onClick={() => setShowMessageModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg">Cancel</button>
<button onClick={handleSendMessage} disabled={!newMessageText.trim()} className="px-4 py-2 bg-accent text-white rounded-lg disabled:opacity-50">Send</button>
</div>
</div>
</div>
)}
{showAddNoteModal && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md">
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
<h3 className="font-semibold text-slate-800">Add Note</h3>
<button onClick={() => setShowAddNoteModal(false)} className="text-slate-400 hover:text-slate-600">×</button>
</div>
<div className="p-4">
<textarea
value={newNoteText}
onChange={(e) => setNewNoteText(e.target.value)}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
rows={4}
placeholder="Enter note..."
/>
</div>
<div className="p-4 border-t border-slate-100 flex justify-end gap-2">
<button onClick={() => setShowAddNoteModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg">Cancel</button>
<button onClick={handleAddNote} disabled={!newNoteText.trim()} className="px-4 py-2 bg-accent text-white rounded-lg disabled:opacity-50">Save</button>
</div>
</div>
</div>
)}
{showAddDocModal && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md">
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
<h3 className="font-semibold text-slate-800">Request New Document</h3>
<button onClick={() => setShowAddDocModal(false)} className="text-slate-400 hover:text-slate-600">×</button>
</div>
<div className="p-4">
<input
type="text"
value={newDocName}
onChange={(e) => setNewDocName(e.target.value)}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
placeholder="Document name..."
/>
</div>
<div className="p-4 border-t border-slate-100 flex justify-end gap-2">
<button onClick={() => setShowAddDocModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg">Cancel</button>
<button onClick={handleAddDocument} disabled={!newDocName.trim()} className="px-4 py-2 bg-accent text-white rounded-lg disabled:opacity-50">Add Document</button>
</div>
</div>
</div>
)}
{showUploadDocModal && (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
<div className="bg-white rounded-xl shadow-xl w-full max-w-md">
<div className="p-4 border-b border-slate-100 flex justify-between items-center">
<h3 className="font-semibold text-slate-800">Upload Document</h3>
<button onClick={() => setShowUploadDocModal(false)} className="text-slate-400 hover:text-slate-600">×</button>
</div>
<div className="p-4">
<input
type="file"
accept="image/*,.pdf"
onChange={handleUploadDocument}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm file:mr-4 file:px-4 file:py-2 file:bg-accent file:text-white file:rounded-lg file:border-0 cursor-pointer"
/>
<p className="text-xs text-slate-500 mt-2">Supported: JPG, PNG, PDF</p>
</div>
<div className="p-4 border-t border-slate-100 flex justify-end gap-2">
<button onClick={() => setShowUploadDocModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg">Cancel</button>
</div>
</div>
</div>
)}
</div>
);
}