feat: add swap station management module and settings configuration to admin dashboard

This commit is contained in:
sazzadulalambd
2026-05-05 21:54:46 +06:00
parent 928350b478
commit 278e3fc18c

View File

@@ -1,7 +1,7 @@
'use client';
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, Plus, X, DollarSign } 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, Zap } from 'lucide-react';
interface CompanySettings {
name: string;
@@ -138,6 +138,19 @@ interface CompanySettings {
status: string;
description: string;
}[];
swapStation: {
id: string;
name: string;
batteryCount: number;
swapPrice: number;
monthlySubscription: number;
dailySubscription: number;
minBatteries: number;
maxBatteries: number;
profitSharePercent: number;
status: string;
description: string;
}[];
};
}
@@ -495,12 +508,40 @@ const initialSettings: CompanySettings = {
description: 'Investment plan for 5 bikes - medium scale investment',
}
],
swapStation: [
{
id: 'ss_1',
name: 'Basic Swap Station',
batteryCount: 10,
swapPrice: 50,
monthlySubscription: 500,
dailySubscription: 20,
minBatteries: 1,
maxBatteries: 5,
profitSharePercent: 50,
status: 'active',
description: 'Basic swap station for small operators',
},
{
id: 'ss_2',
name: 'Premium Swap Station',
batteryCount: 50,
swapPrice: 45,
monthlySubscription: 2000,
dailySubscription: 80,
minBatteries: 10,
maxBatteries: 30,
profitSharePercent: 55,
status: 'active',
description: 'Premium swap station for large operators',
}
],
},
};
export default function CompanySettingsPage() {
const [settings, setSettings] = useState<CompanySettings>(initialSettings);
const [activeTab, setActiveTab] = useState<'general' | 'branding' | 'social' | 'integration' | 'landing' | 'kyc' | 'parts' | 'rental' | 'plans' | 'investment'>('general');
const [activeTab, setActiveTab] = useState<'general' | 'branding' | 'social' | 'integration' | 'landing' | 'kyc' | 'parts' | 'rental' | 'plans' | 'investment' | 'swapstation'>('general');
const [activeMasterTab, setActiveMasterTab] = useState<'investor' | 'merchant' | 'swapstation' | 'rental'>('investor');
const [saved, setSaved] = useState(false);
const [activePlanTab, setActivePlanTab] = useState<'singleRent' | 'rentToOwn' | 'shareEv'>('singleRent');
@@ -553,6 +594,42 @@ export default function CompanySettingsPage() {
}
};
const [activeSwapTab, setActiveSwapTab] = useState(0);
const [addSwapStationPlan, setAddSwapStationPlan] = useState(false);
const [newSwapName, setNewSwapName] = useState('');
const [newSwapStatus, setNewSwapStatus] = useState('active');
const [newSwapBatteryCount, setNewSwapBatteryCount] = useState(10);
const [newSwapPrice, setNewSwapPrice] = useState(50);
const [newSwapMonthly, setNewSwapMonthly] = useState(500);
const [newSwapDaily, setNewSwapDaily] = useState(20);
const [newSwapMin, setNewSwapMin] = useState(1);
const [newSwapMax, setNewSwapMax] = useState(5);
const [newSwapProfit, setNewSwapProfit] = useState(50);
const [newSwapDesc, setNewSwapDesc] = useState('');
const createSwapStationPlan = () => {
if (newSwapName.trim() && typeof window !== 'undefined') {
const newPlan = {
id: 'ss_' + Date.now(),
name: newSwapName,
batteryCount: newSwapBatteryCount,
swapPrice: newSwapPrice,
monthlySubscription: newSwapMonthly,
dailySubscription: newSwapDaily,
minBatteries: newSwapMin,
maxBatteries: newSwapMax,
profitSharePercent: newSwapProfit,
status: newSwapStatus,
description: newSwapDesc
};
const updatedPlans = [...settings.plans.swapStation, newPlan];
setSettings({ ...settings, plans: { ...settings.plans, swapStation: updatedPlans } });
setActiveSwapTab(updatedPlans.length - 1);
setAddSwapStationPlan(false);
setNewSwapName('');
}
};
const handleSave = () => {
setSaved(true);
setTimeout(() => setSaved(false), 2000);
@@ -569,6 +646,7 @@ export default function CompanySettingsPage() {
{ id: 'rental', label: 'Rental Policy', icon: FileCheck },
{ id: 'plans', label: 'Plan Selection', icon: Package },
{ id: 'investment', label: 'Investment Plan', icon: DollarSign },
{ id: 'swapstation', label: 'Swap Station Plan', icon: Zap },
];
return (
@@ -2062,6 +2140,158 @@ export default function CompanySettingsPage() {
))}
</div>
)}
{(activeTab as string) === 'swapstation' && (
<div className="p-6 space-y-6">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-slate-800">Swap Station Plans</h3>
</div>
<div className="flex items-center justify-between bg-blue-50 border border-blue-200 rounded-xl p-4">
<div>
<h4 className="font-semibold text-blue-800">Swap Station Plans ({settings.plans.swapStation.length})</h4>
<p className="text-sm text-blue-600">Manage swap station plans for operators</p>
</div>
<button onClick={() => { setAddSwapStationPlan(true); setNewSwapName(''); }} className="px-4 py-2 bg-blue-600 text-white rounded-lg text-sm font-medium flex items-center gap-2">
<Plus className="w-4 h-4" /> New Plan
</button>
</div>
{addSwapStationPlan && (
<div className="bg-white rounded-xl border border-blue-300 overflow-hidden">
<div className="bg-blue-100 px-4 py-3 border-b border-blue-200 flex items-center justify-between">
<div>
<h4 className="font-semibold text-blue-800">New Swap Station Plan</h4>
<p className="text-sm text-blue-600 mt-1">Fill in the details below</p>
</div>
<button onClick={() => setAddSwapStationPlan(false)} className="text-blue-600 hover:text-blue-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={newSwapName} onChange={(e) => setNewSwapName(e.target.value)} placeholder="e.g., Standard Station" 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={newSwapStatus} onChange={(e) => setNewSwapStatus(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">Battery Count</label>
<input type="number" value={newSwapBatteryCount} onChange={(e) => setNewSwapBatteryCount(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">Swap Price ()</label>
<input type="number" value={newSwapPrice} onChange={(e) => setNewSwapPrice(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 Subscription ()</label>
<input type="number" value={newSwapMonthly} onChange={(e) => setNewSwapMonthly(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">Daily Subscription ()</label>
<input type="number" value={newSwapDaily} onChange={(e) => setNewSwapDaily(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">Min Batteries</label>
<input type="number" value={newSwapMin} onChange={(e) => setNewSwapMin(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 Batteries</label>
<input type="number" value={newSwapMax} onChange={(e) => setNewSwapMax(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 (%)</label>
<input type="number" value={newSwapProfit} onChange={(e) => setNewSwapProfit(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={newSwapDesc} onChange={(e) => setNewSwapDesc(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={createSwapStationPlan} className="mt-4 px-4 py-2 bg-blue-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.swapStation.map((plan, idx) => (
<button key={idx} onClick={() => setActiveSwapTab(idx)} className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${activeSwapTab === idx ? 'border-blue-500 text-blue-600' : 'border-transparent text-slate-500 hover:text-slate-700'}`}> {plan.name}</button>
))}
</div>
{settings.plans.swapStation.length > 0 && settings.plans.swapStation.map((plan, idx) => idx === activeSwapTab && (
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
<div className="bg-blue-50 px-4 py-3 border-b border-blue-100 flex items-center justify-between">
<div>
<h4 className="font-semibold text-blue-800">{plan.name}</h4>
<p className="text-sm text-blue-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.swapStation]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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.swapStation]; updated[idx].status = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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">Battery Count</label>
<input type="number" value={plan.batteryCount} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].batteryCount = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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">Swap Price ()</label>
<input type="number" value={plan.swapPrice} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].swapPrice = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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 Subscription ()</label>
<input type="number" value={plan.monthlySubscription} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].monthlySubscription = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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">Daily Subscription ()</label>
<input type="number" value={plan.dailySubscription} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].dailySubscription = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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 Batteries</label>
<input type="number" value={plan.minBatteries} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].minBatteries = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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 Batteries</label>
<input type="number" value={plan.maxBatteries} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].maxBatteries = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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 (%)</label>
<input type="number" value={plan.profitSharePercent} onChange={(e) => { const updated = [...settings.plans.swapStation]; updated[idx].profitSharePercent = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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.swapStation]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, swapStation: 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-blue-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>