fix(items): normalize item fields and improve data integrity checks
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.
This commit is contained in:
1 parent
6adc8d96e8
commit
b8a8d3cc17
2 files changed
+69
-15
No files matched your search
@@ -123,7 +123,7 @@ export default function LibraryClient({ initial }: { initial: InitialData }) {
|
||||
/>
|
||||
|
||||
<section className="grid gap-6 grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 grid-flow-row-dense">
|
||||
{items.map((item) => {
|
||||
{items.map((item, idx) => {
|
||||
const anyItem = item as any;
|
||||
// Normalização de categoria para os ícones do ItemCard
|
||||
const normalizeCategory = (c: string | undefined): string => {
|
||||
@@ -163,8 +163,27 @@ export default function LibraryClient({ initial }: { initial: InitialData }) {
|
||||
typeof anyItem.categoria === "string"
|
||||
? anyItem.categoria
|
||||
: undefined;
|
||||
const category = normalizeCategory(item.category ?? categoryPt);
|
||||
const name = item.name ?? anyItem.nome ?? String(item.id);
|
||||
const rawCategory = item.category ?? anyItem.category ?? categoryPt;
|
||||
const category = normalizeCategory(rawCategory || "other");
|
||||
|
||||
const idSafe =
|
||||
typeof item.id === "string" || typeof item.id === "number"
|
||||
? String(item.id)
|
||||
: typeof anyItem.item_id === "number"
|
||||
? String(anyItem.item_id)
|
||||
: typeof anyItem.id === "number"
|
||||
? String(anyItem.id)
|
||||
: undefined;
|
||||
|
||||
const name =
|
||||
(typeof item.name === "string" && item.name
|
||||
? item.name
|
||||
: typeof anyItem.item_name === "string" && anyItem.item_name
|
||||
? anyItem.item_name
|
||||
: typeof anyItem.nome === "string" && anyItem.nome
|
||||
? anyItem.nome
|
||||
: idSafe) || "Sem nome";
|
||||
|
||||
const image = item.image ?? anyItem.image_url ?? "";
|
||||
|
||||
// Campos numéricos normalizados
|
||||
@@ -221,12 +240,31 @@ export default function LibraryClient({ initial }: { initial: InitialData }) {
|
||||
? anyItem.voc
|
||||
: undefined;
|
||||
|
||||
const sourceTag = [anyItem.source_table_name, anyItem.source_table_id]
|
||||
.filter((v) => v !== undefined && v !== null && String(v).length > 0)
|
||||
.join(":");
|
||||
|
||||
const fallbackKey = `${page}-${idx}`;
|
||||
const safeKey = [category, idSafe ?? sourceTag ?? name ?? fallbackKey, name]
|
||||
.map((v) => String(v || ""))
|
||||
.join("::");
|
||||
|
||||
// Log de integridade de dados
|
||||
if (!idSafe && (!name || name === "Sem nome")) {
|
||||
console.error("[Library] Item inválido sem id/nome", {
|
||||
index: idx,
|
||||
page,
|
||||
category: rawCategory,
|
||||
itemSnapshot: anyItem,
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<ItemCard
|
||||
key={`${String((anyItem as any).category)}::${String(item.id)}::${name}`}
|
||||
key={safeKey}
|
||||
item={
|
||||
{
|
||||
id: String(item.id),
|
||||
id: (idSafe ?? sourceTag ?? name ?? fallbackKey) as string,
|
||||
name,
|
||||
image,
|
||||
category: category as any,
|
||||
|
||||
+26
-10
@@ -43,23 +43,39 @@ export async function GET(req: NextRequest) {
|
||||
pageSize,
|
||||
});
|
||||
|
||||
// Normaliza campos esperados pelo cliente, preservando compatibilidade
|
||||
const itemsWithImage = items.map((item) => {
|
||||
const img = (item.image_url || item.image_local_path || "").toString();
|
||||
if (/^https?:\/\//i.test(img)) {
|
||||
return { ...item, image_url: img, image: img };
|
||||
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 (img.startsWith("data/")) {
|
||||
if (imgRaw.startsWith("data/")) {
|
||||
return {
|
||||
...item,
|
||||
image_url: img,
|
||||
image: `/api/images?path=${encodeURIComponent(img)}`,
|
||||
...base,
|
||||
image_url: imgRaw,
|
||||
image: `/api/images?path=${encodeURIComponent(imgRaw)}`,
|
||||
};
|
||||
}
|
||||
const category = item.category || "other";
|
||||
return {
|
||||
...item,
|
||||
...base,
|
||||
image_url: item.image_url,
|
||||
image: buildPublicItemImageUrl(category, img),
|
||||
image: buildPublicItemImageUrl(categorySafe, imgRaw),
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user