/admin and with working with db. data is pulling from db
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
"use client";
|
||||
import { useEffect, useState, ChangeEvent, FormEvent } from "react";
|
||||
|
||||
type Mapping = {
|
||||
id: number;
|
||||
feedname: string;
|
||||
affiliatecategory: string;
|
||||
buildercategoryid: number;
|
||||
notes?: string;
|
||||
};
|
||||
|
||||
type MappingForm = {
|
||||
feedname: string;
|
||||
affiliatecategory: string;
|
||||
buildercategoryid: string;
|
||||
notes?: string;
|
||||
};
|
||||
|
||||
export default function CategoryMappingAdmin() {
|
||||
const [mappings, setMappings] = useState<Mapping[]>([]);
|
||||
const [form, setForm] = useState<MappingForm>({ feedname: "", affiliatecategory: "", buildercategoryid: "", notes: "" });
|
||||
const [editingId, setEditingId] = useState<number | null>(null);
|
||||
const [editForm, setEditForm] = useState<MappingForm>({ feedname: "", affiliatecategory: "", buildercategoryid: "", notes: "" });
|
||||
const [productCategories, setProductCategories] = useState<any[]>([]);
|
||||
|
||||
// Fetch all mappings
|
||||
const fetchMappings = async () => {
|
||||
const res = await fetch("/api/category-mapping");
|
||||
const data = await res.json();
|
||||
setMappings(data.data || []);
|
||||
};
|
||||
|
||||
const fetchProductCategories = async () => {
|
||||
const res = await fetch("/api/product-categories");
|
||||
const data = await res.json();
|
||||
setProductCategories(data.data || []);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchMappings();
|
||||
fetchProductCategories();
|
||||
}, []);
|
||||
|
||||
// Add new mapping
|
||||
const handleAdd = async (e: FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
await fetch("/api/category-mapping", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
...form,
|
||||
buildercategoryid: parseInt(form.buildercategoryid, 10)
|
||||
}),
|
||||
});
|
||||
setForm({ feedname: "", affiliatecategory: "", buildercategoryid: "", notes: "" });
|
||||
fetchMappings();
|
||||
};
|
||||
|
||||
// Edit mapping
|
||||
const handleEdit = (mapping: Mapping) => {
|
||||
setEditingId(mapping.id);
|
||||
setEditForm({ ...mapping, buildercategoryid: mapping.buildercategoryid.toString() });
|
||||
};
|
||||
|
||||
const handleUpdate = async (e: FormEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
await fetch("/api/category-mapping", {
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ ...editForm, buildercategoryid: parseInt(editForm.buildercategoryid, 10), id: editingId }),
|
||||
});
|
||||
setEditingId(null);
|
||||
fetchMappings();
|
||||
};
|
||||
|
||||
// Delete mapping
|
||||
const handleDelete = async (id: number) => {
|
||||
await fetch("/api/category-mapping", {
|
||||
method: "DELETE",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ id }),
|
||||
});
|
||||
fetchMappings();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto py-8">
|
||||
<h1 className="text-2xl font-bold mb-4">Affiliate Category Mapping Admin</h1>
|
||||
<div className="mb-8">
|
||||
<h2 className="text-xl font-semibold mb-2">AR15 Category Hierarchy</h2>
|
||||
<table className="min-w-full border text-sm">
|
||||
<thead>
|
||||
<tr className="bg-zinc-100">
|
||||
<th className="border px-2 py-1">ID</th>
|
||||
<th className="border px-2 py-1">Category</th>
|
||||
<th className="border px-2 py-1">Parent</th>
|
||||
<th className="border px-2 py-1">Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{productCategories
|
||||
.filter(cat => cat.type === 'AR15')
|
||||
.map(cat => {
|
||||
const parent = productCategories.find(p => p.id === cat.parent_category_id);
|
||||
return (
|
||||
<tr key={cat.id}>
|
||||
<td className="border px-2 py-1">{cat.id}</td>
|
||||
<td className="border px-2 py-1">{cat.name}</td>
|
||||
<td className="border px-2 py-1">{parent ? parent.name : 'Top Level'}</td>
|
||||
<td className="border px-2 py-1">{cat.type}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<form onSubmit={handleAdd} className="flex gap-2 mb-6">
|
||||
<input className="border px-2 py-1 rounded w-32" placeholder="Feed Name" value={form.feedname} onChange={e => setForm(f => ({ ...f, feedname: e.target.value }))} required />
|
||||
<input className="border px-2 py-1 rounded w-48" placeholder="Affiliate Category" value={form.affiliatecategory} onChange={e => setForm(f => ({ ...f, affiliatecategory: e.target.value }))} required />
|
||||
<input className="border px-2 py-1 rounded w-40" placeholder="Builder Category ID" value={form.buildercategoryid} onChange={e => setForm(f => ({ ...f, buildercategoryid: e.target.value }))} required />
|
||||
<input className="border px-2 py-1 rounded w-32" placeholder="Notes" value={form.notes} onChange={e => setForm(f => ({ ...f, notes: e.target.value }))} />
|
||||
<button className="bg-blue-600 text-white px-3 py-1 rounded" type="submit">Add</button>
|
||||
</form>
|
||||
<table className="min-w-full border text-sm">
|
||||
<thead>
|
||||
<tr className="bg-zinc-100">
|
||||
<th className="border px-2 py-1">Feed Name</th>
|
||||
<th className="border px-2 py-1">Affiliate Category</th>
|
||||
<th className="border px-2 py-1">Builder Category ID</th>
|
||||
<th className="border px-2 py-1">Notes</th>
|
||||
<th className="border px-2 py-1">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{mappings.map((m) => (
|
||||
<tr key={m.id}>
|
||||
{editingId === m.id ? (
|
||||
<>
|
||||
<td className="border px-2 py-1"><input className="border px-1 rounded w-28" value={editForm.feedname} onChange={e => setEditForm(f => ({ ...f, feedname: e.target.value }))} /></td>
|
||||
<td className="border px-2 py-1"><input className="border px-1 rounded w-40" value={editForm.affiliatecategory} onChange={e => setEditForm(f => ({ ...f, affiliatecategory: e.target.value }))} /></td>
|
||||
<td className="border px-2 py-1"><input className="border px-1 rounded w-32" value={editForm.buildercategoryid} onChange={e => setEditForm(f => ({ ...f, buildercategoryid: e.target.value }))} /></td>
|
||||
<td className="border px-2 py-1"><input className="border px-1 rounded w-24" value={editForm.notes} onChange={e => setEditForm(f => ({ ...f, notes: e.target.value }))} /></td>
|
||||
<td className="border px-2 py-1">
|
||||
<button className="bg-green-600 text-white px-2 py-1 rounded mr-1" onClick={handleUpdate}>Save</button>
|
||||
<button className="bg-gray-400 text-white px-2 py-1 rounded" onClick={() => setEditingId(null)}>Cancel</button>
|
||||
</td>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<td className="border px-2 py-1">{m.feedname}</td>
|
||||
<td className="border px-2 py-1">{m.affiliatecategory}</td>
|
||||
<td className="border px-2 py-1">{m.buildercategoryid}</td>
|
||||
<td className="border px-2 py-1">{m.notes}</td>
|
||||
<td className="border px-2 py-1">
|
||||
<button className="bg-yellow-500 text-white px-2 py-1 rounded mr-1" onClick={() => handleEdit(m)}>Edit</button>
|
||||
<button className="bg-red-600 text-white px-2 py-1 rounded" onClick={() => handleDelete(m.id)}>Delete</button>
|
||||
</td>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user