const formatSize = (size) => { if (size === undefined || size === null) { return '—' } if (size === 0) { return '0 B' } const units = ['B', 'KB', 'MB', 'GB'] const index = Math.min(units.length - 1, Math.floor(Math.log(size) / Math.log(1024))) const formatted = size / Math.pow(1024, index) return `${formatted.toFixed(1)} ${units[index]}` } const renderPrintField = (label, value, fallback = '—') => { const display = value !== undefined && value !== null && value !== '' ? value : fallback return `` } const renderPrintCustomFields = (fields = [], title, sectionClass = 'print-section') => { if (!fields.length) { return '' } const items = fields .map(field => ``) .join('') return `

${title}

` } const renderPrintDocuments = (documents = [], title, sectionClass = 'print-section') => { if (!documents.length) { return '' } const rows = documents .map(doc => `${doc.name}${doc.type}${doc.size}`) .join('') return `

${title}

${rows}
` } const renderPrintPieces = ( pieces = [], title = 'Pièces indépendantes', sectionClass = 'print-section print-section--pieces' ) => { if (!pieces.length) { return '' } const cards = pieces .map((piece, idx) => { const indexLabel = piece.indexPath ? piece.indexPath.join('.') : `${idx + 1}` const constructeurBadge = piece.constructeur?.name ? `Constructeur: ${piece.constructeur.name}` : '' const customFields = (piece.customFields || []) .filter(field => field.value && field.value !== '—' && field.value !== '') .map( field => `
  • ${field.label} ${field.value}
  • ` ) .join('') const customFieldsBlock = customFields ? `` : '' const documentsBlock = (piece.documents || []).length ? `` : '' return ` ` }) .join('') return `

    ${title}

    ` } const renderPrintComponents = (components = [], depth = 0, indexPath = []) => { if (!components.length) { return '' } return components .map((component, idx) => { const badges = [] if (component.constructeur?.name) { badges.push(`Constructeur: ${component.constructeur.name}`) } const sectionClass = `print-section print-section--component print-section-depth-${Math.min(depth, 3)}` const currentIndex = [...indexPath, idx + 1] const indexLabel = currentIndex.join('.') return `

    ${indexLabel} Composant : ${component.name}

    ${component.description ? `` : ''} ${badges.length ? `
    ${badges.map(badge => `${badge}`).join('')}
    ` : ''} ${renderPrintCustomFields( component.customFields, 'Champs personnalisés', 'print-section print-subsection print-section--custom-fields' )} ${renderPrintPieces( (component.pieces || []).map((piece, pieceIdx) => ({ ...piece, indexPath: [...currentIndex, pieceIdx + 1] })), 'Pièces du composant', 'print-section print-subsection print-section--pieces' )} ${renderPrintDocuments( component.documents, 'Documents du composant', 'print-section print-subsection print-section--documents' )} ${renderPrintComponents(component.subComponents || [], depth + 1, currentIndex)}
    ` }) .join('') } const normalizeDocuments = (docs = []) => { return docs.map(doc => ({ id: doc.id, name: doc.name || doc.filename || 'Document', type: doc.mimeType || doc.type || '—', size: formatSize(doc.size) })) } const normalizeCustomFields = (values = []) => { return values.map(value => ({ id: value.id, label: value.customField?.name || 'Champ', value: value.value || '—' })) } const normalizeConstructeur = (constructeur) => { if (!constructeur) { return null } return { name: constructeur.name || '—', contact: [constructeur.email, constructeur.phone].filter(Boolean).join(' • ') || '—' } } const normalizePiece = piece => ({ id: piece.id, name: piece.name || 'Pièce sans nom', description: piece.description || '', reference: piece.reference || '', customFields: normalizeCustomFields(piece.customFieldValues || []), documents: normalizeDocuments(piece.documents || []), constructeur: normalizeConstructeur(piece.constructeur), indexPath: piece.indexPath || null }) const normalizeComponent = component => ({ id: component.id, name: component.name || 'Composant sans nom', description: component.description || '', customFields: normalizeCustomFields(component.customFieldValues || []), documents: normalizeDocuments(component.documents || []), pieces: (component.pieces || []).map(normalizePiece), subComponents: (component.sousComposants || component.subComponents || []).map(normalizeComponent), constructeur: normalizeConstructeur(component.constructeur) }) export const buildMachinePrintContext = ({ machine, machineName, machineReference, machinePieces = [], components = [], selection }) => { const selectionState = selection || {} const machineSelection = selectionState.machine || {} const componentSelection = selectionState.components || {} const pieceSelection = selectionState.pieces || {} const includeMachineInfo = machineSelection.info !== false const includeMachineCustomFields = machineSelection.customFields !== false const includeMachineDocuments = machineSelection.documents !== false const isComponentSelected = (id) => { if (!id) { return true } if (Object.prototype.hasOwnProperty.call(componentSelection, id)) { return componentSelection[id] } return true } const isPieceSelected = (id) => { if (!id) { return true } if (Object.prototype.hasOwnProperty.call(pieceSelection, id)) { return pieceSelection[id] } return true } const machineBadges = [] if (machine?.typeMachine?.category) { machineBadges.push(machine.typeMachine.category) } if (machine?.site?.name) { machineBadges.push(`Site: ${machine.site.name}`) } if (machineReference) { machineBadges.push(`Ref: ${machineReference}`) } const normalizedPieces = machinePieces .map(normalizePiece) .filter(piece => isPieceSelected(piece.id)) .map((piece, idx) => ({ ...piece, indexPath: [idx + 1] })) const normalizedComponents = components.map(normalizeComponent) const filterComponentTree = (component) => { const filteredPieces = (component.pieces || []).filter(piece => isPieceSelected(piece.id)) const filteredSubComponents = (component.subComponents || []) .map(filterComponentTree) .filter(Boolean) const includeSelf = isComponentSelected(component.id) const shouldInclude = includeSelf || filteredPieces.length > 0 || filteredSubComponents.length > 0 if (!shouldInclude) { return null } return { ...component, pieces: filteredPieces, subComponents: filteredSubComponents } } const filteredComponents = normalizedComponents .map(filterComponentTree) .filter(Boolean) return { generatedAt: new Date().toLocaleString('fr-FR'), machine: { id: machine?.id || null, name: machineName, description: machine?.description || '', typeDescription: machine?.typeMachine?.description || '', reference: machineReference, site: machine?.site?.name || '', category: machine?.typeMachine?.category || '', badges: machineBadges, constructeur: normalizeConstructeur(machine?.constructeur), includeInfo: includeMachineInfo, customFields: includeMachineCustomFields ? normalizeCustomFields(machine?.customFieldValues || []) : [], documents: includeMachineDocuments ? normalizeDocuments(machine?.documents || []) : [] }, components: filteredComponents, pieces: normalizedPieces } } export const buildMachinePrintHtml = (context, styles) => { const title = context.machine.name ? `Impression - ${context.machine.name}` : 'Impression machine' const badgesHtml = context.machine.badges .map(badge => `${badge}`) .join('') const sections = [] sections.push(` `) if (context.machine.includeInfo) { sections.push(` `) } const customFieldsSection = renderPrintCustomFields( context.machine.customFields, 'Champs personnalisés de la machine', 'print-section print-section--custom-fields' ) if (customFieldsSection) { sections.push(customFieldsSection) } const documentsSection = renderPrintDocuments( context.machine.documents, 'Documents liés à la machine', 'print-section print-section--documents' ) if (documentsSection) { sections.push(documentsSection) } const componentsSection = renderPrintComponents(context.components) if (componentsSection) { sections.push(componentsSection) } const piecesSection = renderPrintPieces( context.pieces, 'Pièces indépendantes', 'print-section print-section--pieces' ) if (piecesSection) { sections.push(piecesSection) } sections.push(` `) const content = sections.join('\n') return ` ${title} ${styles} ` }