M8-R13: simplify prices and meter controls
This commit is contained in:
@@ -23,6 +23,7 @@ import {
|
||||
Group,
|
||||
Paper,
|
||||
SegmentedControl,
|
||||
ScrollArea,
|
||||
} from '@mantine/core'
|
||||
import {
|
||||
LineChart,
|
||||
@@ -60,6 +61,19 @@ function thermalUnit(section: string, key: string, currency: string): string {
|
||||
return currency
|
||||
}
|
||||
|
||||
function humanizeThermalField(value: string): string {
|
||||
return value
|
||||
.replace(/_/g, ' ')
|
||||
.replace(/\b\w/g, (letter) => letter.toUpperCase())
|
||||
}
|
||||
|
||||
function thermalSections(values: Record<string, Record<string, string>>): string[] {
|
||||
const preferred = ['variable', 'standing']
|
||||
return [...preferred.filter((section) => section in values), ...Object.keys(values)
|
||||
.filter((section) => !preferred.includes(section))
|
||||
.sort()]
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Time range helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -399,13 +413,28 @@ export function TibberPrices() {
|
||||
<Text fw={500}>Thermal contract snapshot</Text>
|
||||
<Text size="sm">Version {data.contract_version_id ?? '—'} · effective {data.effective_from ?? '—'} to {data.effective_to ?? 'open'}</Text>
|
||||
<Text size="sm" c="dimmed">This is a contract snapshot, not a 15-minute market spot price.</Text>
|
||||
{Object.entries(data.values).map(([section, values]) => (
|
||||
<Text size="sm" key={section} data-testid={`thermal-price-section-${section}`}>
|
||||
{section}: {Object.entries(values).map(([key, value]) =>
|
||||
`${key} ${value} ${thermalUnit(section, key, currency)}`,
|
||||
).join(', ')}
|
||||
</Text>
|
||||
))}
|
||||
<ScrollArea type="auto">
|
||||
<Table withTableBorder withColumnBorders data-testid="thermal-price-table">
|
||||
<Table.Thead>
|
||||
<Table.Tr>
|
||||
<Table.Th>Category</Table.Th>
|
||||
<Table.Th>Charge</Table.Th>
|
||||
<Table.Th>Rate</Table.Th>
|
||||
<Table.Th>Unit</Table.Th>
|
||||
</Table.Tr>
|
||||
</Table.Thead>
|
||||
<Table.Tbody>
|
||||
{thermalSections(data.values!).flatMap((section) => Object.entries(data.values![section]).map(([key, rate]) => (
|
||||
<Table.Tr key={`${section}-${key}`} data-testid={`thermal-price-row-${section}-${key}`}>
|
||||
<Table.Td>{humanizeThermalField(section)}</Table.Td>
|
||||
<Table.Td>{humanizeThermalField(key)}</Table.Td>
|
||||
<Table.Td>{rate}</Table.Td>
|
||||
<Table.Td>{thermalUnit(section, key, currency)}</Table.Td>
|
||||
</Table.Tr>
|
||||
)))}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</ScrollArea>
|
||||
</Stack>
|
||||
</Paper>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user