// Production - The Idle Game: B2B Procurement Contracts Board // Fine-grained DOM updates without innerHTML teardowns import { getProduct } from '../data/products.js'; import { getClient } from '../data/contracts.js'; import { fmtCurrency, fmtNum, fmtTime } from '../core/formatters.js'; let currentMountedContractUids = ''; export function mountContractsBoard(container, state, onAction) { const contracts = state.activeContracts || []; currentMountedContractUids = contracts.map(c => c.uid).join(','); let html = `

B2B Corporate Procurement Tenders

Supply high-priority commodity shipments to corporate clients for massive cash injections and corporate prestige.

Completed Tenders: ${state.stats.contractsCompleted || 0}
`; if (contracts.length === 0) { html += `

Awaiting New Tenders

Corporate procurement agents are preparing new commodity RFPs...

`; } for (const c of contracts) { const client = getClient(c.clientId); const product = getProduct(c.productId); const currentStock = state.products[c.productId]?.stock || 0; const canFulfill = currentStock >= c.targetAmount; const progressPct = Math.min(100, Math.floor((currentStock / c.targetAmount) * 100)); html += `

${client.name}

${client.badge}
${fmtTime(c.remainingSeconds)}

${c.title}

Required Commodity:
${product?.name}
${fmtNum(currentStock, 0)} / ${fmtNum(c.targetAmount, 0)} ${product?.unit || 'units'}
Contract Payout: ${fmtCurrency(c.rewardCash)}
Corporate Rep: +${c.rewardRep} Rep
`; } html += `
`; container.innerHTML = html; container.querySelectorAll('.btn-fulfill-contract').forEach(btn => { btn.onclick = () => onAction({ type: 'FULFILL_CONTRACT', uid: btn.dataset.uid }); }); } export function updateContractsBoard(container, state, onAction) { const contracts = state.activeContracts || []; const currentUids = contracts.map(c => c.uid).join(','); // If active contracts changed (added, completed, expired), remount cleanly if (currentUids !== currentMountedContractUids) { mountContractsBoard(container, state, onAction); return; } for (const c of contracts) { const currentStock = state.products[c.productId]?.stock || 0; const canFulfill = currentStock >= c.targetAmount; const progressPct = Math.min(100, Math.floor((currentStock / c.targetAmount) * 100)); // Timer const elTimerVal = document.getElementById(`timer-val-${c.uid}`); if (elTimerVal) elTimerVal.textContent = fmtTime(c.remainingSeconds); const elTimerBox = document.getElementById(`timer-box-${c.uid}`); if (elTimerBox) { elTimerBox.classList.toggle('timer-urgent', c.remainingSeconds < 60); } // Current Stock Text const elCurrStock = document.getElementById(`c-curr-stock-${c.uid}`); if (elCurrStock) elCurrStock.textContent = fmtNum(currentStock, 0); // Progress bar const elFill = document.getElementById(`c-fill-${c.uid}`); if (elFill) elFill.style.width = `${progressPct}%`; // Card fulfill class const elCard = document.getElementById(`contract-${c.uid}`); if (elCard) elCard.classList.toggle('ready-to-fulfill', canFulfill); // Button disabled & text const elBtn = document.getElementById(`c-btn-${c.uid}`); if (elBtn) { elBtn.disabled = !canFulfill; const elBtnText = document.getElementById(`c-btn-text-${c.uid}`); if (elBtnText) { elBtnText.textContent = canFulfill ? 'Deliver Shipment & Collect Payout' : `Fulfill Tender (Need ${fmtNum(c.targetAmount - currentStock, 0)} more)`; } } } }