All files / src/pages/analytics/blocks/price-trend PriceChart.tsx

99% Statements 99/100
73.33% Branches 11/15
80% Functions 4/5
99% Lines 99/100

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 1011x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 16x 16x 16x 16x 16x 16x 16x 16x 16x 1x 1x 1x 1x 1x 16x 16x 16x 16x 16x 16x 16x 16x 11x 11x 5x 16x 3x 3x 3x 3x 3x 3x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1x 1x   2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x  
/**
 * @file PriceChart.tsx
 * @description
 * Price trend line chart component.
 * Renders recharts LineChart with date/price formatting.
 */
 
import { Box, Skeleton } from '@mui/material';
import { useTheme as useMuiTheme } from '@mui/material/styles';
import { useMemo } from 'react';
import { ResponsiveContainer, LineChart, CartesianGrid, XAxis, YAxis, Tooltip, Line } from 'recharts';
import type { PricePoint } from '../../../../api/analytics';
import type { DateFormat } from '../../../../context/settings/SettingsContext.types';
import { formatDate, formatNumber } from '../../../../utils/formatters';
 
/**
 * Props for PriceChart
 */
export interface PriceChartProps {
  /** Price data points to render */
  data: PricePoint[];
  /** Whether chart is loading */
  isLoading: boolean;
  /** Date format preference (DD.MM.YYYY, YYYY-MM-DD, MM/DD/YYYY) */
  dateFormat: DateFormat;
  /** Number format preference (DE, EN_US, etc) */
  numberFormat: 'DE' | 'EN_US';
}
 
/**
 * Price trend line chart
 * Displays price movement over time with formatted axes
 */
export function PriceChart({
  data,
  isLoading,
  dateFormat,
  numberFormat,
}: PriceChartProps) {
  const muiTheme = useMuiTheme();
 
  // Format date labels for x-axis
  const formatDateLabel = (value: string | number) => {
    const str = String(value);
    // dateFormat is already typed as DateFormat from props
    const formatted = formatDate(str, dateFormat);
    return formatted || str;
  };
 
  // Sort data by date for deterministic rendering
  const sortedData = useMemo(
    () => [...data].sort((a, b) => (a?.date ?? '').localeCompare(b?.date ?? '')),
    [data]
  );
 
  if (isLoading) {
    return <Skeleton variant="rounded" height={220} />;
  }
 
  if (sortedData.length === 0) {
    return (
      <Box sx={{ height: 220, display: 'grid', placeItems: 'center', color: 'text.secondary' }}>
        No price data available
      </Box>
    );
  }
 
  return (
    <Box sx={{ height: 260 }}>
      <ResponsiveContainer width="100%" height="100%">
        <LineChart data={sortedData} margin={{ top: 8, right: 16, left: 8, bottom: 8 }}>
          <CartesianGrid strokeDasharray="3 3" />
          <XAxis dataKey="date" tickFormatter={formatDateLabel} />
          <YAxis
            domain={['auto', 'auto']}
            tickFormatter={(value) => formatNumber(Number(value), numberFormat, 2)}
          />
          <Tooltip
            labelFormatter={(value) => formatDateLabel(value as string)}
            formatter={(value: number | string) =>
              typeof value === 'number'
                ? formatNumber(value, numberFormat, 2)
                : value
            }
          />
          <Line
            type="monotone"
            dataKey="price"
            stroke={muiTheme.palette.primary.main}
            strokeWidth={2}
            dot={{ r: 2 }}
            activeDot={{ r: 4 }}
            connectNulls
            isAnimationActive={false}
          />
        </LineChart>
      </ResponsiveContainer>
    </Box>
  );
}