Move timezone selection to query parameters

This commit is contained in:
Mike Cao committed 2026-07-27 02:24:59 -07:00
1 parent 9b41053d47
commit 4d7930060c
19 files changed
+127 -145

No files matched your search

@@ -3,7 +3,6 @@ import { useLoginQuery, useMessages } from '@/components/hooks';
import { DateRangeSetting } from './DateRangeSetting'; import { DateRangeSetting } from './DateRangeSetting';
import { LanguageSetting } from './LanguageSetting'; import { LanguageSetting } from './LanguageSetting';
import { ThemeSetting } from './ThemeSetting'; import { ThemeSetting } from './ThemeSetting';
import { TimezoneSetting } from './TimezoneSetting';
import { VersionSetting } from './VersionSetting'; import { VersionSetting } from './VersionSetting';
export function PreferenceSettings() { export function PreferenceSettings() {
@@ -20,10 +19,6 @@ export function PreferenceSettings() {
<Label>{t(labels.defaultDateRange)}</Label> <Label>{t(labels.defaultDateRange)}</Label>
<DateRangeSetting /> <DateRangeSetting />
</Column> </Column>
<Column>
<Label>{t(labels.timezone)}</Label>
<TimezoneSetting />
</Column>
<Column> <Column>
<Label>{t(labels.language)}</Label> <Label>{t(labels.language)}</Label>
<LanguageSetting /> <LanguageSetting />
@@ -1,45 +0,0 @@
import { Button, ListItem, Row, Select } from '@umami/react-zen';
import { useState } from 'react';
import { useMessages, useTimezone } from '@/components/hooks';
import { getTimezone } from '@/lib/date';
const timezones = Intl.supportedValuesOf('timeZone');
export function TimezoneSetting() {
const [search, setSearch] = useState('');
const { t, labels } = useMessages();
const { timezone, saveTimezone } = useTimezone();
const items = search
? timezones.filter(n => n.toLowerCase().includes(search.toLowerCase()))
: timezones;
const handleReset = () => saveTimezone(getTimezone());
const handleOpen = isOpen => {
if (isOpen) {
setSearch('');
}
};
return (
<Row gap>
<Select
value={timezone}
onChange={(value: any) => saveTimezone(value)}
allowSearch={true}
onSearch={setSearch}
onOpenChange={handleOpen}
maxHeight={480}
style={{ minWidth: '250px' }}
>
{items.map((item: any) => (
<ListItem key={item} id={item}>
{item}
</ListItem>
))}
{!items.length && <ListItem></ListItem>}
</Select>
<Button onPress={handleReset}>{t(labels.reset)}</Button>
</Row>
);
}
@@ -1,5 +1,5 @@
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { useDateRange, useTimezone } from '@/components/hooks'; import { useDateRange } from '@/components/hooks';
import { useRevenueChartQuery } from '@/components/hooks/queries/useRevenueChartQuery'; import { useRevenueChartQuery } from '@/components/hooks/queries/useRevenueChartQuery';
import { RevenueChart } from './RevenueChart'; import { RevenueChart } from './RevenueChart';
import { useBoardRevenueCurrency } from './useBoardRevenueCurrency'; import { useBoardRevenueCurrency } from './useBoardRevenueCurrency';
@@ -12,10 +12,9 @@ export function BoardRevenueChart({
currency?: string; currency?: string;
}) { }) {
const currency = useBoardRevenueCurrency(selectedCurrency); const currency = useBoardRevenueCurrency(selectedCurrency);
const { timezone } = useTimezone();
const { const {
dateRange: { startDate, endDate, unit }, dateRange: { startDate, endDate, unit },
} = useDateRange({ timezone }); } = useDateRange();
const { data, isLoading, isFetching, error } = useRevenueChartQuery(websiteId, currency); const { data, isLoading, isFetching, error } = useRevenueChartQuery(websiteId, currency);
return ( return (
@@ -1,14 +1,13 @@
'use client'; 'use client';
import { Column } from '@umami/react-zen'; import { Column } from '@umami/react-zen';
import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls'; import { WebsiteControls } from '@/app/(main)/websites/[websiteId]/WebsiteControls';
import { useDateRange, useTimezone } from '@/components/hooks'; import { useDateRange } from '@/components/hooks';
import { Revenue } from './Revenue'; import { Revenue } from './Revenue';
export function RevenuePage({ websiteId }: { websiteId: string }) { export function RevenuePage({ websiteId }: { websiteId: string }) {
const { timezone } = useTimezone();
const { const {
dateRange: { startDate, endDate, unit }, dateRange: { startDate, endDate, unit },
} = useDateRange({ timezone }); } = useDateRange();
return ( return (
<Column gap> <Column gap>
@@ -1,6 +1,6 @@
import { useMemo } from 'react'; import { useMemo } from 'react';
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { useDateRange, useTimezone } from '@/components/hooks'; import { useDateRange } from '@/components/hooks';
import { useWebsitePageviewsQuery } from '@/components/hooks/queries/useWebsitePageviewsQuery'; import { useWebsitePageviewsQuery } from '@/components/hooks/queries/useWebsitePageviewsQuery';
import { PageviewsChart } from '@/components/metrics/PageviewsChart'; import { PageviewsChart } from '@/components/metrics/PageviewsChart';
@@ -11,8 +11,7 @@ export function WebsiteChart({
websiteId: string; websiteId: string;
compareMode?: boolean; compareMode?: boolean;
}) { }) {
const { timezone } = useTimezone(); const { dateRange, dateCompare } = useDateRange();
const { dateRange, dateCompare } = useDateRange({ timezone: timezone });
const { startDate, endDate, unit, value } = dateRange; const { startDate, endDate, unit, value } = dateRange;
const { data, isLoading, isFetching, error } = useWebsitePageviewsQuery({ const { data, isLoading, isFetching, error } = useWebsitePageviewsQuery({
websiteId, websiteId,
@@ -1,4 +1,4 @@
import { Icon, Row, Text } from '@umami/react-zen'; import { Row } from '@umami/react-zen';
import { Favicon } from '@/components/common/Favicon'; import { Favicon } from '@/components/common/Favicon';
import { IconLabel } from '@/components/common/IconLabel'; import { IconLabel } from '@/components/common/IconLabel';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
@@ -15,7 +15,7 @@ export function WebsiteHeader({
allowLink?: boolean; allowLink?: boolean;
}) { }) {
const website = useWebsite(); const website = useWebsite();
const { renderUrl, pathname } = useNavigation(); const { renderUrl, pathname, query } = useNavigation();
const isSettings = pathname.endsWith('/settings'); const isSettings = pathname.endsWith('/settings');
const { t, labels } = useMessages(); const { t, labels } = useMessages();
@@ -28,7 +28,14 @@ export function WebsiteHeader({
<PageHeader <PageHeader
title={website.name} title={website.name}
icon={<Favicon domain={website.domain} />} icon={<Favicon domain={website.domain} />}
titleHref={allowLink ? renderUrl(`/websites/${website.id}`, false) : undefined} titleHref={
allowLink
? renderUrl(
`/websites/${website.id}`,
query.timezone ? { timezone: query.timezone } : false,
)
: undefined
}
> >
<Row alignItems="center" gap="6" wrap="wrap"> <Row alignItems="center" gap="6" wrap="wrap">
<ActiveUsers websiteId={website.id} allowLink={allowLink} /> <ActiveUsers websiteId={website.id} allowLink={allowLink} />
+3 -3
View File
@@ -13,10 +13,10 @@ export function useDateParameters() {
const { const {
dateRange: { startDate, endDate, unit }, dateRange: { startDate, endDate, unit },
} = useDateRange(); } = useDateRange();
const { timezone, localToUtc, canonicalizeTimezone } = useTimezone(); const { timezone, toUtc, canonicalizeTimezone } = useTimezone();
const utcStart = localToUtc(startDate); const utcStart = toUtc(startDate);
const utcEnd = localToUtc(endDate); const utcEnd = toUtc(endDate);
const startAtValue = +utcStart; const startAtValue = +utcStart;
const endAtValue = +utcEnd; const endAtValue = +utcEnd;
const isStartValid = Number.isFinite(startAtValue); const isStartValid = Number.isFinite(startAtValue);
+7 -5
View File
@@ -4,24 +4,26 @@ import { useNavigation } from '@/components/hooks/useNavigation';
import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants'; import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE_VALUE } from '@/lib/constants';
import { getCompareDate, getOffsetDateRange, parseDateRange } from '@/lib/date'; import { getCompareDate, getOffsetDateRange, parseDateRange } from '@/lib/date';
import { getItem } from '@/lib/storage'; import { getItem } from '@/lib/storage';
import { useTimezone } from './useTimezone';
export function useDateRange(options: { ignoreOffset?: boolean; timezone?: string } = {}) { export function useDateRange(options: { ignoreOffset?: boolean; timezone?: string } = {}) {
const { const {
query: { date = '', unit = '', offset = 0, compare = 'prev' }, query: { date = '', unit = '', offset = 0, compare = 'prev' },
} = useNavigation(); } = useNavigation();
const { locale } = useLocale(); const { locale } = useLocale();
const { timezone: defaultTimezone } = useTimezone();
const timezone = options.timezone ?? defaultTimezone;
const ignoreOffset = options.ignoreOffset;
const dateRange = useMemo(() => { const dateRange = useMemo(() => {
const dateRangeObject = parseDateRange( const dateRangeObject = parseDateRange(
date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE, date || getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE,
unit, unit,
locale, locale,
options.timezone, timezone,
); );
return !options.ignoreOffset && offset return !ignoreOffset && offset ? getOffsetDateRange(dateRangeObject, +offset) : dateRangeObject;
? getOffsetDateRange(dateRangeObject, +offset) }, [date, unit, offset, locale, timezone, ignoreOffset]);
: dateRangeObject;
}, [date, unit, offset, options]);
const dateCompare = getCompareDate(compare, dateRange.startDate, dateRange.endDate); const dateCompare = getCompareDate(compare, dateRange.startDate, dateRange.endDate);
+25 -17
View File
@@ -1,22 +1,35 @@
import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz'; import { formatInTimeZone, fromZonedTime, toZonedTime } from 'date-fns-tz';
import { TIMEZONE_CONFIG, TIMEZONE_LEGACY } from '@/lib/constants'; import { useSyncExternalStore } from 'react';
import { getTimezone } from '@/lib/date'; import { TIMEZONE_LEGACY } from '@/lib/constants';
import { setItem } from '@/lib/storage'; import { getTimezone, isValidTimezone, normalizeTimezone } from '@/lib/date';
import { setTimezone, useApp } from '@/store/app';
import { useLocale } from './useLocale'; import { useLocale } from './useLocale';
import { useNavigation } from './useNavigation';
const selector = (state: { timezone: string }) => state.timezone; function canonicalizeTimezone(timezone: string): string {
return TIMEZONE_LEGACY[timezone] ?? normalizeTimezone(timezone);
}
function subscribe() {
return () => {};
}
function getServerTimezone() {
return 'UTC';
}
export function useTimezone() { export function useTimezone() {
const timezone = useApp(selector); const {
const localTimeZone = getTimezone(); query: { timezone: queryTimezone },
} = useNavigation();
const localTimeZone = canonicalizeTimezone(
useSyncExternalStore(subscribe, getTimezone, getServerTimezone),
);
const requestedTimezone =
typeof queryTimezone === 'string' ? canonicalizeTimezone(queryTimezone) : undefined;
const timezone =
requestedTimezone && isValidTimezone(requestedTimezone) ? requestedTimezone : localTimeZone;
const { dateLocale } = useLocale(); const { dateLocale } = useLocale();
const saveTimezone = (value: string) => {
setItem(TIMEZONE_CONFIG, value);
setTimezone(value);
};
const formatTimezoneDate = (date: string, pattern: string) => { const formatTimezoneDate = (date: string, pattern: string) => {
return formatInTimeZone( return formatInTimeZone(
/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{3})?Z$/.test(date) /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{3})?Z$/.test(date)
@@ -76,10 +89,6 @@ export function useTimezone() {
return toZonedTime(date, localTimeZone); return toZonedTime(date, localTimeZone);
}; };
const canonicalizeTimezone = (timezone: string): string => {
return TIMEZONE_LEGACY[timezone] ?? timezone;
};
return { return {
timezone, timezone,
localTimeZone, localTimeZone,
@@ -87,7 +96,6 @@ export function useTimezone() {
fromUtc, fromUtc,
localToUtc, localToUtc,
localFromUtc, localFromUtc,
saveTimezone,
formatTimezoneDate, formatTimezoneDate,
formatSeriesTimezone, formatSeriesTimezone,
canonicalizeTimezone, canonicalizeTimezone,
+4 -3
View File
@@ -1,7 +1,7 @@
import { Dialog, ListItem, ListSeparator, Modal, Select, type SelectProps } from '@umami/react-zen'; import { Dialog, ListItem, ListSeparator, Modal, Select, type SelectProps } from '@umami/react-zen';
import { Fragment, type Key, useState } from 'react'; import { Fragment, type Key, useState } from 'react';
import { DateDisplay } from '@/components/common/DateDisplay'; import { DateDisplay } from '@/components/common/DateDisplay';
import { useMessages, useMobile } from '@/components/hooks'; import { useMessages, useMobile, useTimezone } from '@/components/hooks';
import { DatePickerForm } from '@/components/metrics/DatePickerForm'; import { DatePickerForm } from '@/components/metrics/DatePickerForm';
import { getMaxSelectableDate, parseDateRange } from '@/lib/date'; import { getMaxSelectableDate, parseDateRange } from '@/lib/date';
@@ -23,7 +23,8 @@ export function DateFilter({
}: DateFilterProps) { }: DateFilterProps) {
const { t, labels } = useMessages(); const { t, labels } = useMessages();
const [showPicker, setShowPicker] = useState(false); const [showPicker, setShowPicker] = useState(false);
const { startDate, endDate } = parseDateRange(value) || {}; const { timezone, fromUtc } = useTimezone();
const { startDate, endDate } = parseDateRange(value, undefined, undefined, timezone) || {};
const { isMobile } = useMobile(); const { isMobile } = useMobile();
const options = [ const options = [
@@ -128,7 +129,7 @@ export function DateFilter({
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
minDate={new Date(2000, 0, 1)} minDate={new Date(2000, 0, 1)}
maxDate={getMaxSelectableDate()} maxDate={getMaxSelectableDate(fromUtc(new Date()))}
onChange={handlePickerChange} onChange={handlePickerChange}
onClose={() => setShowPicker(false)} onClose={() => setShowPicker(false)}
/> />
@@ -1,6 +1,5 @@
import { Button, Column, DialogTrigger, Icon, Label, Popover } from '@umami/react-zen'; import { Button, Column, DialogTrigger, Icon, Label, Popover } from '@umami/react-zen';
import { DateRangeSetting } from '@/app/(main)/settings/preferences/DateRangeSetting'; import { DateRangeSetting } from '@/app/(main)/settings/preferences/DateRangeSetting';
import { TimezoneSetting } from '@/app/(main)/settings/preferences/TimezoneSetting';
import { Panel } from '@/components/common/Panel'; import { Panel } from '@/components/common/Panel';
import { useMessages } from '@/components/hooks'; import { useMessages } from '@/components/hooks';
import { Settings } from '@/components/icons'; import { Settings } from '@/components/icons';
@@ -17,10 +16,6 @@ export function PreferencesButton() {
</Button> </Button>
<Popover placement="bottom end"> <Popover placement="bottom end">
<Panel gap="3"> <Panel gap="3">
<Column>
<Label>{t(labels.timezone)}</Label>
<TimezoneSetting />
</Column>
<Column> <Column>
<Label>{t(labels.defaultDateRange)}</Label> <Label>{t(labels.defaultDateRange)}</Label>
<DateRangeSetting /> <DateRangeSetting />
+62
View File
@@ -0,0 +1,62 @@
import { ListItem, ListSeparator, Select } from '@umami/react-zen';
import { type Key, useState } from 'react';
import { useMessages, useNavigation, useTimezone } from '@/components/hooks';
import { isValidTimezone } from '@/lib/date';
const CURRENT_TIMEZONE = 'current';
const timezones = [
'UTC',
...(Intl.supportedValuesOf?.('timeZone') ?? []).filter(value => value !== 'UTC'),
];
export function TimezoneFilter() {
const [search, setSearch] = useState('');
const { t, labels } = useMessages();
const { router, query, updateParams } = useNavigation();
const { timezone, localTimeZone, canonicalizeTimezone } = useTimezone();
const hasOverride =
typeof query.timezone === 'string' && isValidTimezone(canonicalizeTimezone(query.timezone));
const selectedTimezone = hasOverride ? timezone : CURRENT_TIMEZONE;
const normalizedSearch = search.trim().toLowerCase();
const items = normalizedSearch
? timezones.filter(value => value.toLowerCase().includes(normalizedSearch))
: timezones;
const handleChange = (value: Key) => {
router.push(
updateParams({
timezone: value === CURRENT_TIMEZONE ? undefined : value.toString(),
page: 1,
}),
);
};
const handleOpen = (isOpen: boolean) => {
if (isOpen) {
setSearch('');
}
};
return (
<Select
value={selectedTimezone}
onChange={handleChange}
allowSearch
onSearch={setSearch}
onOpenChange={handleOpen}
maxHeight={480}
style={{ minWidth: 220 }}
>
<ListItem id={CURRENT_TIMEZONE}>
{t(labels.current)} ({localTimeZone})
</ListItem>
<ListSeparator />
{items.map(item => (
<ListItem key={item} id={item}>
{item}
</ListItem>
))}
{!items.length && <ListItem />}
</Select>
);
}
+5 -7
View File
@@ -4,6 +4,7 @@ import { useFilters, useMessages, useNavigation } from '@/components/hooks';
import { ListFilter } from '@/components/icons'; import { ListFilter } from '@/components/icons';
import { DialogButton } from '@/components/input/DialogButton'; import { DialogButton } from '@/components/input/DialogButton';
import { FilterEditForm } from '@/components/input/FilterEditForm'; import { FilterEditForm } from '@/components/input/FilterEditForm';
import { TimezoneFilter } from '@/components/input/TimezoneFilter';
import { import {
filtersArrayToObject, filtersArrayToObject,
serializeSessionPropertyFilters, serializeSessionPropertyFilters,
@@ -78,17 +79,14 @@ export function WebsiteFilterButton({
{({ close }) => { {({ close }) => {
return ( return (
<> <>
<Row position="absolute" top="30px" right="30px" alignItems="center" gap>
{(isOverview || allowBounceFilter) && ( {(isOverview || allowBounceFilter) && (
<Row position="absolute" top="30px" right="30px"> <Checkbox value={excludeBounce ? 'true' : ''} onChange={setExcludeBounce}>
<Checkbox
value={excludeBounce ? 'true' : ''}
onChange={setExcludeBounce}
style={{ marginTop: '3px' }}
>
{t(labels.excludeBounce)} {t(labels.excludeBounce)}
</Checkbox> </Checkbox>
</Row>
)} )}
<TimezoneFilter />
</Row>
<FilterEditForm websiteId={websiteId} onChange={handleChange} onClose={close} /> <FilterEditForm websiteId={websiteId} onChange={handleChange} onClose={close} />
</> </>
); );
+2 -8
View File
@@ -2,12 +2,7 @@ import { colord } from 'colord';
import { useCallback, useEffect, useMemo, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { BarChart, type BarChartProps } from '@/components/charts/BarChart'; import { BarChart, type BarChartProps } from '@/components/charts/BarChart';
import { LoadingPanel } from '@/components/common/LoadingPanel'; import { LoadingPanel } from '@/components/common/LoadingPanel';
import { import { useDateRange, useLocale, useWebsiteEventsSeriesQuery } from '@/components/hooks';
useDateRange,
useLocale,
useTimezone,
useWebsiteEventsSeriesQuery,
} from '@/components/hooks';
import { renderDateLabels } from '@/lib/charts'; import { renderDateLabels } from '@/lib/charts';
import { hex6 } from '@/lib/colors'; import { hex6 } from '@/lib/colors';
import { CHART_COLORS } from '@/lib/constants'; import { CHART_COLORS } from '@/lib/constants';
@@ -20,10 +15,9 @@ export interface EventsChartProps extends BarChartProps {
} }
export function EventsChart({ websiteId, focusLabel, limit }: EventsChartProps) { export function EventsChart({ websiteId, focusLabel, limit }: EventsChartProps) {
const { timezone } = useTimezone();
const { const {
dateRange: { startDate, endDate, unit }, dateRange: { startDate, endDate, unit },
} = useDateRange({ timezone: timezone }); } = useDateRange();
const { locale, dateLocale } = useLocale(); const { locale, dateLocale } = useLocale();
const { data, isLoading, error } = useWebsiteEventsSeriesQuery(websiteId, { limit }); const { data, isLoading, error } = useWebsiteEventsSeriesQuery(websiteId, { limit });
const [label, setLabel] = useState<string>(focusLabel); const [label, setLabel] = useState<string>(focusLabel);
@@ -11,7 +11,6 @@ import {
useMessages, useMessages,
usePropertyArraySeriesQuery, usePropertyArraySeriesQuery,
usePropertySeriesQuery, usePropertySeriesQuery,
useTimezone,
} from '@/components/hooks'; } from '@/components/hooks';
import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery';
import { ListTable } from '@/components/metrics/ListTable'; import { ListTable } from '@/components/metrics/ListTable';
@@ -36,10 +35,9 @@ export function PropertyChart({
seriesType?: 'property' | 'array'; seriesType?: 'property' | 'array';
}) { }) {
const { t, labels } = useMessages(); const { t, labels } = useMessages();
const { timezone } = useTimezone();
const { const {
dateRange: { startDate, endDate, unit }, dateRange: { startDate, endDate, unit },
} = useDateRange({ timezone }); } = useDateRange();
const { locale, dateLocale } = useLocale(); const { locale, dateLocale } = useLocale();
const propertySeriesQuery = usePropertySeriesQuery( const propertySeriesQuery = usePropertySeriesQuery(
source, source,
@@ -9,7 +9,6 @@ import {
useMessages, useMessages,
usePropertyNumericSeriesQuery, usePropertyNumericSeriesQuery,
usePropertyNumericStatsQuery, usePropertyNumericStatsQuery,
useTimezone,
} from '@/components/hooks'; } from '@/components/hooks';
import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery'; import type { PropertyDataSource } from '@/components/hooks/queries/usePropertyFieldsQuery';
import { MetricCard } from '@/components/metrics/MetricCard'; import { MetricCard } from '@/components/metrics/MetricCard';
@@ -35,10 +34,9 @@ export function PropertyNumericChart({
}) { }) {
const { t, labels } = useMessages(); const { t, labels } = useMessages();
const { theme } = useTheme(); const { theme } = useTheme();
const { timezone } = useTimezone();
const { const {
dateRange: { startDate, endDate, unit }, dateRange: { startDate, endDate, unit },
} = useDateRange({ timezone }); } = useDateRange();
const { locale, dateLocale } = useLocale(); const { locale, dateLocale } = useLocale();
const { colors } = useMemo(() => getThemeColors(theme), [theme]); const { colors } = useMemo(() => getThemeColors(theme), [theme]);
-1
View File
@@ -1,7 +1,6 @@
export const CURRENT_VERSION = process.env.currentVersion; export const CURRENT_VERSION = process.env.currentVersion;
export const AUTH_TOKEN = 'umami.auth'; export const AUTH_TOKEN = 'umami.auth';
export const LOCALE_CONFIG = 'umami.locale'; export const LOCALE_CONFIG = 'umami.locale';
export const TIMEZONE_CONFIG = 'umami.timezone';
export const DATE_RANGE_CONFIG = 'umami.date-range'; export const DATE_RANGE_CONFIG = 'umami.date-range';
export const THEME_CONFIG = 'umami.theme'; export const THEME_CONFIG = 'umami.theme';
export const CURRENCY_CONFIG = 'umami.currency'; export const CURRENCY_CONFIG = 'umami.currency';
+1 -21
View File
@@ -1,13 +1,5 @@
import { beforeEach, describe, expect, test } from 'vitest'; import { beforeEach, describe, expect, test } from 'vitest';
import { import { setConfig, setDateRangeValue, setLocale, setShareData, setUser, useApp } from './app';
setConfig,
setDateRangeValue,
setLocale,
setShareData,
setTimezone,
setUser,
useApp,
} from './app';
const initialState = { ...useApp.getState() }; const initialState = { ...useApp.getState() };
@@ -15,18 +7,6 @@ beforeEach(() => {
useApp.setState({ ...initialState }, true); useApp.setState({ ...initialState }, true);
}); });
describe('setTimezone', () => {
test('updates the timezone', () => {
setTimezone('America/New_York');
expect(useApp.getState().timezone).toBe('America/New_York');
});
test('leaves other fields untouched', () => {
setTimezone('UTC');
expect(useApp.getState().locale).toBe(initialState.locale);
});
});
describe('setLocale', () => { describe('setLocale', () => {
test('updates the locale', () => { test('updates the locale', () => {
setLocale('fr-FR'); setLocale('fr-FR');
-7
View File
@@ -6,15 +6,12 @@ import {
DEFAULT_THEME, DEFAULT_THEME,
LOCALE_CONFIG, LOCALE_CONFIG,
THEME_CONFIG, THEME_CONFIG,
TIMEZONE_CONFIG,
} from '@/lib/constants'; } from '@/lib/constants';
import { getTimezone } from '@/lib/date';
import { getItem } from '@/lib/storage'; import { getItem } from '@/lib/storage';
const initialState = { const initialState = {
locale: getItem(LOCALE_CONFIG) || process.env.defaultLocale || DEFAULT_LOCALE, locale: getItem(LOCALE_CONFIG) || process.env.defaultLocale || DEFAULT_LOCALE,
theme: getItem(THEME_CONFIG) || DEFAULT_THEME, theme: getItem(THEME_CONFIG) || DEFAULT_THEME,
timezone: getItem(TIMEZONE_CONFIG) || getTimezone(),
dateRangeValue: getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE, dateRangeValue: getItem(DATE_RANGE_CONFIG) || DEFAULT_DATE_RANGE_VALUE,
share: null, share: null,
shareToken: null, shareToken: null,
@@ -24,10 +21,6 @@ const initialState = {
const store = create(() => ({ ...initialState })); const store = create(() => ({ ...initialState }));
export function setTimezone(timezone: string) {
store.setState({ timezone });
}
export function setLocale(locale: string) { export function setLocale(locale: string) {
store.setState({ locale }); store.setState({ locale });
} }