'use client'; import { useState, useEffect } from 'react'; import { FileText, Search, Filter, Bike, User, Calendar, DollarSign, Clock, MoreVertical, Eye, Plus, Phone, MessageCircle, X, CreditCard, Wallet, Building, Download, Printer } from 'lucide-react'; import Link from 'next/link'; type RentalStatus = 'active' | 'pending' | 'completed' | 'disputed' | 'cancelled' | 'locked'; type RentalType = 'single' | 'shared' | 'rent-to-own'; interface Rental { id: string; bikeId: string; userId: string; type: RentalType; status: RentalStatus; startDate: string; endDate?: string; contractMonths?: number; deposit: number; dailyRate: number; totalPaid: number; dueRental?: number; lockedAt?: string; lockedReason?: string; hubId?: string; hubName?: string; } const mockBikes = [ { id: 'BIKE-001', model: 'AIMA Lightning', plate: 'Dhaka Metro Cha-9012', status: 'available' }, { id: 'BIKE-002', model: 'Yadea DT3', plate: 'Dhaka Metro Ba-5521', status: 'available' }, { id: 'BIKE-003', model: 'AIMA EM5', plate: 'Dhaka Metro Ko-1234', status: 'available' }, { id: 'BIKE-004', model: 'AIMA Lightning', plate: 'Dhaka Metro Cha-9013', status: 'rented' }, { id: 'BIKE-005', model: 'Yadea G5', plate: 'Dhaka Metro Ha-5678', status: 'available' }, ]; const mockUsers = [ { id: 'USR-001', name: 'Rahim Ahmed', phone: '+8801712345678', membership: 'vip' }, { id: 'USR-002', name: 'Karim Hasan', phone: '+8801812345678', membership: 'standard' }, { id: 'USR-003', name: 'Jamal Uddin', phone: '+8801912345678', membership: 'premium' }, { id: 'USR-004', name: 'Rafiq Islam', phone: '+8801512345678', membership: 'standard' }, ]; const mockHubs = [ { id: 'HUB-001', name: 'Gulshan Hub' }, { id: 'HUB-002', name: 'Banani Hub' }, { id: 'HUB-003', name: 'Uttara Hub' }, { id: 'HUB-004', name: 'Mirpur Hub' }, ]; const mockRentals: Rental[] = [ { id: 'RNT-001', bikeId: 'BIKE-001', userId: 'USR-001', type: 'single', status: 'active', startDate: '2024-01-15', deposit: 5000, dailyRate: 300, totalPaid: 81900, dueRental: 0, hubId: 'HUB-001', hubName: 'Gulshan Hub' }, { id: 'RNT-002', bikeId: 'BIKE-002', userId: 'USR-002', type: 'single', status: 'pending', startDate: '2024-02-10', deposit: 0, dailyRate: 150, totalPaid: 150, dueRental: 0, hubId: 'HUB-002', hubName: 'Banani Hub' }, { id: 'RNT-003', bikeId: 'BIKE-003', userId: 'USR-003', type: 'rent-to-own', status: 'completed', startDate: '2023-06-01', endDate: '2023-12-01', deposit: 10000, dailyRate: 500, totalPaid: 150000, hubId: 'HUB-001', hubName: 'Gulshan Hub' } ]; export default function RentalsPage() { const [rentals, setRentals] = useState(mockRentals); const [showCreateModal, setShowCreateModal] = useState(false); const [statusFilter, setStatusFilter] = useState('all'); const [newRental, setNewRental] = useState({ bikeId: '', userId: '', type: 'single' as RentalType, startDate: new Date().toISOString().split('T')[0], contractMonths: 0, deposit: 0, dailyRate: 150, hubId: '', paymentMethod: 'cash' as 'cash' | 'bank' | 'biker_wallet', }); const [showJournalPreview, setShowJournalPreview] = useState(false); const filteredRentals = rentals.filter(r => { if (statusFilter !== 'all' && r.status !== statusFilter) return false; return true; }); const stats = { active: rentals.filter(r => r.status === 'active').length, pending: rentals.filter(r => r.status === 'pending').length, completed: rentals.filter(r => r.status === 'completed').length, disputed: rentals.filter(r => r.status === 'disputed').length, }; const handleCreateRental = () => { if (!newRental.bikeId || !newRental.userId || !newRental.hubId) return; setShowJournalPreview(true); }; const confirmCreateRental = () => { const bike = mockBikes.find(b => b.id === newRental.bikeId); const user = mockUsers.find(u => u.id === newRental.userId); const hub = mockHubs.find(h => h.id === newRental.hubId); const rental: Rental = { id: `RNT-${String(rentals.length + 1).padStart(3, '0')}`, bikeId: newRental.bikeId, userId: newRental.userId, type: newRental.type, status: 'pending', startDate: newRental.startDate, endDate: newRental.contractMonths > 0 ? new Date(new Date(newRental.startDate).setMonth(new Date(newRental.startDate).getMonth() + newRental.contractMonths)).toISOString().split('T')[0] : undefined, contractMonths: newRental.contractMonths || undefined, deposit: newRental.deposit, dailyRate: newRental.dailyRate, totalPaid: newRental.deposit, dueRental: 0, hubId: newRental.hubId, hubName: hub?.name, }; setRentals([...rentals, rental]); setShowJournalPreview(false); setShowCreateModal(false); setNewRental({ bikeId: '', userId: '', type: 'single', startDate: new Date().toISOString().split('T')[0], contractMonths: 0, deposit: 0, dailyRate: 150, hubId: '', paymentMethod: 'cash', }); }; const generateInvoice = () => { if (newRental.deposit <= 0) return; const rentalId = `RNT-${String(rentals.length + 1).padStart(3, '0')}`; const bike = mockBikes.find(b => b.id === newRental.bikeId); const user = mockUsers.find(u => u.id === newRental.userId); const hub = mockHubs.find(h => h.id === newRental.hubId); const date = new Date().toISOString().split('T')[0]; const time = new Date().toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' }); const contractMonths = newRental.contractMonths; const endDate = contractMonths > 0 ? new Date(new Date(newRental.startDate).setMonth(new Date(newRental.startDate).getMonth() + contractMonths)).toISOString().split('T')[0] : ''; import('jspdf').then((jsPDF) => { const doc = new jsPDF.default(); doc.setFillColor(6, 95, 70); doc.rect(0, 0, 220, 40, 'F'); doc.setTextColor(255, 255, 255); doc.setFontSize(24); doc.text('JAIBEN Mobility Ltd', 20, 20); doc.setFontSize(12); doc.text('Payment Receipt', 20, 30); doc.setTextColor(6, 95, 70); doc.setFontSize(18); doc.text('OFFICIAL RECEIPT', 120, 25); doc.setTextColor(0, 0, 0); doc.setFontSize(10); doc.text(`Receipt No: ${rentalId}-DEP`, 20, 55); doc.text(`Date: ${date} ${time}`, 20, 62); doc.line(20, 70, 190, 70); doc.setFontSize(11); doc.text('Payment Details', 20, 82); doc.setFontSize(10); doc.text(`Rental ID: ${rentalId}`, 20, 90); doc.text(`Bike: ${bike?.model} (${bike?.plate})`, 20, 97); doc.text(`Customer: ${user?.name}`, 20, 104); doc.text(`Phone: ${user?.phone}`, 20, 111); doc.text(`Hub: ${hub?.name}`, 20, 118); doc.text(`Rental Type: ${newRental.type}`, 20, 125); doc.text(`Start Date: ${newRental.startDate}`, 20, 132); if (contractMonths > 0) { doc.text(`Contract: ${contractMonths} Months`, 20, 139); doc.text(`End Date: ${endDate}`, 20, 146); doc.text(`Daily Rate: ৳${newRental.dailyRate}/day`, 20, 156); } else { doc.text(`Daily Rate: ৳${newRental.dailyRate}/day`, 20, 139); } doc.line(20, 165, 190, 165); doc.setFontSize(12); doc.text('Amount Details', 20, 175); doc.setFillColor(240, 240, 240); doc.rect(20, 180, 170, 20, 'F'); doc.setFontSize(10); doc.text('Deposit', 30, 192); doc.setFontSize(14); doc.setTextColor(6, 95, 70); doc.text(`৳${newRental.deposit}`, 150, 192); doc.setTextColor(0, 0, 0); doc.setFontSize(10); doc.text(`Payment: ${newRental.paymentMethod === 'cash' ? 'Cash' : newRental.paymentMethod === 'bank' ? 'Bank' : 'Wallet'}`, 20, 210); const qrData = `JAIBEN|${rentalId}|${date}|${user?.name}|${bike?.model}|${newRental.deposit}|${newRental.startDate}|${contractMonths}`; const publicUrl = `https://jaiben.app/rental/${rentalId}`; doc.setFontSize(8); doc.setTextColor(100); doc.text('Generated from JAIBEN Rental System', 20, 250); doc.text(`QR: ${qrData.substring(0, 35)}...`, 20, 258); doc.setTextColor(6, 95, 70); doc.text(`URL: ${publicUrl}`, 20, 266); doc.save(`deposit-receipt-${rentalId}.pdf`); }); }; const getStatusBadge = (status: RentalStatus) => { const styles = { active: 'bg-green-100 text-green-700', pending: 'bg-amber-100 text-amber-700', completed: 'bg-blue-100 text-blue-700', disputed: 'bg-red-100 text-red-700', cancelled: 'bg-slate-100 text-slate-700', locked: 'bg-red-100 text-red-700', }; return styles[status]; }; return (

Rentals

View and manage all rental transactions

{stats.active}

Active Rentals

{stats.pending}

Pending

{stats.completed}

Completed

{stats.disputed}

Disputed

{filteredRentals.map(rental => { const bike = mockBikes.find(b => b.id === rental.bikeId); const user = mockUsers.find(u => u.id === rental.userId); return ( ); })}
Rental ID Bike User Type Start Date Hub Deposit Daily Total Paid Status Actions
{rental.id}
{bike?.model || rental.bikeId}

{bike?.plate}

{user?.name || rental.userId}

{user?.phone}

{rental.type}
{rental.startDate}
{rental.hubName || '-'} ৳{rental.deposit} ৳{rental.dailyRate}/d ৳{rental.totalPaid.toLocaleString()} {rental.status}
{user && ( <> )}
{showCreateModal && (

Create New Rental

setNewRental({ ...newRental, startDate: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
{newRental.contractMonths > 0 && (

End Date: {new Date(new Date(newRental.startDate).setMonth(new Date(newRental.startDate).getMonth() + newRental.contractMonths)).toISOString().split('T')[0]}

)}
{ const val = e.target.value.replace(/[^0-9]/g, ''); setNewRental({ ...newRental, dailyRate: val ? Number(val) : 0 }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="150" />
{ const val = e.target.value.replace(/[^0-9]/g, ''); setNewRental({ ...newRental, deposit: val ? Number(val) : 0 }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="0" />
{newRental.deposit > 0 && (
)}
)} {showJournalPreview && (

Journal Entry Preview

Auto-generated journal for rental deposit

Rental: {newRental.type.toUpperCase()}

Date: {new Date().toISOString().split('T')[0]}

Journal Entries

{newRental.deposit > 0 && ( <> )} {newRental.deposit === 0 && ( )} {newRental.deposit > 0 && ( )}
Account Debit (৳) Credit (৳)
{newRental.paymentMethod === 'cash' && '1000 - Cash'} {newRental.paymentMethod === 'bank' && '1100 - Bank'} {newRental.paymentMethod === 'biker_wallet' && '1200 - Biker Wallet'} {newRental.deposit} -
2100 - Deposit Received - {newRental.deposit}
No deposit amount - Journal not required
Total {newRental.deposit} {newRental.deposit}

Bike: {mockBikes.find(b => b.id === newRental.bikeId)?.model} {mockBikes.find(b => b.id === newRental.bikeId)?.plate}

User: {mockUsers.find(u => u.id === newRental.userId)?.name} ({mockUsers.find(u => u.id === newRental.userId)?.phone})

Hub: {mockHubs.find(h => h.id === newRental.hubId)?.name}

Type: {newRental.type} | Contract: {newRental.contractMonths ? `${newRental.contractMonths} Months` : 'Daily Basis'}

Daily Rate: ৳{newRental.dailyRate}

)}
); }