refactor: update parts schema to include buying and selling prices and implement CRUD functionality in settings page

This commit is contained in:
sazzadulalambd
2026-05-06 02:06:06 +06:00
parent 29ba783b53
commit ac23e8797a

View File

@@ -70,7 +70,7 @@ interface CompanySettings {
documents: { id: string; name: string; required: boolean; description: string }[];
}[];
};
parts: { id: string; name: string; price?: number; minPrice?: number; maxPrice?: number; inStock: number }[];
parts: { id: string; name: string; buyingPrice: number; sellingPrice: number }[];
serviceCenters: { id: string; name: string; address: string; phone: string; rating: number }[];
companyPolicy: {
investor: { title: string; description: string }[];
@@ -333,21 +333,21 @@ const initialSettings: CompanySettings = {
]
},
parts: [
{ id: 'PRT-001', name: 'Battery 60V', price: 15000, inStock: 25 },
{ id: 'PRT-002', name: 'Battery 48V', price: 12000, inStock: 30 },
{ id: 'PRT-003', name: 'Front Tire', price: 2500, inStock: 50 },
{ id: 'PRT-004', name: 'Rear Tire', price: 2500, inStock: 50 },
{ id: 'PRT-005', name: 'Brake Pad', price: 800, inStock: 100 },
{ id: 'PRT-006', name: 'Mirror', price: 350, inStock: 80 },
{ id: 'PRT-007', name: 'Controller', minPrice: 3500, maxPrice: 5000, inStock: 15 },
{ id: 'PRT-008', name: 'Motor', minPrice: 8000, maxPrice: 12000, inStock: 10 },
{ id: 'PRT-009', name: 'Charger', minPrice: 1500, maxPrice: 2500, inStock: 20 },
{ id: 'PRT-010', name: 'Display Meter', price: 1200, inStock: 25 },
{ id: 'PRT-011', name: 'Throttle', price: 800, inStock: 40 },
{ id: 'PRT-012', name: 'Brake Cable', price: 250, inStock: 60 },
{ id: 'PRT-013', name: 'Chain', price: 600, inStock: 35 },
{ id: 'PRT-014', name: 'Sprocket', price: 450, inStock: 45 },
{ id: 'PRT-015', name: 'Foot Peg', price: 300, inStock: 50 },
{ id: 'PRT-001', name: 'Battery 60V', buyingPrice: 12000, sellingPrice: 15000 },
{ id: 'PRT-002', name: 'Battery 48V', buyingPrice: 9000, sellingPrice: 12000 },
{ id: 'PRT-003', name: 'Front Tire', buyingPrice: 1800, sellingPrice: 2500 },
{ id: 'PRT-004', name: 'Rear Tire', buyingPrice: 1800, sellingPrice: 2500 },
{ id: 'PRT-005', name: 'Brake Pad', buyingPrice: 500, sellingPrice: 800 },
{ id: 'PRT-006', name: 'Mirror', buyingPrice: 200, sellingPrice: 350 },
{ id: 'PRT-007', name: 'Controller', buyingPrice: 3000, sellingPrice: 4500 },
{ id: 'PRT-008', name: 'Motor', buyingPrice: 7000, sellingPrice: 10000 },
{ id: 'PRT-009', name: 'Charger', buyingPrice: 1200, sellingPrice: 2000 },
{ id: 'PRT-010', name: 'Display Meter', buyingPrice: 800, sellingPrice: 1200 },
{ id: 'PRT-011', name: 'Throttle', buyingPrice: 500, sellingPrice: 800 },
{ id: 'PRT-012', name: 'Brake Cable', buyingPrice: 150, sellingPrice: 250 },
{ id: 'PRT-013', name: 'Chain', buyingPrice: 400, sellingPrice: 600 },
{ id: 'PRT-014', name: 'Sprocket', buyingPrice: 300, sellingPrice: 450 },
{ id: 'PRT-015', name: 'Foot Peg', buyingPrice: 180, sellingPrice: 300 },
],
serviceCenters: [
{ id: 'SC-001', name: 'JAIBEN Service Center - Gulshan', address: 'House 45, Road 13, Gulshan 1, Dhaka', phone: '+8801712345670', rating: 4.8 },
@@ -1802,47 +1802,86 @@ export default function CompanySettingsPage() {
{activeTab === 'parts' && (
<div className="p-6 space-y-6">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-slate-800">EV Parts</h3>
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-slate-50">
<tr>
<th className="px-3 py-2 text-left text-xs font-semibold">Part ID</th>
<th className="px-3 py-2 text-left text-xs font-semibold">Name</th>
<th className="px-3 py-2 text-left text-xs font-semibold">Price Range</th>
<th className="px-3 py-2 text-left text-xs font-semibold">In Stock</th>
<th className="px-3 py-2 text-left text-xs font-semibold">Type</th>
</tr>
</thead>
<tbody>
{settings.parts.map(part => (
<tr key={part.id} className="border-t">
<td className="px-3 py-2 text-sm">{part.id}</td>
<td className="px-3 py-2 text-sm font-medium">{part.name}</td>
<td className="px-3 py-2 text-sm">
{part.minPrice && part.maxPrice ? (
<span className="text-amber-600">{part.minPrice} - {part.maxPrice}</span>
) : part.price ? (
<span>{part.price}</span>
) : (
<span className="text-slate-400">-</span>
)}
</td>
<td className="px-3 py-2 text-sm">{part.inStock}</td>
<td className="px-3 py-2 text-sm">
{part.minPrice ? (
<span className="text-xs px-2 py-0.5 bg-amber-100 text-amber-700 rounded">Range</span>
) : (
<span className="text-xs px-2 py-0.5 bg-green-100 text-green-700 rounded">Fixed</span>
)}
</td>
</tr>
))}
</tbody>
</table>
<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 Part
</button>
</div>
{showAddPolicy && activeTab === 'parts' && (
<div className="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="Part Name" />
<div className="grid grid-cols-2 gap-2 mb-2">
<input type="number" value={newPolicyDesc} onChange={(e) => setNewPolicyDesc(e.target.value)} className="px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Buying Price" />
<input type="number" value={editPolicyDescHtml} onChange={(e) => setEditPolicyDescHtml(e.target.value)} className="px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Selling Price" />
</div>
<div className="flex gap-2">
<button onClick={() => {
if (!newPolicyName.trim()) return;
const newId = 'PRT-' + String(settings.parts.length + 1).padStart(3, '0');
setSettings({ ...settings, parts: [...settings.parts, { id: newId, name: newPolicyName, buyingPrice: Number(newPolicyDesc), sellingPrice: Number(editPolicyDescHtml) }] });
setNewPolicyName('');
setNewPolicyDesc('');
setEditPolicyDescHtml('');
setShowAddPolicy(false);
}} className="px-3 py-1.5 bg-blue-600 text-white rounded text-sm">Add</button>
<button onClick={() => { setNewPolicyName(''); setNewPolicyDesc(''); setEditPolicyDescHtml(''); setShowAddPolicy(false); }} className="px-3 py-1.5 bg-slate-200 text-slate-600 rounded text-sm">Cancel</button>
</div>
</div>
)}
<div className="space-y-2">
{settings.parts.map((part, i) => (
<div key={part.id} className="p-3 bg-slate-50 rounded-lg border border-slate-200">
{editingPolicy?.tab === 'parts' && 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="Part Name" />
<div className="grid grid-cols-2 gap-2">
<input type="number" value={editPolicyDesc} onChange={(e) => setEditPolicyDesc(e.target.value)} className="px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Buying Price" />
<input type="number" value={newPolicyName} onChange={(e) => setNewPolicyName(e.target.value)} className="px-2 py-1.5 border border-slate-200 rounded text-sm" placeholder="Selling Price" />
</div>
<div className="flex gap-2">
<button onClick={() => {
const updated = [...settings.parts];
updated[i] = { ...part, name: editPolicyName, buyingPrice: Number(editPolicyDesc), sellingPrice: Number(newPolicyName) };
setSettings({ ...settings, parts: updated });
setEditingPolicy(null);
setEditPolicyName('');
setEditPolicyDesc('');
setNewPolicyName('');
}} className="px-2 py-1 bg-blue-600 text-white rounded text-xs">Save</button>
<button onClick={() => { setEditingPolicy(null); setEditPolicyName(''); setEditPolicyDesc(''); setNewPolicyName(''); }} className="px-2 py-1 bg-slate-200 text-slate-600 rounded text-xs">Cancel</button>
</div>
</div>
) : (
<div className="flex items-center justify-between">
<div className="flex-1">
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-slate-700">{part.name}</span>
<span className="text-xs text-slate-400">({part.id})</span>
</div>
<div className="flex items-center gap-4 mt-1">
<span className="text-xs text-slate-500">Buying: <span className="text-green-600">{part.buyingPrice}</span></span>
<span className="text-xs text-slate-500">Selling: <span className="text-amber-600">{part.sellingPrice}</span></span>
</div>
</div>
<div className="flex items-center gap-1 ml-2">
<button onClick={() => { setEditingPolicy({ tab: 'parts', index: i }); setEditPolicyName(part.name); setEditPolicyDesc(String(part.buyingPrice)); setNewPolicyName(String(part.sellingPrice)); }} className="p-1 text-slate-400 hover:text-blue-600">
<Pencil className="w-3.5 h-3.5" />
</button>
<button onClick={() => {
const updated = settings.parts.filter((_, idx) => idx !== i);
setSettings({ ...settings, parts: 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 className="mt-4 text-sm text-accent hover:underline">+ Add Part</button>
</div>
)}