diff --git a/package.json b/package.json
index 8e35c620a..2f5b27dde 100644
--- a/package.json
+++ b/package.json
@@ -11,7 +11,7 @@
},
"type": "module",
"scripts": {
- "dev": "next dev -p 3001 --turbo",
+ "dev": "next dev -p 3001 --turbopack",
"build": "npm-run-all check-env build-db check-db build-tracker build-geo build-app",
"start": "next start",
"build-docker": "npm-run-all build-db build-tracker build-geo build-app",
diff --git a/src/app/(main)/links/[linkId]/LinkControls.tsx b/src/app/(main)/links/[linkId]/LinkControls.tsx
index 4e43c7607..3e59043ca 100644
--- a/src/app/(main)/links/[linkId]/LinkControls.tsx
+++ b/src/app/(main)/links/[linkId]/LinkControls.tsx
@@ -1,8 +1,8 @@
import { Column, Row } from '@umami/react-zen';
-import { WebsiteFilterButton } from '@/components/input/WebsiteFilterButton';
+import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { FilterBar } from '@/components/input/FilterBar';
-import { MonthFilter } from '@/components/input/MonthFilter';
+import { WebsiteMonthSelect } from '@/components/input/WebsiteMonthSelect';
import { ExportButton } from '@/components/input/ExportButton';
export function LinkControls({
@@ -24,7 +24,7 @@ export function LinkControls({
{allowFilter ? :
}
{allowDateFilter && }
{allowDownload && }
- {allowMonthFilter && }
+ {allowMonthFilter && }
{allowFilter && }
diff --git a/src/app/(main)/links/[linkId]/LinkMetricsBar.tsx b/src/app/(main)/links/[linkId]/LinkMetricsBar.tsx
index 43c14050f..5e9d6cbfd 100644
--- a/src/app/(main)/links/[linkId]/LinkMetricsBar.tsx
+++ b/src/app/(main)/links/[linkId]/LinkMetricsBar.tsx
@@ -12,9 +12,10 @@ export function LinkMetricsBar({
showChange?: boolean;
compareMode?: boolean;
}) {
- const { isAllTime } = useDateRange();
+ const { dateRange } = useDateRange(linkId);
const { formatMessage, labels } = useMessages();
const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(linkId);
+ const isAllTime = dateRange.value === 'all';
const { pageviews, visitors, visits, comparison } = data || {};
diff --git a/src/app/(main)/links/[linkId]/LinkPage.tsx b/src/app/(main)/links/[linkId]/LinkPage.tsx
index 10cdaf8d1..e0e10213b 100644
--- a/src/app/(main)/links/[linkId]/LinkPage.tsx
+++ b/src/app/(main)/links/[linkId]/LinkPage.tsx
@@ -7,30 +7,9 @@ import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { LinkMetricsBar } from '@/app/(main)/links/[linkId]/LinkMetricsBar';
import { LinkControls } from '@/app/(main)/links/[linkId]/LinkControls';
import { LinkPanels } from '@/app/(main)/links/[linkId]/LinkPanels';
-import { Column, Dialog, Grid, Modal } from '@umami/react-zen';
-import { WebsiteExpandedView } from '@/app/(main)/websites/[websiteId]/WebsiteExpandedView';
-import { useNavigation } from '@/components/hooks';
-
-const excludedIds = ['path', 'entry', 'exit', 'title', 'language', 'screen', 'event'];
+import { Column, Grid } from '@umami/react-zen';
export function LinkPage({ linkId }: { linkId: string }) {
- const {
- router,
- query: { view },
- updateParams,
- } = useNavigation();
-
- const handleClose = (close: () => void) => {
- router.push(updateParams({ view: undefined }));
- close();
- };
-
- const handleOpenChange = (isOpen: boolean) => {
- if (!isOpen) {
- router.push(updateParams({ view: undefined }));
- }
- };
-
return (
@@ -44,19 +23,6 @@ export function LinkPage({ linkId }: { linkId: string }) {
-
-
-
diff --git a/src/app/(main)/pixels/[pixelId]/PixelControls.tsx b/src/app/(main)/pixels/[pixelId]/PixelControls.tsx
index 33f49222b..c5fee534f 100644
--- a/src/app/(main)/pixels/[pixelId]/PixelControls.tsx
+++ b/src/app/(main)/pixels/[pixelId]/PixelControls.tsx
@@ -1,8 +1,8 @@
import { Column, Row } from '@umami/react-zen';
-import { WebsiteFilterButton } from '@/components/input/WebsiteFilterButton';
+import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { FilterBar } from '@/components/input/FilterBar';
-import { MonthFilter } from '@/components/input/MonthFilter';
+import { WebsiteMonthSelect } from '@/components/input/WebsiteMonthSelect';
import { ExportButton } from '@/components/input/ExportButton';
export function PixelControls({
@@ -24,7 +24,7 @@ export function PixelControls({
{allowFilter ? : }
{allowDateFilter && }
{allowDownload && }
- {allowMonthFilter && }
+ {allowMonthFilter && }
{allowFilter && }
diff --git a/src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx b/src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx
index 0305df7f3..5b01ef842 100644
--- a/src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx
+++ b/src/app/(main)/pixels/[pixelId]/PixelMetricsBar.tsx
@@ -12,9 +12,10 @@ export function PixelMetricsBar({
showChange?: boolean;
compareMode?: boolean;
}) {
- const { isAllTime } = useDateRange();
+ const { dateRange } = useDateRange(pixelId);
const { formatMessage, labels } = useMessages();
const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(pixelId);
+ const isAllTime = dateRange.value === 'all';
const { pageviews, visitors, visits, comparison } = data || {};
diff --git a/src/app/(main)/pixels/[pixelId]/PixelPage.tsx b/src/app/(main)/pixels/[pixelId]/PixelPage.tsx
index be462bfd4..a65c821e0 100644
--- a/src/app/(main)/pixels/[pixelId]/PixelPage.tsx
+++ b/src/app/(main)/pixels/[pixelId]/PixelPage.tsx
@@ -7,30 +7,9 @@ import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { PixelMetricsBar } from '@/app/(main)/pixels/[pixelId]/PixelMetricsBar';
import { PixelControls } from '@/app/(main)/pixels/[pixelId]/PixelControls';
import { PixelPanels } from '@/app/(main)/pixels/[pixelId]/PixelPanels';
-import { Column, Dialog, Grid, Modal } from '@umami/react-zen';
-import { WebsiteExpandedView } from '@/app/(main)/websites/[websiteId]/WebsiteExpandedView';
-import { useNavigation } from '@/components/hooks';
-
-const excludedIds = ['path', 'entry', 'exit', 'title', 'language', 'screen', 'event'];
+import { Column, Grid } from '@umami/react-zen';
export function PixelPage({ pixelId }: { pixelId: string }) {
- const {
- router,
- query: { view },
- updateParams,
- } = useNavigation();
-
- const handleClose = (close: () => void) => {
- router.push(updateParams({ view: undefined }));
- close();
- };
-
- const handleOpenChange = (isOpen: boolean) => {
- if (!isOpen) {
- router.push(updateParams({ view: undefined }));
- }
- };
-
return (
@@ -44,19 +23,6 @@ export function PixelPage({ pixelId }: { pixelId: string }) {
-
-
-
diff --git a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx
index d5c129eec..18f2a625c 100644
--- a/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx
+++ b/src/app/(main)/settings/websites/[websiteId]/WebsiteSettingsPage.tsx
@@ -1,4 +1,5 @@
'use client';
+import { Column } from '@umami/react-zen';
import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider';
import { WebsiteSettings } from '@/app/(main)/websites/[websiteId]/settings/WebsiteSettings';
import { WebsiteSettingsHeader } from '@/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader';
@@ -6,8 +7,10 @@ import { WebsiteSettingsHeader } from '@/app/(main)/websites/[websiteId]/setting
export function WebsiteSettingsPage({ websiteId }: { websiteId: string }) {
return (
-
-
+
+
+
+
);
}
diff --git a/src/app/(main)/websites/WebsitesTable.tsx b/src/app/(main)/websites/WebsitesTable.tsx
index d6d743906..3f781cb7c 100644
--- a/src/app/(main)/websites/WebsitesTable.tsx
+++ b/src/app/(main)/websites/WebsitesTable.tsx
@@ -1,13 +1,15 @@
import { ReactNode } from 'react';
-import { Icon, DataTable, DataColumn } from '@umami/react-zen';
-import { LinkButton } from '@/components/common/LinkButton';
+import { Row, Text, Icon, DataTable, DataColumn, MenuItem } from '@umami/react-zen';
import { useMessages, useNavigation } from '@/components/hooks';
-import { SquarePen } from '@/components/icons';
+import { MenuButton } from '@/components/input/MenuButton';
+import { Eye, SquarePen } from '@/components/icons';
import { Empty } from '@/components/common/Empty';
export function WebsitesTable({
data = [],
showActions,
+ allowEdit,
+ allowView,
renderLink,
}: {
data: Record[];
@@ -35,11 +37,28 @@ export function WebsitesTable({
const websiteId = row.id;
return (
-
-
-
-
-
+
+ {allowView && (
+
+ )}
+ {allowEdit && (
+
+ )}
+
);
}}
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage.tsx
index 497913b78..5b375bded 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/attribution/AttributionPage.tsx
@@ -12,7 +12,7 @@ export function AttributionPage({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
const {
dateRange: { startDate, endDate },
- } = useDateRange();
+ } = useDateRange(websiteId);
return (
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx
index eff072fde..d54797412 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/breakdown/BreakdownPage.tsx
@@ -1,23 +1,26 @@
'use client';
import { useState } from 'react';
-import { Button, Column, Box, DialogTrigger, Popover, Dialog, IconLabel } from '@umami/react-zen';
+import { Button, Column, Box, Text, Icon, DialogTrigger, Modal, Dialog } from '@umami/react-zen';
import { useDateRange, useMessages } from '@/components/hooks';
import { ListCheck } from '@/components/icons';
import { Panel } from '@/components/common/Panel';
import { Breakdown } from './Breakdown';
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
import { FieldSelectForm } from '@/app/(main)/websites/[websiteId]/(reports)/breakdown/FieldSelectForm';
+import { SectionHeader } from '@/components/common/SectionHeader';
export function BreakdownPage({ websiteId }: { websiteId: string }) {
const {
dateRange: { startDate, endDate },
- } = useDateRange();
+ } = useDateRange(websiteId);
const [fields, setFields] = useState(['path']);
return (
-
+
+
+
{
return (
-
);
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx
index c155662ff..1918aadf5 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/funnels/FunnelsPage.tsx
@@ -12,7 +12,7 @@ export function FunnelsPage({ websiteId }: { websiteId: string }) {
const { data, isLoading, error } = useReportsQuery({ websiteId, type: 'funnel' });
const {
dateRange: { startDate, endDate },
- } = useDateRange();
+ } = useDateRange(websiteId);
return (
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx
index 6cd417288..30f92325f 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/goals/GoalsPage.tsx
@@ -12,7 +12,7 @@ export function GoalsPage({ websiteId }: { websiteId: string }) {
const { data, isLoading, error } = useReportsQuery({ websiteId, type: 'goal' });
const {
dateRange: { startDate, endDate },
- } = useDateRange();
+ } = useDateRange(websiteId);
return (
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
index 269279625..d75828222 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/journeys/JourneysPage.tsx
@@ -13,7 +13,7 @@ export function JourneysPage({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
const {
dateRange: { startDate, endDate },
- } = useDateRange();
+ } = useDateRange(websiteId);
const [steps, setSteps] = useState(DEFAULT_STEP);
const [startStep, setStartStep] = useState('');
const [endStep, setEndStep] = useState('');
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage.tsx
index ed5120620..0d74c38e9 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/revenue/RevenuePage.tsx
@@ -7,7 +7,7 @@ import { useDateRange } from '@/components/hooks';
export function RevenuePage({ websiteId }: { websiteId: string }) {
const {
dateRange: { startDate, endDate, unit },
- } = useDateRange();
+ } = useDateRange(websiteId);
return (
diff --git a/src/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage.tsx b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage.tsx
index 30b9bff22..a5999a7c9 100644
--- a/src/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/(reports)/utm/UTMPage.tsx
@@ -7,7 +7,7 @@ import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteContro
export function UTMPage({ websiteId }: { websiteId: string }) {
const {
dateRange: { startDate, endDate },
- } = useDateRange();
+ } = useDateRange(websiteId);
return (
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
index 2406cde24..08e0c1c83 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
@@ -11,7 +11,7 @@ export function WebsiteChart({
websiteId: string;
compareMode?: boolean;
}) {
- const { dateRange, dateCompare } = useDateRange();
+ const { dateRange, dateCompare } = useDateRange(websiteId);
const { startDate, endDate, unit, value } = dateRange;
const { data, isLoading, isFetching, error } = useWebsitePageviewsQuery({
websiteId,
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx b/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx
index 6b03ef6e0..97be18214 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx
@@ -1,8 +1,8 @@
import { Column, Row } from '@umami/react-zen';
-import { WebsiteFilterButton } from '@/components/input/WebsiteFilterButton';
+import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { FilterBar } from '@/components/input/FilterBar';
-import { MonthFilter } from '@/components/input/MonthFilter';
+import { WebsiteMonthSelect } from '@/components/input/WebsiteMonthSelect';
import { ExportButton } from '@/components/input/ExportButton';
export function WebsiteControls({
@@ -26,7 +26,7 @@ export function WebsiteControls({
{allowFilter ? : }
{allowDateFilter && }
{allowDownload && }
- {allowMonthFilter && }
+ {allowMonthFilter && }
{allowFilter && }
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
index b90a6da07..9fac4c8e7 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
@@ -26,11 +26,9 @@ import { Lightning } from '@/components/svg';
export function WebsiteExpandedView({
websiteId,
- excludedIds = [],
onClose,
}: {
websiteId: string;
- excludedIds?: string[];
onClose?: () => void;
}) {
const { formatMessage, labels } = useMessages();
@@ -39,11 +37,9 @@ export function WebsiteExpandedView({
query: { view },
} = useNavigation();
- const filterExcluded = (item: { id: string }) => !excludedIds.includes(item.id);
-
const items = [
{
- label: 'URL',
+ label: formatMessage(labels.pages),
items: [
{
id: 'path',
@@ -75,7 +71,7 @@ export function WebsiteExpandedView({
path: updateParams({ view: 'query' }),
icon: ,
},
- ].filter(filterExcluded),
+ ],
},
{
label: formatMessage(labels.sources),
@@ -98,7 +94,7 @@ export function WebsiteExpandedView({
path: updateParams({ view: 'domain' }),
icon: ,
},
- ].filter(filterExcluded),
+ ],
},
{
label: formatMessage(labels.location),
@@ -121,7 +117,7 @@ export function WebsiteExpandedView({
path: updateParams({ view: 'city' }),
icon: ,
},
- ].filter(filterExcluded),
+ ],
},
{
label: formatMessage(labels.environment),
@@ -156,7 +152,7 @@ export function WebsiteExpandedView({
path: updateParams({ view: 'screen' }),
icon: ,
},
- ].filter(filterExcluded),
+ ],
},
{
label: formatMessage(labels.other),
@@ -179,7 +175,7 @@ export function WebsiteExpandedView({
path: updateParams({ view: 'tag' }),
icon: ,
},
- ].filter(filterExcluded),
+ ],
},
];
diff --git a/src/components/input/WebsiteFilterButton.tsx b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx
similarity index 89%
rename from src/components/input/WebsiteFilterButton.tsx
rename to src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx
index 09fe84538..723c0249b 100644
--- a/src/components/input/WebsiteFilterButton.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx
@@ -1,4 +1,4 @@
-import { Button, Icon, DialogTrigger, Dialog, Popover, Text } from '@umami/react-zen';
+import { Button, Icon, DialogTrigger, Dialog, Modal, Text } from '@umami/react-zen';
import { ListFilter } from '@/components/icons';
import { FilterEditForm } from '@/components/input/FilterEditForm';
import { useMessages, useNavigation } from '@/components/hooks';
@@ -32,13 +32,13 @@ export function WebsiteFilterButton({
{showText && {formatMessage(labels.filter)}}
-
+
-
+
);
}
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx b/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx
index e25541e9a..cf75e86a5 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteLayout.tsx
@@ -2,24 +2,17 @@
import { ReactNode } from 'react';
import { Column, Grid } from '@umami/react-zen';
import { WebsiteProvider } from '@/app/(main)/websites/WebsiteProvider';
-import { useNavigation } from '@/components/hooks';
import { PageBody } from '@/components/common/PageBody';
import { WebsiteHeader } from './WebsiteHeader';
import { WebsiteNav } from './WebsiteNav';
export function WebsiteLayout({ websiteId, children }: { websiteId: string; children: ReactNode }) {
- const { pathname } = useNavigation();
-
- const isSettings = pathname.endsWith('/settings');
-
return (
-
- {!isSettings && (
-
-
-
- )}
+
+
+
+
{children}
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx
index 7522c8ec0..d217b94f6 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx
@@ -12,9 +12,10 @@ export function WebsiteMetricsBar({
showChange?: boolean;
compareMode?: boolean;
}) {
- const { isAllTime } = useDateRange();
+ const { dateRange } = useDateRange(websiteId);
const { formatMessage, labels, getErrorMessage } = useMessages();
const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(websiteId);
+ const isAllTime = dateRange.value === 'all';
const { pageviews, visitors, visits, bounces, totaltime, comparison } = data || {};
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx b/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx
index 3696b7861..2ec171b42 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx
@@ -1,18 +1,9 @@
-import { Text } from '@umami/react-zen';
-import {
- Eye,
- User,
- Clock,
- Sheet,
- Tag,
- ChartPie,
- UserPlus,
- GitCompareArrows,
-} from '@/components/icons';
-import { Lightning, Path, Money, Target, Funnel, Magnet, Network } from '@/components/svg';
+import { Eye, User, Clock, Sheet, Tag, ChartPie, UserPlus } from '@/components/icons';
+import { Lightning, Path, Money, Compare, Target, Funnel, Magnet, Network } from '@/components/svg';
import { useMessages, useNavigation } from '@/components/hooks';
import { SideMenu } from '@/components/common/SideMenu';
import { WebsiteSelect } from '@/components/input/WebsiteSelect';
+import { Text } from '@umami/react-zen';
export function WebsiteNav({ websiteId }: { websiteId: string }) {
const { formatMessage, labels } = useMessages();
@@ -56,7 +47,7 @@ export function WebsiteNav({ websiteId }: { websiteId: string }) {
{
id: 'compare',
label: formatMessage(labels.compare),
- icon: ,
+ icon: ,
path: renderPath('/compare'),
},
{
diff --git a/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx b/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx
index 2c67b76a9..8ed32841e 100644
--- a/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx
+++ b/src/app/(main)/websites/[websiteId]/compare/CompareTables.tsx
@@ -9,7 +9,7 @@ import { useState } from 'react';
export function CompareTables({ websiteId }: { websiteId: string }) {
const [data, setData] = useState([]);
- const { dateRange, dateCompare } = useDateRange();
+ const { dateRange, dateCompare } = useDateRange(websiteId);
const { formatMessage, labels } = useMessages();
const {
router,
diff --git a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx
index 216142ec9..97a0108f0 100644
--- a/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx
+++ b/src/app/(main)/websites/[websiteId]/settings/WebsiteSettingsHeader.tsx
@@ -1,22 +1,9 @@
-import Link from 'next/link';
import { PageHeader } from '@/components/common/PageHeader';
-import { Globe, ArrowLeft } from '@/components/icons';
-import { useMessages, useNavigation, useWebsite } from '@/components/hooks';
-import { IconLabel, Row } from '@umami/react-zen';
+import { Globe } from '@/components/icons';
+import { useWebsite } from '@/components/hooks';
export function WebsiteSettingsHeader() {
const website = useWebsite();
- const { formatMessage, labels } = useMessages();
- const { renderUrl } = useNavigation();
- return (
- <>
-
-
- } label={formatMessage(labels.website)} />
-
-
- } />
- >
- );
+ return } />;
}
diff --git a/src/app/api/users/[userId]/usage/route.ts b/src/app/api/users/[userId]/usage/route.ts
new file mode 100644
index 000000000..677e0bd7a
--- /dev/null
+++ b/src/app/api/users/[userId]/usage/route.ts
@@ -0,0 +1,60 @@
+import { z } from 'zod';
+import { json, unauthorized } from '@/lib/response';
+import { getAllUserWebsitesIncludingTeamOwner } from '@/queries/prisma/website';
+import { getEventUsage } from '@/queries/sql/events/getEventUsage';
+import { getEventDataUsage } from '@/queries/sql/events/getEventDataUsage';
+import { parseRequest, getQueryFilters } from '@/lib/request';
+
+export async function GET(request: Request, { params }: { params: Promise<{ userId: string }> }) {
+ const schema = z.object({
+ startAt: z.coerce.number().int(),
+ endAt: z.coerce.number().int(),
+ });
+
+ const { auth, query, error } = await parseRequest(request, schema);
+
+ if (error) {
+ return error();
+ }
+
+ if (!auth.user.isAdmin) {
+ return unauthorized();
+ }
+
+ const { userId } = await params;
+ const filters = await getQueryFilters(query);
+
+ const websites = await getAllUserWebsitesIncludingTeamOwner(userId);
+
+ const websiteIds = websites.map(a => a.id);
+
+ const websiteEventUsage = await getEventUsage(websiteIds, filters);
+ const eventDataUsage = await getEventDataUsage(websiteIds, filters);
+
+ const websiteUsage = websites.map(a => ({
+ websiteId: a.id,
+ websiteName: a.name,
+ websiteEventUsage: websiteEventUsage.find(b => a.id === b.websiteId)?.count || 0,
+ eventDataUsage: eventDataUsage.find(b => a.id === b.websiteId)?.count || 0,
+ deletedAt: a.deletedAt,
+ }));
+
+ const usage = websiteUsage.reduce(
+ (acc, cv) => {
+ acc.websiteEventUsage += cv.websiteEventUsage;
+ acc.eventDataUsage += cv.eventDataUsage;
+
+ return acc;
+ },
+ { websiteEventUsage: 0, eventDataUsage: 0 },
+ );
+
+ const filteredWebsiteUsage = websiteUsage.filter(
+ a => !a.deletedAt && (a.websiteEventUsage > 0 || a.eventDataUsage > 0),
+ );
+
+ return json({
+ ...usage,
+ websites: filteredWebsiteUsage,
+ });
+}
diff --git a/src/app/api/websites/route.ts b/src/app/api/websites/route.ts
index 776f23b0a..821b6eaff 100644
--- a/src/app/api/websites/route.ts
+++ b/src/app/api/websites/route.ts
@@ -4,11 +4,9 @@ import { json, unauthorized } from '@/lib/response';
import { uuid } from '@/lib/crypto';
import { getQueryFilters, parseRequest } from '@/lib/request';
import { pagingParams, searchParams } from '@/lib/schema';
-import { createWebsite, getWebsiteCount } from '@/queries/prisma';
+import { createWebsite } from '@/queries/prisma';
import { getAllUserWebsitesIncludingTeamOwner, getUserWebsites } from '@/queries/prisma/website';
-const CLOUD_WEBSITE_LIMIT = 3;
-
export async function GET(request: Request) {
const schema = z.object({
...pagingParams,
@@ -38,7 +36,7 @@ export async function POST(request: Request) {
name: z.string().max(100),
domain: z.string().max(500),
shareId: z.string().max(50).nullable().optional(),
- teamId: z.uuid().nullable().optional(),
+ teamId: z.string().nullable().optional(),
id: z.uuid().nullable().optional(),
});
@@ -50,14 +48,6 @@ export async function POST(request: Request) {
const { id, name, domain, shareId, teamId } = body;
- if (process.env.CLOUD_MODE && !teamId && !auth.user.hasSubscription) {
- const count = await getWebsiteCount(auth.user.id);
-
- if (count >= CLOUD_WEBSITE_LIMIT) {
- return unauthorized({ message: 'Website limit reached.' });
- }
- }
-
if ((teamId && !(await canCreateTeamWebsite(auth, teamId))) || !(await canCreateWebsite(auth))) {
return unauthorized();
}
diff --git a/src/components/common/ConfirmationForm.tsx b/src/components/common/ConfirmationForm.tsx
index ce82b54f0..a93dcc7f8 100644
--- a/src/components/common/ConfirmationForm.tsx
+++ b/src/components/common/ConfirmationForm.tsx
@@ -1,5 +1,5 @@
import { ReactNode } from 'react';
-import { Box, Button, FormSubmitButton, Form, FormButtons } from '@umami/react-zen';
+import { Row, Button, FormSubmitButton, Form, FormButtons } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
export interface ConfirmationFormProps {
@@ -25,7 +25,7 @@ export function ConfirmationForm({
return (