diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.module.css b/src/app/(main)/websites/[websiteId]/WebsiteChart.module.css
deleted file mode 100644
index b795047a..00000000
--- a/src/app/(main)/websites/[websiteId]/WebsiteChart.module.css
+++ /dev/null
@@ -1,17 +0,0 @@
-.container {
- position: relative;
- display: flex;
- flex-direction: column;
- align-self: stretch;
-}
-
-.chart {
- position: relative;
- overflow: hidden;
-}
-
-.title {
- font-size: var(--font-size-lg);
- line-height: 60px;
- font-weight: 600;
-}
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteCompareTables.module.css b/src/app/(main)/websites/[websiteId]/WebsiteCompareTables.module.css
deleted file mode 100644
index c4821e88..00000000
--- a/src/app/(main)/websites/[websiteId]/WebsiteCompareTables.module.css
+++ /dev/null
@@ -1,14 +0,0 @@
-.container {
- margin-bottom: 60px;
-}
-
-.nav {
- width: 200px;
- margin-top: 40px;
-}
-
-.title {
- color: var(--base800);
- text-align: center;
- font-weight: 700;
-}
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx b/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx
index fb84df87..1e36b729 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteControls.tsx
@@ -2,23 +2,27 @@ import { Column, Row } from '@umami/react-zen';
import { WebsiteFilterButton } from '@/app/(main)/websites/[websiteId]/WebsiteFilterButton';
import { WebsiteDateFilter } from '@/components/input/WebsiteDateFilter';
import { FilterBar } from '@/components/input/FilterBar';
+import { WebsiteMonthSelect } from '@/components/input/WebsiteMonthSelect';
export function WebsiteControls({
websiteId,
allowFilter = true,
+ allowDateFilter = true,
+ allowMonthFilter,
allowCompare,
}: {
websiteId: string;
allowFilter?: boolean;
allowCompare?: boolean;
+ allowDateFilter?: boolean;
+ allowMonthFilter?: boolean;
}) {
return (
{allowFilter && }
-
-
-
+ {allowDateFilter && }
+ {allowMonthFilter && }
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx
index d0a17b7f..4c247dcd 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteHeader.tsx
@@ -14,15 +14,17 @@ export function WebsiteHeader() {
return (
} showBorder={false}>
-
+
-
-
-
-
-
- Edit
-
+
+
+
+
+
+
+ Edit
+
+
);
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.module.css b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.module.css
deleted file mode 100644
index 6c5a0e56..00000000
--- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.module.css
+++ /dev/null
@@ -1,52 +0,0 @@
-.container {
- display: grid;
- grid-template-columns: 2fr 1fr;
- justify-content: space-between;
- align-items: center;
- background: var(--base50);
- z-index: var(--z-index-above);
- min-height: 120px;
- padding-bottom: 20px;
-}
-
-.actions {
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- gap: 10px;
- flex-wrap: wrap;
-}
-
-.vs {
- display: flex;
- align-items: center;
- justify-content: flex-end;
- flex-basis: 100%;
- gap: 10px;
-}
-
-.dropdown {
- min-width: 200px;
-}
-
-@media screen and (max-width: 1200px) {
- .container {
- grid-template-columns: 1fr;
- }
-
- .actions {
- margin: 20px 0;
- }
-}
-
-@media screen and (min-width: 992px) {
- .sticky {
- position: sticky;
- top: -1px;
- }
-
- .isSticky {
- padding: 10px 0;
- border-bottom: 1px solid var(--base300);
- }
-}
diff --git a/src/app/(main)/websites/[websiteId]/events/EventsMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/events/EventsMetricsBar.tsx
index 5200ab16..2712c985 100644
--- a/src/app/(main)/websites/[websiteId]/events/EventsMetricsBar.tsx
+++ b/src/app/(main)/websites/[websiteId]/events/EventsMetricsBar.tsx
@@ -11,28 +11,30 @@ export function EventsMetricsBar({ websiteId }: { websiteId: string }) {
return (
-
-
-
-
-
-
+ {data && (
+
+
+
+
+
+
+ )}
);
}
diff --git a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
index c46ef097..8e965528 100644
--- a/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
+++ b/src/app/(main)/websites/[websiteId]/realtime/RealtimeLog.tsx
@@ -67,7 +67,7 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
country: string;
device: string;
}) => {
- const { __type, eventName, urlPath: url, browser, os, country, device } = log;
+ const { __type, eventName, urlPath, browser, os, country, device } = log;
if (__type === TYPE_EVENT) {
return formatMessage(messages.eventLog, {
@@ -75,12 +75,12 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
url: (
- {url}
+ {urlPath}
),
});
@@ -89,12 +89,12 @@ export function RealtimeLog({ data }: { data: RealtimeData }) {
if (__type === TYPE_PAGEVIEW) {
return (
- {url}
+ {urlPath}
);
}
diff --git a/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx b/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx
index 6313ca46..f073a12d 100644
--- a/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx
+++ b/src/app/(main)/websites/[websiteId]/reports/ReportsNav.tsx
@@ -66,7 +66,13 @@ export function ReportsNav({ websiteId }: { websiteId: string }) {
const isSelected = selected === id;
return (
-
+
{icon}
diff --git a/src/app/(main)/websites/[websiteId]/reports/retention/Retention.tsx b/src/app/(main)/websites/[websiteId]/reports/retention/Retention.tsx
index 1667c483..b4bd01a7 100644
--- a/src/app/(main)/websites/[websiteId]/reports/retention/Retention.tsx
+++ b/src/app/(main)/websites/[websiteId]/reports/retention/Retention.tsx
@@ -1,7 +1,7 @@
import { ReactNode } from 'react';
import { Grid, Row, Column, Text, Icon } from '@umami/react-zen';
import { Users } from '@/components/icons';
-import { useMessages, useLocale, useResultQuery } from '@/components/hooks';
+import { useMessages, useLocale, useResultQuery, useTimezone } from '@/components/hooks';
import { formatDate } from '@/lib/date';
import { formatLongNumber } from '@/lib/format';
import { Panel } from '@/components/common/Panel';
@@ -19,8 +19,10 @@ export interface RetentionProps {
export function Retention({ websiteId, days = DAYS, startDate, endDate }: RetentionProps) {
const { formatMessage, labels } = useMessages();
const { locale } = useLocale();
+ const { timezone } = useTimezone();
const { data, error, isLoading } = useResultQuery('retention', {
websiteId,
+ timezone,
dateRange: {
startDate,
endDate,
@@ -51,54 +53,56 @@ export function Retention({ websiteId, days = DAYS, startDate, endDate }: Retent
return (
-
-
-
-
-
- {formatMessage(labels.cohort)}
-
-
- {days.map(n => (
-
-
- {formatMessage(labels.day)} {n}
+ {data && (
+
+
+
+
+
+ {formatMessage(labels.cohort)}
- ))}
-
- {rows.map(({ date, visitors, records }: any, rowIndex: number) => {
- return (
-
-
- {formatDate(date, 'PP', locale)}
-
-
-
-
- {formatLongNumber(visitors)}
-
+ {days.map(n => (
+
+
+ {formatMessage(labels.day)} {n}
+
- {days.map(day => {
- if (totalDays - rowIndex < day) {
- return null;
- }
- const percentage = records.filter(a => a.day === day)[0]?.percentage;
- return (
- {percentage ? `${Number(percentage).toFixed(2)}%` : ''} |
- );
- })}
-
- );
- })}
-
-
+ ))}
+
+ {rows.map(({ date, visitors, records }: any, rowIndex: number) => {
+ return (
+
+
+ {formatDate(date, 'PP', locale)}
+
+
+
+
+ {formatLongNumber(visitors)}
+
+
+ {days.map(day => {
+ if (totalDays - rowIndex < day) {
+ return null;
+ }
+ const percentage = records.filter(a => a.day === day)[0]?.percentage;
+ return (
+ {percentage ? `${Number(percentage).toFixed(2)}%` : ''} |
+ );
+ })}
+
+ );
+ })}
+
+
+ )}
);
}
diff --git a/src/app/(main)/websites/[websiteId]/reports/retention/RetentionPage.tsx b/src/app/(main)/websites/[websiteId]/reports/retention/RetentionPage.tsx
index 71ffc6fb..64cf6823 100644
--- a/src/app/(main)/websites/[websiteId]/reports/retention/RetentionPage.tsx
+++ b/src/app/(main)/websites/[websiteId]/reports/retention/RetentionPage.tsx
@@ -3,16 +3,20 @@ import { Column } from '@umami/react-zen';
import { Retention } from './Retention';
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
import { useDateRange } from '@/components/hooks';
+import { endOfMonth, startOfMonth } from 'date-fns';
export function RetentionPage({ websiteId }: { websiteId: string }) {
const {
- dateRange: { startDate, endDate },
+ dateRange: { startDate },
} = useDateRange(websiteId);
+ const monthStartDate = startOfMonth(startDate);
+ const monthEndDate = endOfMonth(startDate);
+
return (
-
-
+
+
);
}
diff --git a/src/app/(main)/websites/[websiteId]/sessions/SessionsMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/sessions/SessionsMetricsBar.tsx
index 1da45000..b959f0da 100644
--- a/src/app/(main)/websites/[websiteId]/sessions/SessionsMetricsBar.tsx
+++ b/src/app/(main)/websites/[websiteId]/sessions/SessionsMetricsBar.tsx
@@ -11,28 +11,30 @@ export function SessionsMetricsBar({ websiteId }: { websiteId: string }) {
return (
-
-
-
-
-
-
+ {data && (
+
+
+
+
+
+
+ )}
);
}
diff --git a/src/app/api/reports/retention/route.ts b/src/app/api/reports/retention/route.ts
index 04842121..cc7433aa 100644
--- a/src/app/api/reports/retention/route.ts
+++ b/src/app/api/reports/retention/route.ts
@@ -14,6 +14,7 @@ export async function POST(request: Request) {
const {
websiteId,
dateRange: { startDate, endDate },
+ timezone,
} = body;
if (!(await canViewWebsite(auth, websiteId))) {
@@ -23,6 +24,7 @@ export async function POST(request: Request) {
const data = await getRetention(websiteId, {
startDate: new Date(startDate),
endDate: new Date(endDate),
+ timezone,
});
return json(data);
diff --git a/src/components/common/Panel.tsx b/src/components/common/Panel.tsx
index 22f9ab9b..7341b3b5 100644
--- a/src/components/common/Panel.tsx
+++ b/src/components/common/Panel.tsx
@@ -62,7 +62,7 @@ export function Panel({
- {formatMessage(labels.expand)}
+ {formatMessage(labels.maximize)}
)}
diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts
index 6a6e16d4..795c4239 100644
--- a/src/components/hooks/useDateRange.ts
+++ b/src/components/hooks/useDateRange.ts
@@ -22,7 +22,7 @@ export function useDateRange(websiteId?: string) {
);
const dateRange = useMemo(
() => (offset ? getOffsetDateRange(dateRangeObject, +offset) : dateRangeObject),
- [date, offset],
+ [date, offset, websiteConfig],
);
const dateCompare = useWebsites(state => state[websiteId]?.dateCompare || DEFAULT_DATE_COMPARE);
diff --git a/src/components/hooks/useFilterParams.ts b/src/components/hooks/useFilterParams.ts
index 55deed14..bee2a649 100644
--- a/src/components/hooks/useFilterParams.ts
+++ b/src/components/hooks/useFilterParams.ts
@@ -8,7 +8,7 @@ export function useFilterParams(websiteId: string) {
const { timezone, toUtc } = useTimezone();
const {
query: {
- url,
+ path,
referrer,
title,
query,
@@ -29,7 +29,7 @@ export function useFilterParams(websiteId: string) {
endAt: +toUtc(endDate),
unit,
timezone,
- url,
+ path,
referrer,
title,
query,
diff --git a/src/components/input/DateFilter.tsx b/src/components/input/DateFilter.tsx
index 72be6c6d..3e2c00ed 100644
--- a/src/components/input/DateFilter.tsx
+++ b/src/components/input/DateFilter.tsx
@@ -99,7 +99,7 @@ export function DateFilter({
};
return (
-
+