document.addEventListener("DOMContentLoaded", () => { const dataElement = document.getElementById("costs-payload"); let capexByScenario = {}; let opexByScenario = {}; let currencyOptions = []; if (dataElement) { try { const parsed = JSON.parse(dataElement.textContent || "{}"); if (parsed && typeof parsed === "object") { if (parsed.capex && typeof parsed.capex === "object") { capexByScenario = parsed.capex; } if (parsed.opex && typeof parsed.opex === "object") { opexByScenario = parsed.opex; } if (Array.isArray(parsed.currency_options)) { currencyOptions = parsed.currency_options; } } } catch (error) { console.error("Unable to parse cost data", error); } } const filterSelect = document.getElementById("costs-scenario-filter"); const costsEmptyState = document.getElementById("costs-empty"); const costsDataWrapper = document.getElementById("costs-data"); const capexTableBody = document.getElementById("capex-table-body"); const opexTableBody = document.getElementById("opex-table-body"); const capexEmpty = document.getElementById("capex-empty"); const opexEmpty = document.getElementById("opex-empty"); const capexTotal = document.getElementById("capex-total"); const opexTotal = document.getElementById("opex-total"); const capexForm = document.getElementById("capex-form"); const opexForm = document.getElementById("opex-form"); const capexFeedback = document.getElementById("capex-feedback"); const opexFeedback = document.getElementById("opex-feedback"); const capexFormScenario = document.getElementById("capex-form-scenario"); const opexFormScenario = document.getElementById("opex-form-scenario"); const capexCurrencySelect = document.getElementById("capex-form-currency"); const opexCurrencySelect = document.getElementById("opex-form-currency"); // If no currency options were injected server-side, fetch from API const fetchCurrencyOptions = async () => { try { const resp = await fetch("/api/currencies/"); if (!resp.ok) return; const list = await resp.json(); if (Array.isArray(list) && list.length) { currencyOptions = list; populateCurrencySelects(); } } catch (err) { console.warn("Unable to fetch currency options", err); } }; const populateCurrencySelects = () => { const selectElements = [capexCurrencySelect, opexCurrencySelect].filter(Boolean); selectElements.forEach((sel) => { if (!sel) return; // Clear non-empty options except the empty placeholder const placeholder = sel.querySelector("option[value='']"); sel.innerHTML = ""; if (placeholder) sel.appendChild(placeholder); currencyOptions.forEach((opt) => { const option = document.createElement("option"); option.value = opt.id; option.textContent = opt.name || opt.id; sel.appendChild(option); }); }); }; // populate from injected options first, then fetch to refresh if (currencyOptions && currencyOptions.length) populateCurrencySelects(); else fetchCurrencyOptions(); const showFeedback = (element, message, type = "success") => { if (!element) { return; } element.textContent = message; element.classList.remove("hidden", "success", "error"); element.classList.add(type); }; const hideFeedback = (element) => { if (!element) { return; } element.classList.add("hidden"); element.textContent = ""; }; const formatAmount = (value) => Number(value).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2, }); const formatCurrencyAmount = (value, currencyCode) => { if (!currencyCode) { return formatAmount(value); } try { return new Intl.NumberFormat(undefined, { style: "currency", currency: currencyCode, minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(Number(value)); } catch (error) { return `${currencyCode} ${formatAmount(value)}`; } }; const sumAmount = (records) => records.reduce((total, record) => total + Number(record.amount || 0), 0); const describeTotal = (records) => { if (!records || records.length === 0) { return "—"; } const total = sumAmount(records); const currencyCodes = Array.from( new Set( records .map((record) => (record.currency_code || "").trim().toUpperCase()) .filter(Boolean) ) ); if (currencyCodes.length === 1) { return formatCurrencyAmount(total, currencyCodes[0]); } return `${formatAmount(total)} (mixed)`; }; const renderCostTables = (scenarioId) => { if ( !capexTableBody || !opexTableBody || !capexEmpty || !opexEmpty || !capexTotal || !opexTotal ) { return; } const capexRecords = capexByScenario[String(scenarioId)] || []; const opexRecords = opexByScenario[String(scenarioId)] || []; capexTableBody.innerHTML = ""; opexTableBody.innerHTML = ""; if (!capexRecords.length) { capexEmpty.classList.remove("hidden"); } else { capexEmpty.classList.add("hidden"); capexRecords.forEach((record) => { const row = document.createElement("tr"); row.innerHTML = `