105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import type { PieceModelProduct, PieceModelStructure } from '~/shared/types/inventory'
|
|
|
|
/**
|
|
* Extract the products array from a piece model structure, defaulting to [].
|
|
*/
|
|
export const getStructureProducts = (structure: PieceModelStructure | null): PieceModelProduct[] =>
|
|
Array.isArray(structure?.products) ? structure.products : []
|
|
|
|
/**
|
|
* Build a human-readable label for a single product requirement.
|
|
*/
|
|
export const describeProductRequirement = (requirement: PieceModelProduct, index: number): string => {
|
|
if (!requirement) {
|
|
return `Produit ${index + 1}`
|
|
}
|
|
const parts: string[] = []
|
|
if (requirement.role) {
|
|
parts.push(requirement.role)
|
|
}
|
|
if (requirement.typeProductLabel) {
|
|
parts.push(requirement.typeProductLabel)
|
|
} else if (requirement.typeProductId) {
|
|
parts.push(`Catégorie #${requirement.typeProductId}`)
|
|
}
|
|
if (requirement.familyCode) {
|
|
parts.push(`Famille ${requirement.familyCode}`)
|
|
}
|
|
if (parts.length === 0) {
|
|
parts.push(`Produit ${index + 1}`)
|
|
}
|
|
return parts.join(' • ')
|
|
}
|
|
|
|
/**
|
|
* Build description strings for every product requirement in a structure.
|
|
*/
|
|
export const buildProductRequirementDescriptions = (
|
|
products: PieceModelProduct[],
|
|
): string[] =>
|
|
products.map((requirement, index) => describeProductRequirement(requirement, index))
|
|
|
|
/**
|
|
* Build the entry objects used to render product selection inputs.
|
|
*/
|
|
export const buildProductRequirementEntries = (
|
|
products: PieceModelProduct[],
|
|
keyPrefix: string,
|
|
) =>
|
|
products.map((requirement, index) => ({
|
|
index,
|
|
key: `${keyPrefix}-${index}-${requirement?.typeProductId || 'any'}`,
|
|
label: describeProductRequirement(requirement, index),
|
|
typeProductId: requirement?.typeProductId ? String(requirement.typeProductId) : null,
|
|
}))
|
|
|
|
/**
|
|
* Resize the selections array to match the expected count, preserving existing values.
|
|
*/
|
|
export const resizeProductSelections = (
|
|
current: (string | null)[],
|
|
count: number,
|
|
): (string | null)[] =>
|
|
Array.from({ length: count }, (_, index) => current[index] ?? null)
|
|
|
|
/**
|
|
* Return true when all required product slots have a non-empty string value,
|
|
* or when no product selection is required.
|
|
*/
|
|
export const areProductSelectionsFilled = (
|
|
requiresSelection: boolean,
|
|
entries: { index: number }[],
|
|
selections: (string | null)[],
|
|
): boolean =>
|
|
!requiresSelection ||
|
|
entries.every((entry) => {
|
|
const value = selections[entry.index]
|
|
return typeof value === 'string' && value.trim().length > 0
|
|
})
|
|
|
|
/**
|
|
* Set a single product selection by index, returning a new array.
|
|
*/
|
|
export const applyProductSelection = (
|
|
current: (string | null)[],
|
|
index: number,
|
|
value: string | null,
|
|
): (string | null)[] => {
|
|
const normalized = typeof value === 'string' ? value : null
|
|
const next = [...current]
|
|
next[index] = normalized
|
|
return next
|
|
}
|
|
|
|
/**
|
|
* Extract normalized product IDs from the current selections based on requirement entries.
|
|
*/
|
|
export const collectNormalizedProductIds = (
|
|
entries: { index: number }[],
|
|
selections: (string | null)[],
|
|
): string[] =>
|
|
entries
|
|
.map((entry) => selections[entry.index])
|
|
.filter((value): value is string => typeof value === 'string' && value.trim().length > 0)
|
|
.map((value) => value.trim())
|