From 0c78e313004f1343cd8c76a303cfa691db8b7e7d Mon Sep 17 00:00:00 2001 From: Bas Broekhuizen Date: Tue, 8 Jul 2025 10:17:18 +0200 Subject: [PATCH] Add table view as alternative to donut chart for event properties --- .../events/EventProperties.module.css | 12 ++-- .../[websiteId]/events/EventProperties.tsx | 68 ++++++++++++++----- src/components/messages.ts | 2 + 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/app/(main)/websites/[websiteId]/events/EventProperties.module.css b/src/app/(main)/websites/[websiteId]/events/EventProperties.module.css index 0b9c011d..a56df28f 100644 --- a/src/app/(main)/websites/[websiteId]/events/EventProperties.module.css +++ b/src/app/(main)/websites/[websiteId]/events/EventProperties.module.css @@ -14,12 +14,14 @@ color: var(--primary400); } -.title { - text-align: center; - font-weight: bold; - margin: 20px 0; +.header { + margin-bottom: 40px; } -.chart { +.title { + font-weight: bold; +} + +.data { min-height: 620px; } diff --git a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx index 453aa9a8..6d555e5d 100644 --- a/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx +++ b/src/app/(main)/websites/[websiteId]/events/EventProperties.tsx @@ -1,7 +1,9 @@ -import { GridColumn, GridTable } from 'react-basics'; +import { useMemo } from 'react'; +import { GridColumn, GridTable, Flexbox, Button, ButtonGroup } from 'react-basics'; import { useEventDataProperties, useEventDataValues, useMessages } from '@/components/hooks'; import { LoadingPanel } from '@/components/common/LoadingPanel'; import PieChart from '@/components/charts/PieChart'; +import ListTable from '@/components/metrics/ListTable'; import { useState } from 'react'; import { CHART_COLORS } from '@/lib/constants'; import styles from './EventProperties.module.css'; @@ -9,22 +11,38 @@ import styles from './EventProperties.module.css'; export function EventProperties({ websiteId }: { websiteId: string }) { const [propertyName, setPropertyName] = useState(''); const [eventName, setEventName] = useState(''); + const [propertyView, setPropertyView] = useState('table'); + const { formatMessage, labels } = useMessages(); const { data, isLoading, isFetched, error } = useEventDataProperties(websiteId); const { data: values } = useEventDataValues(websiteId, eventName, propertyName); - const chartData = - propertyName && values - ? { - labels: values.map(({ value }) => value), - datasets: [ - { - data: values.map(({ total }) => total), - backgroundColor: CHART_COLORS, - borderWidth: 0, - }, - ], - } - : null; + + const propertySum = useMemo(() => { + return values?.reduce((sum, { total }) => sum + total, 0) ?? 0; + }, [values]); + + const chartData = useMemo(() => { + if (!propertyName || !values) return null; + return { + labels: values.map(({ value }) => value), + datasets: [ + { + data: values.map(({ total }) => total), + backgroundColor: CHART_COLORS, + borderWidth: 0, + }, + ], + }; + }, [propertyName, values]); + + const tableData = useMemo(() => { + if (!propertyName || !values || propertySum === 0) return []; + return values.map(({ value, total }) => ({ + x: value, + y: total, + z: 100 * (total / propertySum), + })); + }, [propertyName, values, propertySum]); const handleRowClick = row => { setEventName(row.eventName); @@ -52,9 +70,25 @@ export function EventProperties({ websiteId }: { websiteId: string }) { {propertyName && ( -
-
{propertyName}
- +
+ +
{`${eventName}: ${propertyName}`}
+ setPropertyView(key as string)} + > + + + +
+ + {values?.length === 0 ? ( +
{formatMessage(labels.noData)}
+ ) : propertyView === 'table' ? ( + + ) : ( + + )}
)}
diff --git a/src/components/messages.ts b/src/components/messages.ts index 19912b05..893bf141 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -310,6 +310,8 @@ export const labels = defineMessages({ paidVideo: { id: 'label.paid-video', defaultMessage: 'Paid video' }, grouped: { id: 'label.grouped', defaultMessage: 'Grouped' }, other: { id: 'label.other', defaultMessage: 'Other' }, + chart: { id: 'label.chart', defaultMessage: 'Chart' }, + table: { id: 'label.table', defaultMessage: 'Table' }, }); export const messages = defineMessages({