diff --git a/src/app/admin/bikers/[id]/page.tsx b/src/app/admin/bikers/[id]/page.tsx index ede53de..d6ee01f 100644 --- a/src/app/admin/bikers/[id]/page.tsx +++ b/src/app/admin/bikers/[id]/page.tsx @@ -752,7 +752,7 @@ function SectionCard({ title, icon: Icon, children, headerBg = 'bg-slate-50', ed {editKey && setEditingSection ? ( editingSection !== editKey ? ( ) : (
@@ -2040,7 +2040,6 @@ export default function BikerDetailPage() { <>

Editing: {biker.bikes.batteries[editForm.editingIndex]?.name}

-
@@ -2083,60 +2082,14 @@ export default function BikerDetailPage() { ) : ( <> -
-

Add New Battery

- {biker.bikes.batteries.length > 0 && ( - - )} -
-
-
- - setEditForm({ ...editForm, batId: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-xs" placeholder="BAT-DH-004" /> -
-
- - setEditForm({ ...editForm, batName: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-xs" placeholder="Battery D" /> -
-
-
-
- - setEditForm({ ...editForm, batPercent: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-xs" placeholder="0-100" /> -
-
- - -
-
-
- - setEditForm({ ...editForm, batLocation: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-xs" placeholder="Swap Station" /> -
-
-
- - setEditForm({ ...editForm, batSwappedAt: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-xs" placeholder="YYYY-MM-DD HH:MM" /> -
-
- - setEditForm({ ...editForm, batOdometer: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-xs" /> -
+
+

Click edit button on existing batteries to update them.

)} ) : ( <> -
- -
{biker.bikes.batteries.map((bat, idx) => (
diff --git a/src/app/admin/rentals/[id]/page.tsx b/src/app/admin/rentals/[id]/page.tsx index 6e78b22..1ca36cf 100644 --- a/src/app/admin/rentals/[id]/page.tsx +++ b/src/app/admin/rentals/[id]/page.tsx @@ -6,7 +6,7 @@ import Link from 'next/link'; import { ArrowLeft, Bike, User, Calendar, DollarSign, Wallet, Shield, CheckCircle, XCircle, Clock, Edit, Save, Plus, Trash2, Image, Upload, Lock, Unlock, AlertTriangle, MessageSquare, MapPin, - Phone, MessageCircle, Play, Check, X, FileText, Download + Phone, MessageCircle, Play, Check, X, FileText, Download, Battery } from 'lucide-react'; import { canRentalAccept, canRentalReject, canRentalCancel, canRentalEdit, @@ -41,6 +41,9 @@ interface Rental { bikeModel: string; bikePlate: string; bikeBattery: number; + batteryId?: string; + batteryName?: string; + batteryRent?: number; type: RentalType; status: RentalStatus; startDate: string; @@ -73,6 +76,17 @@ interface Rental { activatedAt?: string; lockHistory?: LockEvent[]; paymentHistory?: PaymentHistory[]; + batteryHistory?: BatteryRentalHistory[]; +} + +interface BatteryRentalHistory { + id: string; + batteryId: string; + batteryName: string; + assignedAt: string; + returnedAt?: string; + monthlyRent: number; + status: 'active' | 'returned'; } interface LockEvent { @@ -146,6 +160,10 @@ const mockRentals: Rental[] = [ { id: 'lh3', action: 'locked', reason: 'Second payment overdue - Day 2 penalty', performedBy: 'System', performedAt: '2024-03-01' }, { id: 'lh4', action: 'unlocked', reason: 'Payment cleared', performedBy: 'Admin Manager', performedAt: '2024-03-02' }, ], + batteryHistory: [ + { id: 'BAT-RENT-001', batteryId: 'BAT-DH-001', batteryName: 'Galaxy 72V 45Ah', assignedAt: '2024-01-16', monthlyRent: 1500, status: 'active' }, + { id: 'BAT-RENT-002', batteryId: 'BAT-DH-002', batteryName: 'Titan 72V 50Ah', assignedAt: '2024-02-20', returnedAt: '2024-03-15', monthlyRent: 1800, status: 'returned' }, + ], }, { id: 'RNT-002', @@ -710,6 +728,53 @@ export default function RentalDetailPage() {
+ {/* Battery Rental History */} + {rental.batteryHistory && rental.batteryHistory.length > 0 && ( +
+

+ Battery Rental History +

+
+ + + + + + + + + + + + + {rental.batteryHistory.map(bat => ( + + + + + + + + + ))} + +
Battery IDBattery NameAssignedReturnedMonthly RentStatus
{bat.batteryId}{bat.batteryName}{bat.assignedAt}{bat.returnedAt || '-'}৳{bat.monthlyRent} + + {bat.status === 'active' ? 'Active' : 'Returned'} + +
+
+ {rental.batteryHistory.some(b => b.status === 'active') && ( +
+

+ Active Battery Rent: + ৳{rental.batteryHistory.filter(b => b.status === 'active').reduce((sum, b) => sum + b.monthlyRent, 0)}/month +

+
+ )} +
+ )} + {/* Initial Condition Images */} {/* {(rental.status === 'pending' || rental.status === 'accepted') && rental.initialImages && ( */} {rental.initialImages && ( diff --git a/src/app/admin/rentals/page.tsx b/src/app/admin/rentals/page.tsx index d73893f..2b53247 100644 --- a/src/app/admin/rentals/page.tsx +++ b/src/app/admin/rentals/page.tsx @@ -33,6 +33,9 @@ interface Rental { bikeModel: string; bikePlate: string; bikeBattery: number; + batteryId?: string; + batteryName?: string; + batteryRent?: number; type: RentalType; status: RentalStatus; startDate: string; @@ -63,6 +66,15 @@ interface Rental { createdAt: string; acceptedAt?: string; activatedAt?: string; + batteryHistory?: { + id: string; + batteryId: string; + batteryName: string; + assignedAt: string; + returnedAt?: string; + monthlyRent: number; + status: 'active' | 'returned'; + }[]; } interface Bike { @@ -103,6 +115,23 @@ const mockHubs = [ { id: 'HUB-004', name: 'Mirpur Hub' }, ]; +interface Battery { + id: string; + brand: string; + model: string; + soc: number; + monthlyRent: number; + status: 'available' | 'in-use' | 'maintenance'; +} + +const mockBatteries: Battery[] = [ + { id: 'BAT-DH-001', brand: 'Galaxy', model: '72V 45Ah', soc: 85, monthlyRent: 1500, status: 'available' }, + { id: 'BAT-DH-002', brand: 'Titan', model: '72V 50Ah', soc: 92, monthlyRent: 1800, status: 'available' }, + { id: 'BAT-DH-003', brand: 'PowerMax', model: '60V 40Ah', soc: 78, monthlyRent: 1200, status: 'available' }, + { id: 'BAT-DH-004', brand: 'UltraCell', model: '72V 55Ah', soc: 88, monthlyRent: 2000, status: 'available' }, + { id: 'BAT-DH-005', brand: 'EcoVolt', model: '48V 30Ah', soc: 65, monthlyRent: 800, status: 'available' }, +]; + const rentalSettings = { single: { Premium: { deposit: 5000, contractMonths: [1, 3, 6, 12], dailyRate: 200, weeklyRate: 1200, monthlyRate: 5000 }, @@ -304,6 +333,8 @@ export default function RentalsPage() { subscriptionType: 'daily' | 'weekly' | 'monthly'; contractMonths: number; bikeId: string; + batteryId: string; + batteryRent: number; startDate: string; hubId: string; depositAmount: number; @@ -316,12 +347,16 @@ export default function RentalsPage() { subscriptionType: 'daily', contractMonths: 0, bikeId: '', + batteryId: '', + batteryRent: 0, startDate: new Date().toISOString().split('T')[0], hubId: '', depositAmount: 0, depositPaymentMethod: 'cash', }); + const availableBatteries = mockBatteries.filter(b => b.status === 'available'); + const [showJournalPreview, setShowJournalPreview] = useState(false); useEffect(() => { @@ -439,6 +474,7 @@ export default function RentalsPage() { 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 battery = mockBatteries.find(b => b.id === newRental.batteryId); const settings = planConditions[newRental.type]?.find(p => p.name === newRental.planConditionName) || planConditions[newRental.type]?.[0]; const rental: Rental = { @@ -450,6 +486,9 @@ export default function RentalsPage() { bikeModel: bike?.model || '', bikePlate: bike?.plate || '', bikeBattery: bike?.battery || 0, + batteryId: newRental.batteryId || undefined, + batteryName: battery ? `${battery.brand} ${battery.model}` : undefined, + batteryRent: newRental.batteryRent || undefined, type: newRental.type, status: 'pending', startDate: newRental.startDate, @@ -473,6 +512,14 @@ export default function RentalsPage() { hubName: hub?.name || '', imagesApproved: false, createdAt: new Date().toISOString().split('T')[0], + batteryHistory: newRental.batteryId ? [{ + id: `BAT-RENT-${Date.now()}`, + batteryId: newRental.batteryId, + batteryName: battery ? `${battery.brand} ${battery.model}` : '', + assignedAt: new Date().toISOString().split('T')[0], + monthlyRent: newRental.batteryRent, + status: 'active' as const, + }] : undefined, }; setRentals([...rentals, rental]); @@ -486,6 +533,8 @@ export default function RentalsPage() { subscriptionType: 'daily', contractMonths: 0, bikeId: '', + batteryId: '', + batteryRent: 0, evModel: '', startDate: new Date().toISOString().split('T')[0], hubId: '', @@ -927,26 +976,52 @@ export default function RentalsPage() { )} {createStep === 3 && ( -
-

Step 3: Select Bike

- - {selectedBike && ( -
- Battery: - 70 ? 'bg-green-100 text-green-700' : selectedBike.battery > 40 ? 'bg-amber-100 text-amber-700' : 'bg-red-100 text-red-700'}`}> - {selectedBike.battery}% - -
- )} +
+

Step 3: Select Bike & Battery

+ +
+ + + {selectedBike && ( +
+ Battery: + 70 ? 'bg-green-100 text-green-700' : selectedBike.battery > 40 ? 'bg-amber-100 text-amber-700' : 'bg-red-100 text-red-700'}`}> + {selectedBike.battery}% + +
+ )} +
+ +
+ + + {newRental.batteryId && ( +
+

Battery Monthly Rent: ৳{newRental.batteryRent}/month

+
+ )} +
)} @@ -958,7 +1033,18 @@ export default function RentalsPage() {

Deposit Amount: ৳{selectedPlan?.deposit.toLocaleString()}

User: {selectedUser?.name}

Bike: {selectedBike?.model} ({selectedBike?.plate})

+ {newRental.batteryId && ( +

Battery: {availableBatteries.find(b => b.id === newRental.batteryId)?.brand} {availableBatteries.find(b => b.id === newRental.batteryId)?.model} (Rent: ৳{newRental.batteryRent}/month)

+ )}

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

+ {newRental.batteryId && ( +
+

+ Combined Monthly Rent: ৳{(newRental.subscriptionType === 'daily' ? selectedPlan?.dailyRate : newRental.subscriptionType === 'weekly' ? selectedPlan?.weeklyRate : selectedPlan?.monthlyRate) + newRental.batteryRent}/month + (Bike: ৳{newRental.subscriptionType === 'daily' ? selectedPlan?.dailyRate : newRental.subscriptionType === 'weekly' ? selectedPlan?.weeklyRate : selectedPlan?.monthlyRate} + Battery: ৳{newRental.batteryRent}) +

+
+ )}