feat: implement battery investment settings tab and configuration component
This commit is contained in:
271
src/app/admin/settings/components/BatteryInvestmentSettings.tsx
Normal file
271
src/app/admin/settings/components/BatteryInvestmentSettings.tsx
Normal file
@@ -0,0 +1,271 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { Plus, X, Save, Battery } from 'lucide-react';
|
||||||
|
import type { CompanySettings } from '../page';
|
||||||
|
|
||||||
|
interface BatteryInvestmentSettingsProps {
|
||||||
|
settings: CompanySettings;
|
||||||
|
setSettings: React.Dispatch<React.SetStateAction<CompanySettings>>;
|
||||||
|
activeBatteryTab: number;
|
||||||
|
setActiveBatteryTab: (n: number) => void;
|
||||||
|
addBatteryPlan: boolean;
|
||||||
|
setAddBatteryPlan: (v: boolean) => void;
|
||||||
|
newBatteryName: string;
|
||||||
|
setNewBatteryName: (v: string) => void;
|
||||||
|
newBatteryStatus: string;
|
||||||
|
setNewBatteryStatus: (v: string) => void;
|
||||||
|
newBatteryTarget: number;
|
||||||
|
setNewBatteryTarget: (n: number) => void;
|
||||||
|
newBatteryStart: string;
|
||||||
|
setNewBatteryStart: (v: string) => void;
|
||||||
|
newBatteryEnd: string;
|
||||||
|
setNewBatteryEnd: (v: string) => void;
|
||||||
|
newBatteryMin: number;
|
||||||
|
setNewBatteryMin: (n: number) => void;
|
||||||
|
newBatteryMax: number;
|
||||||
|
setNewBatteryMax: (n: number) => void;
|
||||||
|
newBatteryDuration: number;
|
||||||
|
setNewBatteryDuration: (n: number) => void;
|
||||||
|
newBatteryLock: number;
|
||||||
|
setNewBatteryLock: (n: number) => void;
|
||||||
|
newBatteryPenalty: number;
|
||||||
|
setNewBatteryPenalty: (n: number) => void;
|
||||||
|
newBatteryProfitShare: number;
|
||||||
|
setNewBatteryProfitShare: (n: number) => void;
|
||||||
|
newBatteryDesc: string;
|
||||||
|
setNewBatteryDesc: (v: string) => void;
|
||||||
|
newBatteryBasePrice: number;
|
||||||
|
setNewBatteryBasePrice: (n: number) => void;
|
||||||
|
newBatteryMinQuantity: number;
|
||||||
|
setNewBatteryMinQuantity: (n: number) => void;
|
||||||
|
createBatteryPlan: () => void;
|
||||||
|
handleSave: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function BatteryInvestmentSettings({
|
||||||
|
settings, setSettings,
|
||||||
|
activeBatteryTab, setActiveBatteryTab,
|
||||||
|
addBatteryPlan, setAddBatteryPlan,
|
||||||
|
newBatteryName, setNewBatteryName,
|
||||||
|
newBatteryStatus, setNewBatteryStatus,
|
||||||
|
newBatteryTarget, setNewBatteryTarget,
|
||||||
|
newBatteryStart, setNewBatteryStart,
|
||||||
|
newBatteryEnd, setNewBatteryEnd,
|
||||||
|
newBatteryMin, setNewBatteryMin,
|
||||||
|
newBatteryMax, setNewBatteryMax,
|
||||||
|
newBatteryDuration, setNewBatteryDuration,
|
||||||
|
newBatteryLock, setNewBatteryLock,
|
||||||
|
newBatteryPenalty, setNewBatteryPenalty,
|
||||||
|
newBatteryProfitShare, setNewBatteryProfitShare,
|
||||||
|
newBatteryDesc, setNewBatteryDesc,
|
||||||
|
newBatteryBasePrice, setNewBatteryBasePrice,
|
||||||
|
newBatteryMinQuantity, setNewBatteryMinQuantity,
|
||||||
|
createBatteryPlan, handleSave,
|
||||||
|
}: BatteryInvestmentSettingsProps) {
|
||||||
|
const calculatedMinInvestment = newBatteryMinQuantity * newBatteryBasePrice;
|
||||||
|
return (
|
||||||
|
<div className="p-6 space-y-6">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<h3 className="text-lg font-semibold text-slate-800 flex items-center gap-2">
|
||||||
|
<Battery className="w-5 h-5 text-emerald-600 animate-pulse" />
|
||||||
|
Battery Investment Plans
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex items-center justify-between bg-emerald-50 border border-emerald-200 rounded-xl p-4">
|
||||||
|
<div>
|
||||||
|
<h4 className="font-semibold text-emerald-800">Battery Investment Plans ({(settings.plans as any).batteryInvestment?.length || 0})</h4>
|
||||||
|
<p className="text-sm text-emerald-600">Manage high-yield battery pack investment plans for partners</p>
|
||||||
|
</div>
|
||||||
|
<button onClick={() => { setAddBatteryPlan(true); setNewBatteryName(''); }} className="px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm font-medium flex items-center gap-2 hover:bg-emerald-700 transition-colors">
|
||||||
|
<Plus className="w-4 h-4" /> New Plan
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{addBatteryPlan && (
|
||||||
|
<div className="bg-white rounded-xl border border-emerald-300 overflow-hidden shadow-sm">
|
||||||
|
<div className="bg-emerald-50 px-4 py-3 border-b border-emerald-100 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h4 className="font-semibold text-emerald-800">New Battery Investment Plan</h4>
|
||||||
|
<p className="text-sm text-emerald-600 mt-1">Configure high-yield battery fleet assets</p>
|
||||||
|
</div>
|
||||||
|
<button onClick={() => setAddBatteryPlan(false)} className="text-emerald-600 hover:text-emerald-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={newBatteryName} onChange={(e) => setNewBatteryName(e.target.value)} placeholder="e.g., Standard Battery 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={newBatteryStatus} onChange={(e) => setNewBatteryStatus(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={newBatteryTarget} onChange={(e) => setNewBatteryTarget(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={newBatteryStart} onChange={(e) => setNewBatteryStart(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={newBatteryEnd} onChange={(e) => setNewBatteryEnd(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">Battery Base Price (৳)</label>
|
||||||
|
<input type="number" value={newBatteryBasePrice} onChange={(e) => setNewBatteryBasePrice(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="Single battery unit cost" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600">Minimum Quantity (Packs)</label>
|
||||||
|
<input type="number" value={newBatteryMinQuantity} onChange={(e) => setNewBatteryMinQuantity(parseInt(e.target.value))} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" placeholder="Min battery packs to invest" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600">Min Investment (৳)</label>
|
||||||
|
<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>
|
||||||
|
<label className="text-sm text-slate-600">Max Investment (৳)</label>
|
||||||
|
<input type="number" value={newBatteryMax} onChange={(e) => setNewBatteryMax(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">Duration (Months)</label>
|
||||||
|
<input type="number" value={newBatteryDuration} onChange={(e) => setNewBatteryDuration(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={newBatteryLock} onChange={(e) => setNewBatteryLock(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">Early Exit Penalty (%)</label>
|
||||||
|
<input type="number" value={newBatteryPenalty} onChange={(e) => setNewBatteryPenalty(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">Profit Share Percent (%)</label>
|
||||||
|
<input type="number" value={newBatteryProfitShare} onChange={(e) => setNewBatteryProfitShare(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">
|
||||||
|
<label className="text-sm text-slate-600">Description</label>
|
||||||
|
<textarea value={newBatteryDesc} onChange={(e) => setNewBatteryDesc(e.target.value)} placeholder="Enter battery investment plan description" className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" rows={2} />
|
||||||
|
</div>
|
||||||
|
<button onClick={createBatteryPlan} className="mt-4 px-4 py-2 bg-emerald-600 text-white rounded-lg text-sm font-medium hover:bg-emerald-700 transition-colors">Create Plan</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div className="flex gap-2 border-b border-slate-200">
|
||||||
|
{((settings.plans as any).batteryInvestment || []).map((plan: any, idx: number) => (
|
||||||
|
<button key={idx} onClick={() => setActiveBatteryTab(idx)} className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${activeBatteryTab === idx ? 'border-emerald-500 text-emerald-600 font-bold' : 'border-transparent text-slate-500 hover:text-slate-700'}`}> {plan.name}</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{((settings.plans as any).batteryInvestment || []).length > 0 && ((settings.plans as any).batteryInvestment || []).map((plan: any, idx: number) => idx === activeBatteryTab && (
|
||||||
|
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden shadow-sm">
|
||||||
|
<div className="bg-emerald-50/50 px-4 py-3 border-b border-emerald-100 flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<h4 className="font-semibold text-emerald-800">{plan.name}</h4>
|
||||||
|
<p className="text-sm text-emerald-600 mt-1">{plan.description}</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<span className={`px-2.5 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>
|
||||||
|
<button
|
||||||
|
onClick={() => {
|
||||||
|
const updated = ((settings.plans as any).batteryInvestment || []).filter((_: any, i: number) => i !== idx);
|
||||||
|
setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: updated } });
|
||||||
|
setActiveBatteryTab(0);
|
||||||
|
}}
|
||||||
|
className="p-1.5 text-red-600 hover:bg-red-50 rounded-lg transition-colors"
|
||||||
|
title="Delete Plan"
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</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 as any).batteryInvestment || [])]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 as any).batteryInvestment || [])]; updated[idx].status = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 as any).batteryInvestment || [])]; updated[idx].targetAmount = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 as any).batteryInvestment || [])]; updated[idx].startDate = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 as any).batteryInvestment || [])]; updated[idx].endDate = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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">Battery Base Price (৳)</label>
|
||||||
|
<input type="number" value={plan.batteryBasePrice} onChange={(e) => { const updated = [...((settings.plans as any).batteryInvestment || [])]; updated[idx].batteryBasePrice = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 (Packs)</label>
|
||||||
|
<input type="number" value={plan.minQuantity} onChange={(e) => { const updated = [...((settings.plans as any).batteryInvestment || [])]; updated[idx].minQuantity = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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>
|
||||||
|
<div className="flex items-center gap-2 mt-1">
|
||||||
|
<input type="number" value={plan.batteryBasePrice * 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 × Price</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label className="text-sm text-slate-600">Max Investment (৳)</label>
|
||||||
|
<input type="number" value={plan.maxInvestment} onChange={(e) => { const updated = [...((settings.plans as any).batteryInvestment || [])]; updated[idx].maxInvestment = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 as any).batteryInvestment || [])]; updated[idx].durationMonths = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 as any).batteryInvestment || [])]; updated[idx].lockInMonths = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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 as any).batteryInvestment || [])]; updated[idx].earlyExitPenalty = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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">Profit Share Percent (%)</label>
|
||||||
|
<input type="number" value={plan.profitSharePercent} onChange={(e) => { const updated = [...((settings.plans as any).batteryInvestment || [])]; updated[idx].profitSharePercent = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||||
|
</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 as any).batteryInvestment || [])]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: 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-emerald-600 text-white rounded-lg text-sm font-medium flex items-center gap-2 hover:bg-emerald-700 transition-colors shadow-sm">
|
||||||
|
<Save className="w-4 h-4" /> Save Changes
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Settings, Package, Palette, Link2, Mail, Monitor, FileCheck, DollarSign, Zap, Users, Plus, X, Save, Pencil, Trash2, FileText } from 'lucide-react';
|
import { Settings, Package, Palette, Link2, Mail, Monitor, FileCheck, DollarSign, Zap, Users, Plus, X, Save, Pencil, Trash2, FileText, Battery } from 'lucide-react';
|
||||||
import RichTextEditor from '@/components/RichTextEditor';
|
import RichTextEditor from '@/components/RichTextEditor';
|
||||||
import GeneralSettings from './components/GeneralSettings';
|
import GeneralSettings from './components/GeneralSettings';
|
||||||
import BrandingSettings from './components/BrandingSettings';
|
import BrandingSettings from './components/BrandingSettings';
|
||||||
@@ -13,6 +13,7 @@ import PartsSettings from './components/PartsSettings';
|
|||||||
import CompanyPolicySettings from './components/CompanyPolicySettings';
|
import CompanyPolicySettings from './components/CompanyPolicySettings';
|
||||||
import PlanSelection from './components/PlanSelection';
|
import PlanSelection from './components/PlanSelection';
|
||||||
import InvestmentSettings from './components/InvestmentSettings';
|
import InvestmentSettings from './components/InvestmentSettings';
|
||||||
|
import BatteryInvestmentSettings from './components/BatteryInvestmentSettings';
|
||||||
import SwapStationSettings from './components/SwapStationSettings';
|
import SwapStationSettings from './components/SwapStationSettings';
|
||||||
import RiderRequestSettings from './components/RiderRequestSettings';
|
import RiderRequestSettings from './components/RiderRequestSettings';
|
||||||
import EmailSMSTemplates from './components/EmailSMSTemplates';
|
import EmailSMSTemplates from './components/EmailSMSTemplates';
|
||||||
@@ -201,6 +202,24 @@ export interface CompanySettings {
|
|||||||
ficoRentToOwn: number;
|
ficoRentToOwn: number;
|
||||||
ficoShareEv: number;
|
ficoShareEv: number;
|
||||||
}[];
|
}[];
|
||||||
|
batteryInvestment: {
|
||||||
|
id: string;
|
||||||
|
tier: string;
|
||||||
|
name: string;
|
||||||
|
minQuantity: number;
|
||||||
|
batteryBasePrice: number;
|
||||||
|
minInvestment: number;
|
||||||
|
maxInvestment: number;
|
||||||
|
durationMonths: number;
|
||||||
|
profitSharePercent: number;
|
||||||
|
lockInMonths: number;
|
||||||
|
earlyExitPenalty: number;
|
||||||
|
startDate: string;
|
||||||
|
endDate: string;
|
||||||
|
targetAmount: number;
|
||||||
|
status: string;
|
||||||
|
description: string;
|
||||||
|
}[];
|
||||||
swapStation: {
|
swapStation: {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -734,6 +753,44 @@ const initialSettings: CompanySettings = {
|
|||||||
ficoShareEv: 60,
|
ficoShareEv: 60,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
batteryInvestment: [
|
||||||
|
{
|
||||||
|
id: 'bat_inv_demo_1',
|
||||||
|
name: 'Standard Battery Plan',
|
||||||
|
tier: 'Economy',
|
||||||
|
minQuantity: 10,
|
||||||
|
batteryBasePrice: 15000,
|
||||||
|
minInvestment: 150000,
|
||||||
|
maxInvestment: 500000,
|
||||||
|
durationMonths: 12,
|
||||||
|
profitSharePercent: 40,
|
||||||
|
lockInMonths: 3,
|
||||||
|
earlyExitPenalty: 10,
|
||||||
|
startDate: '2026-01-01',
|
||||||
|
endDate: '2026-12-31',
|
||||||
|
targetAmount: 500000,
|
||||||
|
status: 'active',
|
||||||
|
description: 'Investment plan for 10 batteries - entry level battery investment',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'bat_inv_demo_2',
|
||||||
|
name: 'Premium Battery Plan',
|
||||||
|
tier: 'Premium',
|
||||||
|
minQuantity: 50,
|
||||||
|
batteryBasePrice: 15000,
|
||||||
|
minInvestment: 750000,
|
||||||
|
maxInvestment: 2000000,
|
||||||
|
durationMonths: 24,
|
||||||
|
profitSharePercent: 50,
|
||||||
|
lockInMonths: 6,
|
||||||
|
earlyExitPenalty: 15,
|
||||||
|
startDate: '2026-01-01',
|
||||||
|
endDate: '2026-12-31',
|
||||||
|
targetAmount: 2000000,
|
||||||
|
status: 'active',
|
||||||
|
description: 'Investment plan for 50 batteries - premium scale battery investment',
|
||||||
|
},
|
||||||
|
],
|
||||||
swapStation: [
|
swapStation: [
|
||||||
{
|
{
|
||||||
id: 'ss_1',
|
id: 'ss_1',
|
||||||
@@ -814,7 +871,7 @@ const initialSettings: CompanySettings = {
|
|||||||
|
|
||||||
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' | 'companyPolicy' | 'plans' | 'investment' | 'swapstation' | 'riderrequest' | 'templates'>('general');
|
const [activeTab, setActiveTab] = useState<'general' | 'branding' | 'social' | 'integration' | 'landing' | 'kyc' | 'parts' | 'companyPolicy' | 'plans' | 'investment' | 'batteryinvestment' | 'swapstation' | 'riderrequest' | 'templates'>('general');
|
||||||
const [activeMasterTab, setActiveMasterTab] = useState<'investor' | 'merchant' | 'swapstation' | 'rentalType'>('investor');
|
const [activeMasterTab, setActiveMasterTab] = useState<'investor' | 'merchant' | 'swapstation' | 'rentalType'>('investor');
|
||||||
const [activeRentalTypeTab, setActiveRentalTypeTab] = useState<'single' | 'shared' | 'renttoown'>('single');
|
const [activeRentalTypeTab, setActiveRentalTypeTab] = useState<'single' | 'shared' | 'renttoown'>('single');
|
||||||
const [saved, setSaved] = useState(false);
|
const [saved, setSaved] = useState(false);
|
||||||
@@ -837,6 +894,8 @@ export default function CompanySettingsPage() {
|
|||||||
const [newPolicyDesc, setNewPolicyDesc] = useState('');
|
const [newPolicyDesc, setNewPolicyDesc] = useState('');
|
||||||
const [newPolicyShowApp, setNewPolicyShowApp] = useState(true);
|
const [newPolicyShowApp, setNewPolicyShowApp] = useState(true);
|
||||||
const [newPolicyShowWeb, setNewPolicyShowWeb] = useState(true);
|
const [newPolicyShowWeb, setNewPolicyShowWeb] = useState(true);
|
||||||
|
|
||||||
|
// Bike Investment
|
||||||
const [addInvestPlan, setAddInvestPlan] = useState(false);
|
const [addInvestPlan, setAddInvestPlan] = useState(false);
|
||||||
const [newInvestName, setNewInvestName] = useState('');
|
const [newInvestName, setNewInvestName] = useState('');
|
||||||
const [newInvestTier, setNewInvestTier] = useState('Standard');
|
const [newInvestTier, setNewInvestTier] = useState('Standard');
|
||||||
@@ -857,6 +916,24 @@ export default function CompanySettingsPage() {
|
|||||||
const [newInvestEvBasePrice, setNewInvestEvBasePrice] = useState(200000);
|
const [newInvestEvBasePrice, setNewInvestEvBasePrice] = useState(200000);
|
||||||
const [newInvestMinQuantity, setNewInvestMinQuantity] = useState(1);
|
const [newInvestMinQuantity, setNewInvestMinQuantity] = useState(1);
|
||||||
|
|
||||||
|
// Battery Investment
|
||||||
|
const [activeBatteryTab, setActiveBatteryTab] = useState(0);
|
||||||
|
const [addBatteryPlan, setAddBatteryPlan] = useState(false);
|
||||||
|
const [newBatteryName, setNewBatteryName] = useState('');
|
||||||
|
const [newBatteryStatus, setNewBatteryStatus] = useState('active');
|
||||||
|
const [newBatteryTarget, setNewBatteryTarget] = useState(1000000);
|
||||||
|
const [newBatteryStart, setNewBatteryStart] = useState('2026-01-01');
|
||||||
|
const [newBatteryEnd, setNewBatteryEnd] = useState('2026-12-31');
|
||||||
|
const [newBatteryMin, setNewBatteryMin] = useState(150000);
|
||||||
|
const [newBatteryMax, setNewBatteryMax] = useState(500000);
|
||||||
|
const [newBatteryDuration, setNewBatteryDuration] = useState(12);
|
||||||
|
const [newBatteryLock, setNewBatteryLock] = useState(3);
|
||||||
|
const [newBatteryPenalty, setNewBatteryPenalty] = useState(10);
|
||||||
|
const [newBatteryProfitShare, setNewBatteryProfitShare] = useState(40);
|
||||||
|
const [newBatteryDesc, setNewBatteryDesc] = useState('');
|
||||||
|
const [newBatteryBasePrice, setNewBatteryBasePrice] = useState(15000);
|
||||||
|
const [newBatteryMinQuantity, setNewBatteryMinQuantity] = useState(10);
|
||||||
|
|
||||||
const createInvestPlan = () => {
|
const createInvestPlan = () => {
|
||||||
if (newInvestName.trim() && typeof window !== 'undefined') {
|
if (newInvestName.trim() && typeof window !== 'undefined') {
|
||||||
const newPlan = {
|
const newPlan = {
|
||||||
@@ -888,6 +965,35 @@ export default function CompanySettingsPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const createBatteryPlan = () => {
|
||||||
|
if (newBatteryName.trim() && typeof window !== 'undefined') {
|
||||||
|
const newPlan = {
|
||||||
|
id: 'bat_inv_' + Date.now(),
|
||||||
|
name: newBatteryName,
|
||||||
|
tier: newBatteryMinQuantity >= 50 ? 'Premium' : 'Economy',
|
||||||
|
batteryBasePrice: newBatteryBasePrice,
|
||||||
|
minQuantity: newBatteryMinQuantity,
|
||||||
|
minInvestment: newBatteryBasePrice * newBatteryMinQuantity,
|
||||||
|
maxInvestment: newBatteryMax,
|
||||||
|
durationMonths: newBatteryDuration,
|
||||||
|
profitSharePercent: newBatteryProfitShare,
|
||||||
|
lockInMonths: newBatteryLock,
|
||||||
|
earlyExitPenalty: newBatteryPenalty,
|
||||||
|
startDate: newBatteryStart,
|
||||||
|
endDate: newBatteryEnd,
|
||||||
|
targetAmount: newBatteryTarget,
|
||||||
|
status: newBatteryStatus,
|
||||||
|
description: newBatteryDesc,
|
||||||
|
};
|
||||||
|
const updatedPlans = [...(settings.plans.batteryInvestment || []), newPlan];
|
||||||
|
updateSettings({ ...settings, plans: { ...settings.plans, batteryInvestment: updatedPlans } });
|
||||||
|
setActiveBatteryTab(updatedPlans.length - 1);
|
||||||
|
setAddBatteryPlan(false);
|
||||||
|
setNewBatteryName('');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const [activeSwapTab, setActiveSwapTab] = useState(0);
|
const [activeSwapTab, setActiveSwapTab] = useState(0);
|
||||||
const [addSwapStationPlan, setAddSwapStationPlan] = useState(false);
|
const [addSwapStationPlan, setAddSwapStationPlan] = useState(false);
|
||||||
const [newSwapName, setNewSwapName] = useState('');
|
const [newSwapName, setNewSwapName] = useState('');
|
||||||
@@ -1123,7 +1229,8 @@ export default function CompanySettingsPage() {
|
|||||||
{ id: 'kyc', label: 'KYC Documents', icon: Package },
|
{ id: 'kyc', label: 'KYC Documents', icon: Package },
|
||||||
|
|
||||||
{ id: 'plans', label: 'Plan Selection', icon: Package },
|
{ id: 'plans', label: 'Plan Selection', icon: Package },
|
||||||
{ id: 'investment', label: 'Investment Plan', icon: DollarSign },
|
{ id: 'investment', label: 'Bike Investment Plan', icon: DollarSign },
|
||||||
|
{ id: 'batteryinvestment', label: 'Battery Investment Plan', icon: Battery },
|
||||||
{ id: 'swapstation', label: 'Swap Station Plan (P3)', icon: Zap },
|
{ id: 'swapstation', label: 'Swap Station Plan (P3)', icon: Zap },
|
||||||
{ id: 'riderrequest', label: 'Rider Request Plan (P2)', icon: Users },
|
{ id: 'riderrequest', label: 'Rider Request Plan (P2)', icon: Users },
|
||||||
{ id: 'parts', label: 'EV Parts', icon: Package },
|
{ id: 'parts', label: 'EV Parts', icon: Package },
|
||||||
@@ -1316,6 +1423,29 @@ export default function CompanySettingsPage() {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{activeTab === 'batteryinvestment' && (
|
||||||
|
<BatteryInvestmentSettings
|
||||||
|
settings={settings} setSettings={setSettings}
|
||||||
|
activeBatteryTab={activeBatteryTab} setActiveBatteryTab={setActiveBatteryTab}
|
||||||
|
addBatteryPlan={addBatteryPlan} setAddBatteryPlan={setAddBatteryPlan}
|
||||||
|
newBatteryName={newBatteryName} setNewBatteryName={setNewBatteryName}
|
||||||
|
newBatteryStatus={newBatteryStatus} setNewBatteryStatus={setNewBatteryStatus}
|
||||||
|
newBatteryTarget={newBatteryTarget} setNewBatteryTarget={setNewBatteryTarget}
|
||||||
|
newBatteryStart={newBatteryStart} setNewBatteryStart={setNewBatteryStart}
|
||||||
|
newBatteryEnd={newBatteryEnd} setNewBatteryEnd={setNewBatteryEnd}
|
||||||
|
newBatteryMin={newBatteryMin} setNewBatteryMin={setNewBatteryMin}
|
||||||
|
newBatteryMax={newBatteryMax} setNewBatteryMax={setNewBatteryMax}
|
||||||
|
newBatteryDuration={newBatteryDuration} setNewBatteryDuration={setNewBatteryDuration}
|
||||||
|
newBatteryLock={newBatteryLock} setNewBatteryLock={setNewBatteryLock}
|
||||||
|
newBatteryPenalty={newBatteryPenalty} setNewBatteryPenalty={setNewBatteryPenalty}
|
||||||
|
newBatteryProfitShare={newBatteryProfitShare} setNewBatteryProfitShare={setNewBatteryProfitShare}
|
||||||
|
newBatteryDesc={newBatteryDesc} setNewBatteryDesc={setNewBatteryDesc}
|
||||||
|
newBatteryBasePrice={newBatteryBasePrice} setNewBatteryBasePrice={setNewBatteryBasePrice}
|
||||||
|
newBatteryMinQuantity={newBatteryMinQuantity} setNewBatteryMinQuantity={setNewBatteryMinQuantity}
|
||||||
|
createBatteryPlan={createBatteryPlan} handleSave={handleSave}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{
|
{
|
||||||
activeTab === 'swapstation' && (
|
activeTab === 'swapstation' && (
|
||||||
<SwapStationSettings
|
<SwapStationSettings
|
||||||
|
|||||||
Reference in New Issue
Block a user