Versie 0.2.0
This commit is contained in:
commit
e77d8fd373
495 files changed
+81026
No files matched your search
@@ -0,0 +1,87 @@
|
||||
// Generated, do not edit. sha256:ae09cffb6bcb813ac103c0c39e8227c38347409ffb83175ba705ade666f63970
|
||||
import { listMetalAssets, listMetalProducts, createMetalProduct, updateMetalProduct, deleteMetalProduct } from '../data/metals.js';
|
||||
import { tableViewCfg } from '../data/preferences.js';
|
||||
import { t, localeTag } from '../i18n/index.js';
|
||||
import * as dialog from '../ui/dialog.js';
|
||||
import { ENUMS, CONFIG } from '../../shared/config.js';
|
||||
import { renderTable } from '../ui/table.js';
|
||||
import { toBaseByFactor, fromBaseByFactor } from '../ui/format.js';
|
||||
import { assetLabelHtml } from '../ui/asset-label.js';
|
||||
import { esc } from '../ui/escape.js';
|
||||
|
||||
let tableApi = null;
|
||||
|
||||
export async function mount(host) {
|
||||
await buildTable(host);
|
||||
}
|
||||
|
||||
async function assetOpts() { return (await listMetalAssets()).map(a => ({ value: a.id, label: `${a.symbol}: ${a.name}` })); }
|
||||
function formOpts() { return ENUMS.METAL_FORM.map(v => ({ value: v, label: t('enums.metal_form.' + v) })); }
|
||||
|
||||
const DEC = CONFIG.METALS.DISPLAY_DECIMALS;
|
||||
const fmtG = grams => grams.toLocaleString(localeTag(), { maximumFractionDigits: DEC });
|
||||
|
||||
async function buildTable(el) {
|
||||
const metalAssets = await listMetalAssets();
|
||||
|
||||
const columns = [
|
||||
{ key: 'assetId', label: t('metalProducts.asset'), sortable: true, sortValue: r => r.asset_symbol,
|
||||
render: r => assetLabelHtml({ asset_name: r.asset_name, asset_symbol: r.asset_symbol }),
|
||||
group: { value: r => r.asset_symbol, label: v => v },
|
||||
edit: { type: 'select', options: assetOpts } },
|
||||
{ key: 'name', label: t('metalProducts.name'), sortable: true, text: true,
|
||||
edit: { type: 'text', placeholder: 'Krugerrand 1 oz' } },
|
||||
{ key: 'form', label: t('metalProducts.form'), sortable: true,
|
||||
render: r => t('enums.metal_form.' + r.form),
|
||||
group: { value: r => r.form, label: v => t('enums.metal_form.' + v) },
|
||||
edit: { type: 'select', options: formOpts } },
|
||||
{ key: 'fineGrams', label: t('metalProducts.fineWeight'), align: 'num', sortable: true, sortValue: r => r.fineGrams,
|
||||
render: r => `${fmtG(fromBaseByFactor(r.fineGrams, 'g'))} g <span class="t-muted-cell">· ${fmtG(fromBaseByFactor(r.fineGrams, 'ozt'))} ozt</span>`,
|
||||
edit: {
|
||||
render: vals => {
|
||||
const grams = Number.isFinite(Number(vals.fineGrams)) && vals.fineGrams !== '' && vals.fineGrams != null
|
||||
? fromBaseByFactor(vals.fineGrams, 'g') : '';
|
||||
const opt = u => `<option value="${u}">${u}</option>`;
|
||||
return `<div data-field="fineGrams" style="display:flex;gap:.4rem;align-items:center">
|
||||
<input class="input" data-mp-weight type="number" min="0" step="any" value="${esc(grams)}" style="min-width:90px">
|
||||
<select class="input" data-mp-unit style="width:auto">${['g', 'ozt', 'kg'].map(opt).join('')}</select>
|
||||
</div>`;
|
||||
},
|
||||
read: host => {
|
||||
if (!host) return null;
|
||||
const n = parseFloat(host.querySelector('[data-mp-weight]').value);
|
||||
const u = host.querySelector('[data-mp-unit]').value;
|
||||
if (!Number.isFinite(n) || n <= 0) return null;
|
||||
return toBaseByFactor(n, u);
|
||||
},
|
||||
} },
|
||||
];
|
||||
|
||||
function toPayload(v) {
|
||||
const assetId = Number(v.assetId);
|
||||
const name = String(v.name || '').trim();
|
||||
const fineGrams = v.fineGrams;
|
||||
if (!Number.isInteger(assetId) || !name) throw new Error(t('metalProducts.pickMetalAndName'));
|
||||
if (!Number.isInteger(fineGrams) || fineGrams <= 0) throw new Error(t('metalProducts.fillFineGrams'));
|
||||
return { assetId, name, form: v.form, fineGrams };
|
||||
}
|
||||
|
||||
tableApi = renderTable(el, {
|
||||
columns, rows: await listMetalProducts(),
|
||||
title: t('metalProducts.title'),
|
||||
...(await tableViewCfg('metal-products', { key: 'assetId', dir: 'asc' })),
|
||||
emptyText: t('metalProducts.none'),
|
||||
noneLabel: t('table.none'),
|
||||
collapsibleGroups: true,
|
||||
newLabel: t('table.new'),
|
||||
newDefaults: { assetId: metalAssets[0] ? metalAssets[0].id : '', form: 'coin' },
|
||||
saveLabel: t('metalProducts.save'), cancelLabel: t('metalProducts.cancel'),
|
||||
onCreate: async v => { const id = await createMetalProduct(toPayload(v)); tableApi.refresh(await listMetalProducts(), { locate: id }); },
|
||||
onSave: async (id, v) => { await updateMetalProduct(id, toPayload(v)); tableApi.refresh(await listMetalProducts()); },
|
||||
onDelete: async id => {
|
||||
if (!(await dialog.confirm({ message: t('metalProducts.confirmDelete'), danger: true }))) return;
|
||||
try { await deleteMetalProduct(id); tableApi.refresh(await listMetalProducts()); }
|
||||
catch (e) { dialog.alert({ title: t('dialog.error'), message: e.message }); }
|
||||
},
|
||||
});
|
||||
}
|
||||
Reference in new issue
Block a user