98 lines
2.4 KiB
TypeScript
98 lines
2.4 KiB
TypeScript
// app/lib/catalog.ts
|
|
export const API_BASE_URL =
|
|
process.env.NEXT_PUBLIC_API_BASE_URL ?? "";
|
|
|
|
export type ProductListItem = {
|
|
id: string;
|
|
name: string;
|
|
brand: string;
|
|
platform: string;
|
|
partRole: string;
|
|
categoryKey?: string | null;
|
|
price?: number | null;
|
|
buyUrl?: string | null;
|
|
imageUrl?: string | null;
|
|
slug?: string | null; // if your API returns it; otherwise we derive it client-side
|
|
};
|
|
|
|
export type ProductDetail = {
|
|
id: string;
|
|
name: string;
|
|
brand: string;
|
|
platform: string;
|
|
partRole: string;
|
|
rawCategoryKey?: string | null;
|
|
description?: string | null;
|
|
shortDescription?: string | null;
|
|
imageUrl?: string | null;
|
|
offers?: Array<{
|
|
merchantName?: string;
|
|
price?: number | null;
|
|
buyUrl?: string | null;
|
|
inStock?: boolean | null;
|
|
}>;
|
|
};
|
|
|
|
export function slugify(input: string) {
|
|
return (input ?? "")
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9]+/g, "-")
|
|
.replace(/(^-|-$)/g, "");
|
|
}
|
|
|
|
/**
|
|
* Your existing list endpoint:
|
|
* GET /api/v1/products?platform=AR-15&partRoles=complete-upper
|
|
*/
|
|
export async function fetchProducts(params: {
|
|
platform: string;
|
|
partRole: string;
|
|
sort?: string; // ex: "price,asc"
|
|
}) {
|
|
const { platform, partRole, sort } = params;
|
|
|
|
const sp = new URLSearchParams({
|
|
platform,
|
|
partRoles: partRole,
|
|
});
|
|
|
|
if (sort) sp.set("sort", sort);
|
|
|
|
const url = `/api/catalog/products?${sp.toString()}`;
|
|
|
|
const res = await fetch(url, {
|
|
cache: "no-store",
|
|
credentials: 'include',
|
|
});
|
|
if (!res.ok) throw new Error(`Failed to load products (${res.status})`);
|
|
const data = (await res.json()) as ProductListItem[];
|
|
|
|
return data.map((p) => ({
|
|
...p,
|
|
productSlug: `${p.id}-${slugify(p.name)}`,
|
|
}));
|
|
}
|
|
|
|
/**
|
|
* You likely have (or should add) a detail endpoint like:
|
|
* GET /api/v1/products/{id}?platform=AR-15 OR GET /api/v1/products/{id}
|
|
*
|
|
* We'll call /api/v1/products/{id} and optionally include platform as a query param.
|
|
*/
|
|
export async function fetchProductById(params: {
|
|
id: string;
|
|
platform?: string;
|
|
}) {
|
|
const { id, platform } = params;
|
|
|
|
const url =
|
|
`/api/catalog/products/${encodeURIComponent(id)}` +
|
|
(platform ? `?${new URLSearchParams({ platform })}` : "");
|
|
|
|
const res = await fetch(url, {
|
|
cache: "no-store",
|
|
credentials: 'include',
|
|
});
|
|
if (!res.ok) throw new Error(`Failed to load product (${res.status})`);
|
|
return (await res.json()) as ProductDetail;
|
|
} |