sdsad
All checks were successful
Deploy / deploy-staging (push) Successful in 25s
Deploy / deploy-production (push) Has been skipped

This commit is contained in:
2026-08-14 00:40:45 +02:00
parent 2adff4c91d
commit 743c743c2c
3 changed files with 212 additions and 44 deletions

View File

@@ -299,6 +299,29 @@
return `${map.year}-${map.month}-${map.day}`;
}
function isCryptoCurrencyCode(code) {
const normalized = String(code || '').toUpperCase();
return [
'ADA', 'ARB', 'AVAX', 'BNB', 'BTC', 'CTC', 'DAI', 'DOGE', 'DOT', 'ETH',
'HSH', 'LINK', 'LTC', 'MATIC', 'SOL', 'TRX', 'USDC', 'USDT', 'XMR', 'XRP',
].includes(normalized);
}
function entryCoverageMeta(startAt, runtimeMonths, autoRenew) {
const normalizedRuntime = Number(runtimeMonths);
const startDate = parseStoredUtcDate(startAt);
if (!startDate || !Number.isFinite(normalizedRuntime) || normalizedRuntime <= 0) {
return { endAt: null, isCovered: true };
}
const runtimeMs = normalizedRuntime * 30.4375 * 86400 * 1000;
const endAtDate = new Date(startDate.getTime() + runtimeMs);
return {
endAt: endAtDate.toISOString(),
isCovered: !!autoRenew || Date.now() <= endAtDate.getTime(),
};
}
function currentSectionLabel(sectionId) {
return sectionMap.get(String(sectionId || '').trim()) || 'Bereich';
}
@@ -1106,45 +1129,54 @@
const selectableFiatCurrencies = preferredSelectableFiatCurrencies.length ? preferredSelectableFiatCurrencies : fiatCurrencies;
const selectableCryptoCurrencies = preferredSelectableCryptoCurrencies.length ? preferredSelectableCryptoCurrencies : cryptoCurrencies;
const selectedMinerScenario = scenarioMinerOffers.find((offer) => String(offer.id) === String(selectedMinerScenarioId)) || null;
const activeMinerRows = currentPurchasedMiners.map((miner) => ({
id: `purchase-${miner.id}`,
source: 'miete',
starts_at: miner.purchased_at,
label: miner.label,
runtime_months: miner.runtime_months,
auto_renew: !!miner.auto_renew,
effective_amount: miner.total_cost_amount,
effective_currency: miner.currency,
base_amount: miner.reference_price_amount,
base_currency: miner.reference_price_currency,
miner_id: miner.id,
miner_offer_id: miner.miner_offer_id,
payment_type: miner.reference_price_currency
&& miner.currency
&& String(miner.reference_price_currency).toUpperCase() !== String(miner.currency).toUpperCase()
? 'crypto'
: 'fiat',
is_active: miner.is_active !== false,
can_toggle_auto_renew: Number(miner.runtime_months) > 0,
hashrate_text: formatHashrateWithBonus(miner.mining_speed_value, miner.mining_speed_unit, miner.bonus_speed_value, miner.bonus_speed_unit),
type_label: 'Aus Angebot gemietet',
})).concat(currentCostPlans.map((plan) => ({
id: `plan-${plan.id}`,
source: 'manual',
starts_at: plan.starts_at,
label: plan.label,
runtime_months: plan.runtime_months,
auto_renew: !!plan.auto_renew,
effective_amount: plan.total_cost_amount,
effective_currency: plan.currency,
base_amount: plan.base_price_amount,
base_currency: currentSettings.report_currency || 'EUR',
payment_type: plan.payment_type,
is_active: !!plan.is_active,
can_toggle_auto_renew: false,
hashrate_text: formatHashrateWithBonus(plan.mining_speed_value, plan.mining_speed_unit, plan.bonus_speed_value, plan.bonus_speed_unit),
type_label: 'Manuell eingetragen',
}))).sort((left, right) => String(right.starts_at || '').localeCompare(String(left.starts_at || '')));
const activeMinerRows = currentPurchasedMiners.map((miner) => {
const coverage = entryCoverageMeta(miner.purchased_at, miner.runtime_months, miner.auto_renew);
const effectiveCurrency = String(miner.currency || '').toUpperCase();
return {
id: `purchase-${miner.id}`,
source: 'miete',
starts_at: miner.purchased_at,
label: miner.label,
runtime_months: miner.runtime_months,
auto_renew: !!miner.auto_renew,
effective_amount: miner.total_cost_amount,
effective_currency: miner.currency,
base_amount: miner.reference_price_amount,
base_currency: miner.reference_price_currency,
miner_id: miner.id,
miner_offer_id: miner.miner_offer_id,
payment_type: isCryptoCurrencyCode(effectiveCurrency) ? 'crypto' : 'fiat',
is_active: miner.is_active !== false && coverage.isCovered,
end_at: coverage.endAt,
can_toggle_auto_renew: Number(miner.runtime_months) > 0,
toggle_resource: 'purchased-miners',
toggle_id: miner.id,
hashrate_text: formatHashrateWithBonus(miner.mining_speed_value, miner.mining_speed_unit, miner.bonus_speed_value, miner.bonus_speed_unit),
type_label: 'Aus Angebot gemietet',
};
}).concat(currentCostPlans.map((plan) => {
const coverage = entryCoverageMeta(plan.starts_at, plan.runtime_months, plan.auto_renew);
return {
id: `plan-${plan.id}`,
source: 'manual',
starts_at: plan.starts_at,
label: plan.label,
runtime_months: plan.runtime_months,
auto_renew: !!plan.auto_renew,
effective_amount: plan.total_cost_amount,
effective_currency: plan.currency,
base_amount: plan.base_price_amount,
base_currency: currentSettings.report_currency || 'EUR',
payment_type: plan.payment_type,
is_active: !!plan.is_active && coverage.isCovered,
end_at: coverage.endAt,
can_toggle_auto_renew: Number(plan.runtime_months) > 0,
toggle_resource: 'cost-plans',
toggle_id: plan.id,
hashrate_text: formatHashrateWithBonus(plan.mining_speed_value, plan.mining_speed_unit, plan.bonus_speed_value, plan.bonus_speed_unit),
type_label: 'Manuell eingetragen',
};
})).sort((left, right) => String(right.starts_at || '').localeCompare(String(left.starts_at || '')));
useEffect(() => {
if (reportCurrencyOverride) {
@@ -2060,15 +2092,15 @@
}
}
async function togglePurchasedMinerAutoRenew(row) {
if (!row || !row.can_toggle_auto_renew || !row.miner_id) {
async function toggleMinerAutoRenew(row) {
if (!row || !row.can_toggle_auto_renew || !row.toggle_resource || !row.toggle_id) {
return;
}
setSaving(true);
setError('');
try {
await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/purchased-miners/${encodeURIComponent(row.miner_id)}`, {
await request(`${apiBase}/projects/${encodeURIComponent(projectKey)}/${encodeURIComponent(row.toggle_resource)}/${encodeURIComponent(row.toggle_id)}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ auto_renew: !row.auto_renew }),
@@ -2721,6 +2753,16 @@
const reinvestedCapital = latest ? convertMeasurementMoney(latest, latest.reinvested_capital, reportCurrency) : null;
const walletValue = latest ? convertMeasurementMoney(latest, latest.wallet_value, reportCurrency) : null;
const totalHoldingsValue = latest ? convertMeasurementMoney(latest, latest.total_holdings_value, reportCurrency) : null;
const totalEarnedOverall = latest && latest.growth_since_baseline !== null && latest.growth_since_baseline !== undefined
? Number(latest.growth_since_baseline)
: null;
const totalSpentOverallCurrentAsset = latest
? convertMeasurementMoney(
latest,
(Number(latest.cash_invested_capital) || 0) + (Number(latest.reinvested_capital) || 0),
currentCoinCurrency
)
: null;
const breakEvenReached = breakEvenRemainingAmount !== null && breakEvenRemainingAmount <= 0;
const breakEvenEta = latest && latest.break_even_eta_at ? fmtDate(latest.break_even_eta_at) : null;
const walletBalanceCurrentAsset = payload?.summary?.payouts?.wallet_balance_current_asset;
@@ -2759,6 +2801,20 @@
? `Wallet-Gegenwert ${fmtNumber(walletBalanceCurrentAsset, 6)} ${currentCoinCurrency}${currentWalletPrimaryCurrency !== currentCoinCurrency ? ` · direkt ${fmtNumber(walletBalanceCurrentAssetDirect, 6)} ${currentCoinCurrency}` : ''} · Miner ${fmtNumber(latest?.coins_total_visible ?? latest?.coins_total, 6)} ${currentCoinCurrency}`
: '',
}),
h(StatCard, {
key: 'earned-overall',
label: `Bisher verdient gesamt ${currentCoinCurrency}`,
value: totalEarnedOverall !== null ? fmtNumber(totalEarnedOverall, 6) : 'n/a',
sub: currentSettings?.baseline_measured_at
? `Seit Baseline ${fmtDate(currentSettings.baseline_measured_at)}`
: 'Benötigt Baseline',
}),
h(StatCard, {
key: 'spent-overall',
label: `Bisher ausgegeben gesamt ${currentCoinCurrency}`,
value: totalSpentOverallCurrentAsset !== null ? fmtNumber(totalSpentOverallCurrentAsset, 6) : 'n/a',
sub: 'FIAT und Krypto auf die aktuelle Mining-Währung reduziert',
}),
h(StatCard, {
key: 'perday',
label: perDayLabel,
@@ -3182,6 +3238,7 @@
h('td', { key: 'runtime' }, [
h('div', { key: 'months' }, `${row.runtime_months} Monate`),
h('div', { key: 'hash', className: 'mc-kicker' }, row.hashrate_text),
row.end_at ? h('div', { key: 'end', className: 'mc-kicker' }, `Ende ${fmtDate(row.end_at)}`) : null,
]),
h('td', { key: 'renew' }, row.auto_renew ? 'ja' : 'nein'),
h('td', { key: 'cost' }, [
@@ -3200,7 +3257,7 @@
? h('button', {
type: 'button',
className: 'mc-button mc-button--ghost',
onClick: () => togglePurchasedMinerAutoRenew(row),
onClick: () => toggleMinerAutoRenew(row),
disabled: saving,
}, row.auto_renew ? 'Verlaengerung aus' : 'Verlaengerung an')
: '—'