"use client"; import { useEffect, useState } from "react"; import Link from "next/link"; const API_BASE_URL = process.env.NEXT_PUBLIC_API_BASE_URL ?? ""; type AdminOverview = { totalProducts: number; mappedProducts: number; unmappedProducts: number; merchantCount: number; categoryMappingCount: number; }; export default function AdminLandingPage() { const [overview, setOverview] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { async function load() { try { setLoading(true); setError(null); const res = await fetch(`${API_BASE_URL}/api/admin/dashboard/overview`); if (!res.ok) { throw new Error(`Failed to load dashboard (${res.status})`); } const data: AdminOverview = await res.json(); setOverview(data); } catch (e: any) { console.error(e); setError(e.message ?? "Failed to load admin dashboard"); } finally { setLoading(false); } } load(); }, []); return (

Battl Builder – Admin

Control room for feeds, mappings, and catalog health.

{loading && (

Loading dashboard…

)} {error && (

Error: {error}

)} {overview && !loading && !error && ( <> {/* Stats row */}

Total Products

{overview.totalProducts.toLocaleString()}

Mapped Products

{overview.mappedProducts.toLocaleString()}

Unmapped Products

{overview.unmappedProducts.toLocaleString()}

Products still in PENDING_MAPPING.

Merchants / Mappings

{overview.merchantCount}{" "} merchants

{overview.categoryMappingCount.toLocaleString()} mappings

{/* Nav cards */}

Admin Tools

{/* Bulk Mapping */}

Bulk Category Mapping

Bucket raw merchant categories and map them to part roles to keep the catalog clean.

{overview.unmappedProducts.toLocaleString()} products pending mapping

{/* Import Status */}

Import Status

Inspect last feed runs, per-merchant health, and errors.

View import summaries  →

{/* Placeholder for future admin tools */}

Catalog Explorer

(Future) Browse normalized products, offers, and compatibility.

Coming soon

)}
); }