CostMetrics
Three "$/MWh" tiles that summarise the cost-summary period. Order mirrors the OSS Cost page: All-in (highlighted), Energy, Operations.
Three "$/MWh" tiles that summarise the cost-summary period. Order mirrors the OSS Cost page: All-in (highlighted), Energy, Operations.
import { CostMetrics } from "@tetherto/mdk-react-devkit";| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
metrics | Required | CostSummaryDisplayMetrics | — | — |
Usage
Composite financial reporting page for a single mining site. Renders a page header, a period selector slot, and a 2×2 grid of charts and metric tiles driven by the cost-summary view model.
Minimal example
import {
buildCostSummaryViewModel,
Cost,
PERIOD,
TimeframeControls,
} from "@tetherto/mdk-react-devkit/foundation";
const viewModel = buildCostSummaryViewModel({ data: costSummaryApiResponse });
<Cost
metrics={viewModel.metrics}
costLog={viewModel.costLog}
btcPriceLog={viewModel.btcPriceLog}
totals={viewModel.totals}
dateRange={{ start, end, period: PERIOD.MONTHLY }}
controls={<TimeframeControls dateRange={{ start, end }} onRangeChange={handleChange} />}
/>
Notes
- Use
buildCostSummaryViewModelto transform the raw API response into the props this component expects. avgAllInCostDatacomes from a separate endpoint (useAvgAllInPowerCostDatain the OSS app) — omit it to hide the Avg All-in Cost panel.- For a custom page layout (different header, navigation), mount
CostContentdirectly instead and supply your own chrome. - Multi-site aggregation is out of scope for this component; mount one
Costper site and compose them yourself.
Examples
import { AvgAllInCostChart } from '@tetherto/mdk-react-devkit'export const AvgAllInCostChartExample = () => ( <div className="mdk-example-row"> <AvgAllInCostChart dateRange={null} isLoading={false} /> </div>)import { CostCharts } from '@tetherto/mdk-react-devkit'export const CostChartsExample = () => ( <div className="mdk-example-row"> <CostCharts costLog={[]} btcPriceLog={[]} totals={null} dateRange={null} isLoading={false} /> </div>)import { CostContent } from '@tetherto/mdk-react-devkit'export const CostContentExample = () => ( <div className="mdk-example-row"> <CostContent metrics={null} costLog={[]} btcPriceLog={[]} totals={null} dateRange={null} isLoading={false} /> </div>)import { CostMetrics } from '@tetherto/mdk-react-devkit'export const CostMetricsExample = () => ( <div className="mdk-example-row"> <CostMetrics metrics={{ allIn: 42.5, energy: 38.0, operations: 4.5 } as never} /> </div>)/** * Runnable example for Cost. * All imports must come from "@tetherto/mdk-react-devkit/foundation". */import { type AvgAllInCostDataPoint, buildCostSummaryViewModel, Cost, type CostSummaryLogEntry, type CostSummaryResponse, type FinancialDateRange, PERIOD, TimeframeControls, type TimeframeControlsOnRangeChange,} from '@tetherto/mdk-react-devkit/foundation'import { endOfMonth } from 'date-fns/endOfMonth'import { startOfMonth } from 'date-fns/startOfMonth'import { useMemo, useState } from 'react'const buildInitialDateRange = (): FinancialDateRange => ({ start: startOfMonth(new Date('2025-01-01T00:00:00.000Z')).getTime(), end: endOfMonth(new Date('2025-12-31T00:00:00.000Z')).getTime(), period: PERIOD.MONTHLY,})const monthTs = (month: number): number => Date.UTC(2025, month - 1, 15, 12)const buildLogEntry = (input: { month: number consumptionMWh: number energyCostsUSD: number operationalCostsUSD: number btcPrice: number}): CostSummaryLogEntry => { const totalCostsUSD = input.energyCostsUSD + input.operationalCostsUSD return { ts: monthTs(input.month), consumptionMWh: input.consumptionMWh, energyCostsUSD: input.energyCostsUSD, operationalCostsUSD: input.operationalCostsUSD, totalCostsUSD, allInCostPerMWh: totalCostsUSD / input.consumptionMWh, energyCostPerMWh: input.energyCostsUSD / input.consumptionMWh, btcPrice: input.btcPrice, }}const MOCK_LOG: CostSummaryLogEntry[] = [ { month: 1, consumptionMWh: 1_180, energyCostsUSD: 14_200, operationalCostsUSD: 7_100, btcPrice: 64_500, }, { month: 2, consumptionMWh: 1_320, energyCostsUSD: 15_900, operationalCostsUSD: 7_950, btcPrice: 67_800, }, { month: 3, consumptionMWh: 1_410, energyCostsUSD: 17_400, operationalCostsUSD: 8_600, btcPrice: 71_200, }, { month: 4, consumptionMWh: 1_290, energyCostsUSD: 15_500, operationalCostsUSD: 7_650, btcPrice: 65_900, }, { month: 5, consumptionMWh: 1_360, energyCostsUSD: 16_800, operationalCostsUSD: 8_200, btcPrice: 68_400, }, { month: 6, consumptionMWh: 1_470, energyCostsUSD: 18_500, operationalCostsUSD: 9_100, btcPrice: 72_500, },].map(buildLogEntry)const MOCK_SUMMARY: CostSummaryResponse = { log: MOCK_LOG, summary: { totalEnergyCostsUSD: MOCK_LOG.reduce((s, e) => s + e.energyCostsUSD, 0), totalOperationalCostsUSD: MOCK_LOG.reduce((s, e) => s + e.operationalCostsUSD, 0), totalCostsUSD: MOCK_LOG.reduce((s, e) => s + e.totalCostsUSD, 0), totalConsumptionMWh: MOCK_LOG.reduce((s, e) => s + e.consumptionMWh, 0), avgAllInCostPerMWh: MOCK_LOG.reduce((s, e) => s + e.totalCostsUSD, 0) / MOCK_LOG.reduce((s, e) => s + e.consumptionMWh, 0), avgEnergyCostPerMWh: MOCK_LOG.reduce((s, e) => s + e.energyCostsUSD, 0) / MOCK_LOG.reduce((s, e) => s + e.consumptionMWh, 0), avgBtcPrice: MOCK_LOG.reduce((s, e) => s + e.btcPrice, 0) / MOCK_LOG.length, },}const MOCK_AVG_ALL_IN: AvgAllInCostDataPoint[] = MOCK_LOG.map((e) => ({ ts: e.ts, revenueUSDPerMWh: (e.allInCostPerMWh ?? 0) * 1.28, costUSDPerMWh: e.allInCostPerMWh ?? 0,}))export const CostExample = () => { const [dateRange, setDateRange] = useState<FinancialDateRange>(buildInitialDateRange) const viewModel = useMemo(() => buildCostSummaryViewModel({ data: MOCK_SUMMARY }), []) const handleRangeChange: TimeframeControlsOnRangeChange = (range, options) => { setDateRange({ start: range[0].getTime(), end: range[1].getTime(), period: (options.period ?? dateRange.period) as FinancialDateRange['period'], }) } return ( <Cost metrics={viewModel.metrics} costLog={viewModel.costLog} btcPriceLog={viewModel.btcPriceLog} totals={viewModel.totals} dateRange={dateRange} avgAllInCostData={MOCK_AVG_ALL_IN} controls={ <TimeframeControls isMonthSelectVisible isWeekSelectVisible={false} dateRange={{ start: dateRange.start, end: dateRange.end }} onRangeChange={handleRangeChange} /> } /> )}import { OperationsEnergyChart } from '@tetherto/mdk-react-devkit'export const OperationsEnergyChartExample = () => ( <div className="mdk-example-row"> <OperationsEnergyChart totals={null} isLoading={false} /> </div>)import { ProductionCostChart } from '@tetherto/mdk-react-devkit'export const ProductionCostChartExample = () => ( <div className="mdk-example-row"> <ProductionCostChart costLog={[]} btcPriceLog={[]} dateRange={null} isLoading={false} /> </div>)