Files
JML/src/app/admin/settings/components/BatteryInvestmentSettings.tsx

272 lines
19 KiB
TypeScript
Raw Normal View History

'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>
);
}