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
This commit is contained in:
Carl-Gerhard Lindesvärd
2025-11-26 12:33:41 +01:00
parent 828c8c4f91
commit b421474616
70 changed files with 6867 additions and 1918 deletions

View File

@@ -0,0 +1,44 @@
import type { RouterOutputs } from '@/trpc/client';
import { useMemo } from 'react';
export function useConversionRechartDataModel(
series: RouterOutputs['chart']['conversion']['current'],
) {
return useMemo(() => {
if (!series.length || !series[0]?.data.length) {
return [];
}
// Get all unique dates from the first series (all series should have same dates)
const dates = series[0].data.map((item) => item.date);
return dates.map((date) => {
const baseItem = series[0].data.find((item) => item.date === date);
if (!baseItem) {
return {
date,
timestamp: new Date(date).getTime(),
};
}
// Build data object with all series values
const dataPoint: Record<string, any> = {
date,
timestamp: new Date(date).getTime(),
};
series.forEach((serie) => {
const item = serie.data.find((d) => d.date === date);
if (item) {
dataPoint[`${serie.id}:rate`] = item.rate;
dataPoint[`${serie.id}:previousRate`] = item.previousRate;
dataPoint[`${serie.id}:total`] = item.total;
dataPoint[`${serie.id}:conversions`] = item.conversions;
}
});
return dataPoint;
});
}, [series]);
}

View File

@@ -0,0 +1,35 @@
import type { RouterOutputs } from '@/trpc/client';
import { useEffect, useMemo, useState } from 'react';
export type IVisibleConversionSeries = ReturnType<
typeof useVisibleConversionSeries
>['series'];
export function useVisibleConversionSeries(
data: RouterOutputs['chart']['conversion'],
limit?: number | undefined,
) {
const max = limit ?? 5;
const [visibleSeries, setVisibleSeries] = useState<string[]>(
data?.current?.slice(0, max).map((serie) => serie.id) ?? [],
);
useEffect(() => {
setVisibleSeries(
data?.current?.slice(0, max).map((serie) => serie.id) ?? [],
);
}, [data, max]);
return useMemo(() => {
return {
series: data.current
.map((serie, index) => ({
...serie,
index,
}))
.filter((serie) => visibleSeries.includes(serie.id)),
setVisibleSeries,
} as const;
}, [visibleSeries, data.current]);
}