feat: implement editable profile sections and update layout in investor details page

This commit is contained in:
sazzadulalambd
2026-05-14 13:54:02 +06:00
parent 92554c177c
commit 456e7200fc
4 changed files with 2320 additions and 293 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -30,10 +30,6 @@ interface InvestmentSettingsProps {
setNewInvestLock: (n: number) => void; setNewInvestLock: (n: number) => void;
newInvestPenalty: number; newInvestPenalty: number;
setNewInvestPenalty: (n: number) => void; setNewInvestPenalty: (n: number) => void;
newInvestMonthly: number;
setNewInvestMonthly: (n: number) => void;
newInvestTotal: number;
setNewInvestTotal: (n: number) => void;
newInvestFicoSingleRent: number; newInvestFicoSingleRent: number;
setNewInvestFicoSingleRent: (n: number) => void; setNewInvestFicoSingleRent: (n: number) => void;
newInvestFicoRentToOwn: number; newInvestFicoRentToOwn: number;
@@ -42,6 +38,10 @@ interface InvestmentSettingsProps {
setNewInvestFicoShareEv: (n: number) => void; setNewInvestFicoShareEv: (n: number) => void;
newInvestDesc: string; newInvestDesc: string;
setNewInvestDesc: (v: string) => void; setNewInvestDesc: (v: string) => void;
newInvestEvBasePrice: number;
setNewInvestEvBasePrice: (n: number) => void;
newInvestMinQuantity: number;
setNewInvestMinQuantity: (n: number) => void;
createInvestPlan: () => void; createInvestPlan: () => void;
handleSave: () => void; handleSave: () => void;
} }
@@ -60,14 +60,15 @@ export default function InvestmentSettings({
newInvestDuration, setNewInvestDuration, newInvestDuration, setNewInvestDuration,
newInvestLock, setNewInvestLock, newInvestLock, setNewInvestLock,
newInvestPenalty, setNewInvestPenalty, newInvestPenalty, setNewInvestPenalty,
newInvestMonthly, setNewInvestMonthly,
newInvestTotal, setNewInvestTotal,
newInvestFicoSingleRent, setNewInvestFicoSingleRent, newInvestFicoSingleRent, setNewInvestFicoSingleRent,
newInvestFicoRentToOwn, setNewInvestFicoRentToOwn, newInvestFicoRentToOwn, setNewInvestFicoRentToOwn,
newInvestFicoShareEv, setNewInvestFicoShareEv, newInvestFicoShareEv, setNewInvestFicoShareEv,
newInvestDesc, setNewInvestDesc, newInvestDesc, setNewInvestDesc,
newInvestEvBasePrice, setNewInvestEvBasePrice,
newInvestMinQuantity, setNewInvestMinQuantity,
createInvestPlan, handleSave, createInvestPlan, handleSave,
}: InvestmentSettingsProps) { }: InvestmentSettingsProps) {
const calculatedMinInvestment = newInvestMinQuantity * newInvestEvBasePrice;
return ( return (
<div className="p-6 space-y-6"> <div className="p-6 space-y-6">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@@ -121,9 +122,20 @@ export default function InvestmentSettings({
<label className="text-sm text-slate-600">End Date</label> <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" /> <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>
<div>
<label className="text-sm text-slate-600">EV Base Price ()</label>
<input type="number" value={newInvestEvBasePrice} onChange={(e) => setNewInvestEvBasePrice(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="Single EV cost" />
</div>
<div>
<label className="text-sm text-slate-600">Minimum Quantity (Bikes)</label>
<input type="number" value={newInvestMinQuantity} onChange={(e) => setNewInvestMinQuantity(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="Min bikes to invest" />
</div>
<div> <div>
<label className="text-sm text-slate-600">Min Investment ()</label> <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 className="flex items-center gap-2 mt-1">
<input type="number" value={calculatedMinInvestment} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100" />
<span className="text-xs text-slate-500 whitespace-nowrap">= Qty × Base Price</span>
</div>
</div> </div>
<div> <div>
<label className="text-sm text-slate-600">Max Investment ()</label> <label className="text-sm text-slate-600">Max Investment ()</label>
@@ -141,14 +153,6 @@ export default function InvestmentSettings({
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label> <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" /> <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>
<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">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> </div>
<div className="grid grid-cols-3 gap-4 mt-4"> <div className="grid grid-cols-3 gap-4 mt-4">
<div> <div>
@@ -183,7 +187,7 @@ export default function InvestmentSettings({
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden"> <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 className="bg-amber-50 px-4 py-3 border-b border-amber-100 flex items-center justify-between">
<div> <div>
<h4 className="font-semibold text-amber-800">{plan.name} - {plan.monthlyReturnPercent}% per month</h4> <h4 className="font-semibold text-amber-800">{plan.name}</h4>
<p className="text-sm text-amber-600 mt-1">{plan.description}</p> <p className="text-sm text-amber-600 mt-1">{plan.description}</p>
</div> </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> <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>
@@ -214,9 +218,20 @@ export default function InvestmentSettings({
<label className="text-sm text-slate-600">End Date</label> <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" /> <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>
<div>
<label className="text-sm text-slate-600">EV Base Price ()</label>
<input type="number" value={plan.evBasePrice} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].evBasePrice = 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">Minimum Quantity (Bikes)</label>
<input type="number" value={plan.minQuantity} onChange={(e) => { const updated = [...settings.plans.investment]; updated[idx].minQuantity = 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>
<label className="text-sm text-slate-600">Min Investment ()</label> <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 className="flex items-center gap-2 mt-1">
<input type="number" value={plan.evBasePrice * plan.minQuantity} disabled className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm bg-slate-100" />
<span className="text-xs text-slate-500 whitespace-nowrap">= Qty × Base Price</span>
</div>
</div> </div>
<div> <div>
<label className="text-sm text-slate-600">Max Investment ()</label> <label className="text-sm text-slate-600">Max Investment ()</label>
@@ -234,14 +249,6 @@ export default function InvestmentSettings({
<label className="text-sm text-slate-600">Early Exit Penalty (%)</label> <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" /> <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>
<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">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> </div>
<div className="grid grid-cols-3 gap-4 mt-4"> <div className="grid grid-cols-3 gap-4 mt-4">
<div> <div>

View File

@@ -184,13 +184,13 @@ export interface CompanySettings {
id: string; id: string;
tier: string; tier: string;
name: string; name: string;
minQuantity: number;
evBasePrice: number;
minInvestment: number; minInvestment: number;
maxInvestment: number; maxInvestment: number;
monthlyReturnPercent: number;
durationMonths: number; durationMonths: number;
profitSharePercent: number; profitSharePercent: number;
lockInMonths: number; lockInMonths: number;
totalReturnPercent: number;
earlyExitPenalty: number; earlyExitPenalty: number;
startDate: string; startDate: string;
endDate: string; endDate: string;
@@ -695,13 +695,13 @@ const initialSettings: CompanySettings = {
id: 'inv_demo_1', id: 'inv_demo_1',
name: '1 Bike Plan', name: '1 Bike Plan',
tier: 'Economy', tier: 'Economy',
minInvestment: 50000, minQuantity: 1,
maxInvestment: 100000, evBasePrice: 200000,
monthlyReturnPercent: 2, minInvestment: 200000,
maxInvestment: 1000000,
durationMonths: 12, durationMonths: 12,
profitSharePercent: 50, profitSharePercent: 50,
lockInMonths: 3, lockInMonths: 3,
totalReturnPercent: 24,
earlyExitPenalty: 10, earlyExitPenalty: 10,
startDate: '2026-01-01', startDate: '2026-01-01',
endDate: '2026-12-31', endDate: '2026-12-31',
@@ -716,13 +716,13 @@ const initialSettings: CompanySettings = {
id: 'inv_demo_2', id: 'inv_demo_2',
name: '5 Bike Plan', name: '5 Bike Plan',
tier: 'Standard', tier: 'Standard',
minInvestment: 150000, minQuantity: 5,
maxInvestment: 500000, evBasePrice: 180000,
monthlyReturnPercent: 2.5, minInvestment: 900000,
maxInvestment: 5000000,
durationMonths: 24, durationMonths: 24,
profitSharePercent: 50, profitSharePercent: 50,
lockInMonths: 6, lockInMonths: 6,
totalReturnPercent: 60,
earlyExitPenalty: 10, earlyExitPenalty: 10,
startDate: '2026-01-01', startDate: '2026-01-01',
endDate: '2026-12-31', endDate: '2026-12-31',
@@ -846,16 +846,16 @@ export default function CompanySettingsPage() {
const [newInvestEnd, setNewInvestEnd] = useState('2026-12-31'); const [newInvestEnd, setNewInvestEnd] = useState('2026-12-31');
const [newInvestMin, setNewInvestMin] = useState(10000); const [newInvestMin, setNewInvestMin] = useState(10000);
const [newInvestMax, setNewInvestMax] = useState(100000); const [newInvestMax, setNewInvestMax] = useState(100000);
const [newInvestMonthly, setNewInvestMonthly] = useState(2);
const [newInvestDuration, setNewInvestDuration] = useState(12); const [newInvestDuration, setNewInvestDuration] = useState(12);
const [newInvestLock, setNewInvestLock] = useState(3); const [newInvestLock, setNewInvestLock] = useState(3);
const [newInvestTotal, setNewInvestTotal] = useState(24);
const [newInvestPenalty, setNewInvestPenalty] = useState(10); const [newInvestPenalty, setNewInvestPenalty] = useState(10);
const [newInvestProfitShare, setNewInvestProfitShare] = useState(50); const [newInvestProfitShare, setNewInvestProfitShare] = useState(50);
const [newInvestFicoSingleRent, setNewInvestFicoSingleRent] = useState(45); const [newInvestFicoSingleRent, setNewInvestFicoSingleRent] = useState(45);
const [newInvestFicoRentToOwn, setNewInvestFicoRentToOwn] = useState(55); const [newInvestFicoRentToOwn, setNewInvestFicoRentToOwn] = useState(55);
const [newInvestFicoShareEv, setNewInvestFicoShareEv] = useState(60); const [newInvestFicoShareEv, setNewInvestFicoShareEv] = useState(60);
const [newInvestDesc, setNewInvestDesc] = useState(''); const [newInvestDesc, setNewInvestDesc] = useState('');
const [newInvestEvBasePrice, setNewInvestEvBasePrice] = useState(200000);
const [newInvestMinQuantity, setNewInvestMinQuantity] = useState(1);
const createInvestPlan = () => { const createInvestPlan = () => {
if (newInvestName.trim() && typeof window !== 'undefined') { if (newInvestName.trim() && typeof window !== 'undefined') {
@@ -863,13 +863,13 @@ export default function CompanySettingsPage() {
id: 'inv_' + Date.now(), id: 'inv_' + Date.now(),
name: newInvestName, name: newInvestName,
tier: newInvestTier, tier: newInvestTier,
minInvestment: newInvestMin, evBasePrice: newInvestEvBasePrice,
minQuantity: newInvestMinQuantity,
minInvestment: newInvestEvBasePrice * newInvestMinQuantity,
maxInvestment: newInvestMax, maxInvestment: newInvestMax,
monthlyReturnPercent: newInvestMonthly,
durationMonths: newInvestDuration, durationMonths: newInvestDuration,
profitSharePercent: newInvestProfitShare, profitSharePercent: newInvestProfitShare,
lockInMonths: newInvestLock, lockInMonths: newInvestLock,
totalReturnPercent: newInvestTotal,
earlyExitPenalty: newInvestPenalty, earlyExitPenalty: newInvestPenalty,
startDate: newInvestStart, startDate: newInvestStart,
endDate: newInvestEnd, endDate: newInvestEnd,
@@ -1306,12 +1306,12 @@ export default function CompanySettingsPage() {
newInvestDuration={newInvestDuration} setNewInvestDuration={setNewInvestDuration} newInvestDuration={newInvestDuration} setNewInvestDuration={setNewInvestDuration}
newInvestLock={newInvestLock} setNewInvestLock={setNewInvestLock} newInvestLock={newInvestLock} setNewInvestLock={setNewInvestLock}
newInvestPenalty={newInvestPenalty} setNewInvestPenalty={setNewInvestPenalty} newInvestPenalty={newInvestPenalty} setNewInvestPenalty={setNewInvestPenalty}
newInvestMonthly={newInvestMonthly} setNewInvestMonthly={setNewInvestMonthly}
newInvestTotal={newInvestTotal} setNewInvestTotal={setNewInvestTotal}
newInvestFicoSingleRent={newInvestFicoSingleRent} setNewInvestFicoSingleRent={setNewInvestFicoSingleRent} newInvestFicoSingleRent={newInvestFicoSingleRent} setNewInvestFicoSingleRent={setNewInvestFicoSingleRent}
newInvestFicoRentToOwn={newInvestFicoRentToOwn} setNewInvestFicoRentToOwn={setNewInvestFicoRentToOwn} newInvestFicoRentToOwn={newInvestFicoRentToOwn} setNewInvestFicoRentToOwn={setNewInvestFicoRentToOwn}
newInvestFicoShareEv={newInvestFicoShareEv} setNewInvestFicoShareEv={setNewInvestFicoShareEv} newInvestFicoShareEv={newInvestFicoShareEv} setNewInvestFicoShareEv={setNewInvestFicoShareEv}
newInvestDesc={newInvestDesc} setNewInvestDesc={setNewInvestDesc} newInvestDesc={newInvestDesc} setNewInvestDesc={setNewInvestDesc}
newInvestEvBasePrice={newInvestEvBasePrice} setNewInvestEvBasePrice={setNewInvestEvBasePrice}
newInvestMinQuantity={newInvestMinQuantity} setNewInvestMinQuantity={setNewInvestMinQuantity}
createInvestPlan={createInvestPlan} handleSave={handleSave} createInvestPlan={createInvestPlan} handleSave={handleSave}
/> />
)} )}