fix broken retention page
This commit is contained in:
@@ -4,6 +4,7 @@ import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { getChartColor } from '@/utils/theme';
|
||||
import {
|
||||
Area,
|
||||
@@ -33,74 +34,76 @@ export function ReportAreaChart({ data }: ReportAreaChartProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResponsiveContainer>
|
||||
{({ width, height }) => (
|
||||
<AreaChart width={width} height={height} data={rechartData}>
|
||||
<Tooltip content={<ReportChartTooltip />} />
|
||||
<XAxis
|
||||
axisLine={false}
|
||||
fontSize={12}
|
||||
dataKey="date"
|
||||
tickFormatter={(m: string) => formatDate(m)}
|
||||
tickLine={false}
|
||||
allowDuplicatedCategory={false}
|
||||
/>
|
||||
<YAxis
|
||||
width={getYAxisWidth(data.metrics.max)}
|
||||
fontSize={12}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
allowDecimals={false}
|
||||
tickFormatter={number.short}
|
||||
/>
|
||||
<div className={cn(editMode && 'card p-4')}>
|
||||
<ResponsiveContainer>
|
||||
{({ width, height }) => (
|
||||
<AreaChart width={width} height={height} data={rechartData}>
|
||||
<Tooltip content={<ReportChartTooltip />} />
|
||||
<XAxis
|
||||
axisLine={false}
|
||||
fontSize={12}
|
||||
dataKey="date"
|
||||
tickFormatter={(m: string) => formatDate(m)}
|
||||
tickLine={false}
|
||||
allowDuplicatedCategory={false}
|
||||
/>
|
||||
<YAxis
|
||||
width={getYAxisWidth(data.metrics.max)}
|
||||
fontSize={12}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
allowDecimals={false}
|
||||
tickFormatter={number.short}
|
||||
/>
|
||||
|
||||
{series.map((serie) => {
|
||||
const color = getChartColor(serie.index);
|
||||
return (
|
||||
<React.Fragment key={serie.id}>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={`color${color}`}
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.8}
|
||||
></stop>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.1}
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<Area
|
||||
key={serie.id}
|
||||
type={lineType}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={color}
|
||||
fill={`url(#color${color})`}
|
||||
stackId={'1'}
|
||||
fillOpacity={1}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
horizontal={true}
|
||||
vertical={false}
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
</AreaChart>
|
||||
)}
|
||||
</ResponsiveContainer>
|
||||
{series.map((serie) => {
|
||||
const color = getChartColor(serie.index);
|
||||
return (
|
||||
<React.Fragment key={serie.id}>
|
||||
<defs>
|
||||
<linearGradient
|
||||
id={`color${color}`}
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.8}
|
||||
></stop>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.1}
|
||||
></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<Area
|
||||
key={serie.id}
|
||||
type={lineType}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={color}
|
||||
fill={`url(#color${color})`}
|
||||
stackId={'1'}
|
||||
fillOpacity={1}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
horizontal={true}
|
||||
vertical={false}
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
</AreaChart>
|
||||
)}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
{editMode && (
|
||||
<ReportTable
|
||||
data={data}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useNumber } from '@/hooks/useNumerFormatter';
|
||||
import { useRechartDataModel } from '@/hooks/useRechartDataModel';
|
||||
import { useVisibleSeries } from '@/hooks/useVisibleSeries';
|
||||
import type { IChartData } from '@/trpc/client';
|
||||
import { cn } from '@/utils/cn';
|
||||
import { getChartColor, theme } from '@/utils/theme';
|
||||
import { Bar, BarChart, CartesianGrid, Tooltip, XAxis, YAxis } from 'recharts';
|
||||
|
||||
@@ -40,57 +41,59 @@ export function ReportHistogramChart({ data }: ReportHistogramChartProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResponsiveContainer>
|
||||
{({ width, height }) => (
|
||||
<BarChart width={width} height={height} data={rechartData}>
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
vertical={false}
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
<Tooltip content={<ReportChartTooltip />} cursor={<BarHover />} />
|
||||
<XAxis
|
||||
fontSize={12}
|
||||
dataKey="date"
|
||||
tickFormatter={formatDate}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
<YAxis
|
||||
fontSize={12}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
width={getYAxisWidth(data.metrics.max)}
|
||||
allowDecimals={false}
|
||||
domain={[0, data.metrics.max]}
|
||||
tickFormatter={number.short}
|
||||
/>
|
||||
{series.map((serie) => {
|
||||
return (
|
||||
<React.Fragment key={serie.id}>
|
||||
{previous && (
|
||||
<div className={cn(editMode && 'card p-4')}>
|
||||
<ResponsiveContainer>
|
||||
{({ width, height }) => (
|
||||
<BarChart width={width} height={height} data={rechartData}>
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
vertical={false}
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
<Tooltip content={<ReportChartTooltip />} cursor={<BarHover />} />
|
||||
<XAxis
|
||||
fontSize={12}
|
||||
dataKey="date"
|
||||
tickFormatter={formatDate}
|
||||
tickLine={false}
|
||||
axisLine={false}
|
||||
/>
|
||||
<YAxis
|
||||
fontSize={12}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
width={getYAxisWidth(data.metrics.max)}
|
||||
allowDecimals={false}
|
||||
domain={[0, data.metrics.max]}
|
||||
tickFormatter={number.short}
|
||||
/>
|
||||
{series.map((serie) => {
|
||||
return (
|
||||
<React.Fragment key={serie.id}>
|
||||
{previous && (
|
||||
<Bar
|
||||
key={`${serie.id}:prev`}
|
||||
name={`${serie.id}:prev`}
|
||||
dataKey={`${serie.id}:prev:count`}
|
||||
fill={getChartColor(serie.index)}
|
||||
fillOpacity={0.2}
|
||||
radius={3}
|
||||
/>
|
||||
)}
|
||||
<Bar
|
||||
key={`${serie.id}:prev`}
|
||||
name={`${serie.id}:prev`}
|
||||
dataKey={`${serie.id}:prev:count`}
|
||||
key={serie.id}
|
||||
name={serie.id}
|
||||
dataKey={`${serie.id}:count`}
|
||||
fill={getChartColor(serie.index)}
|
||||
fillOpacity={0.2}
|
||||
radius={3}
|
||||
/>
|
||||
)}
|
||||
<Bar
|
||||
key={serie.id}
|
||||
name={serie.id}
|
||||
dataKey={`${serie.id}:count`}
|
||||
fill={getChartColor(serie.index)}
|
||||
radius={3}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</BarChart>
|
||||
)}
|
||||
</ResponsiveContainer>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</BarChart>
|
||||
)}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
{editMode && (
|
||||
<ReportTable
|
||||
data={data}
|
||||
|
||||
@@ -7,6 +7,7 @@ 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 { SplineIcon } from 'lucide-react';
|
||||
@@ -127,159 +128,161 @@ export function ReportLineChart({ data }: ReportLineChartProps) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ResponsiveContainer>
|
||||
{({ width, height }) => (
|
||||
<ComposedChart width={width} height={height} data={rechartData}>
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
horizontal={true}
|
||||
vertical={false}
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
{references.data?.map((ref) => (
|
||||
<ReferenceLine
|
||||
key={ref.id}
|
||||
x={ref.date.getTime()}
|
||||
stroke={'#94a3b8'}
|
||||
strokeDasharray={'3 3'}
|
||||
label={{
|
||||
value: ref.title,
|
||||
position: 'centerTop',
|
||||
fill: '#334155',
|
||||
fontSize: 12,
|
||||
}}
|
||||
fontSize={10}
|
||||
<div className={cn(editMode && 'card p-4')}>
|
||||
<ResponsiveContainer>
|
||||
{({ width, height }) => (
|
||||
<ComposedChart width={width} height={height} data={rechartData}>
|
||||
<CartesianGrid
|
||||
strokeDasharray="3 3"
|
||||
horizontal={true}
|
||||
vertical={false}
|
||||
className="stroke-def-200"
|
||||
/>
|
||||
))}
|
||||
<YAxis
|
||||
width={getYAxisWidth(data.metrics.max)}
|
||||
fontSize={12}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
allowDecimals={false}
|
||||
tickFormatter={number.short}
|
||||
/>
|
||||
{series.length > 1 && (
|
||||
<Legend
|
||||
wrapperStyle={{ fontSize: '10px' }}
|
||||
content={<CustomLegend />}
|
||||
{references.data?.map((ref) => (
|
||||
<ReferenceLine
|
||||
key={ref.id}
|
||||
x={ref.date.getTime()}
|
||||
stroke={'#94a3b8'}
|
||||
strokeDasharray={'3 3'}
|
||||
label={{
|
||||
value: ref.title,
|
||||
position: 'centerTop',
|
||||
fill: '#334155',
|
||||
fontSize: 12,
|
||||
}}
|
||||
fontSize={10}
|
||||
/>
|
||||
))}
|
||||
<YAxis
|
||||
width={getYAxisWidth(data.metrics.max)}
|
||||
fontSize={12}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
allowDecimals={false}
|
||||
tickFormatter={number.short}
|
||||
/>
|
||||
)}
|
||||
<Tooltip content={<ReportChartTooltip />} />
|
||||
<XAxis
|
||||
axisLine={false}
|
||||
fontSize={12}
|
||||
dataKey="timestamp"
|
||||
scale="utc"
|
||||
domain={['dataMin', 'dataMax']}
|
||||
tickFormatter={(m: string) => formatDate(new Date(m))}
|
||||
type="number"
|
||||
tickLine={false}
|
||||
/>
|
||||
{series.map((serie) => {
|
||||
const color = getChartColor(serie.index);
|
||||
return (
|
||||
<React.Fragment key={serie.id}>
|
||||
<defs>
|
||||
{isAreaStyle && (
|
||||
<linearGradient
|
||||
id={`color${color}`}
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.8}
|
||||
></stop>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.1}
|
||||
></stop>
|
||||
</linearGradient>
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideAllButLastInterval_${serie.id}`,
|
||||
'rgba(0,0,0,0)',
|
||||
color,
|
||||
lastIntervalPercent
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideJustLastInterval_${serie.id}`,
|
||||
color,
|
||||
'rgba(0,0,0,0)',
|
||||
lastIntervalPercent
|
||||
)}
|
||||
</defs>
|
||||
<Line
|
||||
dot={false}
|
||||
type={lineType}
|
||||
name={serie.id}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={useDashedLastLine ? 'transparent' : color}
|
||||
// Use for legend
|
||||
fill={color}
|
||||
/>
|
||||
{isAreaStyle && (
|
||||
<Area
|
||||
name={`${serie.id}:area:noTooltip`}
|
||||
dataKey={`${serie.id}:count`}
|
||||
fill={`url(#color${color})`}
|
||||
type={lineType}
|
||||
isAnimationActive={false}
|
||||
fillOpacity={0.1}
|
||||
/>
|
||||
)}
|
||||
{useDashedLastLine && (
|
||||
<>
|
||||
<Line
|
||||
dot={false}
|
||||
type={lineType}
|
||||
name={`${serie.id}:dashed:noTooltip`}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={`url('#hideAllButLastInterval_${serie.id}')`}
|
||||
strokeDasharray="4 2"
|
||||
strokeOpacity={0.7}
|
||||
/>
|
||||
<Line
|
||||
dot={false}
|
||||
type={lineType}
|
||||
name={`${serie.id}:solid:noTooltip`}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={`url('#hideJustLastInterval_${serie.id}')`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{previous && (
|
||||
{series.length > 1 && (
|
||||
<Legend
|
||||
wrapperStyle={{ fontSize: '10px' }}
|
||||
content={<CustomLegend />}
|
||||
/>
|
||||
)}
|
||||
<Tooltip content={<ReportChartTooltip />} />
|
||||
<XAxis
|
||||
axisLine={false}
|
||||
fontSize={12}
|
||||
dataKey="timestamp"
|
||||
scale="utc"
|
||||
domain={['dataMin', 'dataMax']}
|
||||
tickFormatter={(m: string) => formatDate(new Date(m))}
|
||||
type="number"
|
||||
tickLine={false}
|
||||
/>
|
||||
{series.map((serie) => {
|
||||
const color = getChartColor(serie.index);
|
||||
return (
|
||||
<React.Fragment key={serie.id}>
|
||||
<defs>
|
||||
{isAreaStyle && (
|
||||
<linearGradient
|
||||
id={`color${color}`}
|
||||
x1="0"
|
||||
y1="0"
|
||||
x2="0"
|
||||
y2="1"
|
||||
>
|
||||
<stop
|
||||
offset="0%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.8}
|
||||
></stop>
|
||||
<stop
|
||||
offset="100%"
|
||||
stopColor={color}
|
||||
stopOpacity={0.1}
|
||||
></stop>
|
||||
</linearGradient>
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideAllButLastInterval_${serie.id}`,
|
||||
'rgba(0,0,0,0)',
|
||||
color,
|
||||
lastIntervalPercent
|
||||
)}
|
||||
{gradientTwoColors(
|
||||
`hideJustLastInterval_${serie.id}`,
|
||||
color,
|
||||
'rgba(0,0,0,0)',
|
||||
lastIntervalPercent
|
||||
)}
|
||||
</defs>
|
||||
<Line
|
||||
type={lineType}
|
||||
name={`${serie.id}:prev`}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={1}
|
||||
dot={false}
|
||||
strokeDasharray={'1 1'}
|
||||
strokeOpacity={0.5}
|
||||
dataKey={`${serie.id}:prev:count`}
|
||||
stroke={color}
|
||||
type={lineType}
|
||||
name={serie.id}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={useDashedLastLine ? 'transparent' : color}
|
||||
// Use for legend
|
||||
fill={color}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</ComposedChart>
|
||||
)}
|
||||
</ResponsiveContainer>
|
||||
{isAreaStyle && (
|
||||
<Area
|
||||
name={`${serie.id}:area:noTooltip`}
|
||||
dataKey={`${serie.id}:count`}
|
||||
fill={`url(#color${color})`}
|
||||
type={lineType}
|
||||
isAnimationActive={false}
|
||||
fillOpacity={0.1}
|
||||
/>
|
||||
)}
|
||||
{useDashedLastLine && (
|
||||
<>
|
||||
<Line
|
||||
dot={false}
|
||||
type={lineType}
|
||||
name={`${serie.id}:dashed:noTooltip`}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={`url('#hideAllButLastInterval_${serie.id}')`}
|
||||
strokeDasharray="4 2"
|
||||
strokeOpacity={0.7}
|
||||
/>
|
||||
<Line
|
||||
dot={false}
|
||||
type={lineType}
|
||||
name={`${serie.id}:solid:noTooltip`}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={2}
|
||||
dataKey={`${serie.id}:count`}
|
||||
stroke={`url('#hideJustLastInterval_${serie.id}')`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{previous && (
|
||||
<Line
|
||||
type={lineType}
|
||||
name={`${serie.id}:prev`}
|
||||
isAnimationActive={false}
|
||||
strokeWidth={1}
|
||||
dot={false}
|
||||
strokeDasharray={'1 1'}
|
||||
strokeOpacity={0.5}
|
||||
dataKey={`${serie.id}:prev:count`}
|
||||
stroke={color}
|
||||
// Use for legend
|
||||
fill={color}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</ComposedChart>
|
||||
)}
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
{editMode && (
|
||||
<ReportTable
|
||||
data={data}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { cn } from '@/utils/cn';
|
||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||
|
||||
import { useChartContext } from './ChartProvider';
|
||||
|
||||
interface ResponsiveContainerProps {
|
||||
children: (props: { width: number; height: number }) => React.ReactNode;
|
||||
}
|
||||
|
||||
export function ResponsiveContainer({ children }: ResponsiveContainerProps) {
|
||||
const { editMode } = useChartContext();
|
||||
const maxHeight = 300;
|
||||
const minHeight = 200;
|
||||
return (
|
||||
@@ -17,17 +13,13 @@ export function ResponsiveContainer({ children }: ResponsiveContainerProps) {
|
||||
maxHeight,
|
||||
minHeight,
|
||||
}}
|
||||
className={cn('aspect-video w-full max-sm:-mx-3', editMode && 'card p-4')}
|
||||
className={'aspect-video w-full max-sm:-mx-3'}
|
||||
>
|
||||
<AutoSizer disableHeight>
|
||||
{({ width }) =>
|
||||
children({
|
||||
width,
|
||||
height: Math.min(
|
||||
Math.max(width * 0.5625, minHeight),
|
||||
// we add p-4 (16px) padding in edit mode
|
||||
editMode ? maxHeight - 16 : maxHeight
|
||||
),
|
||||
height: Math.min(maxHeight, width * 0.5625),
|
||||
})
|
||||
}
|
||||
</AutoSizer>
|
||||
|
||||
Reference in New Issue
Block a user