sdsf
This commit is contained in:
@@ -179,6 +179,40 @@
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
#mining-checker-app .mc-history-stack {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
#mining-checker-app .mc-history-card {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
padding: 18px;
|
||||
border: 1px solid var(--mc-line);
|
||||
border-radius: 16px;
|
||||
background: var(--mc-surface);
|
||||
box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
|
||||
}
|
||||
|
||||
#mining-checker-app .mc-history-asset-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
#mining-checker-app .mc-history-asset-card {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
padding: 12px 14px;
|
||||
border: 1px solid var(--mc-line);
|
||||
border-radius: 14px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#mining-checker-app .mc-history-asset-card strong {
|
||||
color: var(--mc-text);
|
||||
}
|
||||
|
||||
#mining-checker-app .mc-asset-row {
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
return 'Historie der letzten Uploads mit Performance- und Trendwerten.';
|
||||
}
|
||||
if (sectionId === 'wallet') {
|
||||
return 'Wallet-Snapshots, Transfers und erkannte Asset-Bestände auswerten.';
|
||||
return 'NC-Wallet, Transfers, echte Wallet-Auszahlungen und erkannte Asset-Bestaende auswerten.';
|
||||
}
|
||||
if (sectionId === 'mining') {
|
||||
return 'Miner, Angebote und operative Daten verwalten.';
|
||||
@@ -472,6 +472,7 @@
|
||||
cost_plans: [],
|
||||
currencies: [],
|
||||
payouts: [],
|
||||
wallet_withdrawals: [],
|
||||
miner_offers: [],
|
||||
purchased_miners: [],
|
||||
measurement_rates: [],
|
||||
@@ -922,6 +923,13 @@
|
||||
note: '',
|
||||
});
|
||||
const [payoutModalOpen, setPayoutModalOpen] = useState(false);
|
||||
const [walletWithdrawalForm, setWalletWithdrawalForm] = useState({
|
||||
withdrawal_at: '',
|
||||
coins_amount: '',
|
||||
withdrawal_currency: 'DOGE',
|
||||
note: '',
|
||||
});
|
||||
const [walletWithdrawalModalOpen, setWalletWithdrawalModalOpen] = useState(false);
|
||||
const [minerOfferForm, setMinerOfferForm] = useState({
|
||||
label: '',
|
||||
runtime_months: '',
|
||||
@@ -982,6 +990,7 @@
|
||||
];
|
||||
const currentCostPlans = Array.isArray(currentSettings.cost_plans) ? currentSettings.cost_plans : [];
|
||||
const currentPayouts = Array.isArray(currentSettings.payouts) ? currentSettings.payouts : [];
|
||||
const currentWalletWithdrawals = Array.isArray(currentSettings.wallet_withdrawals) ? currentSettings.wallet_withdrawals : [];
|
||||
const currentWalletSnapshots = Array.isArray(payload?.wallet_snapshots) ? payload.wallet_snapshots : [];
|
||||
const currentMinerOffers = Array.isArray(currentSettings.miner_offers) ? currentSettings.miner_offers : [];
|
||||
const currentPurchasedMiners = Array.isArray(currentSettings.purchased_miners) ? currentSettings.purchased_miners : [];
|
||||
@@ -1946,6 +1955,61 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function submitWalletWithdrawal(event) {
|
||||
event.preventDefault();
|
||||
setSaving(true);
|
||||
setError('');
|
||||
setMessage('');
|
||||
try {
|
||||
await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/wallet-withdrawals`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(walletWithdrawalForm),
|
||||
timeoutMs: 8000,
|
||||
});
|
||||
invalidateProjectBootstrapCache(projectKey);
|
||||
setMessage('Wallet-Auszahlung gespeichert.');
|
||||
setWalletWithdrawalForm({
|
||||
withdrawal_at: '',
|
||||
coins_amount: '',
|
||||
withdrawal_currency: currentSettings.crypto_currency || 'DOGE',
|
||||
note: '',
|
||||
});
|
||||
setWalletWithdrawalModalOpen(false);
|
||||
await reloadBootstrapAfterMutation('Wallet-Auszahlung gespeichert.');
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteWalletWithdrawal(withdrawal) {
|
||||
if (!withdrawal || !withdrawal.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const label = `${fmtNumber(withdrawal.coins_amount, 6)} ${withdrawal.withdrawal_currency || ''}`.trim();
|
||||
if (!window.confirm(`Diese Wallet-Auszahlung (${label}) wirklich loeschen?`)) {
|
||||
return;
|
||||
}
|
||||
|
||||
setSaving(true);
|
||||
setError('');
|
||||
setMessage('');
|
||||
try {
|
||||
await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/wallet-withdrawals/${encodeURIComponent(withdrawal.id)}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
invalidateProjectBootstrapCache(projectKey);
|
||||
await reloadBootstrapAfterMutation('Wallet-Auszahlung geloescht.');
|
||||
} catch (err) {
|
||||
setError(err.message);
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function submitMinerOffer(event) {
|
||||
event.preventDefault();
|
||||
setSaving(true);
|
||||
@@ -2637,7 +2701,7 @@
|
||||
: [];
|
||||
|
||||
return h('div', { className: 'mc-stack' }, [
|
||||
panel('Wallet-Bestaende', 'Der letzte Wallet-Snapshot zeigt alle erkannten Assets separat.', latestWalletAssets.length
|
||||
panel('NC Wallet-Bestaende', 'Der letzte Snapshot zeigt alle erkannten Assets des internen NC Wallet separat.', latestWalletAssets.length
|
||||
? h('div', { className: 'mc-asset-grid' }, latestWalletAssets.map(([code, asset]) => {
|
||||
const balance = asset && typeof asset === 'object' ? asset.balance : asset;
|
||||
const priceAmount = asset && typeof asset === 'object' ? asset.price_amount : null;
|
||||
@@ -2651,33 +2715,6 @@
|
||||
]);
|
||||
}))
|
||||
: h('div', { className: 'mc-empty' }, 'Noch keine Wallet-Assets erkannt.')),
|
||||
panel('Wallet-Historie', 'Die letzten 10 Wallet-Uploads mit allen aus dem Screenshot gelesenen Assets.', h('div', { className: 'mc-table-shell' }, [
|
||||
h('table', { key: 'wallet-table', className: 'mc-table' }, [
|
||||
h('thead', { key: 'thead' }, h('tr', null, [
|
||||
'Zeit', 'Quelle', 'Assets'
|
||||
].map((label) => h('th', { key: label }, label)))),
|
||||
h('tbody', { key: 'tbody' },
|
||||
currentWalletSnapshots.length
|
||||
? currentWalletSnapshots.slice(0, 10).map((row) => h('tr', { key: row.id }, [
|
||||
h('td', { key: 'measured' }, fmtDate(row.measured_at)),
|
||||
h('td', { key: 'source' }, row.source || 'manual'),
|
||||
h('td', { key: 'assets' }, h('div', { className: 'mc-asset-list' }, Object.entries(row.balances_json || {}).map(([code, asset]) => {
|
||||
const balance = asset && typeof asset === 'object' ? asset.balance : asset;
|
||||
const priceAmount = asset && typeof asset === 'object' ? asset.price_amount : null;
|
||||
const priceCurrency = asset && typeof asset === 'object' ? asset.price_currency : null;
|
||||
return h('div', { key: code, className: 'mc-asset-row' }, [
|
||||
h('strong', { key: 'code' }, code),
|
||||
h('span', { key: 'balance' }, `${fmtNumber(balance, 8)} ${code}`),
|
||||
priceAmount !== null && priceAmount !== undefined
|
||||
? h('span', { key: 'price', className: 'mc-text' }, `1 ${code} = ${fmtNumber(priceAmount, 6)} ${priceCurrency || ''}`.trim())
|
||||
: null,
|
||||
]);
|
||||
}))),
|
||||
]))
|
||||
: [h('tr', { key: 'empty' }, h('td', { colSpan: 3 }, 'Noch keine Wallet-Snapshots gespeichert.'))]
|
||||
),
|
||||
]),
|
||||
])),
|
||||
panel('Wallet-Transfers', 'Transfers zum hier verfolgten Wallet erhoehen den Wallet-Bestand und reduzieren den sichtbaren Miner-Bestand. Reinvestierte Krypto-Minerkaeufe werden davon automatisch wieder abgezogen.', [
|
||||
h('div', { key: 'actions', className: 'mc-inline-row' }, [
|
||||
h('button', {
|
||||
@@ -2717,6 +2754,71 @@
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
panel('Wallet-Auszahlungen', 'Echte Auszahlungen vom NC Wallet an ein externes, hier nicht getracktes Wallet reduzieren den NC-Wallet-Bestand.', [
|
||||
h('div', { key: 'actions', className: 'mc-inline-row' }, [
|
||||
h('button', {
|
||||
key: 'add-wallet-withdrawal',
|
||||
type: 'button',
|
||||
className: 'mc-button mc-button--secondary',
|
||||
onClick: () => {
|
||||
setWalletWithdrawalForm((previous) => ({
|
||||
withdrawal_at: previous.withdrawal_at || nowDateTimeLocalValue(),
|
||||
coins_amount: previous.coins_amount || '',
|
||||
withdrawal_currency: currentCoinCurrency,
|
||||
note: previous.note || '',
|
||||
}));
|
||||
setWalletWithdrawalModalOpen(true);
|
||||
},
|
||||
}, 'Aus NC Wallet auszahlen'),
|
||||
]),
|
||||
h('div', { key: 'withdrawal-list', className: 'mc-table-shell' }, [
|
||||
h('table', { key: 'withdrawal-table', className: 'mc-table' }, [
|
||||
h('thead', { key: 'head' }, h('tr', null, ['Zeit', 'Coins', 'Waehrung', 'Notiz', 'Aktion'].map((label) => h('th', { key: label }, label)))),
|
||||
h('tbody', { key: 'body' },
|
||||
currentWalletWithdrawals.length
|
||||
? currentWalletWithdrawals.slice().reverse().map((withdrawal) => h('tr', { key: withdrawal.id }, [
|
||||
h('td', { key: 'time' }, fmtDate(withdrawal.withdrawal_at)),
|
||||
h('td', { key: 'coins' }, fmtNumber(withdrawal.coins_amount, 6)),
|
||||
h('td', { key: 'currency' }, withdrawal.withdrawal_currency),
|
||||
h('td', { key: 'note' }, withdrawal.note || '—'),
|
||||
h('td', { key: 'action' }, h('button', {
|
||||
type: 'button',
|
||||
className: 'mc-button mc-button--ghost',
|
||||
onClick: () => deleteWalletWithdrawal(withdrawal),
|
||||
disabled: saving,
|
||||
}, 'Loeschen')),
|
||||
]))
|
||||
: [h('tr', { key: 'empty' }, h('td', { colSpan: 5 }, 'Noch keine Wallet-Auszahlungen hinterlegt.'))]
|
||||
),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
panel('NC Wallet-Historie', 'Die letzten 10 NC-Wallet-Uploads mit allen aus dem Screenshot gelesenen Assets.', h('div', { className: 'mc-history-stack' },
|
||||
currentWalletSnapshots.length
|
||||
? currentWalletSnapshots.slice(0, 10).map((row) => h('article', { key: row.id, className: 'mc-history-card' }, [
|
||||
h('div', { key: 'head', className: 'mc-flex-split' }, [
|
||||
h('div', { key: 'time' }, [
|
||||
h('h3', { key: 'timestamp' }, fmtDate(row.measured_at)),
|
||||
h('div', { key: 'source', className: 'mc-kicker' }, row.source || 'manual'),
|
||||
]),
|
||||
]),
|
||||
h('div', { key: 'assets', className: 'mc-history-asset-grid' },
|
||||
Object.entries(row.balances_json || {}).map(([code, asset]) => {
|
||||
const balance = asset && typeof asset === 'object' ? asset.balance : asset;
|
||||
const priceAmount = asset && typeof asset === 'object' ? asset.price_amount : null;
|
||||
const priceCurrency = asset && typeof asset === 'object' ? asset.price_currency : null;
|
||||
return h('div', { key: code, className: 'mc-history-asset-card' }, [
|
||||
h('strong', { key: 'code' }, code),
|
||||
h('span', { key: 'balance' }, `${fmtNumber(balance, 8)} ${code}`),
|
||||
priceAmount !== null && priceAmount !== undefined
|
||||
? h('span', { key: 'price', className: 'mc-text' }, `1 ${code} = ${fmtNumber(priceAmount, 6)} ${priceCurrency || ''}`.trim())
|
||||
: h('span', { key: 'price-empty', className: 'mc-text' }, 'Kein Kurs erkannt'),
|
||||
]);
|
||||
})
|
||||
),
|
||||
]))
|
||||
: h('div', { className: 'mc-empty' }, 'Noch keine NC-Wallet-Snapshots gespeichert.')
|
||||
)),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -3080,6 +3182,18 @@
|
||||
]),
|
||||
]),
|
||||
], () => setPayoutModalOpen(false)) : null,
|
||||
walletWithdrawalModalOpen ? renderModal('Aus NC Wallet auszahlen', [
|
||||
h('form', { key: 'form', className: 'mc-form', onSubmit: submitWalletWithdrawal }, [
|
||||
inputField('Auszahlungszeitpunkt', 'datetime-local', walletWithdrawalForm.withdrawal_at, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_at: value })),
|
||||
inputField('Coins', 'number', walletWithdrawalForm.coins_amount, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, coins_amount: value }), '0.000001'),
|
||||
selectField('Waehrung', walletWithdrawalForm.withdrawal_currency, [currentCoinCurrency].concat(selectableCurrencies.map((currency) => currency.code).filter((code) => code !== currentCoinCurrency)), (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, withdrawal_currency: value })),
|
||||
textareaField('Notiz', walletWithdrawalForm.note, (value) => setWalletWithdrawalForm({ ...walletWithdrawalForm, note: value })),
|
||||
h('div', { className: 'mc-inline-row' }, [
|
||||
h('button', { type: 'button', className: 'mc-button mc-button--ghost', onClick: () => setWalletWithdrawalModalOpen(false) }, 'Abbrechen'),
|
||||
h('button', { type: 'submit', className: 'mc-button mc-button--secondary', disabled: saving }, saving ? 'Speichert …' : 'Wallet-Auszahlung speichern'),
|
||||
]),
|
||||
]),
|
||||
], () => setWalletWithdrawalModalOpen(false)) : null,
|
||||
minerOfferModalOpen ? renderModal('Basis-Miner-Angebot anlegen', [
|
||||
h('form', { key: 'form', className: 'mc-form', onSubmit: submitMinerOffer }, [
|
||||
inputField('Label', 'text', minerOfferForm.label, (value) => setMinerOfferForm({ ...minerOfferForm, label: value })),
|
||||
|
||||
Reference in New Issue
Block a user