feat: add investment plan management section to company settings

This commit is contained in:
sazzadulalambd
2026-05-05 21:48:18 +06:00
parent da0df6db3e
commit 928350b478

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import { useState } from 'react'; import { useState } from 'react';
import { Settings, Upload, Image, Globe, Mail, MessageSquare, Phone, MapPin, Link2, Clock, Save, FileText, Camera, Palette, Ruler, Sun, Moon, Monitor, Smartphone, Tablet, Package, Wrench, FileCheck, BadgeDollarSign, CreditCard } from 'lucide-react'; import { Settings, Upload, Image, Globe, Mail, MessageSquare, Phone, MapPin, Link2, Clock, Save, FileText, Camera, Palette, Ruler, Sun, Moon, Monitor, Smartphone, Tablet, Package, Wrench, FileCheck, BadgeDollarSign, CreditCard, Plus, X, DollarSign } from 'lucide-react';
interface CompanySettings { interface CompanySettings {
name: string; name: string;
@@ -120,6 +120,24 @@ interface CompanySettings {
ficoSharePercent: number; ficoSharePercent: number;
description: string; description: string;
}[]; }[];
investment: {
id: string;
tier: string;
name: string;
minInvestment: number;
maxInvestment: number;
monthlyReturnPercent: number;
durationMonths: number;
profitSharePercent: number;
lockInMonths: number;
totalReturnPercent: number;
earlyExitPenalty: number;
startDate: string;
endDate: string;
targetAmount: number;
status: string;
description: string;
}[];
}; };
} }
@@ -439,18 +457,101 @@ const initialSettings: CompanySettings = {
description: 'Economy shared EV plan', description: 'Economy shared EV plan',
} }
], ],
investment: [
{
id: 'inv_demo_1',
name: '1 Bike Plan',
tier: 'Economy',
minInvestment: 50000,
maxInvestment: 100000,
monthlyReturnPercent: 2,
durationMonths: 12,
profitSharePercent: 50,
lockInMonths: 3,
totalReturnPercent: 24,
earlyExitPenalty: 10,
startDate: '2026-01-01',
endDate: '2026-12-31',
targetAmount: 1000000,
status: 'active',
description: 'Investment plan for 1 bike - perfect for small investors',
},
{
id: 'inv_demo_2',
name: '5 Bike Plan',
tier: 'Standard',
minInvestment: 150000,
maxInvestment: 500000,
monthlyReturnPercent: 2.5,
durationMonths: 24,
profitSharePercent: 50,
lockInMonths: 6,
totalReturnPercent: 60,
earlyExitPenalty: 10,
startDate: '2026-01-01',
endDate: '2026-12-31',
targetAmount: 5000000,
status: 'active',
description: 'Investment plan for 5 bikes - medium scale investment',
}
],
}, },
}; };
export default function CompanySettingsPage() { export default function CompanySettingsPage() {
const [settings, setSettings] = useState<CompanySettings>(initialSettings); const [settings, setSettings] = useState<CompanySettings>(initialSettings);
const [activeTab, setActiveTab] = useState<'general' | 'branding' | 'social' | 'integration' | 'landing' | 'kyc' | 'parts' | 'rental' | 'plans'>('general'); const [activeTab, setActiveTab] = useState<'general' | 'branding' | 'social' | 'integration' | 'landing' | 'kyc' | 'parts' | 'rental' | 'plans' | 'investment'>('general');
const [activeMasterTab, setActiveMasterTab] = useState<'investor' | 'merchant' | 'swapstation' | 'rental'>('investor'); const [activeMasterTab, setActiveMasterTab] = useState<'investor' | 'merchant' | 'swapstation' | 'rental'>('investor');
const [saved, setSaved] = useState(false); const [saved, setSaved] = useState(false);
const [activePlanTab, setActivePlanTab] = useState<'singleRent' | 'rentToOwn' | 'shareEv'>('singleRent'); const [activePlanTab, setActivePlanTab] = useState<'singleRent' | 'rentToOwn' | 'shareEv'>('singleRent');
const [addDocType, setAddDocType] = useState<'investor' | 'merchant' | 'swapstation' | 'rental' | null>(null); const [addDocType, setAddDocType] = useState<'investor' | 'merchant' | 'swapstation' | 'rental' | null>(null);
const [newDocName, setNewDocName] = useState(''); const [newDocName, setNewDocName] = useState('');
const [newDocDesc, setNewDocDesc] = useState(''); const [newDocDesc, setNewDocDesc] = useState('');
const [activeInvestTab, setActiveInvestTab] = useState(0);
const [addInvestPlan, setAddInvestPlan] = useState(false);
const [newInvestName, setNewInvestName] = useState('');
const [newInvestTier, setNewInvestTier] = useState('Standard');
const [newInvestStatus, setNewInvestStatus] = useState('active');
const [newInvestTarget, setNewInvestTarget] = useState(1000000);
const [newInvestStart, setNewInvestStart] = useState('2026-01-01');
const [newInvestEnd, setNewInvestEnd] = useState('2026-12-31');
const [newInvestMin, setNewInvestMin] = useState(10000);
const [newInvestMax, setNewInvestMax] = useState(100000);
const [newInvestMonthly, setNewInvestMonthly] = useState(2);
const [newInvestDuration, setNewInvestDuration] = useState(12);
const [newInvestLock, setNewInvestLock] = useState(3);
const [newInvestTotal, setNewInvestTotal] = useState(24);
const [newInvestPenalty, setNewInvestPenalty] = useState(10);
const [newInvestDesc, setNewInvestDesc] = useState('');
const createInvestPlan = () => {
if (newInvestName.trim() && typeof window !== 'undefined') {
const ficoShare = settings.plans.singleRent[0]?.ficoSharePercent || 50;
const newPlan = {
id: 'inv_' + Date.now(),
name: newInvestName,
tier: newInvestTier,
minInvestment: newInvestMin,
maxInvestment: newInvestMax,
monthlyReturnPercent: newInvestMonthly,
durationMonths: newInvestDuration,
profitSharePercent: ficoShare,
lockInMonths: newInvestLock,
totalReturnPercent: newInvestTotal,
earlyExitPenalty: newInvestPenalty,
startDate: newInvestStart,
endDate: newInvestEnd,
targetAmount: newInvestTarget,
status: newInvestStatus,
description: newInvestDesc
};
const updatedPlans = [...settings.plans.investment, newPlan];
setSettings({ ...settings, plans: { ...settings.plans, investment: updatedPlans } });
setActiveInvestTab(updatedPlans.length - 1);
setAddInvestPlan(false);
setNewInvestName('');
}
};
const handleSave = () => { const handleSave = () => {
setSaved(true); setSaved(true);
@@ -467,6 +568,7 @@ export default function CompanySettingsPage() {
{ id: 'parts', label: 'EV Parts', icon: Package }, { id: 'parts', label: 'EV Parts', icon: Package },
{ id: 'rental', label: 'Rental Policy', icon: FileCheck }, { id: 'rental', label: 'Rental Policy', icon: FileCheck },
{ id: 'plans', label: 'Plan Selection', icon: Package }, { id: 'plans', label: 'Plan Selection', icon: Package },
{ id: 'investment', label: 'Investment Plan', icon: DollarSign },
]; ];
return ( return (
@@ -476,12 +578,12 @@ export default function CompanySettingsPage() {
<h1 className="text-2xl lg:text-3xl font-extrabold text-slate-800">Company Settings</h1> <h1 className="text-2xl lg:text-3xl font-extrabold text-slate-800">Company Settings</h1>
<p className="text-sm text-slate-500 mt-1">Manage your company information and configurations</p> <p className="text-sm text-slate-500 mt-1">Manage your company information and configurations</p>
</div> </div>
<button {/* <button
onClick={handleSave} onClick={handleSave}
className="py-2.5 px-4 bg-accent text-white rounded-lg font-semibold text-sm hover:bg-accent-dark transition-colors flex items-center gap-2" className="py-2.5 px-4 bg-accent text-white rounded-lg font-semibold text-sm hover:bg-accent-dark transition-colors flex items-center gap-2"
> >
<Save className="w-4 h-4" /> Save Changes <Save className="w-4 h-4" /> Save Changes
</button> </button> */}
</div> </div>
{saved && ( {saved && (
@@ -1772,6 +1874,194 @@ export default function CompanySettingsPage() {
)} )}
</div> </div>
)} )}
{(activeTab as string) === 'investment' && (
<div className="p-6 space-y-6">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-slate-800">Investment Plans</h3>
</div>
<div className="flex items-center justify-between bg-amber-50 border border-amber-200 rounded-xl p-4">
<div>
<h4 className="font-semibold text-amber-800">Investment Plans ({settings.plans.investment.length})</h4>
<p className="text-sm text-amber-600">Manage investment plans for investors</p>
</div>
<button onClick={() => { setAddInvestPlan(true); setNewInvestName(''); }} className="px-4 py-2 bg-amber-600 text-white rounded-lg text-sm font-medium flex items-center gap-2">
<Plus className="w-4 h-4" /> New Plan
</button>
</div>
{addInvestPlan && (
<div className="bg-white rounded-xl border border-amber-300 overflow-hidden">
<div className="bg-amber-100 px-4 py-3 border-b border-amber-200 flex items-center justify-between">
<div>
<h4 className="font-semibold text-amber-800">New Investment Plan</h4>
<p className="text-sm text-amber-600 mt-1">Fill in the details below</p>
</div>
<button onClick={() => setAddInvestPlan(false)} className="text-amber-600 hover:text-amber-800">
<X className="w-5 h-5" />
</button>
</div>
<div className="p-4">
<div className="grid lg:grid-cols-3 gap-4">
<div>
<label className="text-sm text-slate-600">Plan Name</label>
<input type="text" value={newInvestName} onChange={(e) => setNewInvestName(e.target.value)} placeholder="e.g., 1 Bike Plan" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Status</label>
<select value={newInvestStatus} onChange={(e) => setNewInvestStatus(e.target.value)} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1">
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="closed">Closed</option>
</select>
</div>
<div>
<label className="text-sm text-slate-600">Target Amount ()</label>
<input type="number" value={newInvestTarget} onChange={(e) => setNewInvestTarget(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Start Date</label>
<input type="date" value={newInvestStart} onChange={(e) => setNewInvestStart(e.target.value)} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">End Date</label>
<input type="date" value={newInvestEnd} onChange={(e) => setNewInvestEnd(e.target.value)} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Min Investment ()</label>
<input type="number" value={newInvestMin} onChange={(e) => setNewInvestMin(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Max Investment ()</label>
<input type="number" value={newInvestMax} onChange={(e) => setNewInvestMax(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Monthly Return (%)</label>
<input type="number" step="0.1" value={newInvestMonthly} onChange={(e) => setNewInvestMonthly(parseFloat(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Duration (Months)</label>
<input type="number" value={newInvestDuration} onChange={(e) => setNewInvestDuration(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Lock-in Period (Months)</label>
<input type="number" value={newInvestLock} onChange={(e) => setNewInvestLock(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Total Return (%)</label>
<input type="number" step="0.1" value={newInvestTotal} onChange={(e) => setNewInvestTotal(parseFloat(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label>
<input type="number" value={newInvestPenalty} onChange={(e) => setNewInvestPenalty(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
</div>
<div className="mt-4 p-3 bg-slate-50 rounded-lg">
<div className="flex items-center justify-between text-sm">
<span className="text-slate-600">Profit from Plan Selection (FICO Share):</span>
<span className="font-semibold text-green-600">{settings.plans.singleRent[0]?.ficoSharePercent || 50}%</span>
</div>
</div>
<div className="mt-4">
<label className="text-sm text-slate-600">Description</label>
<textarea value={newInvestDesc} onChange={(e) => setNewInvestDesc(e.target.value)} placeholder="Enter plan description" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" rows={2} />
</div>
<button onClick={createInvestPlan} className="mt-4 px-4 py-2 bg-amber-600 text-white rounded-lg text-sm font-medium">Create Plan</button>
</div>
</div>
)}
<div className="flex gap-2 border-b border-slate-200">
{settings.plans.investment.map((plan, idx) => (
<button key={idx} onClick={() => setActiveInvestTab(idx)} className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${activeInvestTab === idx ? 'border-amber-500 text-amber-600' : 'border-transparent text-slate-500 hover:text-slate-700'}`}> {plan.name}</button>
))}
</div>
{settings.plans.investment.length > 0 && settings.plans.investment.map((plan, idx) => idx === activeInvestTab && (
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
<div className="bg-amber-50 px-4 py-3 border-b border-amber-100 flex items-center justify-between">
<div>
<h4 className="font-semibold text-amber-800">{plan.name} - {plan.monthlyReturnPercent}% per month</h4>
<p className="text-sm text-amber-600 mt-1">{plan.description}</p>
</div>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${plan.status === 'active' ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>{plan.status}</span>
</div>
<div className="p-4">
<div className="grid lg:grid-cols-3 gap-4">
<div>
<label className="text-sm text-slate-600">Plan Name</label>
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Status</label>
<select value={plan.status} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].status = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1">
<option value="active">Active</option>
<option value="paused">Paused</option>
<option value="closed">Closed</option>
</select>
</div>
<div>
<label className="text-sm text-slate-600">Target Amount ()</label>
<input type="number" value={plan.targetAmount} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].targetAmount = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Start Date</label>
<input type="date" value={plan.startDate} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].startDate = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">End Date</label>
<input type="date" value={plan.endDate} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].endDate = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Min Investment ()</label>
<input type="number" value={plan.minInvestment} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].minInvestment = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Max Investment ()</label>
<input type="number" value={plan.maxInvestment} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].maxInvestment = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Monthly Return (%)</label>
<input type="number" step="0.1" value={plan.monthlyReturnPercent} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].monthlyReturnPercent = parseFloat(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Duration (Months)</label>
<input type="number" value={plan.durationMonths} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].durationMonths = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Lock-in Period (Months)</label>
<input type="number" value={plan.lockInMonths} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].lockInMonths = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Total Return (%)</label>
<input type="number" step="0.1" value={plan.totalReturnPercent} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].totalReturnPercent = parseFloat(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
<div>
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label>
<input type="number" value={plan.earlyExitPenalty} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].earlyExitPenalty = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
</div>
</div>
<div className="mt-4 p-3 bg-slate-50 rounded-lg">
<div className="flex items-center justify-between text-sm">
<span className="text-slate-600">Profit from Plan Selection (FICO Share):</span>
<span className="font-semibold text-green-600">{settings.plans.singleRent[0]?.ficoSharePercent || 50}%</span>
</div>
</div>
<div className="mt-4">
<label className="text-sm text-slate-600">Description</label>
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, investment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" rows={2} />
</div>
<div className="mt-4 flex justify-end">
<button onClick={handleSave} className="px-4 py-2 bg-amber-600 text-white rounded-lg text-sm font-medium flex items-center gap-2">
<Save className="w-4 h-4" /> Save Changes
</button>
</div>
</div>
</div>
))}
</div>
)}
</div> </div>
</div> </div>