refactor(frontend) : extract assignment fetch logic into composable
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
259
app/shared/utils/structureAssignmentLabels.ts
Normal file
259
app/shared/utils/structureAssignmentLabels.ts
Normal file
@@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Type definitions and pure label/description helpers for structure assignments.
|
||||
*
|
||||
* Extracted from composables/useStructureAssignmentFetch.ts to keep files
|
||||
* under 500 lines. These are stateless utilities that do not depend on Vue
|
||||
* reactivity or API fetching.
|
||||
*/
|
||||
|
||||
import type {
|
||||
ComponentModelPiece,
|
||||
ComponentModelProduct,
|
||||
ComponentModelStructureNode,
|
||||
} from '~/shared/types/inventory'
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Option types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface ComponentOption {
|
||||
id: string
|
||||
name?: string | null
|
||||
reference?: string | null
|
||||
typeComposantId?: string | null
|
||||
typeComposant?: {
|
||||
id: string
|
||||
name?: string | null
|
||||
code?: string | null
|
||||
} | null
|
||||
}
|
||||
|
||||
export interface PieceOption {
|
||||
id: string
|
||||
name?: string | null
|
||||
reference?: string | null
|
||||
typePieceId?: string | null
|
||||
typePiece?: {
|
||||
id: string
|
||||
name?: string | null
|
||||
code?: string | null
|
||||
} | null
|
||||
}
|
||||
|
||||
export interface ProductOption {
|
||||
id: string
|
||||
name?: string | null
|
||||
reference?: string | null
|
||||
typeProductId?: string | null
|
||||
typeProduct?: {
|
||||
id: string
|
||||
name?: string | null
|
||||
code?: string | null
|
||||
} | null
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Assignment node types
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export interface StructurePieceAssignment {
|
||||
path: string
|
||||
definition: ComponentModelPiece
|
||||
selectedPieceId: string
|
||||
}
|
||||
|
||||
export interface StructureProductAssignment {
|
||||
path: string
|
||||
definition: ComponentModelProduct
|
||||
selectedProductId: string
|
||||
}
|
||||
|
||||
export interface StructureAssignmentNode {
|
||||
path: string
|
||||
definition: ComponentModelStructureNode
|
||||
selectedComponentId: string
|
||||
pieces: StructurePieceAssignment[]
|
||||
products: StructureProductAssignment[]
|
||||
subcomponents: StructureAssignmentNode[]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Component label helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const componentOptionLabel = (component?: ComponentOption | null): string => {
|
||||
if (!component) {
|
||||
return 'Composant sans nom'
|
||||
}
|
||||
return component.name || 'Composant sans nom'
|
||||
}
|
||||
|
||||
export const componentOptionDescription = (component?: ComponentOption | null): string => {
|
||||
if (!component) {
|
||||
return ''
|
||||
}
|
||||
const parts: string[] = []
|
||||
const typeLabel =
|
||||
component.typeComposant?.name || component.typeComposant?.code || null
|
||||
if (typeLabel) {
|
||||
parts.push(typeLabel)
|
||||
}
|
||||
if (component.reference) {
|
||||
parts.push(`Ref. ${component.reference}`)
|
||||
}
|
||||
return parts.join(' \u2022 ')
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Piece label helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const pieceOptionLabel = (piece?: PieceOption | null): string => {
|
||||
if (!piece) {
|
||||
return 'Pi\u00e8ce'
|
||||
}
|
||||
return piece.name || 'Pi\u00e8ce'
|
||||
}
|
||||
|
||||
export const pieceOptionDescription = (piece?: PieceOption | null): string => {
|
||||
if (!piece) {
|
||||
return ''
|
||||
}
|
||||
const parts: string[] = []
|
||||
const typeLabel =
|
||||
piece.typePiece?.name || piece.typePiece?.code || null
|
||||
if (typeLabel) {
|
||||
parts.push(typeLabel)
|
||||
}
|
||||
if (piece.reference) {
|
||||
parts.push(`Ref. ${piece.reference}`)
|
||||
}
|
||||
return parts.join(' \u2022 ')
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Product label helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const productOptionLabel = (product?: ProductOption | null): string => {
|
||||
if (!product) {
|
||||
return 'Produit'
|
||||
}
|
||||
return product.name || product.reference || 'Produit'
|
||||
}
|
||||
|
||||
export const productOptionDescription = (product?: ProductOption | null): string => {
|
||||
if (!product) {
|
||||
return ''
|
||||
}
|
||||
const parts: string[] = []
|
||||
const typeLabel =
|
||||
product.typeProduct?.name || product.typeProduct?.code || null
|
||||
if (typeLabel) {
|
||||
parts.push(typeLabel)
|
||||
}
|
||||
if (product.reference) {
|
||||
parts.push(`Ref. ${product.reference}`)
|
||||
}
|
||||
return parts.join(' \u2022 ')
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Requirement description helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
export const describePieceRequirement = (
|
||||
assignment: StructurePieceAssignment,
|
||||
options: PieceOption[],
|
||||
pieceTypeLabelMap: Record<string, string>,
|
||||
): string => {
|
||||
const definition = assignment.definition
|
||||
const parts: string[] = []
|
||||
const addPart = (value?: string | null) => {
|
||||
const trimmed = typeof value === 'string' ? value.trim() : ''
|
||||
if (trimmed && !parts.includes(trimmed)) {
|
||||
parts.push(trimmed)
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackPiece = options[0] || null
|
||||
const fallbackType = fallbackPiece?.typePiece || null
|
||||
|
||||
addPart(definition.role)
|
||||
const explicitLabel =
|
||||
definition.typePieceLabel
|
||||
|| definition.typePiece?.name
|
||||
|| (definition.typePieceId ? pieceTypeLabelMap[definition.typePieceId] : null)
|
||||
|| fallbackType?.name
|
||||
addPart(explicitLabel)
|
||||
|
||||
const family =
|
||||
definition.familyCode
|
||||
|| definition.typePiece?.code
|
||||
|| fallbackType?.code
|
||||
|| null
|
||||
if (family) {
|
||||
addPart(`Famille ${family}`)
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
addPart(fallbackType?.name)
|
||||
if (fallbackType?.code) {
|
||||
addPart(`Famille ${fallbackType.code}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (parts.length === 0 && definition.typePieceId) {
|
||||
addPart(`#${definition.typePieceId}`)
|
||||
}
|
||||
|
||||
return parts.length ? parts.join(' \u2022 ') : 'Pi\u00e8ce du squelette'
|
||||
}
|
||||
|
||||
export const describeProductRequirement = (
|
||||
assignment: StructureProductAssignment,
|
||||
options: ProductOption[],
|
||||
productTypeLabelMap: Record<string, string>,
|
||||
): string => {
|
||||
const definition = assignment.definition
|
||||
const parts: string[] = []
|
||||
const addPart = (value?: string | null) => {
|
||||
const trimmed = typeof value === 'string' ? value.trim() : ''
|
||||
if (trimmed && !parts.includes(trimmed)) {
|
||||
parts.push(trimmed)
|
||||
}
|
||||
}
|
||||
|
||||
const fallbackProduct = options[0] || null
|
||||
const fallbackType = fallbackProduct?.typeProduct || null
|
||||
|
||||
addPart(definition.role)
|
||||
const explicitLabel =
|
||||
definition.typeProductLabel
|
||||
|| definition.typeProduct?.name
|
||||
|| (definition.typeProductId ? productTypeLabelMap[definition.typeProductId] : null)
|
||||
|| fallbackType?.name
|
||||
addPart(explicitLabel)
|
||||
|
||||
const family =
|
||||
definition.familyCode
|
||||
|| definition.typeProduct?.code
|
||||
|| fallbackType?.code
|
||||
|| null
|
||||
if (family) {
|
||||
addPart(`Famille ${family}`)
|
||||
}
|
||||
|
||||
if (parts.length === 0) {
|
||||
addPart(fallbackType?.name)
|
||||
if (fallbackType?.code) {
|
||||
addPart(`Famille ${fallbackType.code}`)
|
||||
}
|
||||
}
|
||||
|
||||
if (parts.length === 0 && definition.typeProductId) {
|
||||
addPart(`#${definition.typeProductId}`)
|
||||
}
|
||||
|
||||
return parts.length ? parts.join(' \u2022 ') : 'Produit du squelette'
|
||||
}
|
||||
Reference in New Issue
Block a user