Files
stats/apps/start/src/components/report-chart/histogram/chart.tsx
Carl-Gerhard Lindesvärd b421474616 feat: report editor
commit bfcf271a64c33a60f61f511cec2198d9c8a9c51a
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Wed Nov 26 12:32:40 2025 +0100

    wip

commit 8cd3b89fa3
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 22:33:58 2025 +0100

    funnel

commit 95af86dc44
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 22:23:25 2025 +0100

    wip

commit 727a218e6b
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 10:18:26 2025 +0100

    conversion wip

commit 958ba535d6
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 10:18:20 2025 +0100

    wip

commit 3bbeb927cc
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Tue Nov 25 09:18:48 2025 +0100

    wip

commit d99335e2f4
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 18:08:10 2025 +0100

    wip

commit 1fa61b1ae9
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 15:50:28 2025 +0100

    ts

commit 548747d826
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 13:17:01 2025 +0100

    fix typecheck events -> series

commit 7b18544085
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Mon Nov 24 13:06:46 2025 +0100

    fix report table

commit 57697a5a39
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Sat Nov 22 00:05:13 2025 +0100

    wip

commit 06fb6c4f3c
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Fri Nov 21 11:21:17 2025 +0100

    wip

commit dd71fd4e11
Author: Carl-Gerhard Lindesvärd <lindesvard@gmail.com>
Date:   Thu Nov 20 13:56:58 2025 +0100

    formulas
2025-11-26 12:33:41 +01:00

224 lines
5.9 KiB
TypeScript

import { useRechartDataModel } from '@/hooks/use-rechart-data-model';
import { useTheme } from '@/hooks/use-theme';
import { useVisibleSeries } from '@/hooks/use-visible-series';
import { useTRPC } from '@/integrations/trpc/react';
import { pushModal } from '@/modals';
import type { IChartData } from '@/trpc/client';
import { cn } from '@/utils/cn';
import { getChartColor } from '@/utils/theme';
import { useQuery } from '@tanstack/react-query';
import { BookmarkIcon, UsersIcon } from 'lucide-react';
import React, { useCallback } from 'react';
import {
Bar,
BarChart,
CartesianGrid,
ReferenceLine,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from 'recharts';
import { useXAxisProps, useYAxisProps } from '../common/axis';
import {
ChartClickMenu,
type ChartClickMenuItem,
} from '../common/chart-click-menu';
import { ReportChartTooltip } from '../common/report-chart-tooltip';
import { ReportTable } from '../common/report-table';
import { useReportChartContext } from '../context';
interface Props {
data: IChartData;
}
function BarHover({ x, y, width, height, top, left, right, bottom }: any) {
const themeMode = useTheme();
const styles = getComputedStyle(document.documentElement);
const def100 = styles.getPropertyValue('--def-100');
const def300 = styles.getPropertyValue('--def-300');
const bg = themeMode?.theme === 'dark' ? def100 : def300;
return (
<rect
{...{ x, y, width, height, top, left, right, bottom }}
rx="3"
fill={bg}
fillOpacity={0.5}
/>
);
}
export function Chart({ data }: Props) {
const {
isEditMode,
report: {
previous,
interval,
projectId,
startDate,
endDate,
range,
series: reportSeries,
breakdowns,
},
options: { hideXAxis, hideYAxis },
} = useReportChartContext();
const trpc = useTRPC();
const references = useQuery(
trpc.reference.getChartReferences.queryOptions(
{
projectId,
startDate,
endDate,
range,
},
{
staleTime: 1000 * 60 * 10,
},
),
);
const { series, setVisibleSeries } = useVisibleSeries(data);
const rechartData = useRechartDataModel(series);
const yAxisProps = useYAxisProps({
hide: hideYAxis,
});
const xAxisProps = useXAxisProps({
hide: hideXAxis,
interval,
});
const getMenuItems = useCallback(
(e: any, clickedData: any): ChartClickMenuItem[] => {
const items: ChartClickMenuItem[] = [];
if (!clickedData?.date) {
return items;
}
// View Users - only show if we have projectId
if (projectId) {
items.push({
label: 'View Users',
icon: <UsersIcon size={16} />,
onClick: () => {
pushModal('ViewChartUsers', {
type: 'chart',
chartData: data,
report: {
projectId,
series: reportSeries,
breakdowns: breakdowns || [],
interval,
startDate,
endDate,
range,
previous,
chartType: 'histogram',
metric: 'sum',
},
date: clickedData.date,
});
},
});
}
// Add Reference - always show
items.push({
label: 'Add Reference',
icon: <BookmarkIcon size={16} />,
onClick: () => {
pushModal('AddReference', {
datetime: new Date(clickedData.date).toISOString(),
});
},
});
return items;
},
[
projectId,
data,
reportSeries,
breakdowns,
interval,
startDate,
endDate,
range,
previous,
],
);
return (
<ReportChartTooltip.TooltipProvider references={references.data}>
<ChartClickMenu getMenuItems={getMenuItems}>
<div className={cn('h-full w-full', isEditMode && 'card p-4')}>
<ResponsiveContainer>
<BarChart data={rechartData}>
<CartesianGrid
strokeDasharray="3 3"
vertical={false}
className="stroke-def-200"
/>
<Tooltip
content={<ReportChartTooltip.Tooltip />}
cursor={<BarHover />}
/>
<YAxis {...yAxisProps} />
<XAxis {...xAxisProps} scale={'auto'} type="category" />
{previous
? series.map((serie) => {
return (
<Bar
key={`${serie.id}:prev`}
name={`${serie.id}:prev`}
dataKey={`${serie.id}:prev:count`}
fill={getChartColor(serie.index)}
fillOpacity={0.3}
radius={5}
/>
);
})
: null}
{series.map((serie) => {
return (
<Bar
key={serie.id}
name={serie.id}
dataKey={`${serie.id}:count`}
fill={getChartColor(serie.index)}
radius={5}
fillOpacity={1}
/>
);
})}
{references.data?.map((ref) => (
<ReferenceLine
key={ref.id}
x={ref.date.getTime()}
stroke={'oklch(from var(--foreground) l c h / 0.1)'}
strokeDasharray={'3 3'}
label={{
value: ref.title,
position: 'centerTop',
fill: '#334155',
fontSize: 12,
}}
fontSize={10}
/>
))}
</BarChart>
</ResponsiveContainer>
</div>
{isEditMode && (
<ReportTable
data={data}
visibleSeries={series}
setVisibleSeries={setVisibleSeries}
/>
)}
</ChartClickMenu>
</ReportChartTooltip.TooltipProvider>
);
}