feat: add manual BMS data refresh functionality and expand battery purchase form with accounting fields
This commit is contained in:
@@ -4,7 +4,8 @@ import { useState, use } from 'react';
|
||||
import Link from 'next/link';
|
||||
import {
|
||||
Battery, ArrowLeft, X, BatteryCharging, Activity, Gauge, MapPin, Bike, User, History,
|
||||
Calendar, DollarSign, CheckCircle, Clock, ArrowRightLeft, Handshake, TrendingUp, Edit
|
||||
Calendar, DollarSign, CheckCircle, Clock, ArrowRightLeft, Handshake, TrendingUp, Edit,
|
||||
RefreshCw
|
||||
} from 'lucide-react';
|
||||
|
||||
interface BMSData {
|
||||
@@ -127,12 +128,37 @@ export default function BatteryDetailPage({ params }: { params: Promise<{ id: st
|
||||
const [battery, setBattery] = useState<Battery>(mockBattery);
|
||||
const [activeTab, setActiveTab] = useState<'info' | 'bms' | 'history' | 'rent'>('info');
|
||||
const [showEditModal, setShowEditModal] = useState(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
const handleSaveEdit = (updatedBattery: Battery) => {
|
||||
setBattery(updatedBattery);
|
||||
setShowEditModal(false);
|
||||
};
|
||||
|
||||
const handleRefreshBMS = () => {
|
||||
if (!battery.bmsData) return;
|
||||
setRefreshing(true);
|
||||
setTimeout(() => {
|
||||
const bms = battery.bmsData!;
|
||||
setBattery({
|
||||
...battery,
|
||||
bmsData: {
|
||||
...bms,
|
||||
voltage: Math.round((60 + Math.random() * 10) * 10) / 10,
|
||||
current: Math.round((-3 + Math.random() * 4) * 10) / 10,
|
||||
soc: Math.floor(Math.random() * 40) + 60,
|
||||
temperature: 25 + Math.floor(Math.random() * 15),
|
||||
cycles: bms.cycles + 1,
|
||||
health: Math.max(70, Math.min(100, bms.health + (Math.random() > 0.7 ? 1 : 0))),
|
||||
timestamp: new Date().toISOString().replace('T', ' ').substring(0, 19)
|
||||
},
|
||||
currentSoc: Math.floor(Math.random() * 40) + 60,
|
||||
health: Math.max(70, Math.min(100, battery.health + (Math.random() > 0.7 ? 1 : 0)))
|
||||
});
|
||||
setRefreshing(false);
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 lg:p-6">
|
||||
<div className="flex items-center gap-4 mb-6">
|
||||
@@ -192,11 +218,18 @@ export default function BatteryDetailPage({ params }: { params: Promise<{ id: st
|
||||
|
||||
{battery.bmsData && (
|
||||
<div className="p-5 border-b border-slate-100 bg-gradient-to-r from-green-50 to-emerald-50">
|
||||
<div className="flex items-center gap-2 mb-3">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Activity className="w-4 h-4 text-green-600" />
|
||||
<span className="font-medium text-green-800">Live BMS Data</span>
|
||||
<span className="text-xs text-green-600 bg-green-100 px-2 py-0.5 rounded-full">Real-time</span>
|
||||
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-xs text-green-600">Updated: {battery.bmsData.timestamp}</span>
|
||||
<button onClick={handleRefreshBMS} disabled={refreshing} className="p-1.5 text-green-600 hover:bg-green-100 rounded-lg">
|
||||
<RefreshCw className={`w-4 h-4 ${refreshing ? 'animate-spin' : ''}`} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-3 md:grid-cols-6 gap-2">
|
||||
<div className="bg-white rounded-lg p-2 text-center">
|
||||
|
||||
@@ -44,6 +44,9 @@ interface Battery {
|
||||
voltage: number;
|
||||
purchaseDate: string;
|
||||
purchasePrice: number;
|
||||
transactionMethod?: 'cash' | 'bank_transfer' | 'mobile_banking' | 'cheque' | 'credit' | 'other';
|
||||
autoJournal?: boolean;
|
||||
autoJournalSource?: 'supplier' | 'import' | 'internal' | 'transfer' | 'other';
|
||||
warrantyExpiry: string;
|
||||
status: 'available' | 'in-use' | 'maintenance' | 'retired' | 'charging';
|
||||
currentSoc: number;
|
||||
@@ -879,6 +882,48 @@ function BatteryForm({ battery, onSave, onCancel }: { battery: Battery | null; o
|
||||
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>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">Transaction Method</label>
|
||||
<select
|
||||
value={formData.transactionMethod || 'cash'}
|
||||
onChange={(e) => handleChange('transactionMethod', e.target.value as any)}
|
||||
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="cash">Cash</option>
|
||||
<option value="bank_transfer">Bank Transfer</option>
|
||||
<option value="mobile_banking">Mobile Banking</option>
|
||||
<option value="cheque">Cheque</option>
|
||||
<option value="credit">Credit</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={formData.autoJournal || false}
|
||||
onChange={(e) => handleChange('autoJournal', e.target.checked)}
|
||||
className="w-4 h-4 text-accent rounded border-slate-300 focus:ring-accent"
|
||||
/>
|
||||
<span className="text-sm text-slate-700">Auto-Journal Entry</span>
|
||||
</label>
|
||||
</div>
|
||||
{formData.autoJournal && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">Auto-Journal Source</label>
|
||||
<select
|
||||
value={formData.autoJournalSource || 'supplier'}
|
||||
onChange={(e) => handleChange('autoJournalSource', e.target.value as any)}
|
||||
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="supplier">Supplier Purchase</option>
|
||||
<option value="import">Import</option>
|
||||
<option value="internal">Internal Transfer</option>
|
||||
<option value="transfer">Transfer</option>
|
||||
<option value="other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-700 mb-1">Warranty Expiry</label>
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user