diff options
| author | Adam Soltys <[email protected]> | 2026-10-02 09:48:21 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-02 09:48:21 -0700 |
| commit | e3015141bc806f87049a13b5e192aee7d67b3a23 (patch) | |
| tree | 12b7e4c5622bfb2c4320a1d082b3a181ad342fe8 | |
| parent | ea20b96e6c633ff38a5221719a9240f77342f792 (diff) | |
| download | coinosv3-e3015141bc806f87049a13b5e192aee7d67b3a23.tar.gz coinosv3-e3015141bc806f87049a13b5e192aee7d67b3a23.zip | |
"Start in point of sale" belongs to one wallet, not the whole device
It was one device-wide localStorage flag, so whoever signed in next on a
till landed in the last owner's point of sale. Now it is keyed by the
wallet (still per device); the old flag is dropped since it can't say
whose it was.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
| -rw-r--r-- | src/features/pos.js | 14 | ||||
| -rw-r--r-- | tools/pos-test.js | 13 |
2 files changed, 21 insertions, 6 deletions
diff --git a/src/features/pos.js b/src/features/pos.js index eead222..dafd388 100644 --- a/src/features/pos.js +++ b/src/features/pos.js @@ -29,10 +29,14 @@ export function posFeature(ctx) { const save = (s) => { try { wallet.saveFeatureState('pos', s); } catch {} }; const SALES_MAX = 500; // Point-of-sale mode is per device (the till, not every phone the owner - // carries): with it on, the app opens straight onto the point of sale. - const POS_MODE = 'btc-wallet-pos-mode'; - const posMode = () => { try { return localStorage.getItem(POS_MODE) === '1'; } catch { return false; } }; - const setPosMode = (on) => { try { if (on) localStorage.setItem(POS_MODE, '1'); else localStorage.removeItem(POS_MODE); } catch {} }; + // carries) AND per wallet: with it on, THIS wallet opens straight onto the + // point of sale here. It used to be one device-wide flag, so whoever signed + // in next on a till landed in the last owner's point of sale. Per wallet, + // it simply comes back with its owner. + const LEGACY_POS_MODE = 'btc-wallet-pos-mode'; + const posKey = () => LEGACY_POS_MODE + ':' + (wallet._cacheKey ? wallet._cacheKey() : ''); + const posMode = () => { try { return localStorage.getItem(posKey()) === '1'; } catch { return false; } }; + const setPosMode = (on) => { try { if (on) localStorage.setItem(posKey(), '1'); else localStorage.removeItem(posKey()); } catch {} }; const fiatLine = (sats, rate = rateNow(), code = getCurrency()) => (rate ? fmtFiat(sats, rate, code) : ''); const pct = (sats, p) => Math.round(sats * p / 100); @@ -321,6 +325,8 @@ export function posFeature(ctx) { id: 'pos', // A wallet just opened: the /pos link or point-of-sale mode lands here. init() { + // the old device-wide flag can't say whose it was: let it go + try { localStorage.removeItem(LEGACY_POS_MODE); } catch {} if (ui.posAtBoot || posMode()) { ui.posAtBoot = false; open(); } }, screenView() { diff --git a/tools/pos-test.js b/tools/pos-test.js index 6e3d801..c7c7c29 100644 --- a/tools/pos-test.js +++ b/tools/pos-test.js @@ -12,7 +12,7 @@ ${domHelper} const state = {}; const ui = { screen: 'wallet' }; let watch = null, cancelled = [], invoices = 0; -const wallet = { loadFeatureState: (k, d) => (k in state ? state[k] : d), saveFeatureState: (k, v) => { state[k] = JSON.parse(JSON.stringify(v)); } }; +const wallet = { loadFeatureState: (k, d) => (k in state ? state[k] : d), saveFeatureState: (k, v) => { state[k] = JSON.parse(JSON.stringify(v)); }, _cacheKey: () => window.__walletKey || 'w1' }; 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'), @@ -30,7 +30,8 @@ const ctx = { }; const feature = posFeature(ctx); window.__feature = feature; function render() { document.querySelector('#app').replaceChildren(feature.screenView() || h('div', { id: 'closed' }, 'closed')); } -window.test = { open: () => { feature.openPos(); }, init: () => { feature.init(); render(); }, settle: (ok) => { const w = watch; watch = null; w.cb({ step: ok ? 'done' : 'failed' }); }, get watch() { return watch && watch.id; }, get cancelled() { return cancelled; }, get sales() { return (state.pos || {}).sales || []; }, ui }; +window.test = { open: () => { feature.openPos(); }, init: () => { feature.init(); render(); }, + cards: () => { document.querySelector('#app').replaceChildren(...feature.posSettingsCards()); }, settle: (ok) => { const w = watch; watch = null; w.cb({ step: ok ? 'done' : 'failed' }); }, get watch() { return watch && watch.id; }, get cancelled() { return cancelled; }, get sales() { return (state.pos || {}).sales || []; }, ui }; render(); `; const bundle = await Bun.build({ @@ -119,6 +120,14 @@ try { 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'))); + + console.log('\n[start in point of sale belongs to one wallet]'); + const boot = async (key) => { await page.evaluate((k) => { window.__walletKey = k; test.ui.pos = null; test.init(); }, key); await pause(50); return !!(await page.$('.pos-amount')); }; + await page.evaluate(() => { localStorage.setItem('btc-wallet-pos-mode', '1'); window.__walletKey = 'owner'; test.cards(); }); await pause(50); + await page.evaluate(() => { const c = [...document.querySelectorAll('label')].find((l) => /Start in point of sale/.test(l.textContent)).querySelector('input'); if (!c.checked) c.click(); }); await pause(50); + check("the old device-wide flag is dropped on start (it can't say whose it was)", await page.evaluate(() => (test.ui.pos = null, true)) && (await boot('owner')) && await page.evaluate(() => localStorage.getItem('btc-wallet-pos-mode') === null)); + check('another wallet on the same device does not start in point of sale', !(await boot('someone-else'))); + check('the owner still does, after anyone else has been in', await boot('owner')); check('no browser errors', errors.length === 0); } finally { await browser.close(); server.stop(true); } console.log('\nā
point of sale'); |
