Skip to content

Commit bfa01bf

Browse files
authored
Limit maximum date to today in calendars (#4746)
* Limit maximum date to today in calendars * Add test * Make calendar max dates sensitive to site timezone
1 parent 40f28ed commit bfa01bf

File tree

7 files changed

+112
-21
lines changed

7 files changed

+112
-21
lines changed

assets/jest.config.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
"globals": {
77
"BUILD_EXTRA": true
88
},
9-
"setupFiles": ["<rootDir>/test-utils/set-fixed-timezone.ts"],
109
"setupFilesAfterEnv": [
1110
"<rootDir>/test-utils/extend-expect.ts",
1211
"<rootDir>/test-utils/reset-state.ts"
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/** @format */
2+
3+
import React from 'react'
4+
import { render, screen } from '@testing-library/react'
5+
import { DateRangeCalendar } from './date-range-calendar'
6+
import userEvent from '@testing-library/user-event'
7+
8+
test('renders with default dates in view, respects max and min dates', async () => {
9+
const onCloseWithNoSelection = jest.fn()
10+
const onCloseWithSelection = jest.fn()
11+
const handlers = { onCloseWithNoSelection, onCloseWithSelection }
12+
13+
render(
14+
<DateRangeCalendar
15+
minDate="2024-09-10"
16+
maxDate="2024-09-25"
17+
defaultDates={['2024-09-12', '2024-09-19']}
18+
{...handlers}
19+
/>
20+
)
21+
22+
const days = await screen.queryAllByLabelText(/, 2024/)
23+
24+
expect(
25+
days.map((d) => [d.getAttribute('aria-label'), d.getAttribute('class')])
26+
).toEqual([
27+
['September 1, 2024', 'flatpickr-day flatpickr-disabled'],
28+
['September 2, 2024', 'flatpickr-day flatpickr-disabled'],
29+
['September 3, 2024', 'flatpickr-day flatpickr-disabled'],
30+
['September 4, 2024', 'flatpickr-day flatpickr-disabled'],
31+
['September 5, 2024', 'flatpickr-day flatpickr-disabled'],
32+
['September 6, 2024', 'flatpickr-day flatpickr-disabled'],
33+
['September 7, 2024', 'flatpickr-day flatpickr-disabled'],
34+
['September 8, 2024', 'flatpickr-day flatpickr-disabled'],
35+
['September 9, 2024', 'flatpickr-day flatpickr-disabled'],
36+
['September 10, 2024', 'flatpickr-day'],
37+
['September 11, 2024', 'flatpickr-day'],
38+
['September 12, 2024', 'flatpickr-day selected startRange'],
39+
['September 13, 2024', 'flatpickr-day inRange'],
40+
['September 14, 2024', 'flatpickr-day inRange'],
41+
['September 15, 2024', 'flatpickr-day inRange'],
42+
['September 16, 2024', 'flatpickr-day inRange'],
43+
['September 17, 2024', 'flatpickr-day inRange'],
44+
['September 18, 2024', 'flatpickr-day inRange'],
45+
['September 19, 2024', 'flatpickr-day selected endRange'],
46+
['September 20, 2024', 'flatpickr-day'],
47+
['September 21, 2024', 'flatpickr-day'],
48+
['September 22, 2024', 'flatpickr-day'],
49+
['September 23, 2024', 'flatpickr-day'],
50+
['September 24, 2024', 'flatpickr-day'],
51+
['September 25, 2024', 'flatpickr-day'],
52+
['September 26, 2024', 'flatpickr-day flatpickr-disabled'],
53+
['September 27, 2024', 'flatpickr-day flatpickr-disabled'],
54+
['September 28, 2024', 'flatpickr-day flatpickr-disabled'],
55+
['September 29, 2024', 'flatpickr-day flatpickr-disabled'],
56+
['September 30, 2024', 'flatpickr-day flatpickr-disabled'],
57+
['October 1, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
58+
['October 2, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
59+
['October 3, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
60+
['October 4, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
61+
['October 5, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
62+
['October 6, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
63+
['October 7, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
64+
['October 8, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
65+
['October 9, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
66+
['October 10, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
67+
['October 11, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled'],
68+
['October 12, 2024', 'flatpickr-day nextMonthDay flatpickr-disabled']
69+
])
70+
71+
const newStart = await screen.getByLabelText('September 20, 2024')
72+
await userEvent.click(newStart)
73+
const newEnd = await screen.getByLabelText('September 25, 2024')
74+
await userEvent.click(newEnd)
75+
76+
expect(onCloseWithSelection).toHaveBeenCalledTimes(1)
77+
expect(onCloseWithSelection).toHaveBeenLastCalledWith([
78+
new Date('2024-09-20'),
79+
new Date('2024-09-25')
80+
])
81+
})

assets/js/dashboard/datepicker.tsx

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* @format */
22
import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'
3-
import { formatDateRange, formatISO } from './util/date'
3+
import { formatDateRange, formatISO, nowForSite } from './util/date'
44
import {
55
shiftQueryPeriod,
66
getDateForShiftedPeriod,
@@ -322,14 +322,16 @@ export default function QueryPeriodPicker() {
322322
() => getCompareLinkItem({ site, query }),
323323
[site, query]
324324
)
325-
const groups = useMemo(() => {
325+
326+
const datePeriodGroups = useMemo(() => {
326327
const groups = getDatePeriodGroups(site)
327328
// add Custom Range link to the last group
328329
groups[groups.length - 1].push(customRangeLink)
330+
329331
if (COMPARISON_DISABLED_PERIODS.includes(query.period)) {
330332
return groups
331333
}
332-
// maybe ass Compare link as another group to the very end
334+
// maybe add Compare link as another group to the very end
333335
return groups.concat([[compareLink]])
334336
}, [site, query, customRangeLink, compareLink])
335337

@@ -364,14 +366,15 @@ export default function QueryPeriodPicker() {
364366
}}
365367
>
366368
{menuVisible === 'datemenu' && (
367-
<QueryPeriodsMenu groups={groups} closeMenu={closeMenu} />
369+
<QueryPeriodsMenu groups={datePeriodGroups} closeMenu={closeMenu} />
368370
)}
369371
{menuVisible === 'datemenu-calendar' && (
370372
<DateRangeCalendar
371373
onCloseWithSelection={(selection) =>
372374
navigate({ search: getSearchToApplyCustomDates(selection) })
373375
}
374376
minDate={site.statsBegin}
377+
maxDate={formatISO(nowForSite(site))}
375378
defaultDates={
376379
query.to && query.from
377380
? [formatISO(query.from), formatISO(query.to)]
@@ -415,6 +418,7 @@ export default function QueryPeriodPicker() {
415418
})
416419
}
417420
minDate={site.statsBegin}
421+
maxDate={formatISO(nowForSite(site))}
418422
defaultDates={
419423
query.compare_from && query.compare_to
420424
? [
@@ -432,7 +436,7 @@ export default function QueryPeriodPicker() {
432436
<>
433437
<ArrowKeybind keyboardKey="ArrowLeft" />
434438
<ArrowKeybind keyboardKey="ArrowRight" />
435-
{groups
439+
{datePeriodGroups
436440
.concat([[last6MonthsLinkItem]])
437441
.flatMap((group) =>
438442
group

assets/js/dashboard/query-time-periods.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,12 @@ export const getDatePeriodGroups = (
398398
export const last6MonthsLinkItem: LinkItem = [
399399
['Last 6 months', 'S'],
400400
{
401-
search: (s) => ({ ...s, period: QueryPeriod['6mo'], keybindHint: 'S' }),
401+
search: (s) => ({
402+
...s,
403+
...clearedDateSearch,
404+
period: QueryPeriod['6mo'],
405+
keybindHint: 'S'
406+
}),
402407
isActive: ({ query }) => query.period === QueryPeriod['6mo']
403408
}
404409
]

assets/js/dashboard/util/date.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@ import { formatISO, nowForSite, shiftMonths, yesterday } from './date'
44

55
jest.useFakeTimers()
66

7+
describe(`${nowForSite.name} and ${formatISO.name}`, () => {
8+
/* prettier-ignore */
9+
const cases = [
10+
[ 'Los Angeles/America', -3600 * 6, '2024-11-01T20:00:00.000Z', '2024-11-01' ],
11+
[ 'Sydney/Australia', 3600 * 6, '2024-11-01T20:00:00.000Z', '2024-11-02' ]
12+
]
13+
test.each(cases)(
14+
'in timezone of %s (offset %p) at %s, today is %s',
15+
(_tz, offset, utcTime, expectedToday) => {
16+
jest.setSystemTime(new Date(utcTime))
17+
expect(formatISO(nowForSite({ offset }))).toEqual(expectedToday)
18+
}
19+
)
20+
})
21+
722
/* prettier-ignore */
823
const dstChangeOverDayEstonia = [
924
// system time today yesterday today-2mo today+2mo today-12mo offset

assets/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "1.4.0",
44
"license": "AGPL-3.0-or-later",
55
"scripts": {
6-
"test": "jest",
6+
"test": "TZ=UTC jest",
77
"format": "prettier --write",
88
"check-format": "prettier --check **/*.{js,css,ts,tsx} --require-pragma",
99
"eslint": "eslint js/**",

assets/test-utils/set-fixed-timezone.ts

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)