// app/admin/category-mappings/page.tsx "use client"; import { useEffect, useState } from "react"; import { useAuth } from "@/context/AuthContext"; import { fetchAdminCategories, fetchPartRoleMappings, createPartRoleMapping, updatePartRoleMapping, deletePartRoleMapping, type AdminCategory, type AdminPartRoleMapping, } from "@/lib/api/adminCategoryMappings"; export default function AdminCategoryMappingsPage() { const { token } = useAuth(); const [categories, setCategories] = useState([]); const [mappings, setMappings] = useState([]); const [platform, setPlatform] = useState("AR-15"); const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); useEffect(() => { if (!token) return; const load = async () => { try { setLoading(true); const [cats, maps] = await Promise.all([ fetchAdminCategories(token), fetchPartRoleMappings(token, platform), ]); setCategories(cats); setMappings(maps); } catch (e: any) { console.error(e); setError(e?.message ?? "Failed to load mappings"); } finally { setLoading(false); } }; load(); }, [token, platform]); const handleCreate = async () => { if (!token) return; const defaultCategory = categories[0]; if (!defaultCategory) return; try { setSaving(true); const created = await createPartRoleMapping(token, { platform, partRole: "NEW_PART_ROLE", categorySlug: defaultCategory.slug, }); setMappings((prev) => [...prev, created]); } catch (e: any) { console.error(e); setError(e?.message ?? "Failed to create mapping"); } finally { setSaving(false); } }; const handleUpdate = async (row: AdminPartRoleMapping, updates: Partial) => { if (!token) return; try { setSaving(true); const updated = await updatePartRoleMapping(token, row.id, { platform: updates.platform ?? row.platform, partRole: updates.partRole ?? row.partRole, categorySlug: updates.categorySlug ?? row.categorySlug, notes: updates.notes ?? row.notes ?? undefined, }); setMappings((prev) => prev.map((m) => (m.id === row.id ? updated : m))); } catch (e: any) { console.error(e); setError(e?.message ?? "Failed to update mapping"); } finally { setSaving(false); } }; const handleDelete = async (row: AdminPartRoleMapping) => { if (!token) return; if (!confirm(`Delete mapping for ${row.partRole}?`)) return; try { setSaving(true); await deletePartRoleMapping(token, row.id); setMappings((prev) => prev.filter((m) => m.id !== row.id)); } catch (e: any) { console.error(e); setError(e?.message ?? "Failed to delete mapping"); } finally { setSaving(false); } }; if (!token) { return
You must be logged in to view this page.
; } return (

Part role → category mappings

FOR LATER! Advanced mapping: defines which canonical category each builder part role uses for a given platform.

{error && (
{error}
)} {loading ? (
Loading…
) : (
{mappings.map((row) => ( ))} {mappings.length === 0 && ( )}
Platform Part role Category Group Notes Actions
{row.platform} { if (e.target.value !== row.partRole) { handleUpdate(row, { partRole: e.target.value }); } }} /> {row.groupName} { if (e.target.value !== (row.notes ?? "")) { handleUpdate(row, { notes: e.target.value }); } }} />
No mappings yet for {platform}. Click “Add mapping” to get started.
)}
); }