feat: add partial payment support for investments and update mock data fields

This commit is contained in:
sazzadulalambd
2026-05-15 03:10:37 +06:00
parent 44745d0252
commit cab01a25ac
4 changed files with 480 additions and 519 deletions

View File

@@ -133,6 +133,8 @@ export default function InvestorDetailPage() {
planType: 'gold' as 'silver' | 'gold' | 'platinum' | 'diamond',
selectedBikeIds: [] as string[],
totalInvestment: 0,
paidAmount: 0,
paymentOption: 'full' as 'full' | 'partial',
monthlyReturn: 0,
expectedRoi: 15,
startDate: new Date().toISOString().split('T')[0],
@@ -205,7 +207,7 @@ export default function InvestorDetailPage() {
sourceType: 'investor_funding',
createdAt: new Date().toISOString(),
type: 'investment',
amount: newInvestment.totalInvestment,
amount: newInvestment.paidAmount,
paymentMethod: newInvestment.paymentMethod
};
@@ -230,6 +232,8 @@ export default function InvestorDetailPage() {
planType: 'gold',
selectedBikeIds: [],
totalInvestment: 0,
paidAmount: 0,
paymentOption: 'full',
monthlyReturn: 0,
expectedRoi: 15,
startDate: new Date().toISOString().split('T')[0],
@@ -2229,6 +2233,8 @@ export default function InvestorDetailPage() {
planName: plan.name,
planType: plan.tier.toLowerCase() as any,
totalInvestment: plan.evBasePrice * plan.minQuantity,
paidAmount: plan.evBasePrice * plan.minQuantity,
paymentOption: 'full',
monthlyReturn: 0
});
}}
@@ -2290,7 +2296,14 @@ export default function InvestorDetailPage() {
<input
type="number"
value={newInvestment.totalInvestment}
onChange={(e) => setNewInvestment({ ...newInvestment, totalInvestment: Number(e.target.value) })}
onChange={(e) => {
const val = Number(e.target.value);
setNewInvestment({
...newInvestment,
totalInvestment: val,
paidAmount: newInvestment.paymentOption === 'full' ? val : Math.max(val * 0.5, newInvestment.paidAmount)
});
}}
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-yellow-50"
/>
</div>
@@ -2416,7 +2429,7 @@ export default function InvestorDetailPage() {
{newInvestment.paymentMethod === 'bank' ? 'Bank - City Bank' : newInvestment.paymentMethod === 'cash' ? 'Cash in Hand' : 'bKash Business'} ({newInvestment.paymentMethod === 'bank' ? '1200' : newInvestment.paymentMethod === 'cash' ? '1100' : '1300'})
</p>
</div>
<p className="font-bold text-green-700">{newInvestment.totalInvestment.toLocaleString()}</p>
<p className="font-bold text-green-700">{newInvestment.paidAmount.toLocaleString()}</p>
</div>
<div className="flex justify-center">
<div className="w-8 h-8 rounded-full bg-green-200 flex items-center justify-center">
@@ -2428,11 +2441,60 @@ export default function InvestorDetailPage() {
<p className="text-xs text-blue-600 font-medium uppercase">Credit (Cr)</p>
<p className="font-medium text-slate-800">Investor Liabilities (2200)</p>
</div>
<p className="font-bold text-blue-700">{newInvestment.totalInvestment.toLocaleString()}</p>
<p className="font-bold text-blue-700">{newInvestment.paidAmount.toLocaleString()}</p>
</div>
</div>
</div>
</div>
<div className="space-y-3">
<label className="text-sm font-medium text-slate-600 block">Payment Options</label>
<div className="grid grid-cols-2 gap-4">
<button
onClick={() => setNewInvestment({ ...newInvestment, paymentOption: 'full', paidAmount: newInvestment.totalInvestment })}
className={`p-4 rounded-xl border-2 text-left transition-all ${newInvestment.paymentOption === 'full' ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`}
>
<div className="flex items-center justify-between mb-1">
<p className="font-bold text-slate-800">Full Payment</p>
{newInvestment.paymentOption === 'full' && <CheckCircle className="w-4 h-4 text-investor" />}
</div>
<p className="text-xs text-slate-500 mb-2">Pay total amount at once</p>
<p className="text-lg font-bold text-investor">{newInvestment.totalInvestment.toLocaleString()}</p>
</button>
<button
onClick={() => setNewInvestment({ ...newInvestment, paymentOption: 'partial', paidAmount: Math.max(newInvestment.totalInvestment * 0.5, newInvestment.paidAmount) })}
className={`p-4 rounded-xl border-2 text-left transition-all ${newInvestment.paymentOption === 'partial' ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`}
>
<div className="flex items-center justify-between mb-1">
<p className="font-bold text-slate-800">Partial Payment</p>
{newInvestment.paymentOption === 'partial' && <CheckCircle className="w-4 h-4 text-investor" />}
</div>
<p className="text-xs text-slate-500 mb-2">Pay initial amount (50% min)</p>
<p className="text-lg font-bold text-slate-800">Min {(newInvestment.totalInvestment * 0.5).toLocaleString()}</p>
</button>
</div>
{newInvestment.paymentOption === 'partial' && (
<div className="bg-slate-50 p-4 rounded-lg border border-slate-200 mt-3 animate-in fade-in slide-in-from-top-2">
<label className="text-sm font-medium text-slate-700 mb-2 block">Enter Initial Payment Amount ()</label>
<div className="relative">
<span className="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400"></span>
<input
type="number"
value={newInvestment.paidAmount}
min={newInvestment.totalInvestment * 0.5}
max={newInvestment.totalInvestment}
onChange={(e) => setNewInvestment({ ...newInvestment, paidAmount: Number(e.target.value) })}
className="w-full pl-8 pr-4 py-2 border border-slate-200 rounded-lg focus:ring-2 focus:ring-investor outline-none text-sm"
/>
</div>
<p className="text-xs text-slate-400 mt-2 flex items-center gap-1">
<AlertTriangle className="w-3 h-3 text-amber-500" /> Remaining {(newInvestment.totalInvestment - newInvestment.paidAmount).toLocaleString()} will be recorded as pending.
</p>
</div>
)}
</div>
</div>
<div className="p-5 border-t border-slate-100 flex justify-end gap-3">