feat: add functionality to create, edit, and delete company policy rules in admin settings
This commit is contained in:
@@ -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, Zap, Users, Check, Pencil } 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, Users, Check, Pencil, Trash2 } from 'lucide-react';
|
||||
import RichTextEditor from '@/components/RichTextEditor';
|
||||
|
||||
interface CompanySettings {
|
||||
@@ -679,6 +679,10 @@ export default function CompanySettingsPage() {
|
||||
const [editingPolicy, setEditingPolicy] = useState<{tab: string; index: number} | null>(null);
|
||||
const [editPolicyName, setEditPolicyName] = useState('');
|
||||
const [editPolicyDesc, setEditPolicyDesc] = useState('');
|
||||
const [editPolicyDescHtml, setEditPolicyDescHtml] = useState('');
|
||||
const [showAddPolicy, setShowAddPolicy] = useState(false);
|
||||
const [newPolicyName, setNewPolicyName] = useState('');
|
||||
const [newPolicyDesc, setNewPolicyDesc] = useState('');
|
||||
const [addInvestPlan, setAddInvestPlan] = useState(false);
|
||||
const [newInvestName, setNewInvestName] = useState('');
|
||||
const [newInvestTier, setNewInvestTier] = useState('Standard');
|
||||
@@ -802,6 +806,51 @@ setNewSwapName('');
|
||||
setTimeout(() => setSaved(false), 2000);
|
||||
};
|
||||
|
||||
const addPolicyRule = (tab: 'investor' | 'merchant' | 'swapstation') => {
|
||||
if (!newPolicyName.trim()) return;
|
||||
const newRule = { name: newPolicyName, description: newPolicyDesc };
|
||||
if (tab === 'investor') {
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, investor: { ...settings.companyPolicy.investor, rules: [...settings.companyPolicy.investor.rules, newRule] } } });
|
||||
} else if (tab === 'merchant') {
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, merchant: { ...settings.companyPolicy.merchant, rules: [...settings.companyPolicy.merchant.rules, newRule] } } });
|
||||
} else if (tab === 'swapstation') {
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, swapStation: { ...settings.companyPolicy.swapStation, rules: [...settings.companyPolicy.swapStation.rules, newRule] } } });
|
||||
}
|
||||
setNewPolicyName('');
|
||||
setNewPolicyDesc('');
|
||||
setShowAddPolicy(false);
|
||||
};
|
||||
|
||||
const deletePolicyRule = (tab: 'investor' | 'merchant' | 'swapstation', index: number) => {
|
||||
if (tab === 'investor') {
|
||||
const newRules = settings.companyPolicy.investor.rules.filter((_, i) => i !== index);
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, investor: { ...settings.companyPolicy.investor, rules: newRules } } });
|
||||
} else if (tab === 'merchant') {
|
||||
const newRules = settings.companyPolicy.merchant.rules.filter((_, i) => i !== index);
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, merchant: { ...settings.companyPolicy.merchant, rules: newRules } } });
|
||||
} else if (tab === 'swapstation') {
|
||||
const newRules = settings.companyPolicy.swapStation.rules.filter((_, i) => i !== index);
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, swapStation: { ...settings.companyPolicy.swapStation, rules: newRules } } });
|
||||
}
|
||||
};
|
||||
|
||||
const updatePolicyRule = (tab: 'investor' | 'merchant' | 'swapstation', index: number) => {
|
||||
if (tab === 'investor') {
|
||||
const newRules = [...settings.companyPolicy.investor.rules];
|
||||
newRules[index] = { name: editPolicyName, description: editPolicyDesc };
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, investor: { ...settings.companyPolicy.investor, rules: newRules } } });
|
||||
} else if (tab === 'merchant') {
|
||||
const newRules = [...settings.companyPolicy.merchant.rules];
|
||||
newRules[index] = { name: editPolicyName, description: editPolicyDesc };
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, merchant: { ...settings.companyPolicy.merchant, rules: newRules } } });
|
||||
} else if (tab === 'swapstation') {
|
||||
const newRules = [...settings.companyPolicy.swapStation.rules];
|
||||
newRules[index] = { name: editPolicyName, description: editPolicyDesc };
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, swapStation: { ...settings.companyPolicy.swapStation, rules: newRules } } });
|
||||
}
|
||||
setEditingPolicy(null);
|
||||
};
|
||||
|
||||
const tabs = [
|
||||
{ id: 'general', label: 'General', icon: Settings },
|
||||
{ id: 'branding', label: 'Branding', icon: Palette },
|
||||
@@ -1842,10 +1891,23 @@ setNewSwapName('');
|
||||
<div className="border-t border-slate-200 pt-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<label className="text-sm text-slate-600 font-medium">Policy List</label>
|
||||
<button onClick={() => setShowAddPolicy(true)} className="text-xs text-blue-600 hover:text-blue-700 flex items-center gap-1">
|
||||
<Plus className="w-3 h-3" /> Add Policy
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{(settings.companyPolicy?.investor?.rules || []).map((policy, i) => (
|
||||
<div key={i} className="p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
{editingPolicy?.tab === 'investor' && editingPolicy?.index === i ? (
|
||||
<div className="space-y-2">
|
||||
<input type="text" value={editPolicyName} onChange={(e) => setEditPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Policy Name" />
|
||||
<textarea value={editPolicyDesc} onChange={(e) => setEditPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => updatePolicyRule('investor', i)} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Save</button>
|
||||
<button onClick={() => setEditingPolicy(null)} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -1853,10 +1915,29 @@ setNewSwapName('');
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-1">{policy.description}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 ml-2">
|
||||
<button onClick={() => { setEditingPolicy({ tab: 'investor', index: i }); setEditPolicyName(policy.name); setEditPolicyDesc(policy.description); }} className="p-1 text-slate-400 hover:text-blue-600">
|
||||
<Pencil className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button onClick={() => deletePolicyRule('investor', i)} className="p-1 text-slate-400 hover:text-red-600">
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{showAddPolicy && (
|
||||
<div className="mt-2 p-3 bg-white rounded-lg border border-blue-200">
|
||||
<input type="text" value={newPolicyName} onChange={(e) => setNewPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" placeholder="Policy Name" />
|
||||
<textarea value={newPolicyDesc} onChange={(e) => setNewPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => addPolicyRule('investor')} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Add</button>
|
||||
<button onClick={() => { setShowAddPolicy(false); setNewPolicyName(''); setNewPolicyDesc(''); }} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -1877,10 +1958,23 @@ setNewSwapName('');
|
||||
<div className="border-t border-slate-200 pt-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<label className="text-sm text-slate-600 font-medium">Policy List</label>
|
||||
<button onClick={() => setShowAddPolicy(true)} className="text-xs text-blue-600 hover:text-blue-700 flex items-center gap-1">
|
||||
<Plus className="w-3 h-3" /> Add Policy
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{(settings.companyPolicy?.merchant?.rules || []).map((policy, i) => (
|
||||
<div key={i} className="p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
{editingPolicy?.tab === 'merchant' && editingPolicy?.index === i ? (
|
||||
<div className="space-y-2">
|
||||
<input type="text" value={editPolicyName} onChange={(e) => setEditPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Policy Name" />
|
||||
<textarea value={editPolicyDesc} onChange={(e) => setEditPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => updatePolicyRule('merchant', i)} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Save</button>
|
||||
<button onClick={() => setEditingPolicy(null)} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -1888,10 +1982,29 @@ setNewSwapName('');
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-1">{policy.description}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 ml-2">
|
||||
<button onClick={() => { setEditingPolicy({ tab: 'merchant', index: i }); setEditPolicyName(policy.name); setEditPolicyDesc(policy.description); }} className="p-1 text-slate-400 hover:text-blue-600">
|
||||
<Pencil className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button onClick={() => deletePolicyRule('merchant', i)} className="p-1 text-slate-400 hover:text-red-600">
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{showAddPolicy && (
|
||||
<div className="mt-2 p-3 bg-white rounded-lg border border-blue-200">
|
||||
<input type="text" value={newPolicyName} onChange={(e) => setNewPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" placeholder="Policy Name" />
|
||||
<textarea value={newPolicyDesc} onChange={(e) => setNewPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => addPolicyRule('merchant')} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Add</button>
|
||||
<button onClick={() => { setShowAddPolicy(false); setNewPolicyName(''); setNewPolicyDesc(''); }} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -1912,10 +2025,23 @@ setNewSwapName('');
|
||||
<div className="border-t border-slate-200 pt-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<label className="text-sm text-slate-600 font-medium">Policy List</label>
|
||||
<button onClick={() => setShowAddPolicy(true)} className="text-xs text-blue-600 hover:text-blue-700 flex items-center gap-1">
|
||||
<Plus className="w-3 h-3" /> Add Policy
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{(settings.companyPolicy?.swapStation?.rules || []).map((policy, i) => (
|
||||
<div key={i} className="p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
{editingPolicy?.tab === 'swapstation' && editingPolicy?.index === i ? (
|
||||
<div className="space-y-2">
|
||||
<input type="text" value={editPolicyName} onChange={(e) => setEditPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Policy Name" />
|
||||
<textarea value={editPolicyDesc} onChange={(e) => setEditPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => updatePolicyRule('swapstation', i)} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Save</button>
|
||||
<button onClick={() => setEditingPolicy(null)} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -1923,10 +2049,29 @@ setNewSwapName('');
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-1">{policy.description}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 ml-2">
|
||||
<button onClick={() => { setEditingPolicy({ tab: 'swapstation', index: i }); setEditPolicyName(policy.name); setEditPolicyDesc(policy.description); }} className="p-1 text-slate-400 hover:text-blue-600">
|
||||
<Pencil className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button onClick={() => deletePolicyRule('swapstation', i)} className="p-1 text-slate-400 hover:text-red-600">
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{showAddPolicy && (
|
||||
<div className="mt-2 p-3 bg-white rounded-lg border border-blue-200">
|
||||
<input type="text" value={newPolicyName} onChange={(e) => setNewPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" placeholder="Policy Name" />
|
||||
<textarea value={newPolicyDesc} onChange={(e) => setNewPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => addPolicyRule('swapstation')} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Add</button>
|
||||
<button onClick={() => { setShowAddPolicy(false); setNewPolicyName(''); setNewPolicyDesc(''); }} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -1936,15 +2081,8 @@ setNewSwapName('');
|
||||
{(settings.companyPolicy?.rentalTypes || []).map((rtype, idx) => (
|
||||
<div key={idx} className="border border-slate-200 rounded-lg overflow-hidden">
|
||||
<div className="bg-slate-50 px-4 py-3 flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<input type="checkbox" checked={rtype.enabled} onChange={(e) => {
|
||||
const updated = [...(settings.companyPolicy?.rentalTypes || [])];
|
||||
updated[idx] = { ...updated[idx], enabled: e.target.checked };
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, rentalTypes: updated } });
|
||||
}} className="w-4 h-4" />
|
||||
<h4 className="font-medium text-slate-700">{rtype.name}</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-4 space-y-3">
|
||||
<input type="text" value={rtype.title} onChange={(e) => {
|
||||
const updated = [...(settings.companyPolicy?.rentalTypes || [])];
|
||||
@@ -1956,6 +2094,73 @@ setNewSwapName('');
|
||||
updated[idx] = { ...updated[idx], description: val };
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, rentalTypes: updated } });
|
||||
}} placeholder="Enter policy description..." minHeight={120} />
|
||||
<div className="border-t border-slate-200 pt-4 mt-4">
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<label className="text-sm text-slate-600 font-medium">Policy List</label>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{(rtype.rules || []).map((policy, policyIdx) => (
|
||||
<div key={policyIdx} className="p-3 bg-slate-50 rounded-lg border border-slate-200">
|
||||
{editingPolicy?.tab === 'rentalType' && editingPolicy?.index === policyIdx ? (
|
||||
<div className="space-y-2">
|
||||
<input type="text" value={editPolicyName} onChange={(e) => setEditPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Policy Name" />
|
||||
<textarea value={editPolicyDesc} onChange={(e) => setEditPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => {
|
||||
const updated = [...(settings.companyPolicy?.rentalTypes || [])];
|
||||
updated[idx].rules[policyIdx] = { name: editPolicyName, description: editPolicyDesc };
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, rentalTypes: updated } });
|
||||
setEditingPolicy(null);
|
||||
}} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Save</button>
|
||||
<button onClick={() => setEditingPolicy(null)} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-slate-700">{policy.name}</span>
|
||||
</div>
|
||||
<p className="text-xs text-slate-500 mt-1">{policy.description}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 ml-2">
|
||||
<button onClick={() => { setEditingPolicy({ tab: 'rentalType', index: policyIdx }); setEditPolicyName(policy.name); setEditPolicyDesc(policy.description); }} className="p-1 text-slate-400 hover:text-blue-600">
|
||||
<Pencil className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
<button onClick={() => {
|
||||
const updated = [...(settings.companyPolicy?.rentalTypes || [])];
|
||||
updated[idx].rules = updated[idx].rules?.filter((_, i) => i !== policyIdx);
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, rentalTypes: updated } });
|
||||
}} className="p-1 text-slate-400 hover:text-red-600">
|
||||
<Trash2 className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button onClick={() => setEditingPolicy({ tab: 'rentalTypeAdd', index: idx })} className="mt-2 text-xs text-blue-600 hover:text-blue-700 flex items-center gap-1">
|
||||
<Plus className="w-3 h-3" /> Add Policy
|
||||
</button>
|
||||
{editingPolicy?.tab === 'rentalTypeAdd' && editingPolicy?.index === idx && (
|
||||
<div className="mt-2 p-3 bg-white rounded-lg border border-blue-200">
|
||||
<input type="text" value={newPolicyName} onChange={(e) => setNewPolicyName(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" placeholder="Policy Name" />
|
||||
<textarea value={newPolicyDesc} onChange={(e) => setNewPolicyDesc(e.target.value)} className="w-full px-2 py-1.5 border border-slate-200 rounded text-sm mb-2" rows={2} placeholder="Description" />
|
||||
<div className="flex gap-2">
|
||||
<button onClick={() => {
|
||||
const updated = [...(settings.companyPolicy?.rentalTypes || [])];
|
||||
updated[idx].rules = [...(updated[idx].rules || []), { name: newPolicyName, description: newPolicyDesc }];
|
||||
setSettings({ ...settings, companyPolicy: { ...settings.companyPolicy, rentalTypes: updated } });
|
||||
setNewPolicyName('');
|
||||
setNewPolicyDesc('');
|
||||
setEditingPolicy(null);
|
||||
}} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Add</button>
|
||||
<button onClick={() => { setEditingPolicy(null); setNewPolicyName(''); setNewPolicyDesc(''); }} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user