Compare commits
2 Commits
44745d0252
...
bb1d4628ee
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb1d4628ee | ||
|
|
cab01a25ac |
@@ -133,6 +133,8 @@ export default function InvestorDetailPage() {
|
||||
planType: 'gold' as 'silver' | 'gold' | 'platinum' | 'diamond',
|
||||
selectedBikeIds: [] as string[],
|
||||
totalInvestment: 0,
|
||||
paidAmount: 0,
|
||||
paymentType: '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,
|
||||
paymentType: '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,
|
||||
paymentType: '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.paymentType === '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>
|
||||
@@ -2315,6 +2328,8 @@ export default function InvestorDetailPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div className="bg-amber-50 border border-amber-200 rounded-xl p-4">
|
||||
<h4 className="text-sm font-semibold text-amber-800 mb-3 flex items-center gap-2">
|
||||
<TrendingUp className="w-4 h-4" />
|
||||
@@ -2357,6 +2372,61 @@ export default function InvestorDetailPage() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 border border-slate-200">
|
||||
<h4 className="text-sm font-semibold text-slate-800 mb-3 flex items-center gap-2">
|
||||
<CreditCard className="w-4 h-4 text-investor" /> Payment Options
|
||||
</h4>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-4">
|
||||
<label className={`flex items-center gap-3 p-3 rounded-lg border-2 cursor-pointer transition-all ${newInvestment.paymentType === 'full' ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="paymentType"
|
||||
value="full"
|
||||
checked={newInvestment.paymentType === 'full'}
|
||||
onChange={() => setNewInvestment({ ...newInvestment, paymentType: 'full', paidAmount: newInvestment.totalInvestment })}
|
||||
className="w-4 h-4 text-investor"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-slate-800 text-sm">Full Payment</p>
|
||||
<p className="text-xs text-slate-500">Pay total amount at once</p>
|
||||
</div>
|
||||
<span className="text-lg font-bold text-green-600">৳{newInvestment.totalInvestment.toLocaleString()}</span>
|
||||
</label>
|
||||
<label className={`flex items-center gap-3 p-3 rounded-lg border-2 cursor-pointer transition-all ${newInvestment.paymentType === 'partial' ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="paymentType"
|
||||
value="partial"
|
||||
checked={newInvestment.paymentType === 'partial'}
|
||||
onChange={() => setNewInvestment({ ...newInvestment, paymentType: 'partial', paidAmount: Math.floor(newInvestment.totalInvestment * 0.5) })}
|
||||
className="w-4 h-4 text-investor"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-slate-800 text-sm">Partial Payment</p>
|
||||
<p className="text-xs text-slate-500">Pay initial amount (50% min)</p>
|
||||
</div>
|
||||
<span className="text-sm font-bold text-amber-600">Min ৳{Math.floor(newInvestment.totalInvestment * 0.5).toLocaleString()}</span>
|
||||
</label>
|
||||
</div>
|
||||
{newInvestment.paymentType === 'partial' && (
|
||||
<div className="border-t border-slate-200 pt-4 mt-4">
|
||||
<label className="text-sm font-medium text-slate-600 mb-2 block">Initial Payment (৳) *</label>
|
||||
<input
|
||||
type="number"
|
||||
value={newInvestment.paidAmount}
|
||||
onChange={(e) => {
|
||||
const val = Number(e.target.value);
|
||||
if (val >= newInvestment.totalInvestment * 0.5 && val <= newInvestment.totalInvestment) {
|
||||
setNewInvestment({ ...newInvestment, paidAmount: val });
|
||||
}
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-investor rounded-lg text-sm bg-white"
|
||||
/>
|
||||
<p className="text-xs text-slate-500 mt-2">Balance: ৳{(newInvestment.totalInvestment - newInvestment.paidAmount).toLocaleString()}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
@@ -2416,7 +2486,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 +2498,13 @@ 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>
|
||||
|
||||
<div className="p-5 border-t border-slate-100 flex justify-end gap-3">
|
||||
|
||||
@@ -1,395 +0,0 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import {
|
||||
ArrowLeft, Zap, Shield, TrendingUp, Check, Info,
|
||||
Calendar, DollarSign, CreditCard, FileText, ChevronRight,
|
||||
AlertCircle, ArrowDown, Wallet, Clock, Activity
|
||||
} from 'lucide-react';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
const PLAN_TEMPLATES = [
|
||||
{
|
||||
id: '1bike',
|
||||
name: '1 Bike Plan',
|
||||
description: 'Investment plan for 1 bike - perfect for small investors',
|
||||
evBasePrice: 200000,
|
||||
minQty: 1,
|
||||
minInvestment: 200000,
|
||||
maxInvestment: 1000000,
|
||||
duration: 12,
|
||||
lockIn: 3,
|
||||
exitPenalty: 10,
|
||||
ficoShare: { single: 45, own: 55, ev: 60 },
|
||||
icon: Zap,
|
||||
color: 'bg-blue-600',
|
||||
lightColor: 'bg-blue-50 text-blue-700'
|
||||
},
|
||||
{
|
||||
id: '5bike',
|
||||
name: '5 Bike Plan',
|
||||
description: 'Perfect for established investors looking for better returns',
|
||||
evBasePrice: 180000,
|
||||
minQty: 5,
|
||||
minInvestment: 900000,
|
||||
maxInvestment: 5000000,
|
||||
duration: 24,
|
||||
lockIn: 6,
|
||||
exitPenalty: 15,
|
||||
ficoShare: { single: 40, own: 50, ev: 55 },
|
||||
icon: TrendingUp,
|
||||
color: 'bg-purple-600',
|
||||
lightColor: 'bg-purple-50 text-purple-700'
|
||||
}
|
||||
];
|
||||
|
||||
export default function NewInvestmentPage() {
|
||||
const router = useRouter();
|
||||
const [step, setStep] = useState<'select' | 'form'>('select');
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<typeof PLAN_TEMPLATES[0] | null>(null);
|
||||
|
||||
const [formData, setFormData] = useState({
|
||||
planName: '',
|
||||
planType: 'Gold',
|
||||
investmentAmount: 0,
|
||||
initialPayment: 0,
|
||||
startDate: new Date().toISOString().split('T')[0],
|
||||
endDate: '',
|
||||
paymentMethod: 'Bank Transfer',
|
||||
transactionRef: '',
|
||||
description: ''
|
||||
});
|
||||
|
||||
const handleSelectTemplate = (template: typeof PLAN_TEMPLATES[0]) => {
|
||||
setSelectedTemplate(template);
|
||||
setFormData({
|
||||
...formData,
|
||||
planName: template.name,
|
||||
investmentAmount: template.minInvestment,
|
||||
initialPayment: Math.floor(template.minInvestment * 0.5) // Default 50% initial
|
||||
});
|
||||
setStep('form');
|
||||
};
|
||||
|
||||
const handleCreateInvestment = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
if (formData.investmentAmount < (selectedTemplate?.minInvestment || 0)) {
|
||||
toast.error(`Minimum investment for this plan is ৳${selectedTemplate?.minInvestment.toLocaleString()}`);
|
||||
return;
|
||||
}
|
||||
toast.success('Investment request created successfully! Admin will review and assign bikes.');
|
||||
router.push('/investor/plans');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 lg:p-6 max-w-5xl mx-auto mb-20 lg:mb-0">
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<button
|
||||
onClick={() => step === 'form' ? setStep('select') : router.back()}
|
||||
className="p-2 hover:bg-slate-100 rounded-xl transition-colors border border-slate-200"
|
||||
>
|
||||
<ArrowLeft className="w-5 h-5 text-slate-600" />
|
||||
</button>
|
||||
<div>
|
||||
<h1 className="text-xl lg:text-2xl font-extrabold text-slate-800 flex items-center gap-2">
|
||||
<Zap className="w-5 h-5 lg:w-6 lg:h-6 text-investor" />
|
||||
{step === 'select' ? 'Select Investment Plan' : 'Configure New Investment'}
|
||||
</h1>
|
||||
<p className="text-sm text-slate-500">
|
||||
{step === 'select' ? 'Choose a template to start' : `Set up investment under ${selectedTemplate?.name}`}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{step === 'select' && (
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
{PLAN_TEMPLATES.map((plan) => {
|
||||
const Icon = plan.icon;
|
||||
return (
|
||||
<div
|
||||
key={plan.id}
|
||||
className="bg-white rounded-2xl border-2 border-slate-100 p-6 hover:border-investor transition-all group cursor-pointer shadow-sm hover:shadow-md"
|
||||
onClick={() => handleSelectTemplate(plan)}
|
||||
>
|
||||
<div className={`w-14 h-14 rounded-2xl mb-6 flex items-center justify-center ${plan.lightColor}`}>
|
||||
<Icon className="w-7 h-7" />
|
||||
</div>
|
||||
<h3 className="text-xl font-extrabold text-slate-800 mb-2">{plan.name}</h3>
|
||||
<p className="text-sm text-slate-500 mb-6 leading-relaxed">{plan.description}</p>
|
||||
|
||||
<div className="space-y-3 mb-8">
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-slate-400 font-medium">Min Investment</span>
|
||||
<span className="text-slate-800 font-extrabold">৳{plan.minInvestment.toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-slate-400 font-medium">EV Base Price</span>
|
||||
<span className="text-slate-800 font-extrabold">৳{plan.evBasePrice.toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center text-sm">
|
||||
<span className="text-slate-400 font-medium">Duration</span>
|
||||
<span className="text-slate-800 font-extrabold">{plan.duration} Months</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button className="w-full py-3.5 bg-slate-50 text-slate-800 rounded-xl font-bold group-hover:bg-investor group-hover:text-white transition-all flex items-center justify-center gap-2">
|
||||
Select Template <ChevronRight className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{step === 'form' && selectedTemplate && (
|
||||
<form onSubmit={handleCreateInvestment} className="space-y-6">
|
||||
<div className="grid lg:grid-cols-3 gap-6">
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
{/* Core Configuration */}
|
||||
<div className="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm">
|
||||
<h3 className="text-lg font-bold text-slate-800 mb-6 flex items-center gap-2">
|
||||
<FileText className="w-5 h-5 text-investor" /> Plan Configuration
|
||||
</h3>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-5 mb-6">
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-slate-700 mb-2">Plan Name *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.planName}
|
||||
onChange={(e) => setFormData({...formData, planName: e.target.value})}
|
||||
className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-investor/20 focus:border-investor outline-none transition-all font-medium"
|
||||
placeholder="e.g. My First Bike"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-slate-700 mb-2">Plan Type</label>
|
||||
<select
|
||||
value={formData.planType}
|
||||
onChange={(e) => setFormData({...formData, planType: e.target.value})}
|
||||
className="w-full px-4 py-3 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-investor/20 focus:border-investor outline-none transition-all font-medium"
|
||||
>
|
||||
<option>Gold</option>
|
||||
<option>Silver</option>
|
||||
<option>Platinum</option>
|
||||
<option>Diamond</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 p-4 bg-slate-50 rounded-xl border border-slate-100 mb-6 text-center">
|
||||
<div>
|
||||
<p className="text-[10px] text-slate-400 font-bold uppercase mb-1">EV Base Price</p>
|
||||
<p className="text-sm font-bold text-slate-800">৳{selectedTemplate.evBasePrice.toLocaleString()}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[10px] text-slate-400 font-bold uppercase mb-1">Min Qty</p>
|
||||
<p className="text-sm font-bold text-slate-800">{selectedTemplate.minQty} Bike(s)</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[10px] text-slate-400 font-bold uppercase mb-1">Min Invest</p>
|
||||
<p className="text-sm font-bold text-slate-800">৳{selectedTemplate.minInvestment.toLocaleString()}</p>
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[10px] text-slate-400 font-bold uppercase mb-1">Max Invest</p>
|
||||
<p className="text-sm font-bold text-slate-800">৳{selectedTemplate.maxInvestment.toLocaleString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-slate-700 mb-2">Investment Amount (৳) *</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.investmentAmount}
|
||||
onChange={(e) => setFormData({...formData, investmentAmount: Number(e.target.value)})}
|
||||
className="w-full px-4 py-3 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-investor/20 focus:border-investor outline-none transition-all font-extrabold"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-slate-700 mb-2">Initial Payment (৳) *</label>
|
||||
<input
|
||||
type="number"
|
||||
value={formData.initialPayment}
|
||||
onChange={(e) => setFormData({...formData, initialPayment: Number(e.target.value)})}
|
||||
className="w-full px-4 py-3 border border-investor rounded-xl text-sm focus:ring-2 focus:ring-investor/20 outline-none transition-all font-extrabold text-investor"
|
||||
placeholder="Amount to pay now"
|
||||
required
|
||||
/>
|
||||
<p className="text-[10px] text-slate-400 mt-1 font-medium">Pay part of your investment now to confirm</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Profit Sharing Policy */}
|
||||
<div className="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm">
|
||||
<h3 className="text-lg font-bold text-slate-800 mb-4 flex items-center gap-2">
|
||||
<TrendingUp className="w-5 h-5 text-investor" /> FICO Share - Jaiben's Profit per Ride
|
||||
</h3>
|
||||
<p className="text-xs text-slate-500 mb-6 font-medium">Profit sharing when bikes are rented to end customers</p>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="bg-slate-50 rounded-xl p-4 border border-slate-100 text-center">
|
||||
<p className="text-[10px] text-slate-500 font-bold uppercase mb-1">Single Rent</p>
|
||||
<p className="text-xl font-extrabold text-slate-800">{selectedTemplate.ficoShare.single}%</p>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 border border-slate-100 text-center">
|
||||
<p className="text-[10px] text-slate-500 font-bold uppercase mb-1">Rent to Own</p>
|
||||
<p className="text-xl font-extrabold text-slate-800">{selectedTemplate.ficoShare.own}%</p>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 border border-slate-100 text-center">
|
||||
<p className="text-[10px] text-slate-500 font-bold uppercase mb-1">Share an EV</p>
|
||||
<p className="text-xl font-extrabold text-slate-800">{selectedTemplate.ficoShare.ev}%</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Auto-Journal Entry Visualization */}
|
||||
<div className="bg-slate-900 rounded-2xl p-6 shadow-xl overflow-hidden relative">
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-investor/10 rounded-full blur-3xl -mr-16 -mt-16" />
|
||||
<h3 className="text-lg font-bold text-white mb-6 flex items-center gap-2">
|
||||
<Activity className="w-5 h-5 text-investor" /> Auto-Journal Entry (Draft)
|
||||
</h3>
|
||||
|
||||
<div className="space-y-4 relative z-10">
|
||||
<div className="flex justify-between items-center text-xs font-bold uppercase text-slate-400 mb-2 px-2">
|
||||
<span>Account Details</span>
|
||||
<span>Amount (৳)</span>
|
||||
</div>
|
||||
|
||||
<div className="bg-white/5 border border-white/10 rounded-xl p-4 flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-[10px] text-green-400 font-bold uppercase mb-1">Debit (Dr)</p>
|
||||
<p className="text-sm font-bold text-white">Bank - City Bank</p>
|
||||
<p className="text-[10px] text-slate-500 font-mono">CODE: 1200</p>
|
||||
</div>
|
||||
<p className="text-lg font-extrabold text-green-400">৳{formData.investmentAmount.toLocaleString()}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-center -my-2 relative z-20">
|
||||
<div className="bg-investor w-8 h-8 rounded-full flex items-center justify-center shadow-lg">
|
||||
<ArrowDown className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white/5 border border-white/10 rounded-xl p-4 flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-[10px] text-blue-400 font-bold uppercase mb-1">Credit (Cr)</p>
|
||||
<p className="text-sm font-bold text-white">Investor Liabilities</p>
|
||||
<p className="text-[10px] text-slate-500 font-mono">CODE: 2200</p>
|
||||
</div>
|
||||
<p className="text-lg font-extrabold text-blue-400">৳{formData.investmentAmount.toLocaleString()}</p>
|
||||
</div>
|
||||
|
||||
<div className="pt-4 border-t border-white/10 mt-2 flex justify-between items-center px-2">
|
||||
<p className="text-[10px] text-slate-500 font-medium">Reference: <span className="text-slate-300 font-mono">INV/{new Date().getFullYear()}/AUTO-{Math.random().toString(36).substring(7).toUpperCase()}</span></p>
|
||||
<p className="text-[10px] text-slate-500 font-medium tracking-tight uppercase">Status: <span className="text-amber-400">Draft - On Creation</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* Time & Period */}
|
||||
<div className="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm">
|
||||
<h3 className="text-base font-bold text-slate-800 mb-4 flex items-center gap-2">
|
||||
<Calendar className="w-5 h-5 text-investor" /> Schedule
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-[11px] font-bold text-slate-500 uppercase tracking-wider mb-2">Start Date *</label>
|
||||
<input
|
||||
type="date"
|
||||
value={formData.startDate}
|
||||
onChange={(e) => setFormData({...formData, startDate: e.target.value})}
|
||||
className="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-investor/20 outline-none font-bold"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[11px] font-bold text-slate-500 uppercase tracking-wider mb-2">End Date (Optional)</label>
|
||||
<input
|
||||
type="date"
|
||||
value={formData.endDate}
|
||||
onChange={(e) => setFormData({...formData, endDate: e.target.value})}
|
||||
className="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-investor/20 outline-none font-bold"
|
||||
/>
|
||||
</div>
|
||||
<div className="p-3 bg-blue-50 rounded-xl border border-blue-100 flex items-start gap-3">
|
||||
<AlertCircle className="w-4 h-4 text-blue-600 shrink-0 mt-0.5" />
|
||||
<p className="text-[10px] text-blue-700 font-medium leading-relaxed">
|
||||
Duration is fixed at <strong>{selectedTemplate.duration} months</strong> with a <strong>{selectedTemplate.lockIn} month</strong> lock-in period as per template.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Payment Details */}
|
||||
<div className="bg-white rounded-2xl border border-slate-200 p-6 shadow-sm">
|
||||
<h3 className="text-base font-bold text-slate-800 mb-4 flex items-center gap-2">
|
||||
<CreditCard className="w-5 h-5 text-investor" /> Payment
|
||||
</h3>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-[11px] font-bold text-slate-500 uppercase tracking-wider mb-2">Method</label>
|
||||
<select
|
||||
value={formData.paymentMethod}
|
||||
onChange={(e) => setFormData({...formData, paymentMethod: e.target.value})}
|
||||
className="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-investor/20 outline-none font-bold"
|
||||
>
|
||||
<option>Bank Transfer</option>
|
||||
<option>Mobile Banking</option>
|
||||
<option>Cheque</option>
|
||||
<option>Cash</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-[11px] font-bold text-slate-500 uppercase tracking-wider mb-2">Reference ID</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.transactionRef}
|
||||
onChange={(e) => setFormData({...formData, transactionRef: e.target.value})}
|
||||
className="w-full px-4 py-2.5 bg-slate-50 border border-slate-200 rounded-xl text-sm focus:ring-2 focus:ring-investor/20 outline-none font-bold"
|
||||
placeholder="Auto-generated if empty"
|
||||
/>
|
||||
</div>
|
||||
<div className="pt-4 border-t border-slate-100">
|
||||
<div className="flex justify-between items-center mb-1">
|
||||
<span className="text-xs text-slate-500 font-bold uppercase">Pay Now</span>
|
||||
<span className="text-lg font-extrabold text-investor">৳{formData.initialPayment.toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="flex justify-between items-center">
|
||||
<span className="text-xs text-slate-500 font-bold uppercase">Balance Due</span>
|
||||
<span className="text-sm font-bold text-slate-800">৳{(formData.investmentAmount - formData.initialPayment).toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="space-y-3">
|
||||
<button
|
||||
type="submit"
|
||||
className="w-full py-4 bg-investor text-white rounded-2xl font-bold text-lg shadow-lg shadow-investor/30 hover:bg-investor-dark transition-all transform hover:-translate-y-1 active:scale-95"
|
||||
>
|
||||
Create Investment
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setStep('select')}
|
||||
className="w-full py-3 text-slate-600 font-bold text-sm hover:bg-slate-100 rounded-xl transition-colors"
|
||||
>
|
||||
Cancel & Back
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -2,140 +2,433 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { Target, ArrowRight, Zap, TrendingUp, CreditCard, Plus, FileText, ChevronRight, Wallet, Clock, Percent } from 'lucide-react';
|
||||
import { Target, Plus, Zap, ChevronRight, ArrowRight, Edit, Trash2, Eye, TrendingUp, X, CreditCard } from 'lucide-react';
|
||||
import { investors } from '@/data/mockData';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
export default function MyInvestmentsPage() {
|
||||
const investor = investors[0]; // mock logged-in investor
|
||||
const investor = investors[0];
|
||||
const [showCreateModal, setShowCreateModal] = useState(false);
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<any>(null);
|
||||
const [newInvestment, setNewInvestment] = useState({
|
||||
planName: '', planType: 'gold', totalInvestment: 0, initialPayment: 0, paymentType: 'full',
|
||||
startDate: '', endDate: '', paymentMethod: 'bank', transactionReference: '', notes: ''
|
||||
});
|
||||
|
||||
const PLAN_TEMPLATES = [
|
||||
{ id: '1bike', name: '1 Bike Plan', tier: 'Standard', evBasePrice: 200000, minQuantity: 1, duration: 12, maxInvestment: 1000000 },
|
||||
{ id: '5bike', name: '5 Bike Plan', tier: 'Premium', evBasePrice: 180000, minQuantity: 5, duration: 24, maxInvestment: 5000000 },
|
||||
{ id: '10bike', name: '10 Bike Plan', tier: 'Enterprise', evBasePrice: 170000, minQuantity: 10, duration: 36, maxInvestment: 10000000 },
|
||||
];
|
||||
|
||||
const planConfig: Record<string, { bg: string; border: string; icon: string }> = {
|
||||
silver: { bg: 'bg-slate-100', border: 'border-slate-300', icon: 'text-slate-500' },
|
||||
gold: { bg: 'bg-amber-100', border: 'border-amber-300', icon: 'text-amber-500' },
|
||||
platinum: { bg: 'bg-purple-100', border: 'border-purple-300', icon: 'text-purple-500' },
|
||||
diamond: { bg: 'bg-blue-100', border: 'border-blue-300', icon: 'text-blue-500' },
|
||||
};
|
||||
|
||||
const handleCreate = () => {
|
||||
if (!newInvestment.planName || !newInvestment.totalInvestment) {
|
||||
toast.error('Please fill all required fields');
|
||||
return;
|
||||
}
|
||||
if (newInvestment.paymentType === 'partial' && newInvestment.initialPayment < newInvestment.totalInvestment * 0.5) {
|
||||
toast.error('Initial payment must be at least 50% of investment amount');
|
||||
return;
|
||||
}
|
||||
toast.success(newInvestment.paymentType === 'partial'
|
||||
? `Investment created! Initial: ৳${newInvestment.initialPayment.toLocaleString()}, Balance: ৳${(newInvestment.totalInvestment - newInvestment.initialPayment).toLocaleString()}`
|
||||
: 'Investment created successfully!'
|
||||
);
|
||||
setShowCreateModal(false);
|
||||
setSelectedTemplate(null);
|
||||
setNewInvestment({ planName: '', planType: 'gold', totalInvestment: 0, initialPayment: 0, paymentType: 'full', startDate: '', endDate: '', paymentMethod: 'bank', transactionReference: '', notes: '' });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-4 lg:p-6 max-w-8xl mx-auto mb-20 lg:mb-0">
|
||||
<div className="flex flex-col md:flex-row md:items-center justify-between gap-4 mb-8">
|
||||
<div>
|
||||
<h1 className="text-xl lg:text-2xl font-bold text-slate-800 flex items-center gap-2">
|
||||
<Target className="w-5 h-5 lg:w-6 lg:h-6 text-investor" /> My Investments
|
||||
</h1>
|
||||
<p className="text-sm text-slate-500 mt-1">Manage your active portfolios and track your earnings.</p>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
href="/investor/plans/new"
|
||||
className="inline-flex items-center gap-2 px-6 py-3 bg-investor text-white rounded-xl font-bold shadow-lg shadow-investor/20 hover:bg-investor-dark transition-all transform hover:-translate-y-0.5 active:scale-95"
|
||||
>
|
||||
<Plus className="w-5 h-5" /> New Investment
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Portfolio Summary */}
|
||||
<div className="mb-10 bg-slate-50 rounded-2xl p-6 border border-slate-200">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<h2 className="text-lg font-bold text-slate-800 flex items-center gap-2">
|
||||
<Target className="w-5 h-5 text-investor" /> Portfolio Overview
|
||||
</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div className="bg-white p-5 rounded-xl shadow-sm border border-slate-200">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
|
||||
<Wallet className="w-5 h-5 text-purple-600" />
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 font-bold uppercase tracking-wider">Total Invested</p>
|
||||
</div>
|
||||
<p className="text-2xl font-extrabold text-slate-800">৳{investor.totalInvested.toLocaleString()}</p>
|
||||
</div>
|
||||
<div className="bg-white p-5 rounded-xl shadow-sm border border-slate-200">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center">
|
||||
<TrendingUp className="w-5 h-5 text-green-600" />
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 font-bold uppercase tracking-wider">Total Returns</p>
|
||||
</div>
|
||||
<p className="text-2xl font-extrabold text-green-600">৳{investor.totalEarnings.toLocaleString()}</p>
|
||||
</div>
|
||||
<div className="bg-white p-5 rounded-xl shadow-sm border border-slate-200">
|
||||
<div className="flex items-center gap-3 mb-3">
|
||||
<div className="w-10 h-10 bg-amber-100 rounded-lg flex items-center justify-center">
|
||||
<Clock className="w-5 h-5 text-amber-600" />
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 font-bold uppercase tracking-wider">Active Bikes</p>
|
||||
</div>
|
||||
<p className="text-2xl font-extrabold text-slate-800">{investor.activeBikes} Units</p>
|
||||
{/* Header */}
|
||||
<div className="mb-6">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-xl sm:text-2xl font-bold text-slate-800 flex items-center gap-2">
|
||||
<Target className="w-5 h-5 sm:w-6 sm:h-6 text-investor" /> My Investments
|
||||
</h1>
|
||||
<p className="text-sm text-slate-500 mt-1">Manage your active portfolios and track your earnings.</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setShowCreateModal(true)}
|
||||
className="px-4 py-2.5 bg-investor text-white rounded-lg text-sm font-medium hover:bg-investor-dark flex items-center gap-2 shadow-sm"
|
||||
>
|
||||
<Plus className="w-4 h-4" /> Create Investment
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* My Active Investments List */}
|
||||
<div className="bg-white rounded-2xl border border-slate-200 shadow-sm overflow-hidden">
|
||||
<div className="p-5 border-b border-slate-100 flex items-center justify-between bg-slate-50/50">
|
||||
<h2 className="text-lg font-bold text-slate-800 flex items-center gap-2">
|
||||
<Zap className="w-5 h-5 text-investor" /> Active Investment Plans
|
||||
</h2>
|
||||
<span className="text-xs font-bold px-3 py-1 bg-investor/10 text-investor rounded-full">
|
||||
{investor.investments?.length || 0} Total
|
||||
</span>
|
||||
{/* Investment Plans Cards */}
|
||||
<div className="space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="font-semibold text-slate-800">Investment Plans</h3>
|
||||
<p className="text-sm text-slate-500">Manage investment portfolios for this investor</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-left">
|
||||
<thead>
|
||||
<tr className="bg-slate-50 border-b border-slate-100">
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Investment Plan</th>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Capital Invested</th>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider text-right">Actual Returns</th>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider">Status</th>
|
||||
<th className="px-6 py-4 text-xs font-bold text-slate-400 uppercase tracking-wider text-right">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="divide-y divide-slate-100">
|
||||
{investor.investments && investor.investments.length > 0 ? investor.investments.map((inv) => (
|
||||
<tr key={inv.id} className="hover:bg-slate-50 transition-colors group">
|
||||
<td className="px-6 py-5">
|
||||
<p className="text-base font-bold text-slate-800">{inv.planName}</p>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<span className="text-[10px] bg-slate-100 text-slate-600 px-1.5 py-0.5 rounded font-bold uppercase">{inv.planType}</span>
|
||||
<span className="text-[10px] text-slate-400 font-medium">Started: {inv.startDate}</span>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{investor.investments?.map((inv) => {
|
||||
const style = planConfig[inv.planType] || planConfig.gold;
|
||||
return (
|
||||
<div key={inv.id} className={`bg-white rounded-xl border ${style.border} overflow-hidden`}>
|
||||
<div className={`${style.bg} p-4 flex items-center justify-between`}>
|
||||
<div>
|
||||
<h4 className="font-semibold text-slate-800">{inv.planName}</h4>
|
||||
<p className="text-sm text-slate-500 capitalize">{inv.planType} Plan</p>
|
||||
</div>
|
||||
<span className={`text-xs font-medium px-2.5 py-1 rounded-full ${inv.status === 'active' ? 'bg-green-100 text-green-700' : 'bg-slate-200 text-slate-600'}`}>
|
||||
{inv.status}
|
||||
</span>
|
||||
</div>
|
||||
<div className="p-4 space-y-4">
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div className="bg-slate-50 rounded-lg p-3">
|
||||
<p className="text-xs text-slate-500">Investment</p>
|
||||
<p className="font-bold text-slate-800">৳{inv.totalInvestment.toLocaleString()}</p>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-6 py-5">
|
||||
<p className="text-sm font-extrabold text-slate-700">৳{inv.totalInvestment.toLocaleString()}</p>
|
||||
</td>
|
||||
<td className="px-6 py-5 text-right">
|
||||
<p className="text-sm font-extrabold text-green-600">৳{inv.actualEarnings.toLocaleString()}</p>
|
||||
<p className="text-[10px] text-slate-400 font-bold uppercase mt-1">+{inv.expectedRoi}% ROI</p>
|
||||
</td>
|
||||
<td className="px-6 py-5">
|
||||
<span className={`inline-flex items-center gap-1.5 px-2.5 py-1 rounded-lg text-[10px] font-bold uppercase ${inv.status === 'active' ? 'bg-green-50 text-green-700 border border-green-100' : 'bg-slate-50 text-slate-600 border border-slate-100'
|
||||
}`}>
|
||||
<div className={`w-1.5 h-1.5 rounded-full ${inv.status === 'active' ? 'bg-green-500' : 'bg-slate-400'}`} />
|
||||
{inv.status}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-6 py-5 text-right">
|
||||
<Link
|
||||
href={`/investor/investments/${inv.id}`}
|
||||
className="inline-flex items-center gap-2 text-investor hover:text-investor-dark font-bold text-sm transition-all group-hover:gap-3"
|
||||
>
|
||||
View Details <ChevronRight className="w-4 h-4" />
|
||||
</Link>
|
||||
</td>
|
||||
</tr>
|
||||
)) : (
|
||||
<tr>
|
||||
<td colSpan={5} className="px-6 py-16 text-center">
|
||||
<div className="flex flex-col items-center">
|
||||
<Target className="w-12 h-12 text-slate-200 mb-3" />
|
||||
<p className="text-slate-500 font-bold">No active investments found.</p>
|
||||
<Link href="/investor/plans/new" className="mt-4 text-invest-600 font-bold text-sm hover:underline">
|
||||
Start your first investment
|
||||
<div className="bg-purple-50 rounded-lg p-3">
|
||||
<p className="text-xs text-purple-600">Total Return</p>
|
||||
<p className="font-bold text-purple-700">৳{inv.actualEarnings.toLocaleString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-lg p-3 space-y-1.5">
|
||||
<div className="flex justify-between text-xs">
|
||||
<span className="text-slate-400">Duration</span>
|
||||
<span className="font-medium">12 months</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs">
|
||||
<span className="text-slate-400">Lock-in Period</span>
|
||||
<span className="font-medium">3 months</span>
|
||||
</div>
|
||||
<div className="flex justify-between text-xs">
|
||||
<span className="text-slate-400">Early Exit Penalty</span>
|
||||
<span className="font-medium text-red-500">10%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<span className="text-slate-400">{inv.startDate} - {inv.endDate || 'Ongoing'}</span>
|
||||
<span className="capitalize text-slate-500">{inv.paymentMethod}</span>
|
||||
</div>
|
||||
<div className="pt-3 border-t border-slate-100">
|
||||
<p className="text-xs text-slate-400 mb-2">ID: #{inv.id?.slice(-6) || 'N/A'}</p>
|
||||
<div className="flex gap-2">
|
||||
<Link href={`/investor/investments/${inv.id}`} className="flex-1 py-2 text-sm font-medium text-slate-600 hover:bg-slate-50 rounded-lg border border-slate-200 text-center">
|
||||
<Eye className="w-4 h-4 inline mr-1" /> View
|
||||
</Link>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{(!investor.investments || investor.investments.length === 0) && (
|
||||
<div className="text-center py-16 bg-slate-50 rounded-xl border-2 border-dashed border-slate-200">
|
||||
<TrendingUp className="w-12 h-12 mx-auto mb-3 text-slate-300" />
|
||||
<h4 className="font-semibold text-slate-600 mb-2">No Investments Yet</h4>
|
||||
<p className="text-slate-400 mb-4">Create your first investment plan</p>
|
||||
<button onClick={() => setShowCreateModal(true)} className="px-4 py-2 bg-investor text-white rounded-lg text-sm font-medium hover:bg-investor-dark">
|
||||
<Plus className="w-4 h-4 inline mr-1" /> Create Investment
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Create Investment Modal */}
|
||||
{showCreateModal && (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div className="bg-white rounded-xl shadow-xl w-full max-w-3xl max-h-[90vh] overflow-hidden flex flex-col">
|
||||
<div className="p-5 border-b border-slate-100 flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-lg font-bold text-slate-800 flex items-center gap-2">
|
||||
<Plus className="w-5 h-5 text-investor" /> Create New Investment
|
||||
</h2>
|
||||
<p className="text-sm text-slate-500">Set up investment for {investor.name}</p>
|
||||
</div>
|
||||
<button onClick={() => setShowCreateModal(false)} className="p-2 hover:bg-slate-100 rounded-lg">
|
||||
<X className="w-5 h-5 text-slate-400" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="p-5 overflow-y-auto flex-1 space-y-5">
|
||||
{!selectedTemplate ? (
|
||||
<>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-2 block">Select Plan Template</label>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||
{PLAN_TEMPLATES.map(plan => (
|
||||
<button
|
||||
key={plan.id}
|
||||
onClick={() => {
|
||||
setSelectedTemplate(plan);
|
||||
setNewInvestment({
|
||||
...newInvestment,
|
||||
planName: plan.name,
|
||||
planType: plan.tier.toLowerCase() as any,
|
||||
totalInvestment: plan.evBasePrice * plan.minQuantity,
|
||||
startDate: new Date().toISOString().split('T')[0],
|
||||
});
|
||||
}}
|
||||
className="p-4 rounded-lg border-2 border-slate-200 hover:border-investor/50 text-left transition-all hover:bg-slate-50"
|
||||
>
|
||||
<p className="font-semibold text-slate-800">{plan.name}</p>
|
||||
<p className="text-xs text-slate-500 mt-1">৳{plan.evBasePrice.toLocaleString()} × {plan.minQuantity} bikes</p>
|
||||
<p className="text-sm text-slate-600 mt-1">Duration: {plan.duration} months</p>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className="flex items-center gap-3 p-3 bg-slate-50 rounded-lg">
|
||||
<button onClick={() => setSelectedTemplate(null)} className="text-xs text-investor hover:underline">← Change Template</button>
|
||||
<span className="text-slate-300">|</span>
|
||||
<span className="text-sm font-medium text-slate-700">{selectedTemplate.name}</span>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Plan Name *</label>
|
||||
<input
|
||||
type="text"
|
||||
value={newInvestment.planName}
|
||||
onChange={(e) => setNewInvestment({ ...newInvestment, planName: e.target.value })}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm"
|
||||
placeholder="Plan name"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Plan Type</label>
|
||||
<select
|
||||
value={newInvestment.planType}
|
||||
onChange={(e) => setNewInvestment({ ...newInvestment, planType: e.target.value as any })}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-white"
|
||||
>
|
||||
<option value="silver">Silver</option>
|
||||
<option value="gold">Gold</option>
|
||||
<option value="platinum">Platinum</option>
|
||||
<option value="diamond">Diamond</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">EV Base Price (৳)</label>
|
||||
<input type="number" value={selectedTemplate.evBasePrice} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-50 cursor-not-allowed" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Minimum Quantity</label>
|
||||
<input type="number" value={selectedTemplate.minQuantity} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-50 cursor-not-allowed" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Min Investment (৳)</label>
|
||||
<input type="number" value={selectedTemplate.evBasePrice * selectedTemplate.minQuantity} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100 cursor-not-allowed" />
|
||||
<p className="text-xs text-slate-400 mt-1">= Qty × Base Price</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Investment Amount (৳) *</label>
|
||||
<input
|
||||
type="number"
|
||||
value={newInvestment.totalInvestment}
|
||||
onChange={(e) => setNewInvestment({ ...newInvestment, totalInvestment: Number(e.target.value) })}
|
||||
className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-yellow-50"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Max Investment (৳)</label>
|
||||
<input type="number" value={selectedTemplate.maxInvestment} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100 cursor-not-allowed" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-slate-50 rounded-xl p-4 border border-slate-200">
|
||||
<h4 className="text-sm font-semibold text-slate-800 mb-3 flex items-center gap-2">
|
||||
<CreditCard className="w-4 h-4 text-investor" /> Payment Options
|
||||
</h4>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-4">
|
||||
<label className={`flex items-center gap-3 p-3 rounded-lg border-2 cursor-pointer transition-all ${newInvestment.paymentType === 'full' ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="paymentType"
|
||||
value="full"
|
||||
checked={newInvestment.paymentType === 'full'}
|
||||
onChange={() => setNewInvestment({ ...newInvestment, paymentType: 'full', initialPayment: newInvestment.totalInvestment })}
|
||||
className="w-4 h-4 text-investor"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-slate-800 text-sm">Full Payment</p>
|
||||
<p className="text-xs text-slate-500">Pay total amount at once</p>
|
||||
</div>
|
||||
<span className="text-lg font-bold text-green-600">৳{newInvestment.totalInvestment.toLocaleString()}</span>
|
||||
</label>
|
||||
<label className={`flex items-center gap-3 p-3 rounded-lg border-2 cursor-pointer transition-all ${newInvestment.paymentType === 'partial' ? 'border-investor bg-investor/5' : 'border-slate-200 hover:border-slate-300'}`}>
|
||||
<input
|
||||
type="radio"
|
||||
name="paymentType"
|
||||
value="partial"
|
||||
checked={newInvestment.paymentType === 'partial'}
|
||||
onChange={() => setNewInvestment({ ...newInvestment, paymentType: 'partial', initialPayment: Math.floor(newInvestment.totalInvestment * 0.5) })}
|
||||
className="w-4 h-4 text-investor"
|
||||
/>
|
||||
<div className="flex-1">
|
||||
<p className="font-medium text-slate-800 text-sm">Partial Payment</p>
|
||||
<p className="text-xs text-slate-500">Pay initial amount (50% min)</p>
|
||||
</div>
|
||||
<span className="text-sm font-bold text-amber-600">Min ৳{Math.floor(newInvestment.totalInvestment * 0.5).toLocaleString()}</span>
|
||||
</label>
|
||||
</div>
|
||||
{newInvestment.paymentType === 'partial' && (
|
||||
<div className="border-t border-slate-200 pt-4 mt-4">
|
||||
<label className="text-sm font-medium text-slate-600 mb-2 block">Initial Payment (৳) *</label>
|
||||
<input
|
||||
type="number"
|
||||
value={newInvestment.initialPayment}
|
||||
onChange={(e) => {
|
||||
const val = Number(e.target.value);
|
||||
if (val >= newInvestment.totalInvestment * 0.5 && val <= newInvestment.totalInvestment) {
|
||||
setNewInvestment({ ...newInvestment, initialPayment: val });
|
||||
}
|
||||
}}
|
||||
className="w-full px-3 py-2 border border-investor rounded-lg text-sm bg-white"
|
||||
/>
|
||||
<p className="text-xs text-slate-500 mt-2">Balance: ৳{(newInvestment.totalInvestment - newInvestment.initialPayment).toLocaleString()}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Duration (Months)</label>
|
||||
<input type="number" value={selectedTemplate.duration} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100 cursor-not-allowed" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Lock-in Period (Months)</label>
|
||||
<input type="number" value={3} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100 cursor-not-allowed" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Exit Penalty (%)</label>
|
||||
<input type="number" value={10} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100 cursor-not-allowed" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-amber-50 border border-amber-200 rounded-xl p-4">
|
||||
<h4 className="text-sm font-semibold text-amber-800 mb-3 flex items-center gap-2">
|
||||
<TrendingUp className="w-4 h-4" /> FICO Share - Profit per Ride
|
||||
</h4>
|
||||
<p className="text-xs text-amber-600 mb-3">Profit sharing when bikes are rented to end customers</p>
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500 mb-1 block">Single Rent (%)</label>
|
||||
<input type="number" value={45} disabled className="w-full px-3 py-2 border border-amber-200 rounded-lg text-sm bg-white cursor-not-allowed" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500 mb-1 block">Rent to Own (%)</label>
|
||||
<input type="number" value={55} disabled className="w-full px-3 py-2 border border-amber-200 rounded-lg text-sm bg-white cursor-not-allowed" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500 mb-1 block">Share EV (%)</label>
|
||||
<input type="number" value={60} disabled className="w-full px-3 py-2 border border-amber-200 rounded-lg text-sm bg-white cursor-not-allowed" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Start Date *</label>
|
||||
<input type="date" value={newInvestment.startDate} onChange={(e) => setNewInvestment({ ...newInvestment, startDate: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">End Date</label>
|
||||
<input type="date" value={newInvestment.endDate} onChange={(e) => setNewInvestment({ ...newInvestment, endDate: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Payment Method</label>
|
||||
<select value={newInvestment.paymentMethod} onChange={(e) => setNewInvestment({ ...newInvestment, paymentMethod: e.target.value as any })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-white">
|
||||
<option value="bank">Bank Transfer</option>
|
||||
<option value="mobile">Mobile Banking</option>
|
||||
<option value="cash">Cash</option>
|
||||
<option value="cheque">Cheque</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Transaction Reference</label>
|
||||
<input type="text" value={newInvestment.transactionReference} onChange={(e) => setNewInvestment({ ...newInvestment, transactionReference: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Auto-generated if empty" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="text-sm font-medium text-slate-600 mb-1 block">Description</label>
|
||||
<textarea value={newInvestment.notes} onChange={(e) => setNewInvestment({ ...newInvestment, notes: e.target.value })} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" rows={2} placeholder="Add notes..." />
|
||||
</div>
|
||||
|
||||
<div className="bg-green-50 border border-green-200 rounded-xl p-4">
|
||||
<h4 className="font-semibold text-green-800 mb-3 flex items-center gap-2">
|
||||
<TrendingUp className="w-4 h-4" /> Auto-Journal Entry
|
||||
</h4>
|
||||
<div className="bg-white rounded-lg p-4 border border-green-100">
|
||||
<div className="flex items-center justify-between text-sm mb-2">
|
||||
<span className="text-slate-500">Date:</span>
|
||||
<span className="font-medium">{newInvestment.startDate || 'Not set'}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-sm mb-3">
|
||||
<span className="text-slate-500">Reference:</span>
|
||||
<span className="font-medium">{newInvestment.transactionReference || `INV/${new Date().getFullYear()}/auto`}</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center justify-between p-3 bg-green-50 rounded-lg border border-green-200">
|
||||
<div>
|
||||
<p className="text-xs text-green-600 font-medium uppercase">Debit (Dr)</p>
|
||||
<p className="font-medium text-slate-800">{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.paymentType === 'partial' ? newInvestment.initialPayment.toLocaleString() : newInvestment.totalInvestment.toLocaleString()}</p>
|
||||
</div>
|
||||
<div className="flex justify-center">
|
||||
<div className="w-8 h-8 rounded-full bg-green-200 flex items-center justify-center">
|
||||
<span className="text-green-600">▼</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between p-3 bg-blue-50 rounded-lg border border-blue-200">
|
||||
<div>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="p-5 border-t border-slate-100 flex justify-end gap-3">
|
||||
<button onClick={() => setShowCreateModal(false)} className="px-4 py-2 border border-slate-200 text-slate-600 rounded-lg text-sm hover:bg-slate-50">Cancel</button>
|
||||
{selectedTemplate && (
|
||||
<button onClick={handleCreate} disabled={!newInvestment.planName || !newInvestment.totalInvestment} className="px-4 py-2 bg-investor text-white rounded-lg text-sm font-medium hover:bg-investor-dark disabled:opacity-50 flex items-center gap-2">
|
||||
<Plus className="w-4 h-4" /> Create Investment
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -345,16 +345,17 @@ export const investors: Investor[] = [
|
||||
gender: 'male',
|
||||
occupation: 'Business',
|
||||
nidNumber: '1234567890',
|
||||
tinNumber: '9876543210',
|
||||
bankName: 'Islami Bank Bangladesh Ltd',
|
||||
bankAccountName: 'Hasan Mahmud',
|
||||
bankAccountNumber: '2050 1500 2345',
|
||||
bankAccountNumber: '205015002345',
|
||||
bankBranch: 'Dhanmondi Branch',
|
||||
bankRouting: '140',
|
||||
bankAccounts: [
|
||||
{ id: 'ba1', bankName: 'Islami Bank Bangladesh Ltd', accountName: 'Hasan Mahmud', accountNumber: '205015002345', branch: 'Dhanmondi Branch', routing: '140', isPrimary: true },
|
||||
{ id: 'ba2', bankName: 'Dutch-Bangla Bank', accountName: 'Hasan Mahmud', accountNumber: '1203456789012', branch: 'Gulshan Branch', routing: '090', isPrimary: false },
|
||||
],
|
||||
mobileBanking: 'Bkash',
|
||||
mobileBanking: 'bKash',
|
||||
mobileBankingNumber: '01712345678',
|
||||
additionalMobileBanking: [
|
||||
{ provider: 'Nagad', number: '01712345679', verified: true }
|
||||
|
||||
Reference in New Issue
Block a user