mirror of
https://github.com/kbenestad/reimburse.git
synced 2026-06-18 08:04:31 +00:00
Replace FX rate tooltip with modal popup; fix Other currency label
Selecting a non-base currency now shows a modal explaining the exchange
rate convention, using the actual currency names. Selecting Other shows
a variant asking the user to enter the ISO code first. Both messages
are configurable via fx-rate-message and fx-rate-message-other in
config.yml using {foreign} and {base} placeholders.
The Other option in the currency dropdown no longer shows __OTHER__.
https://claude.ai/code/session_01MbwfxnjLA9KdFTrfzB55HM
This commit is contained in:
parent
0853fae199
commit
59fcafa135
2 changed files with 21 additions and 10 deletions
|
|
@ -25,6 +25,10 @@ accent-colour: "#1a3a5c"
|
||||||
intro: ""
|
intro: ""
|
||||||
footer: "Confidential"
|
footer: "Confidential"
|
||||||
|
|
||||||
|
# FX rate modal messages ({foreign} = foreign currency name, {base} = base currency name)
|
||||||
|
fx-rate-message: "You have selected an expense in a currency different from the one in which you are submitting your claim. Please enter the exchange rate as amount of {foreign} you pay for 1 {base}."
|
||||||
|
fx-rate-message-other: "You have selected an expense in a currency different from the one in which you are submitting your claim. Enter the three letter currency code first, and then enter the exchange rate as amount of the foreign currency you pay for 1 {base}."
|
||||||
|
|
||||||
# Base currency (ISO code — must appear in currencies list)
|
# Base currency (ISO code — must appear in currencies list)
|
||||||
currency-base: USD
|
currency-base: USD
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -395,8 +395,17 @@ function renderLine(ln, item) {
|
||||||
const vendIn = el('input', {type:'text', value: ln.vendor, placeholder:'Vendor name'});
|
const vendIn = el('input', {type:'text', value: ln.vendor, placeholder:'Vendor name'});
|
||||||
vendIn.addEventListener('input', () => { ln.vendor = vendIn.value; });
|
vendIn.addEventListener('input', () => { ln.vendor = vendIn.value; });
|
||||||
|
|
||||||
|
async function showFxModal(code) {
|
||||||
|
const bn = getCurrencyName(baseCur);
|
||||||
|
const isOther = !code || code === 'Other';
|
||||||
|
const tmpl = isOther
|
||||||
|
? (CFG['fx-rate-message-other'] || 'You have selected an expense in a currency different from the one in which you are submitting your claim. Enter the three letter currency code first, and then enter the exchange rate as amount of the foreign currency you pay for 1 {base}.')
|
||||||
|
: (CFG['fx-rate-message'] || 'You have selected an expense in a currency different from the one in which you are submitting your claim. Please enter the exchange rate as amount of {foreign} you pay for 1 {base}.');
|
||||||
|
const fn = isOther ? 'the foreign currency' : getCurrencyName(code);
|
||||||
|
await showWarningModal(tmpl.replace(/\{foreign\}/g, fn).replace(/\{base\}/g, bn));
|
||||||
|
}
|
||||||
|
|
||||||
function applyFxCurrency(code) {
|
function applyFxCurrency(code) {
|
||||||
fxIn.dataset.tip = buildFxTip(code, baseCur);
|
|
||||||
if (code === baseCur) {
|
if (code === baseCur) {
|
||||||
ln.fxRate = '1.00000'; fxIn.value = '1.00000'; fxIn.readOnly = true;
|
ln.fxRate = '1.00000'; fxIn.value = '1.00000'; fxIn.readOnly = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -409,28 +418,28 @@ function renderLine(ln, item) {
|
||||||
if (progAreaEl) progAreaEl._refresh();
|
if (progAreaEl) progAreaEl._refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
const currenciesWithOther = [...currencies, {code: '__OTHER__', name: 'Other (enter ISO code)'}];
|
const currenciesWithOther = [...currencies, {code: 'Other', name: 'Enter ISO code'}];
|
||||||
const curDD = makeCDD(currenciesWithOther, ln.customCurrency ? '__OTHER__' : ln.currency, code => {
|
const curDD = makeCDD(currenciesWithOther, ln.customCurrency ? 'Other' : ln.currency, async code => {
|
||||||
if (code === '__OTHER__') {
|
if (code === 'Other') {
|
||||||
ln.customCurrency = true;
|
ln.customCurrency = true;
|
||||||
ln.currency = '';
|
ln.currency = '';
|
||||||
curDD.style.display = 'none';
|
curDD.style.display = 'none';
|
||||||
otherCurWrap.style.display = 'flex';
|
otherCurWrap.style.display = 'flex';
|
||||||
ln.fxRate = ''; fxIn.value = ''; fxIn.readOnly = false; fxIn.dataset.tip = '';
|
ln.fxRate = ''; fxIn.value = ''; fxIn.readOnly = false;
|
||||||
recalc(); if (progAreaEl) progAreaEl._refresh();
|
recalc(); if (progAreaEl) progAreaEl._refresh();
|
||||||
|
await showFxModal('Other');
|
||||||
otherCurIn.focus();
|
otherCurIn.focus();
|
||||||
} else {
|
} else {
|
||||||
ln.customCurrency = false;
|
ln.customCurrency = false;
|
||||||
ln.currency = code;
|
ln.currency = code;
|
||||||
applyFxCurrency(code);
|
applyFxCurrency(code);
|
||||||
|
if (code !== baseCur) await showFxModal(code);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (ln.customCurrency) curDD.style.display = 'none';
|
if (ln.customCurrency) curDD.style.display = 'none';
|
||||||
|
|
||||||
const otherCurIn = el('input', {type:'text', maxlength:'3', placeholder:'e.g. THB',
|
const otherCurIn = el('input', {type:'text', maxlength:'3', placeholder:'e.g. THB',
|
||||||
style:{width:'70px', textTransform:'uppercase', letterSpacing:'1px', fontFamily:'inherit'}});
|
style:{width:'70px', textTransform:'uppercase', letterSpacing:'1px', fontFamily:'inherit'}});
|
||||||
otherCurIn.className = 'tip';
|
|
||||||
otherCurIn.dataset.tip = 'You have selected other currency. Please insert the three-letter ISO code (THB for Thai baht, USD for US dollars).';
|
|
||||||
if (ln.customCurrency && ln.currency) otherCurIn.value = ln.currency;
|
if (ln.customCurrency && ln.currency) otherCurIn.value = ln.currency;
|
||||||
otherCurIn.addEventListener('input', () => {
|
otherCurIn.addEventListener('input', () => {
|
||||||
const val = otherCurIn.value.toUpperCase().replace(/[^A-Z]/g, '').slice(0, 3);
|
const val = otherCurIn.value.toUpperCase().replace(/[^A-Z]/g, '').slice(0, 3);
|
||||||
|
|
@ -439,7 +448,7 @@ function renderLine(ln, item) {
|
||||||
if (val.length === 3) {
|
if (val.length === 3) {
|
||||||
applyFxCurrency(val);
|
applyFxCurrency(val);
|
||||||
} else {
|
} else {
|
||||||
ln.fxRate = ''; fxIn.value = ''; fxIn.readOnly = false; fxIn.dataset.tip = '';
|
ln.fxRate = ''; fxIn.value = ''; fxIn.readOnly = false;
|
||||||
recalc(); if (progAreaEl) progAreaEl._refresh();
|
recalc(); if (progAreaEl) progAreaEl._refresh();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -463,8 +472,6 @@ function renderLine(ln, item) {
|
||||||
const fxIn = el('input', {type:'text', style:{width:'120px', textAlign:'right'}, placeholder:'0.00000'});
|
const fxIn = el('input', {type:'text', style:{width:'120px', textAlign:'right'}, placeholder:'0.00000'});
|
||||||
fxIn.value = ln.fxRate;
|
fxIn.value = ln.fxRate;
|
||||||
fxIn.readOnly = !ln.customCurrency && ln.currency === baseCur;
|
fxIn.readOnly = !ln.customCurrency && ln.currency === baseCur;
|
||||||
fxIn.className = 'tip';
|
|
||||||
fxIn.dataset.tip = buildFxTip(ln.currency, baseCur);
|
|
||||||
fxIn.addEventListener('input', () => {
|
fxIn.addEventListener('input', () => {
|
||||||
ln.fxRate = fxIn.value;
|
ln.fxRate = fxIn.value;
|
||||||
const rate = parseFloat(fxIn.value);
|
const rate = parseFloat(fxIn.value);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue