feat: refactor rental plans to use IDs, add support for EV models, and enable dynamic plan creation
This commit is contained in:
@@ -93,8 +93,9 @@ interface CompanySettings {
|
||||
};
|
||||
plans: {
|
||||
singleRent: {
|
||||
tier: 'Economy' | 'Standard' | 'Premium';
|
||||
id: string;
|
||||
name: string;
|
||||
evModels: string[];
|
||||
contractMonths: number[];
|
||||
dailyRent: number;
|
||||
dailyRentPenalty1: number;
|
||||
@@ -113,8 +114,9 @@ interface CompanySettings {
|
||||
description: string;
|
||||
}[];
|
||||
rentToOwn: {
|
||||
tier: 'Economy' | 'Standard' | 'Premium';
|
||||
id: string;
|
||||
name: string;
|
||||
evModels: string[];
|
||||
contractMonths: number[];
|
||||
dailyRent: number;
|
||||
dailyRentPenalty1: number;
|
||||
@@ -138,8 +140,9 @@ interface CompanySettings {
|
||||
description: string;
|
||||
}[];
|
||||
shareEv: {
|
||||
tier: 'Economy' | 'Standard' | 'Premium';
|
||||
id: string;
|
||||
name: string;
|
||||
evModels: string[];
|
||||
contractMonths: number[];
|
||||
dailyRentEach: number;
|
||||
dailyRentPenalty1: number;
|
||||
@@ -445,8 +448,9 @@ const initialSettings: CompanySettings = {
|
||||
plans: {
|
||||
singleRent: [
|
||||
{
|
||||
tier: 'Premium',
|
||||
id: 'sr-1',
|
||||
name: 'Single Rent - Premium',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6, 12],
|
||||
dailyRent: 400,
|
||||
dailyRentPenalty1: 500,
|
||||
@@ -465,8 +469,9 @@ const initialSettings: CompanySettings = {
|
||||
description: 'Premium single person rental plan with extra benefits',
|
||||
},
|
||||
{
|
||||
tier: 'Standard',
|
||||
id: 'sr-2',
|
||||
name: 'Single Rent - Standard',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6, 12],
|
||||
dailyRent: 300,
|
||||
dailyRentPenalty1: 400,
|
||||
@@ -485,8 +490,9 @@ const initialSettings: CompanySettings = {
|
||||
description: 'Standard single person rental plan',
|
||||
},
|
||||
{
|
||||
tier: 'Economy',
|
||||
id: 'sr-3',
|
||||
name: 'Single Rent - Economy',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6, 12],
|
||||
dailyRent: 250,
|
||||
dailyRentPenalty1: 300,
|
||||
@@ -507,8 +513,9 @@ const initialSettings: CompanySettings = {
|
||||
],
|
||||
rentToOwn: [
|
||||
{
|
||||
tier: 'Premium',
|
||||
id: 'rto-1',
|
||||
name: 'Rent to Own - Premium',
|
||||
evModels: [],
|
||||
contractMonths: [12, 18, 24, 36],
|
||||
dailyRent: 350,
|
||||
dailyRentPenalty1: 450,
|
||||
@@ -532,8 +539,9 @@ const initialSettings: CompanySettings = {
|
||||
description: 'Premium rent to own plan with high-end EV',
|
||||
},
|
||||
{
|
||||
tier: 'Standard',
|
||||
id: 'rto-2',
|
||||
name: 'Rent to Own - Standard',
|
||||
evModels: [],
|
||||
contractMonths: [12, 18, 24, 36],
|
||||
dailyRent: 250,
|
||||
dailyRentPenalty1: 350,
|
||||
@@ -557,8 +565,9 @@ const initialSettings: CompanySettings = {
|
||||
description: 'Standard rent to own plan',
|
||||
},
|
||||
{
|
||||
tier: 'Economy',
|
||||
id: 'rto-3',
|
||||
name: 'Rent to Own - Economy',
|
||||
evModels: [],
|
||||
contractMonths: [12, 18, 24, 36],
|
||||
dailyRent: 200,
|
||||
dailyRentPenalty1: 250,
|
||||
@@ -584,8 +593,9 @@ const initialSettings: CompanySettings = {
|
||||
],
|
||||
shareEv: [
|
||||
{
|
||||
tier: 'Premium',
|
||||
id: 'se-1',
|
||||
name: 'Share an EV - Premium',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6, 12],
|
||||
dailyRentEach: 300,
|
||||
dailyRentPenalty1: 400,
|
||||
@@ -611,8 +621,9 @@ const initialSettings: CompanySettings = {
|
||||
description: 'Premium shared EV with premium bikes',
|
||||
},
|
||||
{
|
||||
tier: 'Standard',
|
||||
id: 'se-2',
|
||||
name: 'Share an EV - Standard',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6, 12],
|
||||
dailyRentEach: 200,
|
||||
dailyRentPenalty1: 250,
|
||||
@@ -638,8 +649,9 @@ const initialSettings: CompanySettings = {
|
||||
description: 'Standard shared EV plan',
|
||||
},
|
||||
{
|
||||
tier: 'Economy',
|
||||
id: 'se-3',
|
||||
name: 'Share an EV - Economy',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6, 12],
|
||||
dailyRentEach: 150,
|
||||
dailyRentPenalty1: 200,
|
||||
@@ -934,6 +946,90 @@ export default function CompanySettingsPage() {
|
||||
setTimeout(() => setSaved(false), 2000);
|
||||
};
|
||||
|
||||
const addNewPlan = (type: 'singleRent' | 'rentToOwn' | 'shareEv') => {
|
||||
const newId = `${type}-${Date.now()}`;
|
||||
const defaultPlan = type === 'singleRent' ? {
|
||||
id: newId,
|
||||
name: '',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6],
|
||||
dailyRent: 300,
|
||||
dailyRentPenalty1: 400,
|
||||
dailyRentPenalty2: 800,
|
||||
dailyRentPenalty3: 4000,
|
||||
deposit: 20000,
|
||||
weeklySubscription: 2100,
|
||||
weeklyPenalty1: 2600,
|
||||
weeklyPenalty2: 5200,
|
||||
weeklyPenalty3: 12000,
|
||||
monthlySubscription: 9000,
|
||||
monthlyPenalty1: 11000,
|
||||
monthlyPenalty2: 22000,
|
||||
monthlyPenalty3: 40000,
|
||||
ficoSharePercent: 45,
|
||||
description: '',
|
||||
} : type === 'rentToOwn' ? {
|
||||
id: newId,
|
||||
name: '',
|
||||
evModels: [],
|
||||
contractMonths: [12, 18, 24],
|
||||
dailyRent: 250,
|
||||
dailyRentPenalty1: 350,
|
||||
dailyRentPenalty2: 700,
|
||||
dailyRentPenalty3: 3500,
|
||||
deposit: 18000,
|
||||
weeklySubscription: 1750,
|
||||
weeklyPenalty1: 2200,
|
||||
weeklyPenalty2: 4400,
|
||||
weeklyPenalty3: 10000,
|
||||
monthlySubscription: 7000,
|
||||
monthlyPenalty1: 9000,
|
||||
monthlyPenalty2: 18000,
|
||||
monthlyPenalty3: 30000,
|
||||
durationMonths: 18,
|
||||
evPrice: 120000,
|
||||
totalPayment: 135000,
|
||||
profit: 15000,
|
||||
ficoRentSharePercent: 45,
|
||||
ficoProfitSharePercent: 45,
|
||||
description: '',
|
||||
} : {
|
||||
id: newId,
|
||||
name: '',
|
||||
evModels: [],
|
||||
contractMonths: [1, 3, 6],
|
||||
dailyRentEach: 200,
|
||||
dailyRentPenalty1: 250,
|
||||
dailyRentPenalty2: 500,
|
||||
dailyRentPenalty3: 2500,
|
||||
totalDailyRent: 400,
|
||||
depositEach: 15000,
|
||||
depositPenalty1: 18000,
|
||||
depositPenalty2: 25000,
|
||||
depositPenalty3: 40000,
|
||||
totalDeposit: 30000,
|
||||
weeklySubscriptionEach: 1400,
|
||||
weeklyPenalty1: 1800,
|
||||
weeklyPenalty2: 3500,
|
||||
weeklyPenalty3: 8000,
|
||||
totalWeeklySubscription: 2800,
|
||||
monthlySubscriptionEach: 5600,
|
||||
monthlyPenalty1: 7000,
|
||||
monthlyPenalty2: 14000,
|
||||
monthlyPenalty3: 25000,
|
||||
totalMonthlySubscription: 11200,
|
||||
ficoSharePercent: 45,
|
||||
description: '',
|
||||
};
|
||||
if (type === 'singleRent') {
|
||||
setSettings({ ...settings, plans: { ...settings.plans, singleRent: [...settings.plans.singleRent, defaultPlan as typeof settings.plans.singleRent[number]] } });
|
||||
} else if (type === 'rentToOwn') {
|
||||
setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: [...settings.plans.rentToOwn, defaultPlan as typeof settings.plans.rentToOwn[number]] } });
|
||||
} else {
|
||||
setSettings({ ...settings, plans: { ...settings.plans, shareEv: [...settings.plans.shareEv, defaultPlan as typeof settings.plans.shareEv[number]] } });
|
||||
}
|
||||
};
|
||||
|
||||
const addPolicyRule = (tab: 'investor' | 'merchant' | 'swapstation') => {
|
||||
if (!newPolicyName.trim()) return;
|
||||
const newRule = { title: newPolicyName, description: newPolicyDesc || '<p></p>' };
|
||||
@@ -2347,19 +2443,52 @@ export default function CompanySettingsPage() {
|
||||
{activePlanTab === 'singleRent' && (
|
||||
<div className="space-y-6">
|
||||
{settings.plans.singleRent.map((plan, idx) => (
|
||||
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div key={plan.id} 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">SINGLE RENT - {plan.tier} - ৳{plan.dailyRent}/day</h4>
|
||||
<h4 className="font-semibold text-blue-800">{plan.name} - ৳{plan.dailyRent}/day</h4>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full bg-transparent text-sm text-blue-600 mt-1 border-0 resize-none p-0 focus:ring-0" rows={1} placeholder="Plan description..." />
|
||||
</div>
|
||||
<button onClick={handleSave} className="px-3 py-1.5 bg-blue-600 text-white rounded-lg text-xs font-medium flex items-center gap-1">
|
||||
<Save className="w-3 h-3" /> Save
|
||||
</button>
|
||||
<div className="flex items-center gap-2 ml-3">
|
||||
<button onClick={handleSave} className="px-3 py-1.5 bg-blue-600 text-white rounded-lg text-xs font-medium flex items-center gap-1 hover:bg-blue-700">
|
||||
<Save className="w-3 h-3" /> Save
|
||||
</button>
|
||||
<button onClick={() => { if (confirm('Delete this plan?')) { const updated = settings.plans.singleRent.filter((_, i) => i !== idx); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); } }} className="px-2 py-1.5 bg-red-50 text-red-600 rounded-lg text-xs font-medium flex items-center gap-1 hover:bg-red-100">
|
||||
<Trash2 className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 space-y-4">
|
||||
<div className="p-5 space-y-5">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Name</label>
|
||||
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Name" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label>
|
||||
<select multiple value={plan.evModels} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].evModels = Array.from(e.target.selectedOptions, opt => opt.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-2 py-2 border border-slate-200 rounded-lg text-sm bg-white min-h-[70px] cursor-pointer">
|
||||
<option value="Etron ET50">Etron ET50</option>
|
||||
<option value="Yadea DT3">Yadea DT3</option>
|
||||
<option value="AIMA Lightning">AIMA Lightning</option>
|
||||
<option value="AIMA EM5">AIMA EM5</option>
|
||||
<option value="Yadea G5">Yadea G5</option>
|
||||
<option value="TVS iQube">TVS iQube</option>
|
||||
<option value="Bajaj Chetak">Bajaj Chetak</option>
|
||||
<option value="Hero Photon">Hero Photon</option>
|
||||
<option value="Okinawa Praise">Okinawa Praise</option>
|
||||
<option value="Ampere Magnus">Ampere Magnus</option>
|
||||
<option value="Benling Aura">Benling Aura</option>
|
||||
<option value="Lectrix LXS">Lectrix LXS</option>
|
||||
<option value="Revolt RV400">Revolt RV400</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Deposit (৳)</label>
|
||||
<input type="number" value={plan.deposit} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].deposit = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Daily Rent</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Daily Rent</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2374,13 +2503,13 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.dailyRentPenalty2} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].dailyRentPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.dailyRentPenalty3} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].dailyRentPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Weekly Subscription</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Weekly Subscription</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2395,13 +2524,13 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.weeklyPenalty2} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].weeklyPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.weeklyPenalty3} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].weeklyPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Monthly Subscription</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Monthly Subscription</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2416,97 +2545,89 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.monthlyPenalty2} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].monthlyPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.monthlyPenalty3} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].monthlyPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm text-slate-600">Deposit (৳)</label>
|
||||
<input type="number" value={plan.deposit} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].deposit = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-lg p-3">
|
||||
<label className="text-sm font-semibold text-slate-700 block mb-2">Contract Duration (Months)</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide block mb-2">Contract Duration (Months)</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{plan.contractMonths.map(month => (
|
||||
<button
|
||||
key={month}
|
||||
onClick={() => {
|
||||
const updated = [...settings.plans.singleRent];
|
||||
updated[idx].contractMonths = updated[idx].contractMonths.filter(m => m !== month);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } });
|
||||
}}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium bg-blue-600 text-white hover:bg-red-500 transition-all flex items-center gap-1"
|
||||
>
|
||||
<button key={month} onClick={() => { const updated = [...settings.plans.singleRent]; updated[idx].contractMonths = updated[idx].contractMonths.filter(m => m !== month); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="px-3 py-1.5 rounded-lg text-xs font-medium bg-blue-600 text-white hover:bg-red-500 transition-all flex items-center gap-1">
|
||||
{month} {month === 1 ? 'Month' : 'Months'}
|
||||
<span className="ml-1 font-bold">×</span>
|
||||
</button>
|
||||
))}
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="Add"
|
||||
className="w-20 px-2 py-1.5 border border-slate-200 rounded-lg text-xs"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
const val = parseInt((e.target as HTMLInputElement).value);
|
||||
if (val > 0 && !plan.contractMonths.includes(val)) {
|
||||
const updated = [...settings.plans.singleRent];
|
||||
updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } });
|
||||
(e.target as HTMLInputElement).value = '';
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
const input = (e.currentTarget.previousElementSibling as HTMLInputElement);
|
||||
const val = parseInt(input.value);
|
||||
if (val > 0 && !plan.contractMonths.includes(val)) {
|
||||
const updated = [...settings.plans.singleRent];
|
||||
updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } });
|
||||
input.value = '';
|
||||
}
|
||||
}}
|
||||
className="px-2 py-1.5 bg-blue-600 text-white rounded-lg text-xs hover:bg-blue-700"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<input type="number" min="1" placeholder="Add" className="w-20 px-2 py-1.5 border border-slate-200 rounded-lg text-xs" onKeyDown={(e) => { if (e.key === 'Enter') { const val = parseInt((e.target as HTMLInputElement).value); if (val > 0 && !plan.contractMonths.includes(val)) { const updated = [...settings.plans.singleRent]; updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); (e.target as HTMLInputElement).value = ''; } } }} />
|
||||
<button onClick={(e) => { const input = (e.currentTarget.previousElementSibling as HTMLInputElement); const val = parseInt(input.value); if (val > 0 && !plan.contractMonths.includes(val)) { const updated = [...settings.plans.singleRent]; updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b); setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); input.value = ''; } }} className="px-2 py-1.5 bg-blue-600 text-white rounded-lg text-xs hover:bg-blue-700">+</button>
|
||||
</div>
|
||||
</div>
|
||||
{plan.contractMonths.length === 0 && (
|
||||
<p className="text-xs text-slate-400 mt-2">No contract months selected.</p>
|
||||
)}
|
||||
{plan.contractMonths.length === 0 && <p className="text-xs text-slate-400 mt-2">No contract months selected.</p>}
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm text-slate-600">Description</label>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" rows={2} />
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Description</label>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.singleRent]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, singleRent: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" rows={2} placeholder="Enter plan description..." />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button onClick={() => addNewPlan('singleRent')} className="w-full py-3 border-2 border-dashed border-slate-300 rounded-xl text-slate-500 hover:border-blue-400 hover:text-blue-500 hover:bg-blue-50 transition-all flex items-center justify-center gap-2 text-sm font-medium">
|
||||
<Plus className="w-4 h-4" /> Add New Plan
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activePlanTab === 'rentToOwn' && (
|
||||
<div className="space-y-6">
|
||||
{settings.plans.rentToOwn.map((plan, idx) => (
|
||||
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div key={plan.id} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div className="bg-purple-50 px-4 py-3 border-b border-purple-100 flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="font-semibold text-purple-800">RENT TO OWN - {plan.tier} - ৳{plan.dailyRent}/day</h4>
|
||||
<h4 className="font-semibold text-purple-800">{plan.name} - ৳{plan.dailyRent}/day</h4>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full bg-transparent text-sm text-purple-600 mt-1 border-0 resize-none p-0 focus:ring-0" rows={1} placeholder="Plan description..." />
|
||||
</div>
|
||||
<button onClick={handleSave} className="px-3 py-1.5 bg-purple-600 text-white rounded-lg text-xs font-medium flex items-center gap-1">
|
||||
<Save className="w-3 h-3" /> Save
|
||||
</button>
|
||||
<div className="flex items-center gap-2 ml-3">
|
||||
<button onClick={handleSave} className="px-3 py-1.5 bg-purple-600 text-white rounded-lg text-xs font-medium flex items-center gap-1 hover:bg-purple-700">
|
||||
<Save className="w-3 h-3" /> Save
|
||||
</button>
|
||||
<button onClick={() => { if (confirm('Delete this plan?')) { const updated = settings.plans.rentToOwn.filter((_, i) => i !== idx); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); } }} className="px-2 py-1.5 bg-red-50 text-red-600 rounded-lg text-xs font-medium flex items-center gap-1 hover:bg-red-100">
|
||||
<Trash2 className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 space-y-4">
|
||||
<div className="p-5 space-y-5">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Name</label>
|
||||
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Name" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label>
|
||||
<select multiple value={plan.evModels} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].evModels = Array.from(e.target.selectedOptions, opt => opt.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-2 py-2 border border-slate-200 rounded-lg text-sm bg-white min-h-[70px] cursor-pointer">
|
||||
<option value="Etron ET50">Etron ET50</option>
|
||||
<option value="Yadea DT3">Yadea DT3</option>
|
||||
<option value="AIMA Lightning">AIMA Lightning</option>
|
||||
<option value="AIMA EM5">AIMA EM5</option>
|
||||
<option value="Yadea G5">Yadea G5</option>
|
||||
<option value="TVS iQube">TVS iQube</option>
|
||||
<option value="Bajaj Chetak">Bajaj Chetak</option>
|
||||
<option value="Hero Photon">Hero Photon</option>
|
||||
<option value="Okinawa Praise">Okinawa Praise</option>
|
||||
<option value="Ampere Magnus">Ampere Magnus</option>
|
||||
<option value="Benling Aura">Benling Aura</option>
|
||||
<option value="Lectrix LXS">Lectrix LXS</option>
|
||||
<option value="Revolt RV400">Revolt RV400</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Deposit (৳)</label>
|
||||
<input type="number" value={plan.deposit} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].deposit = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Daily Rent</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Daily Rent</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2521,13 +2642,13 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.dailyRentPenalty2} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].dailyRentPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.dailyRentPenalty3} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].dailyRentPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Weekly Subscription</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Weekly Subscription</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2542,13 +2663,13 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.weeklyPenalty2} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].weeklyPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.weeklyPenalty3} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].weeklyPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Monthly Subscription</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Monthly Subscription</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2563,98 +2684,89 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.monthlyPenalty2} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].monthlyPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.monthlyPenalty3} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].monthlyPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm text-slate-600">Deposit (৳)</label>
|
||||
<input type="number" value={plan.deposit} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].deposit = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" />
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-lg p-3">
|
||||
<label className="text-sm font-semibold text-slate-700 block mb-2">Contract Duration (Months)</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide block mb-2">Contract Duration (Months)</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{plan.contractMonths.map(month => (
|
||||
<button
|
||||
key={month}
|
||||
onClick={() => {
|
||||
const updated = [...settings.plans.rentToOwn];
|
||||
updated[idx].contractMonths = updated[idx].contractMonths.filter(m => m !== month);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } });
|
||||
}}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium bg-purple-600 text-white hover:bg-red-500 transition-all flex items-center gap-1"
|
||||
>
|
||||
{month} Months
|
||||
<button key={month} onClick={() => { const updated = [...settings.plans.rentToOwn]; updated[idx].contractMonths = updated[idx].contractMonths.filter(m => m !== month); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="px-3 py-1.5 rounded-lg text-xs font-medium bg-purple-600 text-white hover:bg-red-500 transition-all flex items-center gap-1">
|
||||
{month} {month === 1 ? 'Month' : 'Months'}
|
||||
<span className="ml-1 font-bold">×</span>
|
||||
</button>
|
||||
))}
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="Add"
|
||||
className="w-20 px-2 py-1.5 border border-slate-200 rounded-lg text-xs"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
const val = parseInt((e.target as HTMLInputElement).value);
|
||||
if (val > 0 && !plan.contractMonths.includes(val)) {
|
||||
const updated = [...settings.plans.rentToOwn];
|
||||
updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } });
|
||||
(e.target as HTMLInputElement).value = '';
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
const input = (e.currentTarget.previousElementSibling as HTMLInputElement);
|
||||
const val = parseInt(input.value);
|
||||
if (val > 0 && !plan.contractMonths.includes(val)) {
|
||||
const updated = [...settings.plans.rentToOwn];
|
||||
updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } });
|
||||
input.value = '';
|
||||
}
|
||||
}}
|
||||
className="px-2 py-1.5 bg-purple-600 text-white rounded-lg text-xs hover:bg-purple-700"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<input type="number" min="1" placeholder="Add" className="w-20 px-2 py-1.5 border border-slate-200 rounded-lg text-xs" onKeyDown={(e) => { if (e.key === 'Enter') { const val = parseInt((e.target as HTMLInputElement).value); if (val > 0 && !plan.contractMonths.includes(val)) { const updated = [...settings.plans.rentToOwn]; updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); (e.target as HTMLInputElement).value = ''; } } }} />
|
||||
<button onClick={(e) => { const input = (e.currentTarget.previousElementSibling as HTMLInputElement); const val = parseInt(input.value); if (val > 0 && !plan.contractMonths.includes(val)) { const updated = [...settings.plans.rentToOwn]; updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b); setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); input.value = ''; } }} className="px-2 py-1.5 bg-purple-600 text-white rounded-lg text-xs hover:bg-purple-700">+</button>
|
||||
</div>
|
||||
</div>
|
||||
{plan.contractMonths.length === 0 && (
|
||||
<p className="text-xs text-slate-400 mt-2">No contract months selected.</p>
|
||||
)}
|
||||
{plan.contractMonths.length === 0 && <p className="text-xs text-slate-400 mt-2">No contract months selected.</p>}
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm text-slate-600">Description</label>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" rows={2} />
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Description</label>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.rentToOwn]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, rentToOwn: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" rows={2} placeholder="Enter plan description..." />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
))}
|
||||
<button onClick={() => addNewPlan('rentToOwn')} className="w-full py-3 border-2 border-dashed border-slate-300 rounded-xl text-slate-500 hover:border-purple-400 hover:text-purple-500 hover:bg-purple-50 transition-all flex items-center justify-center gap-2 text-sm font-medium">
|
||||
<Plus className="w-4 h-4" /> Add New Plan
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{activePlanTab === 'shareEv' && (
|
||||
<div className="space-y-6">
|
||||
{settings.plans.shareEv.map((plan, idx) => (
|
||||
<div key={idx} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div key={plan.id} className="bg-white rounded-xl border border-slate-200 overflow-hidden">
|
||||
<div className="bg-green-50 px-4 py-3 border-b border-green-100 flex items-center justify-between">
|
||||
<div>
|
||||
<h4 className="font-semibold text-green-800">SHARE AN EV - {plan.tier} - ৳{plan.dailyRentEach}/day each (Total: ৳{plan.totalDailyRent})</h4>
|
||||
<h4 className="font-semibold text-green-800">{plan.name} - ৳{plan.dailyRentEach}/day each</h4>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full bg-transparent text-sm text-green-600 mt-1 border-0 resize-none p-0 focus:ring-0" rows={1} placeholder="Plan description..." />
|
||||
</div>
|
||||
<button onClick={handleSave} className="px-3 py-1.5 bg-green-600 text-white rounded-lg text-xs font-medium flex items-center gap-1">
|
||||
<Save className="w-3 h-3" /> Save
|
||||
</button>
|
||||
<div className="flex items-center gap-2 ml-3">
|
||||
<button onClick={handleSave} className="px-3 py-1.5 bg-green-600 text-white rounded-lg text-xs font-medium flex items-center gap-1 hover:bg-green-700">
|
||||
<Save className="w-3 h-3" /> Save
|
||||
</button>
|
||||
<button onClick={() => { if (confirm('Delete this plan?')) { const updated = settings.plans.shareEv.filter((_, i) => i !== idx); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); } }} className="px-2 py-1.5 bg-red-50 text-red-600 rounded-lg text-xs font-medium flex items-center gap-1 hover:bg-red-100">
|
||||
<Trash2 className="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 space-y-4">
|
||||
<div className="p-5 space-y-5">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Plan Name</label>
|
||||
<input type="text" value={plan.name} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].name = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" placeholder="Plan Name" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">EV Model Numbers</label>
|
||||
<select multiple value={plan.evModels} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].evModels = Array.from(e.target.selectedOptions, opt => opt.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-2 border border-slate-200 rounded-lg text-sm bg-white min-h-[70px] cursor-pointer">
|
||||
<option value="Etron ET50">Etron ET50</option>
|
||||
<option value="Yadea DT3">Yadea DT3</option>
|
||||
<option value="AIMA Lightning">AIMA Lightning</option>
|
||||
<option value="AIMA EM5">AIMA EM5</option>
|
||||
<option value="Yadea G5">Yadea G5</option>
|
||||
<option value="TVS iQube">TVS iQube</option>
|
||||
<option value="Bajaj Chetak">Bajaj Chetak</option>
|
||||
<option value="Hero Photon">Hero Photon</option>
|
||||
<option value="Okinawa Praise">Okinawa Praise</option>
|
||||
<option value="Ampere Magnus">Ampere Magnus</option>
|
||||
<option value="Benling Aura">Benling Aura</option>
|
||||
<option value="Lectrix LXS">Lectrix LXS</option>
|
||||
<option value="Revolt RV400">Revolt RV400</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Deposit Each (৳)</label>
|
||||
<input type="number" value={plan.depositEach} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].depositEach = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Daily Rent (Each)</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Daily Rent (Each)</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2669,13 +2781,13 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.dailyRentPenalty2} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].dailyRentPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.dailyRentPenalty3} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].dailyRentPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Weekly Subscription (Each)</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Weekly Subscription (Each)</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2690,13 +2802,13 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.weeklyPenalty2} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].weeklyPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.weeklyPenalty3} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].weeklyPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Monthly Subscription (Each)</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide">Monthly Subscription (Each)</label>
|
||||
<div className="grid grid-cols-4 gap-3">
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
@@ -2711,81 +2823,37 @@ export default function CompanySettingsPage() {
|
||||
<input type="number" value={plan.monthlyPenalty2} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].monthlyPenalty2 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">3rd Day Penalty + Bike Lock (৳)</label>
|
||||
<label className="text-xs text-slate-500">3rd Day Bike Lock (৳)</label>
|
||||
<input type="number" value={plan.monthlyPenalty3} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].monthlyPenalty3 = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-xl p-4 space-y-3">
|
||||
<label className="text-sm font-semibold text-slate-700">Deposit (Each)</label>
|
||||
<div>
|
||||
<label className="text-xs text-slate-500">Base (৳)</label>
|
||||
<input type="number" value={plan.depositEach} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].depositEach = parseInt(e.target.value); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-2 py-1.5 border border-slate-200 rounded-lg text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-slate-50 rounded-lg p-3">
|
||||
<label className="text-sm font-semibold text-slate-700 block mb-2">Contract Duration (Months)</label>
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide block mb-2">Contract Duration (Months)</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{plan.contractMonths.map(month => (
|
||||
<button
|
||||
key={month}
|
||||
onClick={() => {
|
||||
const updated = [...settings.plans.shareEv];
|
||||
updated[idx].contractMonths = updated[idx].contractMonths.filter(m => m !== month);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } });
|
||||
}}
|
||||
className="px-3 py-1.5 rounded-lg text-xs font-medium bg-green-600 text-white hover:bg-red-500 transition-all flex items-center gap-1"
|
||||
>
|
||||
<button key={month} onClick={() => { const updated = [...settings.plans.shareEv]; updated[idx].contractMonths = updated[idx].contractMonths.filter(m => m !== month); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="px-3 py-1.5 rounded-lg text-xs font-medium bg-green-600 text-white hover:bg-red-500 transition-all flex items-center gap-1">
|
||||
{month} {month === 1 ? 'Month' : 'Months'}
|
||||
<span className="ml-1 font-bold">×</span>
|
||||
</button>
|
||||
))}
|
||||
<div className="flex items-center gap-1">
|
||||
<input
|
||||
type="number"
|
||||
min="1"
|
||||
placeholder="Add"
|
||||
className="w-20 px-2 py-1.5 border border-slate-200 rounded-lg text-xs"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
const val = parseInt((e.target as HTMLInputElement).value);
|
||||
if (val > 0 && !plan.contractMonths.includes(val)) {
|
||||
const updated = [...settings.plans.shareEv];
|
||||
updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } });
|
||||
(e.target as HTMLInputElement).value = '';
|
||||
}
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
const input = (e.currentTarget.previousElementSibling as HTMLInputElement);
|
||||
const val = parseInt(input.value);
|
||||
if (val > 0 && !plan.contractMonths.includes(val)) {
|
||||
const updated = [...settings.plans.shareEv];
|
||||
updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b);
|
||||
setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } });
|
||||
input.value = '';
|
||||
}
|
||||
}}
|
||||
className="px-2 py-1.5 bg-green-600 text-white rounded-lg text-xs hover:bg-green-700"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<input type="number" min="1" placeholder="Add" className="w-20 px-2 py-1.5 border border-slate-200 rounded-lg text-xs" onKeyDown={(e) => { if (e.key === 'Enter') { const val = parseInt((e.target as HTMLInputElement).value); if (val > 0 && !plan.contractMonths.includes(val)) { const updated = [...settings.plans.shareEv]; updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); (e.target as HTMLInputElement).value = ''; } } }} />
|
||||
<button onClick={(e) => { const input = (e.currentTarget.previousElementSibling as HTMLInputElement); const val = parseInt(input.value); if (val > 0 && !plan.contractMonths.includes(val)) { const updated = [...settings.plans.shareEv]; updated[idx].contractMonths = [...updated[idx].contractMonths, val].sort((a, b) => a - b); setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); input.value = ''; } }} className="px-2 py-1.5 bg-green-600 text-white rounded-lg text-xs hover:bg-green-700">+</button>
|
||||
</div>
|
||||
</div>
|
||||
{plan.contractMonths.length === 0 && (
|
||||
<p className="text-xs text-slate-400 mt-2">No contract months selected.</p>
|
||||
)}
|
||||
{plan.contractMonths.length === 0 && <p className="text-xs text-slate-400 mt-2">No contract months selected.</p>}
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm text-slate-600">Description</label>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm mt-1" rows={2} />
|
||||
<label className="text-xs font-semibold text-slate-500 uppercase tracking-wide mb-2 block">Description</label>
|
||||
<textarea value={plan.description} onChange={(e) => { const updated = [...settings.plans.shareEv]; updated[idx].description = e.target.value; setSettings({ ...settings, plans: { ...settings.plans, shareEv: updated } }); }} className="w-full px-3 py-2 border border-slate-200 rounded-lg text-sm" rows={2} placeholder="Enter plan description..." />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button onClick={() => addNewPlan('shareEv')} className="w-full py-3 border-2 border-dashed border-slate-300 rounded-xl text-slate-500 hover:border-green-400 hover:text-green-500 hover:bg-green-50 transition-all flex items-center justify-center gap-2 text-sm font-medium">
|
||||
<Plus className="w-4 h-4" /> Add New Plan
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user