update
This commit is contained in:
@@ -131,6 +131,38 @@
|
|||||||
}).format(Number(value));
|
}).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) {
|
function parseStoredUtcDate(value) {
|
||||||
const raw = String(value || '').trim();
|
const raw = String(value || '').trim();
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
@@ -1258,8 +1290,10 @@
|
|||||||
}, [payload, projectKey]);
|
}, [payload, projectKey]);
|
||||||
|
|
||||||
const overviewCharts = useMemo(() => {
|
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 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 miningRate = Number(row.doge_per_hour_per_mh_interval);
|
||||||
const price = Number(row.effective_price_per_coin ?? row.price_per_coin);
|
const price = Number(row.effective_price_per_coin ?? row.price_per_coin);
|
||||||
return Number.isFinite(miningRate) && miningRate > 0 && Number.isFinite(price) && price > 0;
|
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;
|
const basePrice = baseComparison ? Number(baseComparison.effective_price_per_coin ?? baseComparison.price_per_coin) : null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
mining: measurements.map((row) => ({ x: fmtDate(row.measured_at), y: row.coins_total })),
|
mining: overviewRows.map((row) => ({ x: fmtDate(row.measured_at), y: row.coins_total })),
|
||||||
performance: measurements.filter((row) => row.doge_per_day_interval !== null)
|
performance: overviewRows.filter((row) => row.doge_per_day_interval !== null)
|
||||||
.map((row) => ({ x: fmtDate(row.measured_at), y: row.doge_per_day_interval })),
|
.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 })),
|
.map((row) => ({ x: fmtDate(row.measured_at), y: row.price_per_coin })),
|
||||||
miningVsPrice: baseMining && basePrice ? [
|
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) {
|
async function submitMeasurement(fromPreview) {
|
||||||
const preview = normalizeOcrPreview(ocrPreview);
|
const preview = normalizeOcrPreview(ocrPreview);
|
||||||
|
|||||||
@@ -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
|
private function filterMeasurementsToRecentWindow(array $rows, int $windowDays): array
|
||||||
|
|||||||
@@ -201,8 +201,11 @@ final class AnalyticsService
|
|||||||
return $result;
|
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 === []) {
|
if ($measurements === []) {
|
||||||
return [
|
return [
|
||||||
'latest_measurement' => null,
|
'latest_measurement' => null,
|
||||||
@@ -355,28 +358,35 @@ final class AnalyticsService
|
|||||||
'break_even_days_overall' => $this->roundOrNull($breakEvenDaysOverall, 4),
|
'break_even_days_overall' => $this->roundOrNull($breakEvenDaysOverall, 4),
|
||||||
'break_even_eta_at' => $breakEvenProjection['eta'] ?? null,
|
'break_even_eta_at' => $breakEvenProjection['eta'] ?? null,
|
||||||
]);
|
]);
|
||||||
$currentProjection = $this->projectPerformance(
|
if ($includeLongTermProjection) {
|
||||||
is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [],
|
$currentProjection = $this->projectPerformance(
|
||||||
$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,
|
|
||||||
is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [],
|
is_array($settings['cost_plans'] ?? null) ? $settings['cost_plans'] : [],
|
||||||
$purchasedMiners
|
$purchasedMiners,
|
||||||
),
|
$latestSummary,
|
||||||
$offerSummary
|
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 [
|
return [
|
||||||
'latest_measurement' => $latestSummary,
|
'latest_measurement' => $latestSummary,
|
||||||
|
|||||||
Reference in New Issue
Block a user