feat: implement dynamic payment tracking with local storage and update transaction UI for battery investments
This commit is contained in:
@@ -344,10 +344,61 @@ export default function InvestmentDetailPage({ params }: { params: Promise<{ id:
|
||||
date: new Date().toISOString().split('T')[0],
|
||||
notes: ''
|
||||
});
|
||||
const [investmentPayments, setInvestmentPayments] = useState<any[]>([
|
||||
const [investmentPayments, setInvestmentPayments] = useState<any[]>(() => {
|
||||
if (!investment) return [];
|
||||
const isBatteryPlan = investment.assetType === 'battery' || investment.planName?.toLowerCase().includes('battery');
|
||||
|
||||
if (typeof window !== 'undefined') {
|
||||
const stored = localStorage.getItem(`jaiben_payments_${investmentId}`);
|
||||
if (stored) {
|
||||
try {
|
||||
return JSON.parse(stored);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isBatteryPlan) {
|
||||
return [
|
||||
{
|
||||
id: `pay_${investmentId}`,
|
||||
date: investment.startDate || '2024-02-01',
|
||||
amount: investment.totalInvestment,
|
||||
paymentMethod: investment.paymentMethod || 'bank',
|
||||
transactionRef: investment.transactionId || 'TXN-BAT-001',
|
||||
status: 'completed',
|
||||
notes: 'Full Payment'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
if (investmentId === 'ip2') {
|
||||
return [
|
||||
{
|
||||
id: 'pay1_ip2',
|
||||
date: '2024-01-20',
|
||||
amount: investment.totalInvestment,
|
||||
paymentMethod: 'mobile',
|
||||
transactionRef: 'TXN-002',
|
||||
status: 'completed',
|
||||
notes: 'Full Payment'
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
// Default for ip1 or others
|
||||
return [
|
||||
{ id: 'pay1', date: '2024-01-15', amount: 50000, paymentMethod: 'bank', transactionRef: 'TXN-001', status: 'completed', notes: 'First installment' },
|
||||
{ id: 'pay2', date: '2024-01-20', amount: 35000, paymentMethod: 'mobile', transactionRef: 'TXN-002', status: 'completed', notes: 'Second installment' },
|
||||
]);
|
||||
];
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem(`jaiben_payments_${investmentId}`, JSON.stringify(investmentPayments));
|
||||
}
|
||||
}, [investmentPayments, investmentId]);
|
||||
|
||||
if (!investor || !investment) {
|
||||
return (
|
||||
@@ -622,12 +673,7 @@ export default function InvestmentDetailPage({ params }: { params: Promise<{ id:
|
||||
>
|
||||
Transactions
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('payments')}
|
||||
className={`px-4 py-2 text-sm font-medium rounded-lg transition-colors ${activeTab === 'payments' ? 'bg-investor text-white' : 'text-slate-600 hover:bg-slate-100'}`}
|
||||
>
|
||||
Payments
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setActiveTab('pnl')}
|
||||
className={`px-4 py-2 text-sm font-medium rounded-lg transition-colors ${activeTab === 'pnl' ? 'bg-investor text-white' : 'text-slate-600 hover:bg-slate-100'}`}
|
||||
@@ -762,33 +808,37 @@ export default function InvestmentDetailPage({ params }: { params: Promise<{ id:
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-100">
|
||||
<tr>
|
||||
<td className="px-4 py-3 text-sm text-slate-500">2024-01-15</td>
|
||||
<td className="px-4 py-3 text-sm text-slate-500">{investment.startDate || '2024-01-15'}</td>
|
||||
<td className="px-4 py-3 text-sm">Investment Funded</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-green-100 text-green-700 rounded text-xs">Credit</span></td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-green-600">+৳85,000</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-green-600">+৳{investment.totalInvestment.toLocaleString()}</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-green-100 text-green-700 rounded text-xs">Completed</span></td>
|
||||
</tr>
|
||||
{investment.status === 'active' && (
|
||||
<>
|
||||
<tr>
|
||||
<td className="px-4 py-3 text-sm text-slate-500">2024-02-15</td>
|
||||
<td className="px-4 py-3 text-sm">Monthly Return</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-blue-100 text-blue-700 rounded text-xs">Return</span></td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-blue-600">+৳1,700</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-blue-600">+৳{(investment.monthlyReturn || (isBattery ? 4500 : 1700)).toLocaleString()}</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-green-100 text-green-700 rounded text-xs">Completed</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-4 py-3 text-sm text-slate-500">2024-03-15</td>
|
||||
<td className="px-4 py-3 text-sm">Monthly Return</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-blue-100 text-blue-700 rounded text-xs">Return</span></td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-blue-600">+৳1,700</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-blue-600">+৳{(investment.monthlyReturn || (isBattery ? 4500 : 1700)).toLocaleString()}</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-green-100 text-green-700 rounded text-xs">Completed</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="px-4 py-3 text-sm text-slate-500">2024-04-15</td>
|
||||
<td className="px-4 py-3 text-sm">Monthly Return</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-blue-100 text-blue-700 rounded text-xs">Return</span></td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-blue-600">+৳1,700</td>
|
||||
<td className="px-4 py-3 text-sm text-right font-medium text-blue-600">+৳{(investment.monthlyReturn || (isBattery ? 4500 : 1700)).toLocaleString()}</td>
|
||||
<td className="px-4 py-3 text-sm"><span className="px-2 py-1 bg-green-100 text-green-700 rounded text-xs">Completed</span></td>
|
||||
</tr>
|
||||
</>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -825,12 +875,14 @@ export default function InvestmentDetailPage({ params }: { params: Promise<{ id:
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<h4 className="font-semibold text-slate-800">Payment History</h4>
|
||||
{!isBattery && (investment.totalInvestment - investmentPayments.reduce((sum, p) => sum + p.amount, 0)) > 0 && (
|
||||
<button
|
||||
onClick={() => setShowPartialPaymentModal(true)}
|
||||
className="px-3 py-1.5 text-xs bg-investor text-white rounded-lg flex items-center gap-1 hover:bg-investor-dark"
|
||||
>
|
||||
<Plus className="w-3 h-3" /> Record Payment
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="bg-slate-50 rounded-xl p-4">
|
||||
@@ -938,24 +990,6 @@ export default function InvestmentDetailPage({ params }: { params: Promise<{ id:
|
||||
<button onClick={() => setShowAssignBatteryModal(true)} className="px-3 py-1.5 text-xs bg-emerald-50 text-emerald-700 border border-emerald-200 rounded-lg flex items-center gap-1 hover:bg-emerald-100 transition-colors">
|
||||
<Plus className="w-3 h-3" /> Assign Existing
|
||||
</button>
|
||||
<button onClick={() => {
|
||||
setRegisterBatteryForm({
|
||||
serialNumber: `SN-${new Date().getFullYear()}-${Math.floor(10000 + Math.random() * 90000)}`,
|
||||
brand: 'BYD',
|
||||
model: 'Li-Ion 60V50Ah',
|
||||
type: 'lithium-ion',
|
||||
capacity: 50,
|
||||
voltage: 60,
|
||||
purchasePrice: 45000,
|
||||
deposit: 5000,
|
||||
rentPrice: 150,
|
||||
investorShare: 100,
|
||||
investedAmount: investment.totalInvestment / 10
|
||||
});
|
||||
setShowRegisterBatteryModal(true);
|
||||
}} className="px-3 py-1.5 text-xs bg-investor text-white rounded-lg flex items-center gap-1 hover:bg-investor-dark transition-colors">
|
||||
<Plus className="w-3 h-3" /> Register & Assign New
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{assignedBatteries.length > 0 ? (
|
||||
@@ -1065,20 +1099,6 @@ export default function InvestmentDetailPage({ params }: { params: Promise<{ id:
|
||||
<button onClick={() => setShowAddBikeModal(true)} className="px-3 py-1.5 text-xs bg-blue-50 text-blue-700 border border-blue-200 rounded-lg flex items-center gap-1 hover:bg-blue-100 transition-colors">
|
||||
<Plus className="w-3 h-3" /> Assign Existing
|
||||
</button>
|
||||
<button onClick={() => {
|
||||
setRegisterBikeForm({
|
||||
plateNumber: `DHAKA-METRO-HA-${Math.floor(1000 + Math.random() * 9000)}`,
|
||||
brand: 'Etron',
|
||||
model: 'ET50',
|
||||
currentRent: 150,
|
||||
location: 'Banani',
|
||||
purchasePrice: 200000,
|
||||
rentalType: 'single_rent'
|
||||
});
|
||||
setShowRegisterBikeModal(true);
|
||||
}} className="px-3 py-1.5 text-xs bg-investor text-white rounded-lg flex items-center gap-1 hover:bg-investor-dark transition-colors">
|
||||
<Plus className="w-3 h-3" /> Register & Assign New
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{assignedBikes.length > 0 ? (
|
||||
|
||||
Reference in New Issue
Block a user