Skip to content

Commit

Permalink
Limit maximum date to today in calendars (#4746)
Browse files Browse the repository at this point in the history
* Limit maximum date to today in calendars

* Add test

* Make calendar max dates sensitive to site timezone
  • Loading branch information
apata authored Nov 4, 2024
1 parent 40f28ed commit bfa01bf
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 21 deletions.
1 change: 0 additions & 1 deletion assets/jest.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"globals": {
"BUILD_EXTRA": true
},
"setupFiles": ["<rootDir>/test-utils/set-fixed-timezone.ts"],
"setupFilesAfterEnv": [
"<rootDir>/test-utils/extend-expect.ts",
"<rootDir>/test-utils/reset-state.ts"
Expand Down
81 changes: 81 additions & 0 deletions assets/js/dashboard/date-range-calendar.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/** @format */

import React from 'react'
import { render, screen } from '@testing-library/react'
import { DateRangeCalendar } from './date-range-calendar'
import userEvent from '@testing-library/user-event'

test('renders with default dates in view, respects max and min dates', async () => {
const onCloseWithNoSelection = jest.fn()
const onCloseWithSelection = jest.fn()
const handlers = { onCloseWithNoSelection, onCloseWithSelection }

render(
<DateRangeCalendar
minDate="2024-09-10"
maxDate="2024-09-25"
defaultDates={['2024-09-12', '2024-09-19']}
{...handlers}
/>
)

const days = await screen.queryAllByLabelText(/, 2024/)

expect(
days.map((d) => [d.getAttribute('aria-label'), d.getAttribute('class')])
).toEqual([
['September 1, 2024', 'flatpickr-day flatpickr-disabled'],
['September 2, 2024', 'flatpickr-day flatpickr-disabled'],
['September 3, 2024', 'flatpickr-day flatpickr-disabled'],
['September 4, 2024', 'flatpickr-day flatpickr-disabled'],
['September 5, 2024', 'flatpickr-day flatpickr-disabled'],
['September 6, 2024', 'flatpickr-day flatpickr-disabled'],
['September 7, 2024', 'flatpickr-day flatpickr-disabled'],
['September 8, 2024', 'flatpickr-day flatpickr-disabled'],
['September 9, 2024', 'flatpickr-day flatpickr-disabled'],
['September 10, 2024', 'flatpickr-day'],
['September 11, 2024', 'flatpickr-day'],
['September 12, 2024', 'flatpickr-day selected startRange'],
['September 13, 2024', 'flatpickr-day inRange'],
['September 14, 2024', 'flatpickr-day inRange'],
['September 15, 2024', 'flatpickr-day inRange'],
['September 16, 2024', 'flatpickr-day inRange'],
['September 17, 2024', 'flatpickr-day inRange'],
['September 18, 2024', 'flatpickr-day inRange'],
['September 19, 2024', 'flatpickr-day selected endRange'],
['September 20, 2024', 'flatpickr-day'],
['September 21, 2024', 'flatpickr-day'],
['September 22, 2024', 'flatpickr-day'],
['September 23, 2024', 'flatpickr-day'],
['September 24, 2024', 'flatpickr-day'],
['September 25, 2024', 'flatpickr-day'],
['September 26, 2024', 'flatpickr-day flatpickr-disabled'],
['September 27, 2024', 'flatpickr-day flatpickr-disabled'],
['September 28, 2024', 'flatpickr-day flatpickr-disabled'],
['September 29, 2024', 'flatpickr-day flatpickr-disabled'],
['September 30, 2024', 'flatpickr-day flatpickr-disabled'],
['October 1, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 2, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 3, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 4, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 5, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 6, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 7, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 8, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 9, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 10, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 11, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
['October 12, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled']
])

const newStart = await screen.getByLabelText('September 20, 2024')
await userEvent.click(newStart)
const newEnd = await screen.getByLabelText('September 25, 2024')
await userEvent.click(newEnd)

expect(onCloseWithSelection).toHaveBeenCalledTimes(1)
expect(onCloseWithSelection).toHaveBeenLastCalledWith([
new Date('2024-09-20'),
new Date('2024-09-25')
])
})
14 changes: 9 additions & 5 deletions assets/js/dashboard/datepicker.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* @format */
import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'
import { formatDateRange, formatISO } from './util/date'
import { formatDateRange, formatISO, nowForSite } from './util/date'
import {
shiftQueryPeriod,
getDateForShiftedPeriod,
Expand Down Expand Up @@ -322,14 +322,16 @@ export default function QueryPeriodPicker() {
() => getCompareLinkItem({ site, query }),
[site, query]
)
const groups = useMemo(() => {

const datePeriodGroups = useMemo(() => {
const groups = getDatePeriodGroups(site)
// add Custom Range link to the last group
groups[groups.length - 1].push(customRangeLink)

if (COMPARISON_DISABLED_PERIODS.includes(query.period)) {
return groups
}
// maybe ass Compare link as another group to the very end
// maybe add Compare link as another group to the very end
return groups.concat([[compareLink]])
}, [site, query, customRangeLink, compareLink])

Expand Down Expand Up @@ -364,14 +366,15 @@ export default function QueryPeriodPicker() {
}}
>
{menuVisible === 'datemenu' && (
<QueryPeriodsMenu groups={groups} closeMenu={closeMenu} />
<QueryPeriodsMenu groups={datePeriodGroups} closeMenu={closeMenu} />
)}
{menuVisible === 'datemenu-calendar' && (
<DateRangeCalendar
onCloseWithSelection={(selection) =>
navigate({ search: getSearchToApplyCustomDates(selection) })
}
minDate={site.statsBegin}
maxDate={formatISO(nowForSite(site))}
defaultDates={
query.to && query.from
? [formatISO(query.from), formatISO(query.to)]
Expand Down Expand Up @@ -415,6 +418,7 @@ export default function QueryPeriodPicker() {
})
}
minDate={site.statsBegin}
maxDate={formatISO(nowForSite(site))}
defaultDates={
query.compare_from && query.compare_to
? [
Expand All @@ -432,7 +436,7 @@ export default function QueryPeriodPicker() {
<>
<ArrowKeybind keyboardKey="ArrowLeft" />
<ArrowKeybind keyboardKey="ArrowRight" />
{groups
{datePeriodGroups
.concat([[last6MonthsLinkItem]])
.flatMap((group) =>
group
Expand Down
7 changes: 6 additions & 1 deletion assets/js/dashboard/query-time-periods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,12 @@ export const getDatePeriodGroups = (
export const last6MonthsLinkItem: LinkItem = [
['Last 6 months', 'S'],
{
search: (s) => ({ ...s, period: QueryPeriod['6mo'], keybindHint: 'S' }),
search: (s) => ({
...s,
...clearedDateSearch,
period: QueryPeriod['6mo'],
keybindHint: 'S'
}),
isActive: ({ query }) => query.period === QueryPeriod['6mo']
}
]
Expand Down
15 changes: 15 additions & 0 deletions assets/js/dashboard/util/date.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ import { formatISO, nowForSite, shiftMonths, yesterday } from './date'

jest.useFakeTimers()

describe(`${nowForSite.name} and ${formatISO.name}`, () => {
/* prettier-ignore */
const cases = [
[ 'Los Angeles/America', -3600 * 6, '2024-11-01T20:00:00.000Z', '2024-11-01' ],
[ 'Sydney/Australia', 3600 * 6, '2024-11-01T20:00:00.000Z', '2024-11-02' ]
]
test.each(cases)(
'in timezone of %s (offset %p) at %s, today is %s',
(_tz, offset, utcTime, expectedToday) => {
jest.setSystemTime(new Date(utcTime))
expect(formatISO(nowForSite({ offset }))).toEqual(expectedToday)
}
)
})

/* prettier-ignore */
const dstChangeOverDayEstonia = [
// system time today yesterday today-2mo today+2mo today-12mo offset
Expand Down
2 changes: 1 addition & 1 deletion assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.4.0",
"license": "AGPL-3.0-or-later",
"scripts": {
"test": "jest",
"test": "TZ=UTC jest",
"format": "prettier --write",
"check-format": "prettier --check **/*.{js,css,ts,tsx} --require-pragma",
"eslint": "eslint js/**",
Expand Down
13 changes: 0 additions & 13 deletions assets/test-utils/set-fixed-timezone.ts

This file was deleted.

0 comments on commit bfa01bf

Please sign in to comment.