// Production - The Idle Game: Desktop Inspector & Supply Chain Analytics Panel // Fine-grained DOM updates without innerHTML teardowns import { PRODUCTS, SECTORS, getProduct } from '../data/products.js'; import { fmtCurrency, fmtNum } from '../core/formatters.js'; let currentMountedProductId = null; export function mountInspector(container, state, onAction) { const selectedId = state.selectedProductId || 'wheat'; const product = getProduct(selectedId) || PRODUCTS[0]; const pState = state.products[product.id] || { stock: 0, lines: 0, logistics: 0, unlocked: false }; const sector = SECTORS.find(s => s.id === product.sector); currentMountedProductId = product.id; // Downstream products that consume this product const downstream = PRODUCTS.filter(p => p.inputs && p.inputs.some(inp => inp.id === product.id)); const totalLiquidationValue = (pState.stock || 0) * product.basePrice; const halfLiquidationValue = totalLiquidationValue * 0.5; let html = `
${sector?.name} Tier ${product.tier}

${product.name}

${product.description}

Warehouse Stock: ${fmtNum(pState.stock, 0)} ${product.unit}
Wholesale Price: ${fmtCurrency(product.basePrice)}
Production Lines: ${pState.lines} active
Logistics Fleets: ${pState.logistics || 0} active

Instant Wholesale Liquidation

Liquidate stockpiles immediately onto the wholesale spot market.

Supply Chain Dependencies

Direct Inputs: ${(!product.inputs || product.inputs.length === 0) ? `
Primary commodity • Direct extraction from natural deposits.
` : `
${product.inputs.map(inp => { const parent = getProduct(inp.id); const parentStock = state.products[inp.id]?.stock || 0; return `
${parent.name}
${inp.amount} per unit (${fmtNum(parentStock, 0)} on hand)
`; }).join('')}
`}
Downstream Consumers: ${downstream.length === 0 ? `
End-tier consumer or industrial finished product.
` : `
${downstream.map(child => { const isUnlocked = state.products[child.id]?.unlocked; return `
${child.name}
${isUnlocked ? 'Active' : 'Locked'}
`; }).join('')}
`}
`; container.innerHTML = html; const halfBtn = container.querySelector('#insp-btn-half'); if (halfBtn) { halfBtn.onclick = () => onAction({ type: 'LIQUIDATE_STOCK', productId: product.id, ratio: 0.5 }); } const allBtn = container.querySelector('#insp-btn-all'); if (allBtn) { allBtn.onclick = () => onAction({ type: 'LIQUIDATE_STOCK', productId: product.id, ratio: 1.0 }); } container.querySelectorAll('.chain-item-row').forEach(row => { row.onclick = () => onAction({ type: 'SELECT_PRODUCT', productId: row.dataset.product }); }); } export function updateInspector(container, state) { const selectedId = state.selectedProductId || 'wheat'; if (selectedId !== currentMountedProductId) { return; // Caller should remount if product changed } const product = getProduct(selectedId); if (!product) return; const pState = state.products[product.id] || { stock: 0, lines: 0, logistics: 0 }; // Update stock text const elStock = document.getElementById('insp-stock'); if (elStock) { elStock.textContent = `${fmtNum(pState.stock, 0)} ${product.unit}`; } // Update liquidation values & buttons const totalLiquidationValue = (pState.stock || 0) * product.basePrice; const halfLiquidationValue = totalLiquidationValue * 0.5; const elHalfVal = document.getElementById('insp-val-half'); if (elHalfVal) elHalfVal.textContent = fmtCurrency(halfLiquidationValue); const elAllVal = document.getElementById('insp-val-all'); if (elAllVal) elAllVal.textContent = fmtCurrency(totalLiquidationValue); const btnHalf = document.getElementById('insp-btn-half'); if (btnHalf) btnHalf.disabled = pState.stock < 2; const btnAll = document.getElementById('insp-btn-all'); if (btnAll) btnAll.disabled = pState.stock < 1; // Update input values if (product.inputs) { for (const inp of product.inputs) { const elInp = document.getElementById(`insp-inp-val-${inp.id}`); if (elInp) { elInp.textContent = fmtNum(state.products[inp.id]?.stock || 0, 0); } } } }