diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx index 896c733a..b2ea2a83 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx @@ -21,28 +21,30 @@ export function WebsiteChart({ const { pageviews, sessions, compare } = (data || {}) as any; const chartData = useMemo(() => { - if (!data) { - return { pageviews: [], sessions: [] }; - } + if (data) { + const result = { + pageviews, + sessions, + }; - return { - pageviews, - sessions, - ...(compare && { - compare: { - pageviews: pageviews.map(({ x }, i) => ({ + if (compare) { + result.compare = { + pageviews: result.pageviews.map(({ x }, i) => ({ x, y: compare.pageviews[i]?.y, d: compare.pageviews[i]?.x, })), - sessions: sessions.map(({ x }, i) => ({ + sessions: result.sessions.map(({ x }, i) => ({ x, y: compare.sessions[i]?.y, d: compare.sessions[i]?.x, })), - }, - }), - }; + }; + } + + return result; + } + return { pageviews: [], sessions: [] }; }, [data, startDate, endDate, unit]); return ( diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx index 132d3b14..30189534 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMenu.tsx @@ -10,7 +10,7 @@ import { } from '@umami/react-zen'; import { Fragment } from 'react'; import { useMessages, useNavigation } from '@/components/hooks'; -import { Edit, MoreHorizontal, Share } from '@/components/icons'; +import { Edit, More, Share } from '@/components/icons'; export function WebsiteMenu({ websiteId }: { websiteId: string }) { const { formatMessage, labels } = useMessages(); @@ -33,7 +33,7 @@ export function WebsiteMenu({ websiteId }: { websiteId: string }) { diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx index 605ee385..6c91ba6d 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx @@ -7,18 +7,14 @@ import { formatLongNumber, formatShortTime } from '@/lib/format'; export function WebsiteMetricsBar({ websiteId, - compareMode, }: { websiteId: string; showChange?: boolean; compareMode?: boolean; }) { - const { isAllTime, dateCompare } = useDateRange(); + const { isAllTime } = useDateRange(); const { formatMessage, labels, getErrorMessage } = useMessages(); - const { data, isLoading, isFetching, error } = useWebsiteStatsQuery({ - websiteId, - compare: compareMode ? dateCompare?.compare : undefined, - }); + const { data, isLoading, isFetching, error } = useWebsiteStatsQuery(websiteId); 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 9f72c303..ad05b706 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteNav.tsx @@ -29,7 +29,6 @@ export function WebsiteNav({ event: undefined, compare: undefined, view: undefined, - unit: undefined, }); const items = [ diff --git a/src/app/(main)/websites/[websiteId]/WebsitePage.tsx b/src/app/(main)/websites/[websiteId]/WebsitePage.tsx index 5acc9e68..f587e112 100644 --- a/src/app/(main)/websites/[websiteId]/WebsitePage.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsitePage.tsx @@ -1,8 +1,7 @@ 'use client'; -import { Column, Row } from '@umami/react-zen'; +import { Column } from '@umami/react-zen'; import { ExpandedViewModal } from '@/app/(main)/websites/[websiteId]/ExpandedViewModal'; import { Panel } from '@/components/common/Panel'; -import { UnitFilter } from '@/components/input/UnitFilter'; import { WebsiteChart } from './WebsiteChart'; import { WebsiteControls } from './WebsiteControls'; import { WebsiteMetricsBar } from './WebsiteMetricsBar'; @@ -14,9 +13,6 @@ export function WebsitePage({ websiteId }: { websiteId: string }) { - - - diff --git a/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx b/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx index 32d641b0..bca8d244 100644 --- a/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx +++ b/src/app/(main)/websites/[websiteId]/compare/ComparePage.tsx @@ -10,7 +10,7 @@ export function ComparePage({ websiteId }: { websiteId: string }) { return ( - + diff --git a/src/app/api/websites/[websiteId]/stats/route.ts b/src/app/api/websites/[websiteId]/stats/route.ts index 9d21f4f5..b7177b5d 100644 --- a/src/app/api/websites/[websiteId]/stats/route.ts +++ b/src/app/api/websites/[websiteId]/stats/route.ts @@ -31,11 +31,9 @@ export async function GET( const data = await getWebsiteStats(websiteId, filters); - const { startDate, endDate } = getCompareDate( - filters.compare ?? 'prev', - filters.startDate, - filters.endDate, - ); + const compare = filters.compare ?? 'prev'; + + const { startDate, endDate } = getCompareDate(compare, filters.startDate, filters.endDate); const comparison = await getWebsiteStats(websiteId, { ...filters, diff --git a/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts b/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts index 1611c7f8..b2e90199 100644 --- a/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts +++ b/src/components/hooks/queries/useWebsiteExpandedMetricsQuery.ts @@ -19,7 +19,7 @@ export function useWebsiteExpandedMetricsQuery( options?: ReactQueryOptions, ) { const { get, useQuery } = useApi(); - const { startAt, endAt } = useDateParameters(); + const { startAt, endAt, unit, timezone } = useDateParameters(); const filters = useFilterParameters(); return useQuery({ @@ -29,6 +29,8 @@ export function useWebsiteExpandedMetricsQuery( websiteId, startAt, endAt, + unit, + timezone, ...filters, ...params, }, @@ -37,6 +39,8 @@ export function useWebsiteExpandedMetricsQuery( get(`/websites/${websiteId}/metrics/expanded`, { startAt, endAt, + unit, + timezone, ...filters, ...params, }), diff --git a/src/components/hooks/queries/useWebsiteMetricsQuery.ts b/src/components/hooks/queries/useWebsiteMetricsQuery.ts index cd064af6..67c5e4d4 100644 --- a/src/components/hooks/queries/useWebsiteMetricsQuery.ts +++ b/src/components/hooks/queries/useWebsiteMetricsQuery.ts @@ -15,7 +15,7 @@ export function useWebsiteMetricsQuery( options?: ReactQueryOptions, ) { const { get, useQuery } = useApi(); - const { startAt, endAt } = useDateParameters(); + const { startAt, endAt, unit, timezone } = useDateParameters(); const filters = useFilterParameters(); return useQuery({ @@ -25,6 +25,8 @@ export function useWebsiteMetricsQuery( websiteId, startAt, endAt, + unit, + timezone, ...filters, ...params, }, @@ -33,6 +35,8 @@ export function useWebsiteMetricsQuery( get(`/websites/${websiteId}/metrics`, { startAt, endAt, + unit, + timezone, ...filters, ...params, }), diff --git a/src/components/hooks/queries/useWebsiteStatsQuery.ts b/src/components/hooks/queries/useWebsiteStatsQuery.ts index 48484a07..69bae09f 100644 --- a/src/components/hooks/queries/useWebsiteStatsQuery.ts +++ b/src/components/hooks/queries/useWebsiteStatsQuery.ts @@ -1,5 +1,6 @@ import type { UseQueryOptions } from '@tanstack/react-query'; import { useDateParameters } from '@/components/hooks/useDateParameters'; +import { useDateRange } from '@/components/hooks/useDateRange'; import { useApi } from '../useApi'; import { useFilterParameters } from '../useFilterParameters'; @@ -19,16 +20,21 @@ export interface WebsiteStatsData { } export function useWebsiteStatsQuery( - { websiteId, compare }: { websiteId: string; compare?: string }, + websiteId: string, options?: UseQueryOptions, ) { const { get, useQuery } = useApi(); - const { startAt, endAt } = useDateParameters(); + const { startAt, endAt, unit, timezone } = useDateParameters(); + const { compare } = useDateRange(); const filters = useFilterParameters(); return useQuery({ - queryKey: ['websites:stats', { websiteId, compare, startAt, endAt, ...filters }], - queryFn: () => get(`/websites/${websiteId}/stats`, { compare, startAt, endAt, ...filters }), + queryKey: [ + 'websites:stats', + { websiteId, startAt, endAt, unit, timezone, compare, ...filters }, + ], + queryFn: () => + get(`/websites/${websiteId}/stats`, { startAt, endAt, unit, timezone, compare, ...filters }), enabled: !!websiteId, ...options, }); diff --git a/src/components/hooks/queries/useWeeklyTrafficQuery.ts b/src/components/hooks/queries/useWeeklyTrafficQuery.ts index df729ffd..a76ebb3d 100644 --- a/src/components/hooks/queries/useWeeklyTrafficQuery.ts +++ b/src/components/hooks/queries/useWeeklyTrafficQuery.ts @@ -12,12 +12,13 @@ export function useWeeklyTrafficQuery(websiteId: string, params?: Record { return get(`/websites/${websiteId}/sessions/weekly`, { startAt, endAt, + unit, timezone, ...params, ...filters, diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts index 5090bd3d..755f36ee 100644 --- a/src/components/hooks/useDateRange.ts +++ b/src/components/hooks/useDateRange.ts @@ -7,13 +7,13 @@ import { getItem } from '@/lib/storage'; export function useDateRange(options: { ignoreOffset?: boolean; timezone?: string } = {}) { const { - query: { date = '', unit = '', offset = 0, compare = 'prev' }, + query: { date = '', offset = 0, compare = 'prev' }, } = useNavigation(); const { locale } = useLocale(); + const dateRange = useMemo(() => { const dateRangeObject = parseDateRange( date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE, - unit, locale, options.timezone, ); @@ -21,13 +21,12 @@ export function useDateRange(options: { ignoreOffset?: boolean; timezone?: strin return !options.ignoreOffset && offset ? getOffsetDateRange(dateRangeObject, +offset) : dateRangeObject; - }, [date, unit, offset, options]); + }, [date, offset, options]); const dateCompare = getCompareDate(compare, dateRange.startDate, dateRange.endDate); return { date, - unit, offset, compare, isAllTime: date.endsWith(`:all`), diff --git a/src/components/input/UnitFilter.tsx b/src/components/input/UnitFilter.tsx deleted file mode 100644 index 84a15f35..00000000 --- a/src/components/input/UnitFilter.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { ListItem, Row, Select } from '@umami/react-zen'; -import { useMessages, useNavigation } from '@/components/hooks'; -import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants'; -import { getItem } from '@/lib/storage'; - -export function UnitFilter() { - const { formatMessage, labels } = useMessages(); - const { router, query, updateParams } = useNavigation(); - - const DATE_RANGE_UNIT_CONFIG = { - '0week': { - defaultUnit: 'day', - availableUnits: ['day', 'hour'], - }, - '7day': { - defaultUnit: 'day', - availableUnits: ['day', 'hour'], - }, - '0month': { - defaultUnit: 'day', - availableUnits: ['day', 'hour'], - }, - '30day': { - defaultUnit: 'day', - availableUnits: ['day', 'hour'], - }, - '90day': { - defaultUnit: 'day', - availableUnits: ['day', 'month'], - }, - '6month': { - defaultUnit: 'month', - availableUnits: ['month', 'day'], - }, - }; - - const unitConfig = - DATE_RANGE_UNIT_CONFIG[query.date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE]; - - if (!unitConfig) { - return null; - } - - const handleChange = (value: string) => { - router.push(updateParams({ unit: value })); - }; - - const options = unitConfig.availableUnits.map(unit => ({ - id: unit, - label: formatMessage(labels[unit]), - })); - - const selectedUnit = query.unit ?? unitConfig.defaultUnit; - - return ( - - - - ); -} diff --git a/src/components/input/WebsiteDateFilter.tsx b/src/components/input/WebsiteDateFilter.tsx index a76058ec..18b4f13b 100644 --- a/src/components/input/WebsiteDateFilter.tsx +++ b/src/components/input/WebsiteDateFilter.tsx @@ -41,7 +41,7 @@ export function WebsiteDateFilter({ }), ); } else { - router.push(updateParams({ date, offset: undefined, unit: undefined })); + router.push(updateParams({ date, offset: undefined })); } }; diff --git a/src/components/messages.ts b/src/components/messages.ts index 3d7388cd..712495d8 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -245,10 +245,7 @@ export const labels = defineMessages({ tag: { id: 'label.tag', defaultMessage: 'Tag' }, segment: { id: 'label.segment', defaultMessage: 'Segment' }, cohort: { id: 'label.cohort', defaultMessage: 'Cohort' }, - minute: { id: 'label.minute', defaultMessage: 'Minute' }, - hour: { id: 'label.hour', defaultMessage: 'Hour' }, day: { id: 'label.day', defaultMessage: 'Day' }, - month: { id: 'label.month', defaultMessage: 'Month' }, date: { id: 'label.date', defaultMessage: 'Date' }, pageOf: { id: 'label.page-of', defaultMessage: 'Page {current} of {total}' }, create: { id: 'label.create', defaultMessage: 'Create' }, diff --git a/src/components/metrics/MetricCard.tsx b/src/components/metrics/MetricCard.tsx index 590fd5ac..d15bcf13 100644 --- a/src/components/metrics/MetricCard.tsx +++ b/src/components/metrics/MetricCard.tsx @@ -25,7 +25,7 @@ export const MetricCard = ({ showChange = false, }: MetricCardProps) => { const diff = value - change; - const pct = diff !== 0 ? ((value - diff) / diff) * 100 : value !== 0 ? 100 : 0; + const pct = ((value - diff) / diff) * 100; const props = useSpring({ x: Number(value) || 0, from: { x: 0 } }); const changeProps = useSpring({ x: Number(pct) || 0, from: { x: 0 } }); diff --git a/src/lib/date.ts b/src/lib/date.ts index 91af88f6..3c1fd1b7 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -9,7 +9,6 @@ import { differenceInCalendarMonths, differenceInCalendarWeeks, differenceInCalendarYears, - differenceInDays, differenceInHours, differenceInMinutes, endOfDay, @@ -137,12 +136,7 @@ export function parseDateValue(value: string) { return { num: +num, unit }; } -export function parseDateRange( - value: string, - unitValue?: string, - locale = 'en-US', - timezone?: string, -): DateRange { +export function parseDateRange(value: string, locale = 'en-US', timezone?: string): DateRange { if (typeof value !== 'string') { return null; } @@ -152,7 +146,7 @@ export function parseDateRange( const startDate = new Date(+startTime); const endDate = new Date(+endTime); - const unit = getMinimumUnit(startDate, endDate, true); + const unit = getMinimumUnit(startDate, endDate); return { startDate, @@ -175,14 +169,14 @@ export function parseDateRange( endDate: endOfHour(now), offset: 0, num: num || 1, - unit: unitValue || unit, + unit, value, }; case 'day': return { startDate: num ? subDays(startOfDay(now), num) : startOfDay(now), endDate: endOfDay(now), - unit: unitValue ? unitValue : num ? 'day' : 'hour', + unit: num ? 'day' : 'hour', offset: 0, num: num || 1, value, @@ -193,7 +187,7 @@ export function parseDateRange( ? subWeeks(startOfWeek(now, { locale: dateLocale }), num) : startOfWeek(now, { locale: dateLocale }), endDate: endOfWeek(now, { locale: dateLocale }), - unit: unitValue || 'day', + unit: 'day', offset: 0, num: num || 1, value, @@ -202,7 +196,7 @@ export function parseDateRange( return { startDate: num ? subMonths(startOfMonth(now), num) : startOfMonth(now), endDate: endOfMonth(now), - unit: unitValue ? unitValue : num ? 'month' : 'day', + unit: num ? 'month' : 'day', offset: 0, num: num || 1, value, @@ -211,7 +205,7 @@ export function parseDateRange( return { startDate: num ? subYears(startOfYear(now), num) : startOfYear(now), endDate: endOfYear(now), - unit: unitValue || 'month', + unit: 'month', offset: 0, num: num || 1, value, @@ -279,20 +273,12 @@ export function getAllowedUnits(startDate: Date, endDate: Date) { return index >= 0 ? units.splice(index) : []; } -export function getMinimumUnit( - startDate: number | Date, - endDate: number | Date, - isDateRange: boolean = false, -) { +export function getMinimumUnit(startDate: number | Date, endDate: number | Date) { if (differenceInMinutes(endDate, startDate) <= 60) { return 'minute'; - } else if ( - isDateRange - ? differenceInHours(endDate, startDate) <= 48 - : differenceInDays(endDate, startDate) <= 30 - ) { + } else if (differenceInHours(endDate, startDate) <= 48) { return 'hour'; - } else if (differenceInCalendarMonths(endDate, startDate) <= 7) { + } else if (differenceInCalendarMonths(endDate, startDate) <= 6) { return 'day'; } else if (differenceInCalendarMonths(endDate, startDate) <= 24) { return 'month';