'use client'; import { useRechartDataModel } from '@/hooks/useRechartDataModel'; import { useVisibleSeries } from '@/hooks/useVisibleSeries'; import { api } from '@/trpc/client'; import type { IChartData } from '@/trpc/client'; import { cn } from '@/utils/cn'; import { getChartColor } from '@/utils/theme'; import { isSameDay, isSameHour, isSameMonth } from 'date-fns'; import { last } from 'ramda'; import React, { useCallback } from 'react'; import { Area, CartesianGrid, ComposedChart, Legend, Line, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts'; import { useXAxisProps, useYAxisProps } from '../common/axis'; import { ReportChartTooltip } from '../common/report-chart-tooltip'; import { ReportTable } from '../common/report-table'; import { SerieIcon } from '../common/serie-icon'; import { SerieName } from '../common/serie-name'; import { useReportChartContext } from '../context'; interface Props { data: IChartData; } export function Chart({ data }: Props) { const { report: { previous, interval, projectId, startDate, endDate, range, lineType, }, isEditMode, options: { hideXAxis, hideYAxis }, } = useReportChartContext(); const dataLength = data.series[0]?.data?.length || 0; const references = api.reference.getChartReferences.useQuery( { projectId, startDate, endDate, range, }, { staleTime: 1000 * 60 * 10, }, ); const { series, setVisibleSeries } = useVisibleSeries(data); const rechartData = useRechartDataModel(series); // great care should be taken when computing lastIntervalPercent // the expression below works for data.length - 1 equal intervals // but if there are numeric x values in a "linear" axis, the formula // should be updated to use those values const lastIntervalPercent = ((rechartData.length - 2) * 100) / (rechartData.length - 1); const gradientTwoColors = ( id: string, col1: string, col2: string, percentChange: number, ) => ( ); const lastSerieDataItem = last(series[0]?.data || [])?.date || new Date(); const useDashedLastLine = (() => { if (interval === 'hour') { return isSameHour(lastSerieDataItem, new Date()); } if (interval === 'day') { return isSameDay(lastSerieDataItem, new Date()); } if (interval === 'month') { return isSameMonth(lastSerieDataItem, new Date()); } return false; })(); const CustomLegend = useCallback(() => { return (
{series.map((serie) => (
))}
); }, [series]); const yAxisProps = useYAxisProps({ data: [data.metrics.max], hide: hideYAxis, }); const xAxisProps = useXAxisProps({ hide: hideXAxis, interval, }); const isAreaStyle = series.length === 1; return ( <>
{references.data?.map((ref) => ( ))} {series.length > 1 && ( } /> )} } /> {series.map((serie) => { const color = getChartColor(serie.index); return ( {isAreaStyle && ( )} {gradientTwoColors( `hideAllButLastInterval_${serie.id}`, 'rgba(0,0,0,0)', color, lastIntervalPercent, )} {gradientTwoColors( `hideJustLastInterval_${serie.id}`, color, 'rgba(0,0,0,0)', lastIntervalPercent, )} {isAreaStyle && ( )} {useDashedLastLine && ( <> )} {previous && ( )} ); })}
{isEditMode && ( )} ); }