aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-21 11:08:06 -0700
committerAdam Soltys <[email protected]>2026-09-21 11:08:06 -0700
commitdc68a27ecaadb3ea108b9b9f42cc7c471b6b910a (patch)
treeaefa4ecc84d06236e754efe96a072e7610936426
parentffec5e1a52596a3be867558c41b43ac9b3892c0c (diff)
downloadcoinosv3-dc68a27ecaadb3ea108b9b9f42cc7c471b6b910a.tar.gz
coinosv3-dc68a27ecaadb3ea108b9b9f42cc7c471b6b910a.zip
Point of sale: in a currency the pad works like a till — digits shift in from the right.
5 is 0.05, 277 is 2.77, 5588 is 55.88; backspace shifts out; the "." key becomes "00". Sats are whole numbers and type plainly. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
-rw-r--r--src/features/pos.js14
-rw-r--r--tools/pos-test.js13
2 files changed, 24 insertions, 3 deletions
diff --git a/src/features/pos.js b/src/features/pos.js
index 42e4590..127effc 100644
--- a/src/features/pos.js
+++ b/src/features/pos.js
@@ -45,10 +45,20 @@ export function posFeature(ctx) {
render();
}
// Digits on screen, into the same field a keyboard or a paste would fill.
+ // In the user's currency the pad works like a till: digits shift in from
+ // the right with two decimals, so 5 is 0.05, 277 is 2.77, 5588 is 55.88,
+ // and the "." key becomes "00". Sats are whole numbers and type plainly.
function numpad(get, set) {
+ const cents = getUnit() === 'fiat';
const press = (k) => {
let v = String(get() || '');
- if (k === 'del') v = v.slice(0, -1);
+ if (cents) {
+ let d = v.replace(/\D/g, '');
+ if (k === 'del') d = d.slice(0, -1);
+ else d = (d + (k === '.' ? '00' : k)).slice(0, 12);
+ d = d.replace(/^0+/, '');
+ v = d ? (parseInt(d, 10) / 100).toFixed(2) : '';
+ } else if (k === 'del') v = v.slice(0, -1);
else if (k === '.') { if (!v.includes('.')) v = (v || '0') + '.'; }
else if (v === '0') v = k;
else v += k;
@@ -57,7 +67,7 @@ export function posFeature(ctx) {
const key = (k, label) => h('button', { class: 'pos-key' + (k === 'del' ? ' del' : ''), type: 'button', 'aria-label': k === 'del' ? t('posBackspace') : label, onClick: () => press(k) }, label);
return h('div', { class: 'pos-pad' },
...['1', '2', '3', '4', '5', '6', '7', '8', '9'].map((k) => key(k, k)),
- key('.', '.'), key('0', '0'), key('del', '\u232b'));
+ key('.', cents ? '00' : '.'), key('0', '0'), key('del', '\u232b'));
}
function close() {
const p = ui.pos;
diff --git a/tools/pos-test.js b/tools/pos-test.js
index a50d9de..c38c3ea 100644
--- a/tools/pos-test.js
+++ b/tools/pos-test.js
@@ -16,7 +16,7 @@ const wallet = { loadFeatureState: (k, d) => (k in state ? state[k] : d), saveFe
const ctx = {
h, ui, wallet, render, toast: (m) => (window.toasts = (window.toasts || [])).push(m), copy: (x) => (window.copied = x),
fmtAmount: (n) => Number(n).toLocaleString('en-US'), unitLabel: () => 'sats', unitTag: () => h('span', { class: 'unit-tag' }, 'sats'),
- parseAmount: (v) => { const n = Number(String(v).replace(/,/g, '')); return isFinite(n) ? Math.round(n) : null; }, getUnit: () => 'sats',
+ parseAmount: (v) => { const n = Number(String(v).replace(/,/g, '')); return isFinite(n) ? Math.round(n) : null; }, getUnit: () => window.__unit || 'sats',
brandHeader: () => null,
hook(name, ...a) {
if (name === 'arkReady') return true;
@@ -97,6 +97,17 @@ try {
check('with the prompt off, Charge goes straight to the invoice', /Scan to pay/.test(await text()) && /300 sats/.test(await text()) && await page.evaluate(() => test.watch === 'ln3'));
await page.evaluate(() => test.settle(false)); await pause(50);
check('an expired invoice returns to the amount screen and says so', /That invoice expired/.test(await text()));
+ console.log('\n[a till in dollars]');
+ await page.evaluate(() => { window.__unit = 'fiat'; test.ui.pos = null; test.open(); }); await pause(50);
+ await click('5');
+ check('one digit is cents', await page.$eval('.pos-amount', (i) => i.value) === '0.05');
+ await click('\u232b'); for (const k of ['2', '7', '7']) await click(k);
+ check('digits shift in from the right', await page.$eval('.pos-amount', (i) => i.value) === '2.77');
+ await click('\u232b'); await click('\u232b'); await click('\u232b'); for (const k of ['5', '5', '8', '8']) await click(k);
+ check('...to any length', await page.$eval('.pos-amount', (i) => i.value) === '55.88');
+ await click('\u232b'); await click('\u232b'); await click('00');
+ check('the dot key is 00 in a currency', await page.$eval('.pos-amount', (i) => i.value) === '55.00');
+ await page.evaluate(() => { window.__unit = 'sats'; });
await page.evaluate(() => { test.ui.pos = null; test.ui.posAtBoot = true; test.init(); }); await pause(50);
check('the /pos link opens the till once a wallet is up', !!(await page.$('.pos-amount')));
check('no browser errors', errors.length === 0);