Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,156 @@
|
||||
// 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 = `
|
||||
<div id="tbl"></div>
|
||||
<div id="mp-section"></div>`;
|
||||
await buildTable(el);
|
||||
if (await hasMetalAssets()) {
|
||||
const sec = el.querySelector('#mp-section');
|
||||
sec.innerHTML = `<div id="mp-tbl" class="mt-lg"></div>`;
|
||||
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 => `<strong>${esc(a.symbol)}</strong>`,
|
||||
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 ? ` <span class="t-muted-cell">/ ${esc(a.subunit)}</span>` : ''}`,
|
||||
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 `<strong>${esc(a.unit)}</strong>`;
|
||||
const subChosen = a.displayUnit === 'subunit';
|
||||
const part = (txt, chosen) => chosen ? `<strong>${txt}</strong>` : `<span class="t-muted-cell">${txt}</span>`;
|
||||
return `${part(esc(a.unit), !subChosen)} <span class="t-muted-cell">/</span> ${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)
|
||||
: `<span class="t-muted-cell">${categorieVoorAsset(a)
|
||||
? t('assets.taxCategoryAutoIs', { waarde: t('enums.tax_category.' + categorieVoorAsset(a)) })
|
||||
: t('assets.taxCategoryAuto')}</span>`,
|
||||
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)
|
||||
: `<span class="t-muted-cell">${t('assets.taxScopeAuto')}</span>`,
|
||||
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
|
||||
? `<span class="t-muted-cell">${t(balanceCaptureOn(a) ? 'assets.balanceCaptureAutoOn' : 'assets.balanceCaptureAutoOff')}</span>`
|
||||
: a.balanceCapture === 1
|
||||
? `<span class="badge badge-accent">${t('assets.balanceCaptureOn')}</span>`
|
||||
: `<span class="badge badge-neutral">${t('assets.balanceCaptureOff')}</span>`,
|
||||
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'));
|
||||
}
|
||||
Reference in new issue
Block a user