// Generated, do not edit. sha256:7de3dc53eab20f070a6ac8c7162fee1bd0695f724c6a13e314a994181782906e import { listAssets, listBookableAssets, createAsset, updateAsset, deleteAsset } from '../data/assets.js'; import { hasMetalAssets } from '../data/metals.js'; import { tableViewCfg } from '../data/preferences.js'; import { t } from '../i18n/index.js'; import * as dialog from '../ui/dialog.js'; import { esc } from '../ui/escape.js'; import { ENUMS, CONFIG, balanceCaptureOn } from '../../shared/config.js'; import { REIKWIJDTE, categorieVoorAsset } from '../tax/constants.js'; import { renderTable } from '../ui/table.js'; import { takeRowFocus } from '../ui/row-focus.js'; import * as metalProducts from './metal-products.js'; import { capacityCfg } from '../ui/lock.js'; import { baseCurrency } from '../app-settings.js'; let tableApi = null; export async function render(el) { el.innerHTML = `
`; await buildTable(el); if (await hasMetalAssets()) { const sec = el.querySelector('#mp-section'); sec.innerHTML = ``; metalProducts.mount(sec.querySelector('#mp-tbl')); } } function kindOpts() { return ENUMS.ASSET_KIND.map(v => ({ value: v, label: t('enums.asset_kind.' + v) })); } function displayUnitOpts() { return ENUMS.ASSET_DISPLAY_UNIT.map(v => ({ value: v, label: t('enums.displayUnit.' + v) })); } function taxCategorieOpts(vals = {}) { const derived = categorieVoorAsset(vals); return [{ value: '', label: derived ? t('assets.taxCategoryAutoIs', { waarde: t('enums.tax_category.' + derived) }) : t('assets.taxCategoryAuto') }, ...ENUMS.TAX_CATEGORY.filter(v => v !== derived || v === vals.taxCategory) .map(v => ({ value: v, label: t('enums.tax_category.' + v) }))]; } function taxScopeOpts(vals = {}) { return [{ value: '', label: t('assets.taxScopeAuto') }, ...ENUMS.TAX_SCOPE.filter(v => v !== REIKWIJDTE.ALL || v === vals.taxScope) .map(v => ({ value: v, label: t('enums.tax_scope.' + v) }))]; } function balanceCaptureOpts() { return [{ value: '', label: t('assets.taxCategoryAuto') }, { value: '1', label: t('assets.balanceCaptureOn') }, { value: '0', label: t('assets.balanceCaptureOff') }]; } const captureValue = v => (v === '' || v == null ? null : Number(v)); async function buildTable(el) { const columns = [ { key: 'name', label: t('assets.name'), sortable: true, text: true, edit: { type: 'text', placeholder: 'Bitcoin' } }, { key: 'symbol', label: t('assets.symbol'), sortable: true, render: a => `${esc(a.symbol)}`, edit: { type: 'text', placeholder: 'BTC' } }, { key: 'kind', label: t('assets.kind'), sortable: true, render: a => t('enums.asset_kind.' + a.kind), group: { value: a => a.kind, label: v => t('enums.asset_kind.' + v) }, edit: { type: 'select', options: kindOpts, reactive: true } }, { key: 'unit', label: t('assets.unit'), sortable: true, render: a => `${esc(a.unit)}${a.subunit ? ` / ${esc(a.subunit)}` : ''}`, edit: { type: 'text', placeholder: 'BTC / g / ozt' } }, { key: 'subunit', label: t('assets.subunit'), render: a => (a.subunit ? esc(a.subunit) : '-'), edit: { type: 'text', placeholder: 'sat / mg' } }, { key: 'displayUnit', label: t('assets.displayUnit'), sortable: true, render: a => { if (!a.subunit) return `${esc(a.unit)}`; const subChosen = a.displayUnit === 'subunit'; const part = (txt, chosen) => chosen ? `${txt}` : `${txt}`; return `${part(esc(a.unit), !subChosen)} / ${part(esc(a.subunit), subChosen)}`; }, edit: { type: 'select', options: displayUnitOpts } }, { key: 'decimals', label: t('assets.decimals'), align: 'num', sortable: true, edit: { type: 'number', attrs: { min: 0, step: 1 } } }, { key: 'taxCategory', label: t('assets.taxCategory'), sortable: true, render: a => a.taxCategory ? t('enums.tax_category.' + a.taxCategory) : `${categorieVoorAsset(a) ? t('assets.taxCategoryAutoIs', { waarde: t('enums.tax_category.' + categorieVoorAsset(a)) }) : t('assets.taxCategoryAuto')}`, group: { value: a => a.taxCategory || '', label: v => v ? t('enums.tax_category.' + v) : t('assets.taxCategoryAuto') }, edit: { type: 'select', options: taxCategorieOpts } }, { key: 'taxScope', label: t('assets.taxScope'), sortable: true, render: a => a.taxScope ? t('enums.tax_scope.' + a.taxScope) : `${t('assets.taxScopeAuto')}`, group: { value: a => a.taxScope || '', label: v => v ? t('enums.tax_scope.' + v) : t('assets.taxScopeAuto') }, edit: { type: 'select', options: taxScopeOpts } }, { key: 'balanceCapture', label: t('assets.balanceCapture'), sortable: true, render: a => a.balanceCapture == null ? `${t(balanceCaptureOn(a) ? 'assets.balanceCaptureAutoOn' : 'assets.balanceCaptureAutoOff')}` : a.balanceCapture === 1 ? `${t('assets.balanceCaptureOn')}` : `${t('assets.balanceCaptureOff')}`, edit: { type: 'select', options: balanceCaptureOpts } }, ]; function toPayload(v) { const symbol = String(v.symbol || '').trim(); const name = String(v.name || '').trim(); const unit = String(v.unit || '').trim(); if (!symbol || !name || !unit) throw new Error(t('assets.fillSymbolNameUnit')); if (v.kind === 'metal') { const M = CONFIG.METALS; if (!M.UNITS[unit]) { throw new Error(t('assets.metalUnitUnknown', { eenheden: Object.keys(M.UNITS).join(', ') })); } return { symbol, name, kind: 'metal', unit, subunit: M.BASE_UNIT, decimals: M.BASE_DECIMALS, displayUnit: v.displayUnit === 'subunit' ? 'subunit' : 'unit', taxCategory: v.taxCategory || null, taxScope: v.taxScope || null, balanceCapture: captureValue(v.balanceCapture), }; } const decimals = parseInt(v.decimals, 10); if (!Number.isInteger(decimals) || decimals < 0) throw new Error(t('assets.fillDecimals')); const subunit = (v.subunit || '').trim() || null; const displayUnit = (subunit && v.displayUnit === 'subunit') ? 'subunit' : 'unit'; return { symbol, name, kind: v.kind, unit, subunit, decimals, displayUnit, taxCategory: v.taxCategory || null, taxScope: v.taxScope || null, balanceCapture: captureValue(v.balanceCapture), }; } const rijen = await listAssets(); const bookable = async () => (await listBookableAssets()).filter(r => r.symbol !== baseCurrency()).length; let used = await bookable(); tableApi = renderTable(el.querySelector('#tbl'), { columns, rows: rijen, ...capacityCfg('assets', () => used), ...(await tableViewCfg('assets', { key: 'symbol', dir: 'asc' })), emptyText: t('assets.none'), noneLabel: t('table.none'), collapsibleGroups: true, newLabel: t('table.new'), newDefaults: { kind: 'crypto', decimals: '', displayUnit: 'unit', taxCategory: '', taxScope: '', balanceCapture: '' }, saveLabel: t('assets.save'), cancelLabel: t('assets.cancel'), onCreate: async v => { const id = await createAsset(toPayload(v)); used = await bookable(); tableApi.refresh(await listAssets(), { locate: id }); }, onSave: async (id, v) => { await updateAsset(id, toPayload(v)); tableApi.refresh(await listAssets()); }, onDelete: async id => { if (!(await dialog.confirm({ message: t('assets.confirmDelete'), danger: true }))) return; try { await deleteAsset(id); used = await bookable(); tableApi.refresh(await listAssets()); } catch (e) { dialog.alert({ title: t('dialog.error'), message: e.message }); } }, }); tableApi.focusRow(takeRowFocus('assets')); }