CostContent
Renders the data-driven portion of the Cost page in a 2x2 Mosaic grid: - (1,1) Production Cost / Price - (1,2) Avg All-in Cost - (2,1) Operations vs Energy C…
Renders the data-driven portion of the Cost page in a 2x2 Mosaic grid:
- (1,1) Production Cost / Price - (1,2) Avg All-in Cost - (2,1) Operations vs Energy Cost - (2,2) Headline metric tiles (stacked)
Exported alongside Cost so consumers who want to embed the cost rendering inside their own page chrome (custom header, layout, navigation) can mount CostContent directly without the default title / "Set Monthly Cost" link.
import { CostContent } from "@tetherto/mdk-react-devkit";| Prop | Status | Type | Default | Description |
|---|---|---|---|---|
metrics | Required | CostSummaryDisplayMetrics | null | — | — |
costLog | Required | readonly CostTimeSeriesEntry[] | — | — |
btcPriceLog | Required | readonly BtcPriceTimeSeriesEntry[] | — | — |
totals | Required | CostSummaryMonetaryTotals | null | — | — |
isLoading | Optional | boolean | undefined | — | — |
error | Optional | unknown | — | — |
dateRange | Required | FinancialDateRange | null | — | — |
avgAllInCostData | Optional | readonly AvgAllInCostDataPoint[] | undefined | — | Optional revenue/cost time-series for the Avg All-in Cost panel. |
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.
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/domain". */import { type AvgAllInCostDataPoint, buildCostSummaryViewModel, Cost, type CostSummaryLogEntry, type CostSummaryResponse, type FinancialDateRange, PERIOD, TimeframeControls, type TimeframeControlsOnRangeChange,} from '@tetherto/mdk-react-devkit/domain'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>)Cost
Cost Summary - composite reporting page (single-site). Reads cost-summary view model fields (from `useCostSummary`) and renders: - page header with "Cost Sum…
EnergyReport
Operational Energy report — site consumption trend, power modes by miner type, and per–mining-unit / per–miner-type bar charts.