diff --git a/app/admin/merchants/page.tsx b/app/admin/merchants/page.tsx index 24b2027..690fe09 100644 --- a/app/admin/merchants/page.tsx +++ b/app/admin/merchants/page.tsx @@ -32,6 +32,17 @@ export default function MerchantsAdminPage() { const [offerSyncId, setOfferSyncId] = useState(null); const [banner, setBanner] = useState(null); + // --- new merchant form state --- + const [showNewMerchantForm, setShowNewMerchantForm] = useState(false); + const [creating, setCreating] = useState(false); + const [newMerchant, setNewMerchant] = useState({ + name: "", + avantlinkMid: "", + feedUrl: "", + offerFeedUrl: "", + isActive: true, + }); + // --- load merchants --- useEffect(() => { const controller = new AbortController(); @@ -179,6 +190,56 @@ export default function MerchantsAdminPage() { } }; + // --- create new merchant --- + const handleCreateMerchant = async () => { + try { + setCreating(true); + setError(null); + setBanner(null); + + const res = await fetch(`${API_BASE_URL}/api/v1/admin/merchants`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + name: newMerchant.name, + avantlinkMid: newMerchant.avantlinkMid, + feedUrl: newMerchant.feedUrl, + offerFeedUrl: newMerchant.offerFeedUrl || null, + isActive: newMerchant.isActive, + }), + }); + + if (!res.ok) { + const text = await res.text().catch(() => ""); + console.error("Merchant creation failed", res.status, text); + throw new Error( + `Creation failed (${res.status})${text ? `: ${text}` : ""}` + ); + } + + const created: MerchantAdminDto = await res.json(); + setMerchants((prev) => [...prev, created]); + + // Reset form + setNewMerchant({ + name: "", + avantlinkMid: "", + feedUrl: "", + offerFeedUrl: "", + isActive: true, + }); + setShowNewMerchantForm(false); + + setBanner("Merchant created successfully."); + } catch (e: any) { + console.error("Error creating merchant", e); + setError(e?.message ?? "Failed to create merchant"); + } finally { + setCreating(false); + setTimeout(() => setBanner(null), 3000); + } + }; + return (
@@ -211,6 +272,152 @@ export default function MerchantsAdminPage() {
)} + {/* Add New Merchant Section */} +
+ {!showNewMerchantForm ? ( + + ) : ( +
+
+

+ Add New Merchant +

+ +
+ +
+
+ + + setNewMerchant((prev) => ({ ...prev, name: e.target.value })) + } + placeholder="e.g., Brownells" + className="w-full rounded-md border border-zinc-700 bg-zinc-900 px-3 py-2 text-sm text-zinc-50 placeholder:text-zinc-600 focus:border-amber-400/70 focus:outline-none focus:ring-0" + /> +
+ +
+ + + setNewMerchant((prev) => ({ + ...prev, + avantlinkMid: e.target.value, + })) + } + placeholder="e.g., 12345" + className="w-full rounded-md border border-zinc-700 bg-zinc-900 px-3 py-2 text-sm text-zinc-50 placeholder:text-zinc-600 focus:border-amber-400/70 focus:outline-none focus:ring-0" + /> +
+ +
+ + + setNewMerchant((prev) => ({ ...prev, feedUrl: e.target.value })) + } + placeholder="https://..." + className="w-full rounded-md border border-zinc-700 bg-zinc-900 px-3 py-2 text-sm text-zinc-50 placeholder:text-zinc-600 focus:border-amber-400/70 focus:outline-none focus:ring-0" + /> +
+ +
+ + + setNewMerchant((prev) => ({ + ...prev, + offerFeedUrl: e.target.value, + })) + } + placeholder="https://..." + className="w-full rounded-md border border-zinc-700 bg-zinc-900 px-3 py-2 text-sm text-zinc-50 placeholder:text-zinc-600 focus:border-amber-400/70 focus:outline-none focus:ring-0" + /> +
+ +
+ +
+
+ +
+ +
+
+ )} +
+ {/* Table */}
{loading ? ( diff --git a/components/parts/PartsBrowseClient.tsx b/components/parts/PartsBrowseClient.tsx index 6bb31b4..5a27068 100644 --- a/components/parts/PartsBrowseClient.tsx +++ b/components/parts/PartsBrowseClient.tsx @@ -303,7 +303,7 @@ export default function PartsBrowseClient(props: { end: Math.min(currentPage * PAGE_SIZE, serverTotalElements), }; - const headingTitle = props.title ?? `${partRole.replaceAll("-", " ")} parts`; + const headingTitle = props.title ?? `${partRole.replaceAll("-", " ")}s`; const headingSubtitle = props.subtitle ?? "Browse available parts."; // ----------------------------