// Generated, do not edit. sha256:b9ab466fcbb17da69242310739ff9bb1a6f805583cc7c757d134c773ce086dc3 import { t, localeTag } from '../i18n/index.js'; import { esc } from './escape.js'; import { INFO } from './icons.js'; import { openPopover, closePopover } from './popover.js'; import { fmtBasePrice, priceFromBase, isBaseAsset as isBase } from './format.js'; import { priceUnitLabel } from '../../shared/units.js'; import { assetLabel } from './asset-label.js'; const dagTekst = iso => new Intl.DateTimeFormat(localeTag(), { day: 'numeric', month: 'short', year: 'numeric' }) .format(new Date(`${iso}T00:00:00Z`)); const tijdTekst = iso => new Intl.DateTimeFormat(localeTag(), { hour: '2-digit', minute: '2-digit' }).format(new Date(iso)); const pct = v => `${v > 0 ? '+' : ''}${v.toLocaleString(localeTag(), { maximumFractionDigits: 2 })}%`; const STERKTE = { close: 'high', manual: 'high', live: 'high', spot: 'lower', carried: 'low' }; export function originLines(origin, asset) { if (!origin || origin.fiatPrice == null || isBase(asset)) return []; const prijs = fmtBasePrice(priceFromBase(origin.fiatPrice, asset)); const eenheid = asset ? priceUnitLabel(asset) : null; const bron = origin.source || t('priceOrigin.someSource'); const regels = [eenheid ? t('priceOrigin.pricePer', { prijs, eenheid, dag: dagTekst(origin.day) }) : t('priceOrigin.price', { prijs, dag: dagTekst(origin.day) })]; if (origin.kind === 'close') regels.push(t('priceOrigin.close', { bron })); else if (origin.kind === 'manual') regels.push(t('priceOrigin.manual')); else if (origin.kind === 'live') regels.push(origin.source ? t('priceOrigin.liveFrom', { bron }) : t('priceOrigin.live')); else if (origin.kind === 'spot') { regels.push(origin.moment ? t('priceOrigin.spotAt', { tijd: tijdTekst(origin.moment), bron }) : t('priceOrigin.spot', { bron })); const d = origin.deviation; const kanten = d ? [d.before != null ? t('priceOrigin.devBefore', { pct: pct(d.before) }) : null, d.after != null ? t('priceOrigin.devAfter', { pct: pct(d.after) }) : null].filter(Boolean) : []; if (kanten.length) regels.push(kanten.join(', ')); } else if (origin.kind === 'carried') { regels.push(t('priceOrigin.carried', { dag: dagTekst(origin.sourceDay || origin.day), n: origin.ageDays, bron })); } const sterkte = STERKTE[origin.kind]; if (sterkte) regels.push(t('priceOrigin.strength', { sterkte: t(`priceOrigin.strength_${sterkte}`) })); return regels; } export function originHtml(origin, asset, voor = []) { return knopHtml([...voor, ...originLines(origin, asset)]); } const RANG = { high: 3, lower: 2, low: 1 }; const rang = o => RANG[STERKTE[o.kind]] ?? 0; export function originSummaryLines(items) { return samenvattingVan(items).regels; } function samenvattingVan(items) { const assetSleutel = x => (x.asset ? x.asset.id ?? x.asset.symbol : '?'); const uniek = new Map(); const zonder = new Map(); for (const x of items || []) { if (!x || isBase(x.asset)) continue; if (!x.origin || x.origin.fiatPrice == null) { if (!zonder.has(assetSleutel(x))) zonder.set(assetSleutel(x), x); continue; } const sleutel = `${assetSleutel(x)}|${x.origin.day}`; if (!uniek.has(sleutel)) uniek.set(sleutel, x); } const met = [...uniek.values()]; if (!met.length && !zonder.size) return { regels: [], onvolledig: false }; if (zonder.size) { const eigen = met.length === 1 ? originLines(met[0].origin, met[0].asset).map((r, i) => (i === 0 ? `${assetLabel(met[0].asset)}: ${r}` : r)) : met.length ? samenvatting(met) : []; const zonderSterkte = eigen.length ? eigen.slice(0, -1) : []; const namen = [...zonder.values()].map(x => assetLabel(x.asset)).join(', '); return { onvolledig: true, regels: [...zonderSterkte, t('priceOrigin.sumMissing', { assets: namen }), t('priceOrigin.strength', { sterkte: t('priceOrigin.strength_missing') })] }; } return { onvolledig: false, regels: met.length === 1 ? originLines(met[0].origin, met[0].asset) : samenvatting(met) }; } function samenvatting(met) { const telling = new Map(); for (const { origin } of met) telling.set(origin.kind, (telling.get(origin.kind) || 0) + 1); const soorten = ['close', 'manual', 'live', 'spot', 'carried'].filter(k => telling.has(k)) .map(k => { const n = telling.get(k); return `${n} ${t(`priceHistory.kindCount_${k}${n === 1 ? 'One' : 'Many'}`)}`; }); const zwakste = met.reduce((a, b) => (rang(b.origin) < rang(a.origin) || (rang(b.origin) === rang(a.origin) && (b.origin.ageDays || 0) > (a.origin.ageDays || 0)) ? b : a)); const regels = [t('priceOrigin.sumHead', { n: met.length }), soorten.join(', ')]; if (STERKTE[zwakste.origin.kind] !== 'high') { const zin = originLines(zwakste.origin, zwakste.asset)[1] || ''; regels.push(t('priceOrigin.sumWeakest', { asset: assetLabel(zwakste.asset), zin: zin.charAt(0).toLowerCase() + zin.slice(1) })); } regels.push(t('priceOrigin.strength', { sterkte: t(`priceOrigin.strength_${STERKTE[zwakste.origin.kind]}`) })); return regels; } export function originsHtml(items, voor = []) { const { regels, onvolledig } = samenvattingVan(items); return knopHtml([...voor, ...regels], { warn: onvolledig }); } export function warningHtml(regels) { return knopHtml(regels, { warn: true }); } const BOEKING_STERKTE = { paid: 'high', market_moment: 'high', market_day: 'lower' }; export function bookingOriginLines(b, asset, dayOrigin = null) { if (!b || b.priceOrigin === 'none' || b.fiatPrice == null || isBase(asset)) return []; const prijs = fmtBasePrice(priceFromBase(b.fiatPrice, asset)); const eenheid = asset ? priceUnitLabel(asset) : null; const dag = dagTekst(String(b.occurredAt).slice(0, 10)); const regels = [eenheid ? t('priceOrigin.bookingPricePer', { prijs, eenheid }) : t('priceOrigin.bookingPrice', { prijs })]; if (b.priceOrigin === 'paid') regels.push(t('priceOrigin.bookingPaid')); else if (b.priceOrigin === 'market_moment') regels.push(t('priceOrigin.bookingMoment')); else if (b.priceOrigin === 'market_day') { const zin = dayOrigin ? originLines(dayOrigin, asset)[1] : null; regels.push(zin ? t('priceOrigin.bookingDayFrom', { dag, zin: zin.charAt(0).toLowerCase() + zin.slice(1) }) : t('priceOrigin.bookingDay', { dag })); regels.push(t('priceOrigin.bookingDayNote')); } else { regels.push(t('priceOrigin.bookingUnknown')); } const sterkte = b.priceOrigin === 'market_day' && dayOrigin && dayOrigin.kind === 'carried' ? 'low' : (BOEKING_STERKTE[b.priceOrigin] || 'unknown'); regels.push(t('priceOrigin.strength', { sterkte: t(`priceOrigin.strength_${sterkte}`) })); return regels; } export function bookingOriginHtml(b, asset, dayOrigin = null) { return knopHtml(bookingOriginLines(b, asset, dayOrigin)); } export function infoLinesHtml(regels) { return knopHtml(regels); } function knopHtml(regels, { warn = false } = {}) { if (!regels.length) return ''; return ``; } let openFor = null; function toon(btn) { if (openFor === btn) return; let regels = []; try { regels = JSON.parse(btn.dataset.originLines || '[]'); } catch { regels = []; } if (!regels.length) return; const pop = openPopover(btn, { className: 'po-pop', onClose: () => { openFor = null; } }); pop.el.setAttribute('role', 'tooltip'); pop.el.innerHTML = regels.map((r, i) => `
${esc(r)}
`).join(''); pop.position(); openFor = btn; } function verberg(btn) { if (openFor === btn) closePopover(); } if (typeof document !== 'undefined' && typeof document.addEventListener === 'function') { const btnVan = e => (e.target && e.target.closest ? e.target.closest('.po-btn') : null); document.addEventListener('mouseover', e => { const b = btnVan(e); if (b) toon(b); }); document.addEventListener('mouseout', e => { const b = btnVan(e); if (b && !(e.relatedTarget && b.contains(e.relatedTarget))) verberg(b); }); document.addEventListener('focusin', e => { const b = btnVan(e); if (b) toon(b); }); document.addEventListener('focusout', e => { const b = btnVan(e); if (b) verberg(b); }); document.addEventListener('click', e => { const b = btnVan(e); if (!b) return; e.stopPropagation(); toon(b); }, true); }