diff --git a/src/app/(main)/settings/preferences/DateRangeSetting.tsx b/src/app/(main)/settings/preferences/DateRangeSetting.tsx
index 2b81985f..e47ce0b6 100644
--- a/src/app/(main)/settings/preferences/DateRangeSetting.tsx
+++ b/src/app/(main)/settings/preferences/DateRangeSetting.tsx
@@ -1,21 +1,24 @@
+import { useState } from 'react';
import { DateFilter } from '@/components/input/DateFilter';
import { Button, Row } from '@umami/react-zen';
-import { useDateRange, useMessages } from '@/components/hooks';
-import { DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
+import { useMessages } from '@/components/hooks';
+import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
+import { setItem, getItem } from '@/lib/storage';
export function DateRangeSetting() {
const { formatMessage, labels } = useMessages();
- const { dateRange, saveDateRange } = useDateRange();
- const { value } = dateRange;
+ const [date, setDate] = useState(getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE);
const handleChange = (value: string) => {
- saveDateRange(value);
+ setItem(DATE_RANGE_CONFIG, value);
+ setDate(value);
};
- const handleReset = () => saveDateRange(DEFAULT_DATE_RANGE_VALUE);
+
+ const handleReset = () => setItem(DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE);
return (
-
+
);
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
index b72f00a0..67412d5c 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx
@@ -15,7 +15,7 @@ export function WebsiteChart({
const { startDate, endDate, unit, value } = dateRange;
const { data, isLoading, isFetching, error } = useWebsitePageviewsQuery({
websiteId,
- compare: compareMode ? dateCompare : undefined,
+ compare: compareMode ? dateCompare?.['value'] : undefined,
});
const { pageviews, sessions, compare } = (data || {}) as any;
diff --git a/src/components/hooks/index.ts b/src/components/hooks/index.ts
index 6af16999..2731e268 100644
--- a/src/components/hooks/index.ts
+++ b/src/components/hooks/index.ts
@@ -9,6 +9,7 @@ export * from './context/useWebsite';
// Query hooks
export * from './queries/useActiveUsersQuery';
+export * from './queries/useDateRangeQuery';
export * from './queries/useDeleteQuery';
export * from './queries/useEventDataEventsQuery';
export * from './queries/useEventDataPropertiesQuery';
@@ -76,6 +77,7 @@ export * from './useModified';
export * from './useNavigation';
export * from './usePagedQuery';
export * from './usePageParameters';
+export * from './useQueryStringDate';
export * from './useRegionNames';
export * from './useSlug';
export * from './useSticky';
diff --git a/src/components/hooks/queries/useDateRangeQuery.ts b/src/components/hooks/queries/useDateRangeQuery.ts
new file mode 100644
index 00000000..4af2011c
--- /dev/null
+++ b/src/components/hooks/queries/useDateRangeQuery.ts
@@ -0,0 +1,12 @@
+import { useApi } from '../useApi';
+import { ReactQueryOptions } from '@/lib/types';
+
+export function useDateRangeQuery(websiteId: string, options?: ReactQueryOptions) {
+ const { get, useQuery } = useApi();
+ return useQuery({
+ queryKey: ['date-range', websiteId],
+ queryFn: () => get(`/websites/${websiteId}/daterange`),
+ enabled: !!websiteId,
+ ...options,
+ });
+}
diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts
index 0a82d5a3..dc81cfd7 100644
--- a/src/components/hooks/useDateRange.ts
+++ b/src/components/hooks/useDateRange.ts
@@ -1,65 +1,35 @@
-import { useMemo } from 'react';
-import { getMinimumUnit, parseDateRange, getOffsetDateRange } from '@/lib/date';
-import { setItem } from '@/lib/storage';
-import { DATE_RANGE_CONFIG, DEFAULT_DATE_COMPARE, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
-import { setWebsiteDateCompare, setWebsiteDateRange, useWebsites } from '@/store/websites';
-import { setDateRangeValue, useApp } from '@/store/app';
-import { useLocale } from './useLocale';
-import { useApi } from './useApi';
-import { useNavigation } from './useNavigation';
+import { getMinimumUnit, parseDateRange } from '@/lib/date';
+import { useLocale } from '@/components/hooks/useLocale';
+import { useApi } from '@/components/hooks//useApi';
+import { useQueryStringDate } from '@/components/hooks/useQueryStringDate';
+import { useGlobalState } from '@/components/hooks/useGlobalState';
-export interface UseDateRangeOptions {
- ignoreOffset?: boolean;
-}
-
-export function useDateRange(websiteId?: string, options: UseDateRangeOptions = {}) {
+export function useDateRange(websiteId: string) {
const { get } = useApi();
const { locale } = useLocale();
- const {
- query: { date, offset = 0 },
- } = useNavigation();
- const websiteConfig = useWebsites(state => state[websiteId]?.dateRange);
- const globalConfig = useApp(state => state.dateRangeValue);
- const dateValue = websiteConfig?.value || date || globalConfig || DEFAULT_DATE_RANGE_VALUE;
+ const { dateRange: defaultDateRange, dateCompare } = useQueryStringDate();
- const dateRange = useMemo(() => {
- const dateRangeObject = parseDateRange(dateValue, locale);
+ const [dateRange, setDateRange] = useGlobalState(`date-range:${websiteId}`, defaultDateRange);
- return !options.ignoreOffset && offset
- ? getOffsetDateRange(dateRangeObject, +offset)
- : dateRangeObject;
- }, [date, offset, dateValue, options]);
+ const setDateRangeValue = async (value: string) => {
+ if (value === 'all') {
+ const result = await get(`/websites/${websiteId}/daterange`);
+ const { mindate, maxdate } = result;
- const dateCompare = useWebsites(state => state[websiteId]?.dateCompare || DEFAULT_DATE_COMPARE);
+ const startDate = new Date(mindate);
+ const endDate = new Date(maxdate);
+ const unit = getMinimumUnit(startDate, endDate);
- const saveDateRange = async (value: string) => {
- if (websiteId) {
- if (value === 'all') {
- const result: any = await get(`/websites/${websiteId}/daterange`);
- const { mindate, maxdate } = result;
-
- const startDate = new Date(mindate);
- const endDate = new Date(maxdate);
- const unit = getMinimumUnit(startDate, endDate);
-
- setWebsiteDateRange(websiteId, {
- startDate,
- endDate,
- unit,
- value,
- });
- } else {
- setWebsiteDateRange(websiteId, parseDateRange(value, locale));
- }
+ setDateRange({
+ startDate,
+ endDate,
+ unit,
+ value,
+ });
} else {
- setItem(DATE_RANGE_CONFIG, value);
- setDateRangeValue(value);
+ setDateRange(parseDateRange(value, locale));
}
};
- const saveDateCompare = (value: string) => {
- setWebsiteDateCompare(websiteId, value);
- };
-
- return { dateRange, saveDateRange, dateCompare, saveDateCompare };
+ return { dateRange, dateCompare, setDateRange, setDateRangeValue };
}
diff --git a/src/components/hooks/useQueryStringDate.ts b/src/components/hooks/useQueryStringDate.ts
new file mode 100644
index 00000000..3b6431a1
--- /dev/null
+++ b/src/components/hooks/useQueryStringDate.ts
@@ -0,0 +1,24 @@
+import { useNavigation } from '@/components/hooks/useNavigation';
+import { useMemo } from 'react';
+import { getCompareDate, getOffsetDateRange, parseDateRange } from '@/lib/date';
+import { useLocale } from '@/components/hooks/useLocale';
+import { DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
+
+export function useQueryStringDate(options: { ignoreOffset?: boolean } = {}) {
+ const {
+ query: { date = DEFAULT_DATE_RANGE_VALUE, offset = 0, compare = 'prev' },
+ } = useNavigation();
+ const { locale } = useLocale();
+
+ const dateRange = useMemo(() => {
+ const dateRangeObject = parseDateRange(date, locale);
+
+ return !options.ignoreOffset && offset
+ ? getOffsetDateRange(dateRangeObject, +offset)
+ : dateRangeObject;
+ }, [date, offset, options]);
+
+ const dateCompare = getCompareDate(compare, dateRange.startDate, dateRange.endDate);
+
+ return { date, offset, dateRange, dateCompare };
+}
diff --git a/src/components/input/WebsiteDateFilter.tsx b/src/components/input/WebsiteDateFilter.tsx
index 1045de21..469da419 100644
--- a/src/components/input/WebsiteDateFilter.tsx
+++ b/src/components/input/WebsiteDateFilter.tsx
@@ -3,6 +3,8 @@ import { isAfter } from 'date-fns';
import { ChevronRight } from '@/components/icons';
import { useDateRange, useMessages, useNavigation } from '@/components/hooks';
import { DateFilter } from './DateFilter';
+import { getOffsetDateRange } from '@/lib/date';
+import { useCallback } from 'react';
export interface WebsiteDateFilterProps {
websiteId: string;
@@ -18,7 +20,7 @@ export function WebsiteDateFilter({
showButtons = true,
allowCompare,
}: WebsiteDateFilterProps) {
- const { dateRange, saveDateRange } = useDateRange(websiteId);
+ const { dateRange, setDateRange, setDateRangeValue } = useDateRange(websiteId);
const { value, endDate } = dateRange;
const { formatMessage, labels } = useMessages();
const {
@@ -27,18 +29,25 @@ export function WebsiteDateFilter({
query: { compare = 'prev', offset = 0 },
} = useNavigation();
const isAllTime = value === 'all';
+
const isCustomRange = value.startsWith('range');
const disableForward = value === 'all' || isAfter(endDate, new Date());
const handleChange = (date: string) => {
- saveDateRange(date);
+ setDateRangeValue(date);
router.push(updateParams({ date, offset: undefined }));
};
- const handleIncrement = (increment: number) => {
- router.push(updateParams({ offset: +offset + increment }));
- };
+ const handleIncrement = useCallback(
+ (increment: number) => {
+ const offsetDate = getOffsetDateRange(dateRange, +offset + increment);
+
+ setDateRange(offsetDate);
+ router.push(updateParams({ offset: +offset + increment }));
+ },
+ [offset],
+ );
const handleSelect = (compare: any) => {
router.push(updateParams({ compare }));