feat: integrate battery selection and sync battery level from mock data in fleet management form

This commit is contained in:
sazzadulalambd
2026-05-17 20:32:54 +06:00
parent a4ff86b953
commit 9370b71b25

View File

@@ -17,6 +17,7 @@ interface Bike {
plateNumber: string; plateNumber: string;
status: 'available' | 'rented' | 'maintenance' | 'retired'; status: 'available' | 'rented' | 'maintenance' | 'retired';
batteryLevel: number; batteryLevel: number;
batteryId?: string;
location?: string; // deprecated - use hubId/hubName location?: string; // deprecated - use hubId/hubName
hubId?: string; hubId?: string;
hubName?: string; hubName?: string;
@@ -56,6 +57,15 @@ const hubs = [
{ id: 'HUB-004', name: 'Mirpur Hub' }, { id: 'HUB-004', name: 'Mirpur Hub' },
]; ];
const mockBatteries = [
{ id: 'BAT-001', brand: 'Lithium', model: '60V/30Ah', serialNumber: 'LTH-2024-001', chargeLevel: 95 },
{ id: 'BAT-002', brand: 'Lithium', model: '60V/30Ah', serialNumber: 'LTH-2024-002', chargeLevel: 75 },
{ id: 'BAT-003', brand: 'Lithium', model: '60V/40Ah', serialNumber: 'LTH-2024-003', chargeLevel: 45 },
{ id: 'BAT-004', brand: 'Lithium', model: '60V/30Ah', serialNumber: 'LTH-2024-004', chargeLevel: 88 },
{ id: 'BAT-005', brand: 'Lithium', model: '48V/25Ah', serialNumber: 'LTH-2024-005', chargeLevel: 62 },
{ id: 'BAT-006', brand: 'Lithium', model: '60V/30Ah', serialNumber: 'LTH-2024-006', chargeLevel: 100 },
];
const statusColors: Record<string, string> = { const statusColors: Record<string, string> = {
available: 'bg-green-100 text-green-700', available: 'bg-green-100 text-green-700',
rented: 'bg-blue-100 text-blue-700', rented: 'bg-blue-100 text-blue-700',
@@ -159,9 +169,9 @@ export default function FleetPage() {
<p className="font-semibold text-slate-700">{selectedMapBike.model}</p> <p className="font-semibold text-slate-700">{selectedMapBike.model}</p>
<p className="text-xs text-slate-500">{selectedMapBike.brand} {selectedMapBike.id}</p> <p className="text-xs text-slate-500">{selectedMapBike.brand} {selectedMapBike.id}</p>
<span className={`inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full mt-1 ${selectedMapBike.status === 'available' ? 'bg-green-100 text-green-700' : <span className={`inline-flex items-center gap-1 text-xs font-medium px-2 py-0.5 rounded-full mt-1 ${selectedMapBike.status === 'available' ? 'bg-green-100 text-green-700' :
selectedMapBike.status === 'rented' ? 'bg-blue-100 text-blue-700' : selectedMapBike.status === 'rented' ? 'bg-blue-100 text-blue-700' :
selectedMapBike.status === 'maintenance' ? 'bg-amber-100 text-amber-700' : selectedMapBike.status === 'maintenance' ? 'bg-amber-100 text-amber-700' :
'bg-slate-100 text-slate-500' 'bg-slate-100 text-slate-500'
}`}> }`}>
{selectedMapBike.status} {selectedMapBike.status}
</span> </span>
@@ -182,7 +192,7 @@ export default function FleetPage() {
<div className="flex justify-between"> <div className="flex justify-between">
<span className="text-slate-500">Battery</span> <span className="text-slate-500">Battery</span>
<span className={`font-medium ${selectedMapBike.batteryLevel > 50 ? 'text-green-600' : <span className={`font-medium ${selectedMapBike.batteryLevel > 50 ? 'text-green-600' :
selectedMapBike.batteryLevel > 20 ? 'text-amber-600' : 'text-red-600' selectedMapBike.batteryLevel > 20 ? 'text-amber-600' : 'text-red-600'
}`}>{selectedMapBike.batteryLevel}%</span> }`}>{selectedMapBike.batteryLevel}%</span>
</div> </div>
<div className="flex justify-between"> <div className="flex justify-between">
@@ -488,6 +498,7 @@ function BikeForm({ bike, onSave, onCancel }: { bike: Bike | null; onSave: (bike
plateNumber: '', plateNumber: '',
status: 'available', status: 'available',
batteryLevel: 100, batteryLevel: 100,
batteryId: '',
location: '', // deprecated location: '', // deprecated
hubId: '', hubId: '',
hubName: '', hubName: '',
@@ -563,14 +574,27 @@ function BikeForm({ bike, onSave, onCancel }: { bike: Bike | null; onSave: (bike
</select> </select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-slate-700 mb-1">Battery Level (%)</label> <label className="block text-sm font-medium text-slate-700 mb-1">Battery</label>
<input <select
type="number" value={formData.batteryId || ''}
value={formData.batteryLevel} onChange={(e) => {
onChange={(e) => handleChange('batteryLevel', parseInt(e.target.value))} const battery = mockBatteries.find(b => b.id === e.target.value);
handleChange('batteryId', e.target.value);
if (battery) {
handleChange('batteryLevel', battery.chargeLevel);
}
}}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-accent" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-accent"
/> >
<option value="">Select Battery...</option>
{mockBatteries.map(battery => (
<option key={battery.id} value={battery.id}>
{battery.brand} {battery.model} - {battery.serialNumber} ({battery.chargeLevel}%)
</option>
))}
</select>
</div> </div>
<div> <div>
<label className="block text-sm font-medium text-slate-700 mb-1">Hub *</label> <label className="block text-sm font-medium text-slate-700 mb-1">Hub *</label>
<select <select
@@ -588,6 +612,16 @@ function BikeForm({ bike, onSave, onCancel }: { bike: Bike | null; onSave: (bike
))} ))}
</select> </select>
</div> </div>
<div>
<label className="block text-sm font-medium text-slate-700 mb-1">Battery Level (%)</label>
<input
type="number"
value={formData.batteryLevel}
onChange={(e) => handleChange('batteryLevel', parseInt(e.target.value))}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-accent"
/>
</div>
<div> <div>
<label className="block text-sm font-medium text-slate-700 mb-1">Assigned To</label> <label className="block text-sm font-medium text-slate-700 mb-1">Assigned To</label>
<input <input
@@ -812,9 +846,9 @@ function FleetMap({ bikes, onSelectBike, selectedBike, large }: { bikes: Bike[];
<path <path
d={large ? "M0,0 L-3,-6 A3.5,3.5 0 1,1 3,-6 L0,0 Z" : "M0,0 L-2,-4 A2.5,2.5 0 1,1 2,-4 L0,0 Z"} d={large ? "M0,0 L-3,-6 A3.5,3.5 0 1,1 3,-6 L0,0 Z" : "M0,0 L-2,-4 A2.5,2.5 0 1,1 2,-4 L0,0 Z"}
className={`${data.bikes[0].status === 'available' ? 'fill-green-500' : className={`${data.bikes[0].status === 'available' ? 'fill-green-500' :
data.bikes[0].status === 'rented' ? 'fill-blue-500' : data.bikes[0].status === 'rented' ? 'fill-blue-500' :
data.bikes[0].status === 'maintenance' ? 'fill-amber-500' : data.bikes[0].status === 'maintenance' ? 'fill-amber-500' :
'fill-slate-400' 'fill-slate-400'
}`} }`}
filter="url(#shadow)" filter="url(#shadow)"
/> />