// Production UI: Compact Facility Card (HTML Mount and Fine-grained DOM update) // High-density overview cards with photographic thumbnail, live rates, bottleneck status, and quick-actions import { getProduct, getNextMilestone, getUnitMilestoneMultiplier, SECTORS } from '../../data/products.js'; import { fmtCurrency, fmtNum } from '../../core/formatters.js'; import { calculateMultiCost, getProductOutputRates } from './ratesCalculator.js'; export function renderCompactFacilityCardHtml(p, pState, state, buyMode) { const sector = SECTORS.find(s => s.id === p.sector); const isSelected = state.selectedProductId === p.id; const productImgPath = `assets/images/products/${p.id}_product.jpg`; if (!pState.unlocked) { const canAffordUnlock = state.cash >= p.unlockCost; return `
${p.name}
${sector?.name || 'Industry'} • T${p.tier} Permit Needed

${p.name}

${p.facilityName} • Wholesale: ${fmtCurrency(p.basePrice)}
`; } const nextM = getNextMilestone(pState.lines || 0); const rates = getProductOutputRates(p, pState, state); const milestoneMult = rates.milestoneMult || getUnitMilestoneMultiplier(pState.lines || 0); const clientRep = state.repAllocations?.clients || 0; const lineDiscount = Math.min(0.50, 0.002 * clientRep); const calc = calculateMultiCost(p.baseFacilityCost, pState.lines || 0, buyMode, lineDiscount); const canAffordBuy = state.cash >= calc.cost; const currentThrottle = pState.productionTarget !== undefined ? pState.productionTarget : 1.0; let statusClass = 'badge-success'; let statusLabel = `${milestoneMult}x Speed`; let statusIcon = 'lucide:check-circle'; if (currentThrottle <= 0.0) { statusClass = 'badge-idle'; statusLabel = 'Paused (0%)'; statusIcon = 'lucide:pause-circle'; } else if (pState.isBottlenecked) { statusClass = 'badge-warning'; statusLabel = 'Starved'; statusIcon = 'lucide:alert-triangle'; } else if (!pState.lines || pState.lines === 0) { statusClass = 'badge-idle'; statusLabel = '0 Lines'; statusIcon = 'lucide:circle-slash'; } const progressPct = Math.min(100, Math.floor((pState.cycleProgress || 0) * 100)); return `
${p.name} T${p.tier}
${sector?.name} ${statusLabel}

${p.name}

${pState.lines} lines
${fmtNum(pState.stock || 0, 0)} • ${rates.isBottlenecked ? '0.0/s' : `${fmtNum(rates.prodRate || 0, 1)}/s`} • +$${fmtNum(rates.revRate || 0, 2)}/s
`; } export function updateCompactFacilityCardDom(p, pState, state, engine) { if (!pState.unlocked) { const canAfford = state.cash >= p.unlockCost; const btn = document.getElementById(`btn-compact-unlock-${p.id}`); if (btn && btn.disabled === canAfford) { btn.disabled = !canAfford; } return; } const buyMode = state.buyMode || '1'; const rates = getProductOutputRates(p, pState, state); const clientRep = state.repAllocations?.clients || 0; const lineDiscount = Math.min(0.50, 0.002 * clientRep); const calc = calculateMultiCost(p.baseFacilityCost, pState.lines || 0, buyMode, lineDiscount); const canAffordBuy = state.cash >= calc.cost; const currentThrottle = pState.productionTarget !== undefined ? pState.productionTarget : 1.0; // Progress bar const elProg = document.getElementById(`compact-progress-${p.id}`); if (elProg) { const pct = Math.min(100, Math.floor((pState.cycleProgress || 0) * 100)); elProg.style.width = `${pct}%`; } // Lines const elLines = document.getElementById(`compact-lines-${p.id}`); if (elLines) { const txt = `${pState.lines || 0} lines`; if (elLines.innerHTML !== txt) elLines.innerHTML = txt; } // Stock const elStock = document.getElementById(`compact-stock-${p.id}`); if (elStock) { const val = fmtNum(pState.stock || 0, 0); if (elStock.textContent !== val) elStock.textContent = val; } // Production Rate const elUnits = document.getElementById(`compact-rate-units-${p.id}`); if (elUnits) { const txt = rates.isBottlenecked ? '0.0/s' : `${fmtNum(rates.prodRate || 0, 1)}/s`; if (elUnits.textContent !== txt) elUnits.textContent = txt; elUnits.className = `compact-stat-item ${rates.isBottlenecked ? 'text-warning' : 'text-profit'}`; } // Logistics Revenue Rate const elRev = document.getElementById(`compact-rate-rev-${p.id}`); if (elRev) { const txt = `+$${fmtNum(rates.revRate || 0, 2)}/s`; if (elRev.textContent !== txt) elRev.textContent = txt; } // Status Badge const elBadge = document.getElementById(`compact-badge-${p.id}`); const elBadgeText = document.getElementById(`compact-badge-text-${p.id}`); if (elBadge && elBadgeText) { let statusClass = 'badge-success'; let statusLabel = `${rates.milestoneMult}x Speed`; let statusIcon = 'lucide:check-circle'; if (currentThrottle <= 0.0) { statusClass = 'badge-idle'; statusLabel = 'Paused'; statusIcon = 'lucide:pause-circle'; } else if (rates.isBottlenecked) { statusClass = 'badge-warning'; statusLabel = 'Starved'; statusIcon = 'lucide:alert-triangle'; } else if (!pState.lines || pState.lines === 0) { statusClass = 'badge-idle'; statusLabel = '0 Lines'; statusIcon = 'lucide:circle-slash'; } if (elBadgeText.textContent !== statusLabel) elBadgeText.textContent = statusLabel; elBadge.className = `compact-status-badge ${statusClass}`; const iconEl = elBadge.querySelector('iconify-icon'); if (iconEl && iconEl.getAttribute('icon') !== statusIcon) { iconEl.setAttribute('icon', statusIcon); } } // Buy Button const btnExpand = document.getElementById(`btn-compact-expand-${p.id}`); const spanExpand = document.getElementById(`compact-expand-text-${p.id}`); if (btnExpand) { if (btnExpand.disabled === canAffordBuy) { btnExpand.disabled = !canAffordBuy; } if (spanExpand) { const expText = `+${calc.count} (${fmtCurrency(calc.cost)})`; if (spanExpand.textContent !== expText) spanExpand.textContent = expText; } } }