Ensure consistent field names and types between API and client components. Add fallback values for missing fields and implement better error logging for invalid items. Improve key generation for item rendering to prevent duplicate keys.
105 lines
3.0 KiB
TypeScript
105 lines
3.0 KiB
TypeScript
import type { NextRequest } from "next/server";
|
|
import { buildPublicItemImageUrl } from "@/lib/item-images";
|
|
import { type ItemSort, searchItems } from "@/lib/prisma/queries/items";
|
|
|
|
function parseArray(param: string | null): string[] {
|
|
if (!param) return [];
|
|
return param
|
|
.split(",")
|
|
.map((value) => value.trim())
|
|
.filter(Boolean);
|
|
}
|
|
|
|
const allowedSorts: ItemSort[] = [
|
|
"name",
|
|
"level-asc",
|
|
"level-desc",
|
|
"weight-asc",
|
|
"weight-desc",
|
|
"category",
|
|
"updated-desc",
|
|
];
|
|
|
|
export async function GET(req: NextRequest) {
|
|
try {
|
|
const { searchParams } = new URL(req.url);
|
|
const q = searchParams.get("q") || undefined;
|
|
const categories = parseArray(searchParams.get("category"));
|
|
const rarities = parseArray(searchParams.get("rarity"));
|
|
const server = searchParams.get("server") || undefined;
|
|
const sortParamRaw = (searchParams.get("sort") || "name").toLowerCase();
|
|
const sortParam = (allowedSorts.find((sort) => sort === sortParamRaw) ||
|
|
"name") as ItemSort;
|
|
const page = Number(searchParams.get("page") || "1");
|
|
const pageSize = Number(searchParams.get("pageSize") || "24");
|
|
|
|
const { items, total } = await searchItems({
|
|
q,
|
|
category: categories[0],
|
|
rarity: rarities[0],
|
|
server,
|
|
sort: sortParam,
|
|
page,
|
|
pageSize,
|
|
});
|
|
|
|
// Normaliza campos esperados pelo cliente, preservando compatibilidade
|
|
const itemsWithImage = items.map((item) => {
|
|
const imgRaw = (item.image_url || item.image_local_path || "").toString();
|
|
const categorySafe = item.category || "other";
|
|
|
|
const idSafe = typeof item.item_id === "number" ? item.item_id : undefined;
|
|
const nameSafe =
|
|
typeof (item as any).item_name === "string" && (item as any).item_name
|
|
? (item as any).item_name
|
|
: undefined;
|
|
|
|
const base = {
|
|
...item,
|
|
// Aliases usados pelos clientes públicos (Library, etc.)
|
|
id: idSafe,
|
|
name: nameSafe,
|
|
category: categorySafe,
|
|
} as any;
|
|
|
|
if (/^https?:\/\//i.test(imgRaw)) {
|
|
return { ...base, image_url: imgRaw, image: imgRaw };
|
|
}
|
|
if (imgRaw.startsWith("data/")) {
|
|
return {
|
|
...base,
|
|
image_url: imgRaw,
|
|
image: `/api/images?path=${encodeURIComponent(imgRaw)}`,
|
|
};
|
|
}
|
|
return {
|
|
...base,
|
|
image_url: item.image_url,
|
|
image: buildPublicItemImageUrl(categorySafe, imgRaw),
|
|
};
|
|
});
|
|
|
|
const totalPages = Math.max(1, Math.ceil(total / Math.max(1, pageSize)));
|
|
return Response.json(
|
|
{
|
|
items: itemsWithImage,
|
|
page,
|
|
pageSize,
|
|
total,
|
|
totalPages,
|
|
sort: sortParam,
|
|
},
|
|
{ status: 200 },
|
|
);
|
|
} catch (error: any) {
|
|
console.error("[api/items] Erro:", error?.message, error?.stack);
|
|
return Response.json(
|
|
{
|
|
error: "Falha ao consultar itens",
|
|
message: error?.message || "Erro desconhecido",
|
|
},
|
|
{ status: 500 },
|
|
);
|
|
}
|
|
}
|