mirror of
https://github.com/kbenestad/reimburse.git
synced 2026-06-18 08:04:31 +00:00
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
This commit is contained in:
parent
d35429314d
commit
09ceaaf360
1 changed files with 19 additions and 11 deletions
30
index.html
30
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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue