// Strapi product thumbnails for picking surfaces — batched (max 5 concurrent), cached // per product for the whole session, fail-soft (no image = caller shows a placeholder). // // The /api/processes/inouts/{docNo} response $expands m_product_id without $select, so // every shipment line already carries M_Product_ID.Strapi_Product_documentId — no extra // iDempiere lookups are needed, only the two Strapi gallery calls per product. const thumbs = ref>({}) // productId -> resolved image URL (shared) const requested = new Set() // productIds already requested (incl. failures) export const useProductThumbs = () => { const config = useRuntimeConfig() const fetchOne = async (strapiDocumentId: string, productId: string) => { try { const [strapiProductRes, imagesRes]: any[] = await Promise.all([ $fetch(`/api/materials/products/${strapiDocumentId}/galleries`, { headers: useRequestHeaders(['cookie']) }), $fetch(`/api/materials/products/${strapiDocumentId}/galleries/images`, { headers: useRequestHeaders(['cookie']) }), ]) if (!imagesRes?.length) return let mainImage = imagesRes[0] if (strapiProductRes?.data?.Main_Image && strapiProductRes.data.Main_Image != 0) { const foundMain = imagesRes.find((img: any) => img.id == strapiProductRes.data.Main_Image) if (foundMain) mainImage = foundMain } let imageUrl: string | null = null if (mainImage?.formats?.small) { imageUrl = config.public.strapi + '/files-api/' + mainImage.formats.small.hash + mainImage.formats.small.ext } else if (mainImage?.formats?.thumbnail) { imageUrl = config.public.strapi + '/files-api/' + mainImage.formats.thumbnail.hash + mainImage.formats.thumbnail.ext } else if (mainImage?.url) { imageUrl = config.public.strapi + mainImage.url } if (imageUrl) thumbs.value = { ...thumbs.value, [productId]: imageUrl } } catch (err: any) { console.error('[useProductThumbs] product image error:', err?.data ?? err) } } // Load thumbnails for every distinct product of the given lines (once per product). const fetchForLines = async (lines: any[]) => { const unique = new Map() for (const line of lines || []) { const product = line?.M_Product_ID ?? line const pid = product?.id != null ? String(product.id) : '' const docId = product?.Strapi_Product_documentId if (pid && docId && !requested.has(pid) && !unique.has(pid)) unique.set(pid, docId) } const entries = [...unique.entries()] for (let i = 0; i < entries.length; i += 5) { await Promise.all(entries.slice(i, i + 5).map(([pid, docId]) => { requested.add(pid) return fetchOne(docId, pid) })) } } // Image source for a product: Strapi first, legacy M_Product.ImageURL fallback. const thumbFor = (product: any): string | null => { if (!product) return null const pid = product.id != null ? String(product.id) : '' return (pid && thumbs.value[pid]) || product.ImageURL || null } return { thumbs, fetchForLines, thumbFor } }