diff --git a/src/app/(main)/reports/event-data/EventDataParameters.tsx b/src/app/(main)/reports/event-data/EventDataParameters.tsx
index e0afda3f..7b61c112 100644
--- a/src/app/(main)/reports/event-data/EventDataParameters.tsx
+++ b/src/app/(main)/reports/event-data/EventDataParameters.tsx
@@ -48,7 +48,7 @@ export function EventDataParameters() {
groups,
};
- const handleSubmit = values => {
+ const handleSubmit = (values: any) => {
runReport(values);
};
diff --git a/src/app/(main)/websites/[websiteId]/events/EventDataPage.tsx b/src/app/(main)/websites/[websiteId]/events/EventDataPage.tsx
deleted file mode 100644
index 77d367e5..00000000
--- a/src/app/(main)/websites/[websiteId]/events/EventDataPage.tsx
+++ /dev/null
@@ -1,12 +0,0 @@
-'use client';
-import WebsiteHeader from '../WebsiteHeader';
-import WebsiteEventData from './WebsiteEventData';
-
-export default function EventDataPage({ websiteId }) {
- return (
- <>
-
-
- >
- );
-}
diff --git a/src/app/(main)/websites/[websiteId]/events/EventDataTable.tsx b/src/app/(main)/websites/[websiteId]/events/EventDataTable.tsx
deleted file mode 100644
index 71c36992..00000000
--- a/src/app/(main)/websites/[websiteId]/events/EventDataTable.tsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import Link from 'next/link';
-import { GridTable, GridColumn } from 'react-basics';
-import { useMessages, useNavigation } from 'components/hooks';
-import Empty from 'components/common/Empty';
-import { DATA_TYPES } from 'lib/constants';
-
-export function EventDataTable({ data = [] }) {
- const { formatMessage, labels } = useMessages();
- const { renderUrl } = useNavigation();
-
- if (data.length === 0) {
- return ;
- }
-
- return (
-
-
- {row => (
-
- {row.eventName}
-
- )}
-
-
- {row => row.fieldName}
-
-
- {row => DATA_TYPES[row.dataType]}
-
-
- {({ total }) => total.toLocaleString()}
-
-
- );
-}
-
-export default EventDataTable;
diff --git a/src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx b/src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx
new file mode 100644
index 00000000..f2bf7cb9
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx
@@ -0,0 +1,25 @@
+import { useWebsiteEvents } from 'components/hooks';
+import EventsTable from './EventsTable';
+import DataTable from 'components/common/DataTable';
+import { ReactNode } from 'react';
+
+export default function EventsDataTable({
+ websiteId,
+ children,
+}: {
+ websiteId?: string;
+ teamId?: string;
+ children?: ReactNode;
+}) {
+ const queryResult = useWebsiteEvents(websiteId);
+
+ if (queryResult?.result?.data?.length === 0) {
+ return children;
+ }
+
+ return (
+
+ {({ data }) => }
+
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx b/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx
new file mode 100644
index 00000000..8f793d81
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/events/EventsPage.tsx
@@ -0,0 +1,12 @@
+'use client';
+import WebsiteHeader from '../WebsiteHeader';
+import EventsDataTable from './EventsDataTable';
+
+export default function EventsPage({ websiteId }) {
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx b/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
new file mode 100644
index 00000000..5a625ee9
--- /dev/null
+++ b/src/app/(main)/websites/[websiteId]/events/EventsTable.tsx
@@ -0,0 +1,43 @@
+import { GridTable, GridColumn } from 'react-basics';
+import { useLocale, useMessages } from 'components/hooks';
+import Empty from 'components/common/Empty';
+import { formatDistance } from 'date-fns';
+import Profile from 'components/common/Profile';
+import Link from 'next/link';
+
+export function EventsTable({ data = [] }) {
+ const { dateLocale } = useLocale();
+ const { formatMessage, labels } = useMessages();
+
+ if (data.length === 0) {
+ return ;
+ }
+
+ return (
+
+
+
+ {row => (
+
+
+
+ )}
+
+
+ {row => formatMessage(row.eventName ? labels.triggeredEvent : labels.viewedPage)}
+
+
+
+
+ {row =>
+ formatDistance(new Date(row.createdAt), new Date(), {
+ addSuffix: true,
+ locale: dateLocale,
+ })
+ }
+
+
+ );
+}
+
+export default EventsTable;
diff --git a/src/app/(main)/websites/[websiteId]/events/WebsiteEventData.tsx b/src/app/(main)/websites/[websiteId]/events/WebsiteEventData.tsx
index d7d24cee..296c8a66 100644
--- a/src/app/(main)/websites/[websiteId]/events/WebsiteEventData.tsx
+++ b/src/app/(main)/websites/[websiteId]/events/WebsiteEventData.tsx
@@ -1,5 +1,5 @@
import { Flexbox, Loading } from 'react-basics';
-import EventDataTable from './EventDataTable';
+import EventsTable from './EventsTable';
import EventDataValueTable from './EventDataValueTable';
import { EventDataMetricsBar } from './EventDataMetricsBar';
import { useDateRange, useApi, useNavigation } from 'components/hooks';
@@ -33,7 +33,7 @@ export default function WebsiteEventData({ websiteId }) {
return (
- {!event && }
+ {!event && }
{isLoading && }
{event && data && }
diff --git a/src/app/(main)/websites/[websiteId]/events/page.tsx b/src/app/(main)/websites/[websiteId]/events/page.tsx
index 24cf4fea..b5dc4d62 100644
--- a/src/app/(main)/websites/[websiteId]/events/page.tsx
+++ b/src/app/(main)/websites/[websiteId]/events/page.tsx
@@ -1,8 +1,8 @@
import { Metadata } from 'next';
-import EventDataPage from './EventDataPage';
+import EventsPage from './EventsPage';
export default async function ({ params: { websiteId } }) {
- return ;
+ return ;
}
export const metadata: Metadata = {
diff --git a/src/components/common/DataTable.tsx b/src/components/common/DataTable.tsx
index ed910def..041c2ba5 100644
--- a/src/components/common/DataTable.tsx
+++ b/src/components/common/DataTable.tsx
@@ -1,7 +1,7 @@
import { ReactNode } from 'react';
import classNames from 'classnames';
import { Banner, Loading, SearchField } from 'react-basics';
-import { useMessages } from 'components/hooks';
+import { useMessages, useNavigation } from 'components/hooks';
import Empty from 'components/common/Empty';
import Pager from 'components/common/Pager';
import { FilterQueryResult } from 'lib/types';
@@ -35,6 +35,7 @@ export function DataTable({
const { query } = params || {};
const hasData = Boolean(!isLoading && data?.length);
const noResults = Boolean(!isLoading && query && !hasData);
+ const { router, renderUrl } = useNavigation();
const handleSearch = (query: string) => {
setParams({ ...params, query, page: params.page ? page : 1 });
@@ -42,6 +43,7 @@ export function DataTable({
const handlePageChange = (page: number) => {
setParams({ ...params, query, page });
+ router.push(renderUrl({ page }));
};
if (error) {
diff --git a/src/components/hooks/queries/useFilterQuery.ts b/src/components/hooks/queries/useFilterQuery.ts
index 5963d099..82fc4d61 100644
--- a/src/components/hooks/queries/useFilterQuery.ts
+++ b/src/components/hooks/queries/useFilterQuery.ts
@@ -2,15 +2,17 @@ import { UseQueryOptions } from '@tanstack/react-query';
import { useState } from 'react';
import { useApi } from './useApi';
import { PageResult, PageParams, FilterQueryResult } from 'lib/types';
+import { useNavigation } from '../useNavigation';
export function useFilterQuery({
queryKey,
queryFn,
...options
}: Omit & { queryFn: (params?: object) => any }): FilterQueryResult {
- const [params, setParams] = useState({
+ const { query: queryParams } = useNavigation();
+ const [params, setParams] = useState({
query: '',
- page: 1,
+ page: +queryParams.page || 1,
});
const { useQuery } = useApi();
@@ -21,7 +23,7 @@ export function useFilterQuery({
});
return {
- result: data as PageResult,
+ result: data as PageResult,
query,
params,
setParams,
diff --git a/src/components/hooks/queries/useWebsiteEvents.ts b/src/components/hooks/queries/useWebsiteEvents.ts
index 588d4fb5..f0132470 100644
--- a/src/components/hooks/queries/useWebsiteEvents.ts
+++ b/src/components/hooks/queries/useWebsiteEvents.ts
@@ -1,17 +1,19 @@
import useApi from './useApi';
-import { useFilterParams } from '../useFilterParams';
import { UseQueryOptions } from '@tanstack/react-query';
+import { useFilterParams } from '../useFilterParams';
+import { useFilterQuery } from 'components/hooks';
export function useWebsiteEvents(
websiteId: string,
options?: Omit,
) {
- const { get, useQuery } = useApi();
+ const { get } = useApi();
const params = useFilterParams(websiteId);
- return useQuery({
+ return useFilterQuery({
queryKey: ['websites:events', { websiteId, ...params }],
- queryFn: () => get(`/websites/${websiteId}/events`, params),
+ queryFn: pageParams =>
+ get(`/websites/${websiteId}/events`, { ...params, ...pageParams, pageSize: 20 }),
enabled: !!websiteId,
...options,
});
diff --git a/src/components/messages.ts b/src/components/messages.ts
index 2dfe61ee..703ccba3 100644
--- a/src/components/messages.ts
+++ b/src/components/messages.ts
@@ -130,6 +130,7 @@ export const labels = defineMessages({
selectRole: { id: 'label.select-role', defaultMessage: 'Select role' },
selectDate: { id: 'label.select-date', defaultMessage: 'Select date' },
all: { id: 'label.all', defaultMessage: 'All' },
+ session: { id: 'label.session', defaultMessage: 'Session' },
sessions: { id: 'label.sessions', defaultMessage: 'Sessions' },
pageNotFound: { id: 'message.page-not-found', defaultMessage: 'Page not found' },
activityLog: { id: 'label.activity-log', defaultMessage: 'Activity log' },
@@ -275,6 +276,7 @@ export const labels = defineMessages({
lastSeen: { id: 'label.last-seen', defaultMessage: 'Last seen' },
firstSeen: { id: 'label.first-seen', defaultMessage: 'First seen' },
properties: { id: 'label.properties', defaultMessage: 'Properties' },
+ path: { id: 'label.path', defaultMessage: 'Path' },
});
export const messages = defineMessages({
diff --git a/src/pages/api/event-data/events.ts b/src/pages/api/events/[eventId]/data.ts
similarity index 100%
rename from src/pages/api/event-data/events.ts
rename to src/pages/api/events/[eventId]/data.ts
diff --git a/src/pages/api/websites/[websiteId]/events/index.ts b/src/pages/api/websites/[websiteId]/events/index.ts
new file mode 100644
index 00000000..2aa791b1
--- /dev/null
+++ b/src/pages/api/websites/[websiteId]/events/index.ts
@@ -0,0 +1,42 @@
+import * as yup from 'yup';
+import { canViewWebsite } from 'lib/auth';
+import { useAuth, useCors, useValidate } from 'lib/middleware';
+import { NextApiRequestQueryBody, PageParams } from 'lib/types';
+import { NextApiResponse } from 'next';
+import { methodNotAllowed, ok, unauthorized } from 'next-basics';
+import { pageInfo } from 'lib/schema';
+import { getWebsiteEvents } from 'queries';
+
+export interface ReportsRequestQuery extends PageParams {
+ websiteId: string;
+}
+
+const schema = {
+ GET: yup.object().shape({
+ websiteId: yup.string().uuid().required(),
+ ...pageInfo,
+ }),
+};
+
+export default async (
+ req: NextApiRequestQueryBody,
+ res: NextApiResponse,
+) => {
+ await useCors(req, res);
+ await useAuth(req, res);
+ await useValidate(schema, req, res);
+
+ const { websiteId } = req.query;
+
+ if (req.method === 'GET') {
+ if (!(await canViewWebsite(req.auth, websiteId))) {
+ return unauthorized(res);
+ }
+
+ const data = await getWebsiteEvents(websiteId, {}, req.query);
+
+ return ok(res, data);
+ }
+
+ return methodNotAllowed(res);
+};
diff --git a/src/pages/api/websites/[websiteId]/events.ts b/src/pages/api/websites/[websiteId]/events/series.ts
similarity index 100%
rename from src/pages/api/websites/[websiteId]/events.ts
rename to src/pages/api/websites/[websiteId]/events/series.ts
diff --git a/src/queries/analytics/events/getEvents.ts b/src/queries/analytics/events/getWebsiteEvents.ts
similarity index 97%
rename from src/queries/analytics/events/getEvents.ts
rename to src/queries/analytics/events/getWebsiteEvents.ts
index 540c1a05..b76d1ee5 100644
--- a/src/queries/analytics/events/getEvents.ts
+++ b/src/queries/analytics/events/getWebsiteEvents.ts
@@ -3,7 +3,7 @@ import { CLICKHOUSE, PRISMA, runQuery } from 'lib/db';
import prisma from 'lib/prisma';
import { PageParams, QueryFilters } from 'lib/types';
-export function getEvents(
+export function getWebsiteEvents(
...args: [websiteId: string, filters: QueryFilters, pageParams?: PageParams]
) {
return runQuery({
diff --git a/src/queries/analytics/getRealtimeData.ts b/src/queries/analytics/getRealtimeData.ts
index e25cc866..3e691b4e 100644
--- a/src/queries/analytics/getRealtimeData.ts
+++ b/src/queries/analytics/getRealtimeData.ts
@@ -1,4 +1,9 @@
-import { getWebsiteSessions, getEvents, getPageviewStats, getSessionStats } from 'queries/index';
+import {
+ getWebsiteSessions,
+ getWebsiteEvents,
+ getPageviewStats,
+ getSessionStats,
+} from 'queries/index';
const MAX_SIZE = 50;
@@ -19,7 +24,7 @@ export async function getRealtimeData(
const { startDate, timezone } = criteria;
const filters = { startDate, endDate: new Date(), unit: 'minute', timezone };
const [events, sessions, pageviews, sessionviews] = await Promise.all([
- getEvents(websiteId, { startDate, timezone }, { pageSize: 10000 }),
+ getWebsiteEvents(websiteId, { startDate, timezone }, { pageSize: 10000 }),
getWebsiteSessions(websiteId, { startDate, timezone }, { pageSize: 10000 }),
getPageviewStats(websiteId, filters),
getSessionStats(websiteId, filters),
diff --git a/src/queries/index.ts b/src/queries/index.ts
index 82d40ee5..51c1e14b 100644
--- a/src/queries/index.ts
+++ b/src/queries/index.ts
@@ -8,7 +8,7 @@ export * from './analytics/events/getEventDataFields';
export * from './analytics/events/getEventDataStats';
export * from './analytics/events/getEventDataUsage';
export * from './analytics/events/getEventMetrics';
-export * from './analytics/events/getEvents';
+export * from './analytics/events/getWebsiteEvents';
export * from './analytics/events/getEventUsage';
export * from './analytics/events/saveEvent';
export * from './analytics/reports/getFunnel';