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

695 lines
34 KiB
TypeScript
Raw Normal View History

'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>
);
}