diff --git a/apps/web/src/app/(app)/[organizationId]/[projectId]/overview-metrics.tsx b/apps/web/src/app/(app)/[organizationId]/[projectId]/overview-metrics.tsx index 77383e5e..bf1fb31c 100644 --- a/apps/web/src/app/(app)/[organizationId]/[projectId]/overview-metrics.tsx +++ b/apps/web/src/app/(app)/[organizationId]/[projectId]/overview-metrics.tsx @@ -182,7 +182,7 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) { name: 'Visit duration', range, previous, - formula: 'A/1000/60', + formula: 'A/1000', metric: 'average', unit: 'min', }, @@ -192,24 +192,26 @@ export default function OverviewMetrics({ projectId }: OverviewMetricsProps) { return ( <> - {reports.map((report, index) => ( - - ))} +
+ {reports.map((report, index) => ( + + ))} +
{selectedMetric.events[0]?.displayName}
diff --git a/apps/web/src/components/overview/overview-live-histogram.tsx b/apps/web/src/components/overview/overview-live-histogram.tsx index 78d3741b..fc434345 100644 --- a/apps/web/src/components/overview/overview-live-histogram.tsx +++ b/apps/web/src/components/overview/overview-live-histogram.tsx @@ -42,7 +42,7 @@ export function OverviewLiveHistogram({ metric: 'sum', breakdowns: [], lineType: 'monotone', - previous: true, + previous: false, }; return ( diff --git a/apps/web/src/components/report/PreviousDiffIndicator.tsx b/apps/web/src/components/report/PreviousDiffIndicator.tsx index 7d3c3003..ff8dc8ed 100644 --- a/apps/web/src/components/report/PreviousDiffIndicator.tsx +++ b/apps/web/src/components/report/PreviousDiffIndicator.tsx @@ -5,6 +5,25 @@ import { TrendingDownIcon, TrendingUpIcon } from 'lucide-react'; import { Badge } from '../ui/badge'; import { useChartContext } from './chart/ChartProvider'; +export function getDiffIndicator( + inverted: boolean | undefined, + state: string | undefined | null, + positive: A, + negative: B, + neutral: C +): A | B | C { + if (state === 'neutral' || !state) { + return neutral; + } + + if (inverted === true) { + return state === 'positive' ? negative : positive; + } + return state === 'positive' ? positive : negative; +} + +// TODO: Fix this mess! + interface PreviousDiffIndicatorProps { diff?: number | null | undefined; state?: string | null | undefined; @@ -18,38 +37,77 @@ export function PreviousDiffIndicator({ children, }: PreviousDiffIndicatorProps) { const { previous, previousIndicatorInverted } = useChartContext(); + const variant = getDiffIndicator( + previousIndicatorInverted, + state, + 'success', + 'destructive', + undefined + ); const number = useNumber(); + if (diff === null || diff === undefined || previous === false) { return children ?? null; } - if (previousIndicatorInverted === true) { - return ( - <> - - {state === 'negative' && } - {state === 'positive' && } - {number.format(diff)}% - - {children} - - ); - } + const renderIcon = () => { + if (state === 'positive') { + return ; + } + if (state === 'negative') { + return ; + } + return null; + }; return ( <> - - {state === 'positive' && } - {state === 'negative' && } + + {renderIcon()} {number.format(diff)}% {children} ); } + +export function PreviousDiffIndicatorText({ + diff, + state, + className, +}: PreviousDiffIndicatorProps & { className?: string }) { + const { previous, previousIndicatorInverted } = useChartContext(); + const number = useNumber(); + if (diff === null || diff === undefined || previous === false) { + return null; + } + + const renderIcon = () => { + if (state === 'positive') { + return ; + } + if (state === 'negative') { + return ; + } + return null; + }; + + return ( +
+ {renderIcon()} + {number.format(diff)}% +
+ ); +} diff --git a/apps/web/src/components/report/chart/MetricCard.tsx b/apps/web/src/components/report/chart/MetricCard.tsx index de57b954..122b9c54 100644 --- a/apps/web/src/components/report/chart/MetricCard.tsx +++ b/apps/web/src/components/report/chart/MetricCard.tsx @@ -2,14 +2,19 @@ import type { IChartData } from '@/app/_trpc/client'; import { ColorSquare } from '@/components/ColorSquare'; -import { useNumber } from '@/hooks/useNumerFormatter'; +import { fancyMinutes, useNumber } from '@/hooks/useNumerFormatter'; import { theme } from '@/utils/theme'; import AutoSizer from 'react-virtualized-auto-sizer'; import { Area, AreaChart } from 'recharts'; import type { IChartMetric } from '@mixan/validation'; -import { PreviousDiffIndicator } from '../PreviousDiffIndicator'; +import { + getDiffIndicator, + PreviousDiffIndicator, + PreviousDiffIndicatorText, +} from '../PreviousDiffIndicator'; +import { useChartContext } from './ChartProvider'; interface MetricCardProps { serie: IChartData['series'][number]; @@ -24,14 +29,39 @@ export function MetricCard({ metric, unit, }: MetricCardProps) { + const { previousIndicatorInverted } = useChartContext(); const color = _color || theme?.colors['chart-0']; const number = useNumber(); + + const renderValue = (value: number, unitClassName?: string) => { + if (unit === 'min') { + return <>{fancyMinutes(value)}; + } + + return ( + <> + {number.short(value)} + {unit && {unit}} + + ); + }; + + const previous = serie.metrics.previous[metric]; + + const graphColors = getDiffIndicator( + previousIndicatorInverted, + previous?.state, + 'green', + 'red', + 'blue' + ); + return (
-
+
{({ width, height }) => ( - - - + + + + + + + + + + + @@ -60,23 +98,22 @@ export function MetricCard({
-
+
{serie.event.id} - {serie.name || serie.event.displayName || serie.event.name} + + {serie.name || serie.event.displayName || serie.event.name} +
- + {/* */}
-
- {number.format(serie.metrics[metric])} - {unit && {unit}} +
+ {renderValue(serie.metrics[metric], 'ml-1 font-light text-xl')}
- {!!serie.metrics.previous[metric] && ( -
- {number.format(serie.metrics.previous[metric]?.value)} - {unit} -
- )} +
diff --git a/apps/web/src/components/report/chart/ReportAreaChart.tsx b/apps/web/src/components/report/chart/ReportAreaChart.tsx index 64a6b188..8d88b55a 100644 --- a/apps/web/src/components/report/chart/ReportAreaChart.tsx +++ b/apps/web/src/components/report/chart/ReportAreaChart.tsx @@ -1,10 +1,9 @@ import React from 'react'; import type { IChartData } from '@/app/_trpc/client'; -import { AutoSizer } from '@/components/AutoSizer'; import { useFormatDateInterval } from '@/hooks/useFormatDateInterval'; +import { useNumber } from '@/hooks/useNumerFormatter'; import { useRechartDataModel } from '@/hooks/useRechartDataModel'; import { useVisibleSeries } from '@/hooks/useVisibleSeries'; -import { cn } from '@/utils/cn'; import { getChartColor } from '@/utils/theme'; import { Area, @@ -38,6 +37,7 @@ export function ReportAreaChart({ const { series, setVisibleSeries } = useVisibleSeries(data); const formatDate = useFormatDateInterval(interval); const rechartData = useRechartDataModel(series); + const number = useNumber(); return ( <> @@ -59,6 +59,7 @@ export function ReportAreaChart({ axisLine={false} tickLine={false} allowDecimals={false} + tickFormatter={number.short} /> {series.map((serie) => { diff --git a/apps/web/src/components/report/chart/ReportHistogramChart.tsx b/apps/web/src/components/report/chart/ReportHistogramChart.tsx index 402a6bbb..969b07e0 100644 --- a/apps/web/src/components/report/chart/ReportHistogramChart.tsx +++ b/apps/web/src/components/report/chart/ReportHistogramChart.tsx @@ -1,10 +1,9 @@ import React from 'react'; import type { IChartData } from '@/app/_trpc/client'; -import { AutoSizer } from '@/components/AutoSizer'; import { useFormatDateInterval } from '@/hooks/useFormatDateInterval'; +import { useNumber } from '@/hooks/useNumerFormatter'; import { useRechartDataModel } from '@/hooks/useRechartDataModel'; import { useVisibleSeries } from '@/hooks/useVisibleSeries'; -import { cn } from '@/utils/cn'; import { getChartColor, theme } from '@/utils/theme'; import { Bar, BarChart, CartesianGrid, Tooltip, XAxis, YAxis } from 'recharts'; @@ -40,8 +39,8 @@ export function ReportHistogramChart({ const { editMode, previous } = useChartContext(); const formatDate = useFormatDateInterval(interval); const { series, setVisibleSeries } = useVisibleSeries(data); - const rechartData = useRechartDataModel(series); + const number = useNumber(); return ( <> @@ -64,6 +63,7 @@ export function ReportHistogramChart({ width={getYAxisWidth(data.metrics.max)} allowDecimals={false} domain={[0, data.metrics.max]} + tickFormatter={number.short} /> {series.map((serie) => { return ( diff --git a/apps/web/src/components/report/chart/ReportLineChart.tsx b/apps/web/src/components/report/chart/ReportLineChart.tsx index 4284f983..d6559e59 100644 --- a/apps/web/src/components/report/chart/ReportLineChart.tsx +++ b/apps/web/src/components/report/chart/ReportLineChart.tsx @@ -2,11 +2,10 @@ import React from 'react'; import type { IChartData } from '@/app/_trpc/client'; -import { AutoSizer } from '@/components/AutoSizer'; import { useFormatDateInterval } from '@/hooks/useFormatDateInterval'; +import { useNumber } from '@/hooks/useNumerFormatter'; import { useRechartDataModel } from '@/hooks/useRechartDataModel'; import { useVisibleSeries } from '@/hooks/useVisibleSeries'; -import { cn } from '@/utils/cn'; import { getChartColor } from '@/utils/theme'; import { CartesianGrid, @@ -40,7 +39,7 @@ export function ReportLineChart({ const formatDate = useFormatDateInterval(interval); const { series, setVisibleSeries } = useVisibleSeries(data); const rechartData = useRechartDataModel(series); - + const number = useNumber(); return ( <> @@ -57,6 +56,7 @@ export function ReportLineChart({ axisLine={false} tickLine={false} allowDecimals={false} + tickFormatter={number.short} /> } /> { + if (isNil(value)) { + return 'N/A'; + } + return new Intl.NumberFormat(locale, { + maximumSignificantDigits: 20, + }).format(value); + }; + const short = (value: number | null | undefined) => { + if (isNil(value)) { + return 'N/A'; + } + return new Intl.NumberFormat(locale, { + notation: 'compact', + }).format(value); + }; + return { - format: (value: number | null | undefined) => { - if (isNil(value)) { - return 'N/A'; - } - return new Intl.NumberFormat(locale, { - maximumSignificantDigits: 20, - }).format(value); - }, + format, + short, }; }