MDK Logo
UI Kitreact-devkitComponentsFoundationWidgets

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";
PropStatusTypeDefaultDescription
metricsRequiredCostSummaryDisplayMetrics

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 buildCostSummaryViewModel to transform the raw API response into the props this component expects.
  • avgAllInCostData comes from a separate endpoint (useAvgAllInPowerCostData in the OSS app) — omit it to hide the Avg All-in Cost panel.
  • For a custom page layout (different header, navigation), mount CostContent directly instead and supply your own chrome.
  • Multi-site aggregation is out of scope for this component; mount one Cost per 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>)