document.addEventListener("DOMContentLoaded", () => { const dataElement = document.getElementById("costs-payload"); let capexByScenario = {}; let opexByScenario = {}; 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; } } } 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 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 sumAmount = (records) => records.reduce((total, record) => total + Number(record.amount || 0), 0); 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 = ` ${formatAmount(record.amount)} ${record.description || "—"} `; capexTableBody.appendChild(row); }); } if (!opexRecords.length) { opexEmpty.classList.remove("hidden"); } else { opexEmpty.classList.add("hidden"); opexRecords.forEach((record) => { const row = document.createElement("tr"); row.innerHTML = ` ${formatAmount(record.amount)} ${record.description || "—"} `; opexTableBody.appendChild(row); }); } capexTotal.textContent = formatAmount(sumAmount(capexRecords)); opexTotal.textContent = formatAmount(sumAmount(opexRecords)); }; const toggleCostView = (show) => { if ( !costsEmptyState || !costsDataWrapper || !capexTableBody || !opexTableBody ) { return; } if (show) { costsEmptyState.classList.add("hidden"); costsDataWrapper.classList.remove("hidden"); } else { costsEmptyState.classList.remove("hidden"); costsDataWrapper.classList.add("hidden"); capexTableBody.innerHTML = ""; opexTableBody.innerHTML = ""; if (capexTotal) { capexTotal.textContent = "—"; } if (opexTotal) { opexTotal.textContent = "—"; } if (capexEmpty) { capexEmpty.classList.add("hidden"); } if (opexEmpty) { opexEmpty.classList.add("hidden"); } } }; const syncFormSelections = (value) => { if (capexFormScenario) { capexFormScenario.value = value || ""; } if (opexFormScenario) { opexFormScenario.value = value || ""; } }; if (filterSelect) { filterSelect.addEventListener("change", (event) => { const value = event.target.value; if (!value) { toggleCostView(false); syncFormSelections(""); return; } toggleCostView(true); renderCostTables(value); syncFormSelections(value); }); } const submitCostEntry = async (event, targetUrl, storageMap, feedbackEl) => { event.preventDefault(); hideFeedback(feedbackEl); const formData = new FormData(event.target); const scenarioId = formData.get("scenario_id"); const payload = { scenario_id: scenarioId ? Number(scenarioId) : null, amount: Number(formData.get("amount")), description: formData.get("description") || null, }; if (!payload.scenario_id) { showFeedback(feedbackEl, "Select a scenario before submitting.", "error"); return; } try { const response = await fetch(targetUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); if (!response.ok) { const errorDetail = await response.json().catch(() => ({})); throw new Error(errorDetail.detail || "Unable to save cost entry."); } const result = await response.json(); const mapKey = String(result.scenario_id); if (!Array.isArray(storageMap[mapKey])) { storageMap[mapKey] = []; } storageMap[mapKey].push(result); event.target.reset(); showFeedback(feedbackEl, "Entry saved successfully.", "success"); if (filterSelect && filterSelect.value === mapKey) { renderCostTables(mapKey); } } catch (error) { showFeedback( feedbackEl, error.message || "An unexpected error occurred.", "error" ); } }; if (capexForm) { capexForm.addEventListener("submit", (event) => submitCostEntry(event, "/api/costs/capex", capexByScenario, capexFeedback) ); } if (opexForm) { opexForm.addEventListener("submit", (event) => submitCostEntry(event, "/api/costs/opex", opexByScenario, opexFeedback) ); } if (filterSelect && filterSelect.value) { toggleCostView(true); renderCostTables(filterSelect.value); syncFormSelections(filterSelect.value); } });