Merges the full git history of Inventory_frontend into the monorepo under frontend/. Removes the submodule in favor of a unified repo. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
133 lines
4.8 KiB
TypeScript
133 lines
4.8 KiB
TypeScript
/**
|
|
* Machine detail — product display sub-composable.
|
|
*
|
|
* Handles product resolution, display helpers, supplier info,
|
|
* and machine-level direct product links.
|
|
*/
|
|
|
|
import { computed } from 'vue'
|
|
import { useProducts } from '~/composables/useProducts'
|
|
import {
|
|
resolveProductReference as _resolveProductReference,
|
|
getProductDisplay as _getProductDisplay,
|
|
getProductSuppliersLabel,
|
|
getProductPriceLabel,
|
|
} from '~/shared/utils/productDisplayUtils'
|
|
import {
|
|
resolveConstructeurs,
|
|
uniqueConstructeurIds,
|
|
} from '~/shared/constructeurUtils'
|
|
|
|
type AnyRecord = Record<string, unknown>
|
|
|
|
interface MachineDetailProductsDeps {
|
|
machineProductLinks: Ref<AnyRecord[]>
|
|
productDocumentsMap: Ref<Map<string, AnyRecord[]>>
|
|
constructeurs: Ref<unknown[]>
|
|
}
|
|
|
|
export function useMachineDetailProducts(deps: MachineDetailProductsDeps) {
|
|
const { machineProductLinks, productDocumentsMap, constructeurs } = deps
|
|
const { products, loadProducts } = useProducts()
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Computed
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const productInventory = computed(() => products.value || [])
|
|
|
|
const productById = computed(() => {
|
|
const map = new Map<string, AnyRecord>()
|
|
;(productInventory.value as AnyRecord[]).forEach((product: AnyRecord) => {
|
|
if (product?.id) map.set(product.id as string, product)
|
|
})
|
|
return map
|
|
})
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Helpers
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const findProductById = (productId: string | null | undefined): AnyRecord | null => {
|
|
if (!productId) return null
|
|
return productById.value.get(productId) || null
|
|
}
|
|
|
|
const resolveProductReference = (source: AnyRecord) =>
|
|
_resolveProductReference(source, findProductById as any)
|
|
const getProductDisplay = (source: AnyRecord) =>
|
|
_getProductDisplay(source, findProductById as any)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Machine direct products
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const machineDirectProducts = computed(() => {
|
|
return machineProductLinks.value.map((link) => {
|
|
const productObj = link.product as AnyRecord | string | null
|
|
let resolved: AnyRecord | null = null
|
|
let productId: string | null = null
|
|
|
|
if (typeof productObj === 'string') {
|
|
productId = productObj.split('/').pop() || null
|
|
resolved = productId ? findProductById(productId) : null
|
|
} else if (productObj && typeof productObj === 'object') {
|
|
productId = (productObj as AnyRecord)?.id as string | null
|
|
// Prefer the embedded product from the structure endpoint — it has richer
|
|
// data (typeProduct as object, supplierPrice, constructeurs) than the
|
|
// global products cache which may store typeProduct as an IRI string.
|
|
const cached = productId ? findProductById(productId) : null
|
|
resolved = productObj as AnyRecord
|
|
if (cached) {
|
|
// Merge: use embedded as base, overlay any non-null cached fields
|
|
resolved = { ...resolved, ...Object.fromEntries(
|
|
Object.entries(cached as AnyRecord).filter(([, v]) => v != null && v !== ''),
|
|
) }
|
|
// But always prefer the embedded typeProduct when it's an object
|
|
if (productObj.typeProduct && typeof productObj.typeProduct === 'object') {
|
|
resolved.typeProduct = productObj.typeProduct
|
|
}
|
|
}
|
|
}
|
|
|
|
const cIds = uniqueConstructeurIds(
|
|
resolved?.constructeurs,
|
|
resolved?.constructeurIds,
|
|
)
|
|
const resolvedConstructeurs = resolveConstructeurs(
|
|
cIds,
|
|
resolved?.constructeurs as any[] || [],
|
|
constructeurs.value as any,
|
|
)
|
|
|
|
return {
|
|
id: (resolved?.id as string) || productId || null,
|
|
linkId: (link.id as string) || (typeof link['@id'] === 'string' ? link['@id'].split('/').pop() : null) || null,
|
|
name: (resolved?.name as string) || 'Produit inconnu',
|
|
reference: (resolved?.reference as string) || null,
|
|
supplierLabel: resolvedConstructeurs.length
|
|
? resolvedConstructeurs.map((c) => c.name).filter(Boolean).join(', ') || null
|
|
: getProductSuppliersLabel(resolved),
|
|
priceLabel: resolved ? getProductPriceLabel(resolved) : null,
|
|
groupLabel: ((resolved?.typeProduct as AnyRecord)?.name as string) || '',
|
|
documents: productId ? (productDocumentsMap.value.get(productId) || []) : [],
|
|
}
|
|
})
|
|
})
|
|
|
|
return {
|
|
// Computed
|
|
productInventory,
|
|
productById,
|
|
machineDirectProducts,
|
|
|
|
// Helpers
|
|
findProductById,
|
|
resolveProductReference,
|
|
getProductDisplay,
|
|
|
|
// Loading
|
|
loadProducts,
|
|
}
|
|
}
|