From 81d1e486e888e769df0e846a9e45fb69cd82b4fd Mon Sep 17 00:00:00 2001 From: Lars Gebhardt-Kusche Date: Wed, 20 May 2026 00:32:18 +0200 Subject: [PATCH] update --- modules/mining-checker/assets/js/app.js | 44 +++++++++++++-- modules/mining-checker/src/Api/Router.php | 5 +- .../src/Domain/AnalyticsService.php | 54 +++++++++++-------- 3 files changed, 75 insertions(+), 28 deletions(-) diff --git a/modules/mining-checker/assets/js/app.js b/modules/mining-checker/assets/js/app.js index 8d1301b..e976f6e 100644 --- a/modules/mining-checker/assets/js/app.js +++ b/modules/mining-checker/assets/js/app.js @@ -131,6 +131,38 @@ }).format(Number(value)); } + function recentMeasurementWindow(rows, windowDays) { + if (!Array.isArray(rows) || rows.length === 0) { + return []; + } + + const normalizedWindowDays = Number(windowDays); + if (!Number.isFinite(normalizedWindowDays) || normalizedWindowDays <= 0) { + return rows; + } + + const sortedRows = rows + .filter((row) => row && row.measured_at) + .slice() + .sort((left, right) => new Date(left.measured_at).getTime() - new Date(right.measured_at).getTime()); + if (sortedRows.length === 0) { + return rows; + } + + const latestTs = new Date(sortedRows[sortedRows.length - 1].measured_at).getTime(); + if (!Number.isFinite(latestTs)) { + return sortedRows; + } + + const minTs = latestTs - (normalizedWindowDays * 86400 * 1000); + const filteredRows = sortedRows.filter((row) => { + const measuredTs = new Date(row.measured_at).getTime(); + return Number.isFinite(measuredTs) && measuredTs >= minTs; + }); + + return filteredRows.length ? filteredRows : [sortedRows[sortedRows.length - 1]]; + } + function parseStoredUtcDate(value) { const raw = String(value || '').trim(); if (!raw) { @@ -1258,8 +1290,10 @@ }, [payload, projectKey]); const overviewCharts = useMemo(() => { + const overviewWindowDays = Number(payload?.bootstrap_meta?.overview_window_days || 15); + const overviewRows = recentMeasurementWindow(measurements, overviewWindowDays); const chartCoinCurrency = String(currentSettings.crypto_currency || 'DOGE').toUpperCase(); - const comparisonRows = measurements.filter((row) => { + const comparisonRows = overviewRows.filter((row) => { const miningRate = Number(row.doge_per_hour_per_mh_interval); const price = Number(row.effective_price_per_coin ?? row.price_per_coin); return Number.isFinite(miningRate) && miningRate > 0 && Number.isFinite(price) && price > 0; @@ -1269,10 +1303,10 @@ const basePrice = baseComparison ? Number(baseComparison.effective_price_per_coin ?? baseComparison.price_per_coin) : null; return { - mining: measurements.map((row) => ({ x: fmtDate(row.measured_at), y: row.coins_total })), - performance: measurements.filter((row) => row.doge_per_day_interval !== null) + mining: overviewRows.map((row) => ({ x: fmtDate(row.measured_at), y: row.coins_total })), + performance: overviewRows.filter((row) => row.doge_per_day_interval !== null) .map((row) => ({ x: fmtDate(row.measured_at), y: row.doge_per_day_interval })), - pricing: measurements.filter((row) => row.price_per_coin !== null) + pricing: overviewRows.filter((row) => row.price_per_coin !== null) .map((row) => ({ x: fmtDate(row.measured_at), y: row.price_per_coin })), miningVsPrice: baseMining && basePrice ? [ { @@ -1295,7 +1329,7 @@ }, ] : [], }; - }, [currentSettings.crypto_currency, measurements]); + }, [currentSettings.crypto_currency, measurements, payload?.bootstrap_meta?.overview_window_days]); async function submitMeasurement(fromPreview) { const preview = normalizeOcrPreview(ocrPreview); diff --git a/modules/mining-checker/src/Api/Router.php b/modules/mining-checker/src/Api/Router.php index 629d247..a18444f 100644 --- a/modules/mining-checker/src/Api/Router.php +++ b/modules/mining-checker/src/Api/Router.php @@ -1285,7 +1285,10 @@ final class Router ]; } - return $this->analytics()->buildSummary($measurements, $settings, $targets); + return $this->analytics()->buildSummary($measurements, $settings, $targets, [ + 'include_offer_scenarios' => $view === 'mining', + 'include_long_term_projection' => $view === 'mining', + ]); } private function filterMeasurementsToRecentWindow(array $rows, int $windowDays): array diff --git a/modules/mining-checker/src/Domain/AnalyticsService.php b/modules/mining-checker/src/Domain/AnalyticsService.php index b4a684d..185b5c3 100644 --- a/modules/mining-checker/src/Domain/AnalyticsService.php +++ b/modules/mining-checker/src/Domain/AnalyticsService.php @@ -201,8 +201,11 @@ final class AnalyticsService return $result; } - public function buildSummary(array $measurements, array $settings, array $targets): array + public function buildSummary(array $measurements, array $settings, array $targets, array $options = []): array { + $includeOfferScenarios = !array_key_exists('include_offer_scenarios', $options) || (bool) $options['include_offer_scenarios']; + $includeLongTermProjection = !array_key_exists('include_long_term_projection', $options) || (bool) $options['include_long_term_projection']; + if ($measurements === []) { return [ 'latest_measurement' => null, @@ -355,28 +358,35 @@ final class AnalyticsService 'break_even_days_overall' => $this->roundOrNull($breakEvenDaysOverall, 4), 'break_even_eta_at' => $breakEvenProjection['eta'] ?? null, ]); - $currentProjection = $this->projectPerformance( - is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [], - $purchasedMiners, - $latestSummary, - 730 - ); - $latestSummary = array_merge($latestSummary, [ - 'projection_days' => $currentProjection['days'], - 'projection_two_year_revenue' => $this->roundOrNull($currentProjection['revenue'], 8), - 'projection_two_year_cost' => $this->roundOrNull($currentProjection['cost'], 8), - 'projection_two_year_profit' => $this->roundOrNull($currentProjection['profit'], 8), - ]); - $offerSummary = array_map( - fn (array $offer): array => $this->enrichOfferScenario( - $offer, - $latestSummary, - $currentHashrateMh, + if ($includeLongTermProjection) { + $currentProjection = $this->projectPerformance( is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [], - $purchasedMiners - ), - $offerSummary - ); + $purchasedMiners, + $latestSummary, + 730 + ); + $latestSummary = array_merge($latestSummary, [ + 'projection_days' => $currentProjection['days'], + 'projection_two_year_revenue' => $this->roundOrNull($currentProjection['revenue'], 8), + 'projection_two_year_cost' => $this->roundOrNull($currentProjection['cost'], 8), + 'projection_two_year_profit' => $this->roundOrNull($currentProjection['profit'], 8), + ]); + } + + if ($includeOfferScenarios) { + $offerSummary = array_map( + fn (array $offer): array => $this->enrichOfferScenario( + $offer, + $latestSummary, + $currentHashrateMh, + is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [], + $purchasedMiners + ), + $offerSummary + ); + } else { + $offerSummary = []; + } return [ 'latest_measurement' => $latestSummary,