refactor(components): extract shared entity utilities and simplify item components (F1.3, F1.4)
Extract 3 entity composables (useEntityCustomFields, useEntityDocuments, useEntityProductDisplay) and entityCustomFieldLogic utility shared across ComponentItem (1336→585 LOC) and PieceItem (1588→740 LOC). Improve type safety in edit/create pages with explicit casts. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
103
app/composables/useEntityProductDisplay.ts
Normal file
103
app/composables/useEntityProductDisplay.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Reactive product display for entity items (ComponentItem, PieceItem).
|
||||
*
|
||||
* Resolves product information from entity.product, entity.__productDisplay,
|
||||
* or a selectedProduct ref, and produces display-ready computed properties.
|
||||
*/
|
||||
|
||||
import { computed, type Ref } from 'vue'
|
||||
|
||||
const currencyFormatter = new Intl.NumberFormat('fr-FR', {
|
||||
style: 'currency',
|
||||
currency: 'EUR',
|
||||
currencyDisplay: 'narrowSymbol',
|
||||
})
|
||||
|
||||
function buildProductDisplay(product: any) {
|
||||
if (!product || typeof product !== 'object') return null
|
||||
|
||||
const suppliers = Array.isArray(product.constructeurs)
|
||||
? product.constructeurs
|
||||
.map((c: any) => c?.name)
|
||||
.filter((name: any) => typeof name === 'string' && name.trim().length > 0)
|
||||
.join(', ')
|
||||
: product.supplierLabel || null
|
||||
|
||||
const priceValue = product.supplierPrice ?? product.price ?? product.priceLabel ?? product.priceDisplay ?? null
|
||||
let price: string | null = null
|
||||
if (priceValue !== null && priceValue !== undefined) {
|
||||
const parsed = Number(priceValue)
|
||||
if (!Number.isNaN(parsed)) {
|
||||
price = currencyFormatter.format(parsed)
|
||||
} else if (typeof priceValue === 'string' && priceValue.trim().length > 0) {
|
||||
price = priceValue
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name: product.name || product.label || product.reference || product.productName || null,
|
||||
reference: product.reference || null,
|
||||
category: product.typeProduct?.name || product.category || null,
|
||||
suppliers,
|
||||
price,
|
||||
}
|
||||
}
|
||||
|
||||
export interface EntityProductDisplayDeps {
|
||||
entity: () => any
|
||||
selectedProduct?: Ref<any>
|
||||
}
|
||||
|
||||
export function useEntityProductDisplay(deps: EntityProductDisplayDeps) {
|
||||
const { entity, selectedProduct } = deps
|
||||
|
||||
const displayProduct = computed(() => {
|
||||
// Priority: selectedProduct (for PieceItem) → entity.product → entity.__productDisplay
|
||||
if (selectedProduct?.value) {
|
||||
const normalized = buildProductDisplay(selectedProduct.value)
|
||||
if (normalized) return normalized
|
||||
}
|
||||
const explicit = entity().product || null
|
||||
const normalized = buildProductDisplay(explicit)
|
||||
if (normalized) return normalized
|
||||
const fallback = entity().__productDisplay
|
||||
if (fallback) {
|
||||
return {
|
||||
name: fallback.name || null,
|
||||
reference: fallback.reference || null,
|
||||
category: fallback.category || null,
|
||||
suppliers: fallback.suppliers || null,
|
||||
price: fallback.price || null,
|
||||
}
|
||||
}
|
||||
return null
|
||||
})
|
||||
|
||||
const displayProductName = computed(() => {
|
||||
if (displayProduct.value?.name) return displayProduct.value.name
|
||||
const e = entity()
|
||||
return e.product?.name || e.productName || e.productLabel || null
|
||||
})
|
||||
|
||||
const productInfoRows = computed(() => {
|
||||
if (!displayProduct.value) return []
|
||||
const rows: { label: string; value: string }[] = []
|
||||
if (displayProduct.value.reference) rows.push({ label: 'Référence', value: displayProduct.value.reference })
|
||||
if (displayProduct.value.price) rows.push({ label: 'Prix indicatif', value: displayProduct.value.price })
|
||||
if (displayProduct.value.suppliers) rows.push({ label: 'Fournisseur(s)', value: displayProduct.value.suppliers })
|
||||
if (displayProduct.value.category) rows.push({ label: 'Catégorie', value: displayProduct.value.category })
|
||||
return rows
|
||||
})
|
||||
|
||||
const productDocuments = computed(() => {
|
||||
const product = selectedProduct?.value || entity().product || null
|
||||
return Array.isArray(product?.documents) ? product.documents : []
|
||||
})
|
||||
|
||||
return {
|
||||
displayProduct,
|
||||
displayProductName,
|
||||
productInfoRows,
|
||||
productDocuments,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user