From 09ceaaf3608cdf9041edcfffbcfb11b6d1e614e2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 09:15:54 +0000 Subject: [PATCH] Add selectable base currency to form header Replace static base currency badge with a currency dropdown (makeCDD). Changing the selection updates state.baseCurrency, re-renders all item/line blocks so closures capture the new base, and recalculates totals. All dynamic references to CFG['currency-base'] replaced with state.baseCurrency. https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1 --- index.html | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/index.html b/index.html index 712e763..49c1f3d 100644 --- a/index.html +++ b/index.html @@ -140,12 +140,12 @@ async function loadConfig() { } // ========== STATE ========== -const state = { staff: '', periodFrom: '', periodTo: '', items: [], _grandTotal: 0 }; +const state = { staff: '', periodFrom: '', periodTo: '', baseCurrency: CFG['currency-base'], items: [], _grandTotal: 0 }; function newItem() { return { id: uid(), name: '', lines: [newLine()], _subtotal: 0 }; } function newLine() { return { - id: uid(), date: '', description: '', currency: CFG['currency-base'], + id: uid(), date: '', description: '', currency: state.baseCurrency, fxRate: '1.00000', vendor: '', hasReceipt: true, receipts: [], noReceiptExplanation: '', amount: '', account: '', program: '', programOther: '' }; @@ -164,11 +164,11 @@ function recalc() { item._subtotal = sub; grand += sub; const se = $(`#sub-${item.id}`); - if (se) se.textContent = `${CFG['currency-base']} ${fmtAmt(sub)}`; + if (se) se.textContent = `${state.baseCurrency} ${fmtAmt(sub)}`; }); state._grandTotal = grand; const ge = $('#grand-total'); - if (ge) ge.textContent = `${CFG['currency-base']} ${fmtAmt(grand)}`; + if (ge) ge.textContent = `${state.baseCurrency} ${fmtAmt(grand)}`; } // ========== CURRENCY DROPDOWN ========== @@ -246,13 +246,21 @@ function render() { const toInput = el('input', {type:'date', value: state.periodTo}); toInput.addEventListener('change', () => { state.periodTo = toInput.value; }); - const baseBadge = el('span', {style:{fontWeight:'600', fontSize:'14px', padding:'7px 0'}}, CFG['currency-base']); + const baseCurDD = makeCDD(CFG.currencies || [], state.baseCurrency, code => { + state.baseCurrency = code; + const box = $('#items-box'); + if (box) { + box.innerHTML = ''; + state.items.forEach(item => box.appendChild(renderItem(item))); + } + recalc(); + }); wrap.appendChild(el('div', {className:'frow'}, [ el('div', {className:'fgrp grow'}, [el('label', null, 'Staff'), staffInput]), el('div', {className:'fgrp'}, [el('label', null, 'Period from'), fromInput]), el('div', {className:'fgrp'}, [el('label', null, 'to'), toInput]), - el('div', {className:'fgrp'}, [el('label', null, 'Base currency'), baseBadge]), + el('div', {className:'fgrp'}, [el('label', null, 'Base currency'), baseCurDD]), ])); wrap.appendChild(el('hr', {className:'divider'})); @@ -274,7 +282,7 @@ function render() { addItemBtn, el('div', {className:'grand-total'}, [ 'Total reimbursement claim: ', - el('span', {id:'grand-total'}, `${CFG['currency-base']} ${fmtAmt(0)}`) + el('span', {id:'grand-total'}, `${state.baseCurrency} ${fmtAmt(0)}`) ]) ])); @@ -301,7 +309,7 @@ function renderItem(item) { blk.appendChild(el('div', {className:'item-hdr'}, [ el('label', null, 'Item / Project / Travel'), el('span', {className:'item-subtotal'}, [ - 'Subtotal: ', el('span', {id:`sub-${item.id}`}, `${CFG['currency-base']} ${fmtAmt(0)}`) + 'Subtotal: ', el('span', {id:`sub-${item.id}`}, `${state.baseCurrency} ${fmtAmt(0)}`) ]), rmBtn ])); @@ -327,7 +335,7 @@ function renderLine(ln, item) { const blk = el('div', {className:'line-blk', id:`line-${ln.id}`}); const currencies = CFG.currencies || []; - const baseCur = CFG['currency-base']; + const baseCur = state.baseCurrency; // Row 1: Date, Description, Currency, FX Rate const dateIn = el('input', {type:'date', value: ln.date, style:{width:'140px'}}); @@ -461,7 +469,7 @@ function validate() { if (!ln.vendor.trim()) errs.push(`${lx}: Vendor is required.`); const amt = parseFloat(ln.amount); if (isNaN(amt) || amt <= 0) errs.push(`${lx}: Amount must be a positive number.`); - if (ln.currency !== CFG['currency-base']) { + if (ln.currency !== state.baseCurrency) { const rate = parseFloat(ln.fxRate); if (isNaN(rate) || rate <= 0) errs.push(`${lx}: FX rate must be a positive number.`); } @@ -499,7 +507,7 @@ async function generatePDF() { const black = rgb(0.13, 0.13, 0.13); const gray = rgb(0.45, 0.45, 0.45); const lineCol = rgb(0.75, 0.75, 0.75); - const baseCur = CFG['currency-base']; + const baseCur = state.baseCurrency; // Logo let logoImage = null;