diff --git a/src/app/(main)/profile/DateRangeSetting.tsx b/src/app/(main)/profile/DateRangeSetting.tsx index c57a209a..25b5afbd 100644 --- a/src/app/(main)/profile/DateRangeSetting.tsx +++ b/src/app/(main)/profile/DateRangeSetting.tsx @@ -7,11 +7,11 @@ import styles from './DateRangeSetting.module.css'; export function DateRangeSetting() { const { formatMessage, labels } = useMessages(); - const [dateRange, setDateRange] = useDateRange(); + const { dateRange, saveDateRange } = useDateRange(); const { value } = dateRange; - const handleChange = (value: string | DateRange) => setDateRange(value); - const handleReset = () => setDateRange(DEFAULT_DATE_RANGE); + const handleChange = (value: string | DateRange) => saveDateRange(value); + const handleReset = () => saveDateRange(DEFAULT_DATE_RANGE); return ( diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx index 470bd792..5144adcc 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx @@ -4,17 +4,33 @@ import { getDateArray } from 'lib/date'; import useWebsitePageviews from 'components/hooks/queries/useWebsitePageviews'; import { useDateRange } from 'components/hooks'; -export function WebsiteChart({ websiteId }: { websiteId: string }) { - const [dateRange] = useDateRange(websiteId); +export function WebsiteChart({ + websiteId, + compareMode = false, +}: { + websiteId: string; + compareMode: boolean; +}) { + const { dateRange, dateCompare } = useDateRange(websiteId); const { startDate, endDate, unit } = dateRange; - const { data, isLoading } = useWebsitePageviews(websiteId); + const { data, isLoading } = useWebsitePageviews(websiteId, compareMode ? dateCompare : undefined); + const { pageviews, sessions, compare } = (data || {}) as any; const chartData = useMemo(() => { if (data) { - return { - pageviews: getDateArray(data.pageviews, startDate, endDate, unit), - sessions: getDateArray(data.sessions, startDate, endDate, unit), + const result = { + pageviews: getDateArray(pageviews, startDate, endDate, unit), + sessions: getDateArray(sessions, startDate, endDate, unit), }; + + if (compare) { + result['compare'] = { + pageviews: result.pageviews.map(({ x }, i) => ({ x, y: compare.pageviews[i].y })), + sessions: result.sessions.map(({ x }, i) => ({ x, y: compare.sessions[i].y })), + }; + } + + return result; } return { pageviews: [], sessions: [] }; }, [data, startDate, endDate, unit]); diff --git a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx index 785f0f36..a6229e95 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteFilterButton.tsx @@ -21,7 +21,9 @@ export function WebsiteFilterButton({ const { formatMessage, labels } = useMessages(); const { renderUrl, router } = useNavigation(); const { fields } = useFields(); - const [{ startDate, endDate }] = useDateRange(websiteId); + const { + dateRange: { startDate, endDate }, + } = useDateRange(websiteId); const handleAddFilter = ({ name, operator, value }) => { const prefix = OPERATOR_PREFIXES[operator]; diff --git a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx index 1b00ed1a..90abc814 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteMetricsBar.tsx @@ -1,4 +1,3 @@ -import { useState } from 'react'; import classNames from 'classnames'; import { useMessages, useSticky } from 'components/hooks'; import WebsiteDateFilter from 'components/input/WebsiteDateFilter'; @@ -9,6 +8,7 @@ import WebsiteFilterButton from './WebsiteFilterButton'; import useWebsiteStats from 'components/hooks/queries/useWebsiteStats'; import styles from './WebsiteMetricsBar.module.css'; import { Dropdown, Item } from 'react-basics'; +import useStore, { setWebsiteDateCompare } from 'store/websites'; export function WebsiteMetricsBar({ websiteId, @@ -22,9 +22,12 @@ export function WebsiteMetricsBar({ compareMode?: boolean; }) { const { formatMessage, labels } = useMessages(); - const [compare, setCompare] = useState('prev'); + const dateCompare = useStore(state => state[websiteId]?.dateCompare); const { ref, isSticky } = useSticky({ enabled: sticky }); - const { data, isLoading, isFetched, error } = useWebsiteStats(websiteId, compare); + const { data, isLoading, isFetched, error } = useWebsiteStats( + websiteId, + compareMode && dateCompare, + ); const { pageviews, visitors, visits, bounces, totaltime } = data || {}; @@ -106,10 +109,10 @@ export function WebsiteMetricsBar({ items.find(i => i.value === value)?.label} alignment="end" - onChange={(e: any) => setCompare(e)} + onChange={(value: any) => setWebsiteDateCompare(websiteId, value)} > {items.map(({ label, value }) => ( {label} diff --git a/src/app/(main)/websites/[websiteId]/compare/WebsiteComparePage.tsx b/src/app/(main)/websites/[websiteId]/compare/WebsiteComparePage.tsx index b9a214f8..da330691 100644 --- a/src/app/(main)/websites/[websiteId]/compare/WebsiteComparePage.tsx +++ b/src/app/(main)/websites/[websiteId]/compare/WebsiteComparePage.tsx @@ -21,7 +21,7 @@ export function WebsiteComparePage({ websiteId }) { - + ); } diff --git a/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx b/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx index fceb86aa..86417c96 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/EventDataMetricsBar.tsx @@ -7,7 +7,7 @@ import styles from './EventDataMetricsBar.module.css'; export function EventDataMetricsBar({ websiteId }: { websiteId: string }) { const { formatMessage, labels } = useMessages(); const { get, useQuery } = useApi(); - const [dateRange] = useDateRange(websiteId); + const { dateRange } = useDateRange(websiteId); const { startDate, endDate } = dateRange; const { data, error, isLoading, isFetched } = useQuery({ diff --git a/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx b/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx index 27ccd96c..d7d24cee 100644 --- a/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx +++ b/src/app/(main)/websites/[websiteId]/event-data/WebsiteEventData.tsx @@ -6,7 +6,7 @@ import { useDateRange, useApi, useNavigation } from 'components/hooks'; import styles from './WebsiteEventData.module.css'; function useData(websiteId: string, event: string) { - const [dateRange] = useDateRange(websiteId); + const { dateRange } = useDateRange(websiteId); const { startDate, endDate } = dateRange; const { get, useQuery } = useApi(); const { data, error, isLoading } = useQuery({ diff --git a/src/components/charts/BarChart.tsx b/src/components/charts/BarChart.tsx index 635bb10d..cfcbe743 100644 --- a/src/components/charts/BarChart.tsx +++ b/src/components/charts/BarChart.tsx @@ -26,7 +26,7 @@ export function BarChart(props: BarChartProps) { stacked = false, } = props; - const options = useMemo(() => { + const options: any = useMemo(() => { return { scales: { x: { diff --git a/src/components/charts/Chart.tsx b/src/components/charts/Chart.tsx index d5d22874..47d29c07 100644 --- a/src/components/charts/Chart.tsx +++ b/src/components/charts/Chart.tsx @@ -79,15 +79,19 @@ export function Chart({ }; const updateChart = (data: any) => { - chart.current.data.datasets.forEach((dataset: { data: any }, index: string | number) => { - if (data?.datasets[index]) { - dataset.data = data?.datasets[index]?.data; + if (data.datasets.length === chart.current.data.datasets.length) { + chart.current.data.datasets.forEach((dataset: { data: any }, index: string | number) => { + if (data?.datasets[index]) { + dataset.data = data?.datasets[index]?.data; - if (chart.current.legend.legendItems[index]) { - chart.current.legend.legendItems[index].text = data?.datasets[index]?.label; + if (chart.current.legend.legendItems[index]) { + chart.current.legend.legendItems[index].text = data?.datasets[index]?.label; + } } - } - }); + }); + } else { + chart.current.data.datasets = data.datasets; + } chart.current.options = options; diff --git a/src/components/hooks/queries/useWebsitePageviews.ts b/src/components/hooks/queries/useWebsitePageviews.ts index 0db1fe63..c9260bcb 100644 --- a/src/components/hooks/queries/useWebsitePageviews.ts +++ b/src/components/hooks/queries/useWebsitePageviews.ts @@ -4,14 +4,15 @@ import { useFilterParams } from '..//useFilterParams'; export function useWebsitePageviews( websiteId: string, + compare?: string, options?: Omit, ) { const { get, useQuery } = useApi(); const params = useFilterParams(websiteId); return useQuery({ - queryKey: ['websites:pageviews', { websiteId, ...params }], - queryFn: () => get(`/websites/${websiteId}/pageviews`, params), + queryKey: ['websites:pageviews', { websiteId, ...params, compare }], + queryFn: () => get(`/websites/${websiteId}/pageviews`, { ...params, compare }), enabled: !!websiteId, ...options, }); diff --git a/src/components/hooks/useDateRange.ts b/src/components/hooks/useDateRange.ts index e022d960..248070f4 100644 --- a/src/components/hooks/useDateRange.ts +++ b/src/components/hooks/useDateRange.ts @@ -1,19 +1,25 @@ import { getMinimumUnit, parseDateRange } from 'lib/date'; import { setItem } from 'next-basics'; -import { DATE_RANGE_CONFIG, DEFAULT_DATE_RANGE } from 'lib/constants'; -import websiteStore, { setWebsiteDateRange } from 'store/websites'; +import { DATE_RANGE_CONFIG, DEFAULT_DATE_COMPARE, DEFAULT_DATE_RANGE } from 'lib/constants'; +import websiteStore, { setWebsiteDateRange, setWebsiteDateCompare } from 'store/websites'; import appStore, { setDateRange } from 'store/app'; import { DateRange } from 'lib/types'; import { useLocale } from './useLocale'; import { useApi } from './queries/useApi'; -export function useDateRange(websiteId?: string): [DateRange, (value: string | DateRange) => void] { +export function useDateRange(websiteId?: string): { + dateRange: DateRange; + saveDateRange: (value: string | DateRange) => void; + dateCompare: string; + saveDateCompare: (value: string) => void; +} { const { get } = useApi(); const { locale } = useLocale(); const websiteConfig = websiteStore(state => state[websiteId]?.dateRange); const defaultConfig = DEFAULT_DATE_RANGE; const globalConfig = appStore(state => state.dateRange); const dateRange = parseDateRange(websiteConfig || globalConfig || defaultConfig, locale); + const dateCompare = websiteStore(state => state[websiteId]?.dateCompare || DEFAULT_DATE_COMPARE); const saveDateRange = async (value: DateRange | string) => { if (websiteId) { @@ -45,7 +51,11 @@ export function useDateRange(websiteId?: string): [DateRange, (value: string | D } }; - return [dateRange, saveDateRange]; + const saveDateCompare = (value: string) => { + setWebsiteDateCompare(websiteId, value); + }; + + return { dateRange, saveDateRange, dateCompare, saveDateCompare }; } export default useDateRange; diff --git a/src/components/hooks/useFilterParams.ts b/src/components/hooks/useFilterParams.ts index fd76fd47..ac934d8c 100644 --- a/src/components/hooks/useFilterParams.ts +++ b/src/components/hooks/useFilterParams.ts @@ -4,7 +4,7 @@ import { useTimezone } from './useTimezone'; import { zonedTimeToUtc } from 'date-fns-tz'; export function useFilterParams(websiteId: string) { - const [dateRange] = useDateRange(websiteId); + const { dateRange } = useDateRange(websiteId); const { startDate, endDate, unit } = dateRange; const { timezone } = useTimezone(); const { diff --git a/src/components/input/RefreshButton.tsx b/src/components/input/RefreshButton.tsx index 4515a574..cd68c40a 100644 --- a/src/components/input/RefreshButton.tsx +++ b/src/components/input/RefreshButton.tsx @@ -12,7 +12,7 @@ export function RefreshButton({ isLoading?: boolean; }) { const { formatMessage, labels } = useMessages(); - const [dateRange] = useDateRange(websiteId); + const { dateRange } = useDateRange(websiteId); function handleClick() { if (!isLoading && dateRange) { diff --git a/src/components/input/WebsiteDateFilter.tsx b/src/components/input/WebsiteDateFilter.tsx index 3cb88766..12718b3d 100644 --- a/src/components/input/WebsiteDateFilter.tsx +++ b/src/components/input/WebsiteDateFilter.tsx @@ -8,17 +8,17 @@ import { DateRange } from 'lib/types'; export function WebsiteDateFilter({ websiteId }: { websiteId: string }) { const { dir } = useLocale(); - const [dateRange, setDateRange] = useDateRange(websiteId); + const { dateRange, saveDateRange } = useDateRange(websiteId); const { value, startDate, endDate, offset } = dateRange; const disableForward = value === 'all' || isAfter(getOffsetDateRange(dateRange, 1).startDate, new Date()); const handleChange = (value: string | DateRange) => { - setDateRange(value); + saveDateRange(value); }; const handleIncrement = (increment: number) => { - setDateRange(getOffsetDateRange(dateRange, increment)); + saveDateRange(getOffsetDateRange(dateRange, increment)); }; return ( diff --git a/src/components/metrics/EventsChart.tsx b/src/components/metrics/EventsChart.tsx index eb2fb703..842ae605 100644 --- a/src/components/metrics/EventsChart.tsx +++ b/src/components/metrics/EventsChart.tsx @@ -13,7 +13,9 @@ export interface EventsChartProps { } export function EventsChart({ websiteId, className }: EventsChartProps) { - const [{ startDate, endDate, unit }] = useDateRange(websiteId); + const { + dateRange: { startDate, endDate, unit }, + } = useDateRange(websiteId); const { locale } = useLocale(); const { data, isLoading } = useWebsiteEvents(websiteId); diff --git a/src/components/metrics/FilterTags.tsx b/src/components/metrics/FilterTags.tsx index ee136ae3..60cf90c1 100644 --- a/src/components/metrics/FilterTags.tsx +++ b/src/components/metrics/FilterTags.tsx @@ -24,7 +24,7 @@ export function FilterTags({ }) { const { formatMessage, labels } = useMessages(); const { formatValue } = useFormat(); - const [dateRange] = useDateRange(websiteId); + const { dateRange } = useDateRange(websiteId); const { router, renderUrl, diff --git a/src/components/metrics/MetricCard.module.css b/src/components/metrics/MetricCard.module.css index 1498c38a..ee8f55b1 100644 --- a/src/components/metrics/MetricCard.module.css +++ b/src/components/metrics/MetricCard.module.css @@ -5,13 +5,9 @@ min-width: 150px; } -.card.compare { - gap: 10px; -} - .card.compare .change { font-size: 16px; - padding: 5px 10px; + margin: 10px 0; } .card:first-child { @@ -23,7 +19,7 @@ } .value { - font-size: 40px; + font-size: 36px; font-weight: 700; white-space: nowrap; color: var(--base900); @@ -46,7 +42,7 @@ gap: 5px; font-size: 13px; font-weight: 700; - padding: 0 5px; + padding: 0.1em 0.5em; border-radius: 5px; color: var(--base500); align-self: flex-start; diff --git a/src/components/metrics/MetricCard.tsx b/src/components/metrics/MetricCard.tsx index e727f925..907263af 100644 --- a/src/components/metrics/MetricCard.tsx +++ b/src/components/metrics/MetricCard.tsx @@ -48,7 +48,7 @@ export const MetricCard = ({ [styles.hide]: ~~change === 0, })} > - + diff --git a/src/components/metrics/PageviewsChart.tsx b/src/components/metrics/PageviewsChart.tsx index 347bf155..e82ba306 100644 --- a/src/components/metrics/PageviewsChart.tsx +++ b/src/components/metrics/PageviewsChart.tsx @@ -5,8 +5,12 @@ import { renderDateLabels } from 'lib/charts'; export interface PageviewsChartProps extends BarChartProps { data: { - sessions: any[]; pageviews: any[]; + sessions: any[]; + compare?: { + pageviews: any[]; + sessions: any[]; + }; }; unit: string; isLoading?: boolean; @@ -36,7 +40,25 @@ export function PageviewsChart({ data, unit, isLoading, ...props }: PageviewsCha borderWidth: 1, ...colors.chart.views, }, - ], + data.compare + ? { + type: 'line', + label: formatMessage(labels.visitors), + data: data.compare.pageviews, + borderWidth: 2, + borderColor: '#f15bb5', + } + : null, + data.compare + ? { + type: 'line', + label: formatMessage(labels.visits), + data: data.compare.sessions, + borderWidth: 2, + borderColor: '#9b5de5', + } + : null, + ].filter(n => n), }; }, [data, locale]); diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 03862660..745673e9 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -20,6 +20,7 @@ export const DEFAULT_DATE_RANGE = '24hour'; export const DEFAULT_WEBSITE_LIMIT = 10; export const DEFAULT_RESET_DATE = '2000-01-01'; export const DEFAULT_PAGE_SIZE = 10; +export const DEFAULT_DATE_COMPARE = 'prev'; export const REALTIME_RANGE = 30; export const REALTIME_INTERVAL = 5000; diff --git a/src/lib/date.ts b/src/lib/date.ts index 861bbde2..de76f7f3 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -326,3 +326,13 @@ export function getDateLength(startDate: Date, endDate: Date, unit: string | num const { diff } = DATE_FUNCTIONS[unit]; return diff(endDate, startDate) + 1; } + +export function getCompareDate(compare: string, startDate: Date, endDate: Date) { + if (compare === 'yoy') { + return { startDate: subYears(startDate, 1), endDate: subYears(endDate, 1) }; + } + + const diff = differenceInMinutes(endDate, startDate); + + return { startDate: subMinutes(startDate, diff), endDate: subMinutes(endDate, diff) }; +} diff --git a/src/pages/api/websites/[websiteId]/pageviews.ts b/src/pages/api/websites/[websiteId]/pageviews.ts index 19671064..5b631515 100644 --- a/src/pages/api/websites/[websiteId]/pageviews.ts +++ b/src/pages/api/websites/[websiteId]/pageviews.ts @@ -1,3 +1,4 @@ +import * as yup from 'yup'; import { canViewWebsite } from 'lib/auth'; import { useAuth, useCors, useValidate } from 'lib/middleware'; import { getRequestFilters, getRequestDateRange } from 'lib/request'; @@ -5,6 +6,8 @@ import { NextApiRequestQueryBody, WebsitePageviews } from 'lib/types'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { getPageviewStats, getSessionStats } from 'queries'; +import { TimezoneTest, UnitTypeTest } from 'lib/yup'; +import { getCompareDate } from 'lib/date'; export interface WebsitePageviewRequestQuery { websiteId: string; @@ -21,10 +24,9 @@ export interface WebsitePageviewRequestQuery { country?: string; region: string; city?: string; + compare?: string; } -import { TimezoneTest, UnitTypeTest } from 'lib/yup'; -import * as yup from 'yup'; const schema = { GET: yup.object().shape({ websiteId: yup.string().uuid().required(), @@ -41,6 +43,7 @@ const schema = { country: yup.string(), region: yup.string(), city: yup.string(), + compare: yup.string(), }), }; @@ -52,7 +55,7 @@ export default async ( await useAuth(req, res); await useValidate(schema, req, res); - const { websiteId, timezone } = req.query; + const { websiteId, timezone, compare } = req.query; if (req.method === 'GET') { if (!(await canViewWebsite(req.auth, websiteId))) { @@ -74,6 +77,40 @@ export default async ( getSessionStats(websiteId, filters), ]); + if (compare) { + const { startDate: compareStartDate, endDate: compareEndDate } = getCompareDate( + compare, + startDate, + endDate, + ); + + const [comparePageviews, compareSessions] = await Promise.all([ + getPageviewStats(websiteId, { + ...filters, + startDate: compareStartDate, + endDate: compareEndDate, + }), + getSessionStats(websiteId, { + ...filters, + startDate: compareStartDate, + endDate: compareEndDate, + }), + ]); + + return ok(res, { + pageviews, + sessions, + startDate, + endDate, + compare: { + pageviews: comparePageviews, + sessions: compareSessions, + startDate: compareStartDate, + endDate: compareEndDate, + }, + }); + } + return ok(res, { pageviews, sessions }); } diff --git a/src/pages/api/websites/[websiteId]/stats.ts b/src/pages/api/websites/[websiteId]/stats.ts index 9108e062..1ce616e7 100644 --- a/src/pages/api/websites/[websiteId]/stats.ts +++ b/src/pages/api/websites/[websiteId]/stats.ts @@ -1,4 +1,4 @@ -import { subMinutes, differenceInMinutes } from 'date-fns'; +import * as yup from 'yup'; import { NextApiResponse } from 'next'; import { methodNotAllowed, ok, unauthorized } from 'next-basics'; import { canViewWebsite } from 'lib/auth'; @@ -6,6 +6,7 @@ import { useAuth, useCors, useValidate } from 'lib/middleware'; import { NextApiRequestQueryBody, WebsiteStats } from 'lib/types'; import { getRequestFilters, getRequestDateRange } from 'lib/request'; import { getWebsiteStats } from 'queries'; +import { getCompareDate } from 'lib/date'; export interface WebsiteStatsRequestQuery { websiteId: string; @@ -25,7 +26,6 @@ export interface WebsiteStatsRequestQuery { compare?: string; } -import * as yup from 'yup'; const schema = { GET: yup.object().shape({ websiteId: yup.string().uuid().required(), @@ -54,7 +54,7 @@ export default async ( await useAuth(req, res); await useValidate(schema, req, res); - const { websiteId } = req.query; + const { websiteId, compare } = req.query; if (req.method === 'GET') { if (!(await canViewWebsite(req.auth, websiteId))) { @@ -62,9 +62,11 @@ export default async ( } const { startDate, endDate } = await getRequestDateRange(req); - const diff = differenceInMinutes(endDate, startDate); - const prevStartDate = subMinutes(startDate, diff); - const prevEndDate = subMinutes(endDate, diff); + const { startDate: compareStartDate, endDate: compareEndDate } = getCompareDate( + compare, + startDate, + endDate, + ); const filters = getRequestFilters(req); @@ -72,8 +74,8 @@ export default async ( const prevPeriod = await getWebsiteStats(websiteId, { ...filters, - startDate: prevStartDate, - endDate: prevEndDate, + startDate: compareStartDate, + endDate: compareEndDate, }); const stats = Object.keys(metrics[0]).reduce((obj, key) => { diff --git a/src/queries/analytics/pageviews/getPageviewStats.ts b/src/queries/analytics/pageviews/getPageviewStats.ts index 3f29c75f..a37a1566 100644 --- a/src/queries/analytics/pageviews/getPageviewStats.ts +++ b/src/queries/analytics/pageviews/getPageviewStats.ts @@ -67,7 +67,7 @@ async function clickhouseQuery( `, params, ).then(result => { - return Object.values(result).map(a => { + return Object.values(result).map((a: any) => { return { x: a.x, y: Number(a.y) }; }); }); diff --git a/src/store/websites.ts b/src/store/websites.ts index a9f6b44d..1c5c21fc 100644 --- a/src/store/websites.ts +++ b/src/store/websites.ts @@ -18,4 +18,18 @@ export function setWebsiteDateRange(websiteId: string, dateRange: DateRange) { ); } +export function setWebsiteDateCompare(websiteId: string, dateCompare: string) { + store.setState( + produce(state => { + if (!state[websiteId]) { + state[websiteId] = {}; + } + + state[websiteId].dateCompare = dateCompare; + + return state; + }), + ); +} + export default store;