{
- this.onInputChange(event)
- // eslint-disable-next-line no-underscore-dangle
- picker.current._closeCalendar()
- if (filterType === 'collection') {
- onChange(event.target.value, false, 'Typed')
- }
- },
- onBlur: onInputBlur,
- onFocus: onInputFocus,
- onKeyDown,
- ...conditionalInputProps
+
+ {
+ this.onInputChange(event)
+ // eslint-disable-next-line no-underscore-dangle
+ picker.current._closeCalendar()
+ if (filterType === 'collection') {
+ onChange(event.target.value, false, 'Typed')
+ }
+ },
+ onBlur: onInputBlur,
+ onFocus: onInputFocus,
+
+ onKeyDown,
+ ...conditionalInputProps
+ }
}
- }
- isValidDate={isValidDate}
- onChange={onChange}
- ref={picker}
- strictParsing
- timeFormat={false}
- utc
- value={value}
- viewMode={viewMode}
- />
+ isValidDate={isValidDate}
+ onChange={onChange}
+ onOpen={
+ () => {
+ requestAnimationFrame(() => this.setupCalendar())
+ }
+ }
+ ref={picker}
+ strictParsing
+ timeFormat={false}
+ utc
+ value={value}
+ viewMode={viewMode}
+ />
+
)
}
}
diff --git a/static/src/js/components/Datepicker/__tests__/Datepicker.test.jsx b/static/src/js/components/Datepicker/__tests__/Datepicker.test.jsx
index cc0bfdd16d..50b697730b 100644
--- a/static/src/js/components/Datepicker/__tests__/Datepicker.test.jsx
+++ b/static/src/js/components/Datepicker/__tests__/Datepicker.test.jsx
@@ -3,8 +3,10 @@ import React from 'react'
import {
act,
render,
- screen
+ screen,
+ waitFor
} from '@testing-library/react'
+import MockDate from 'mockdate'
import userEvent from '@testing-library/user-event'
@@ -50,6 +52,14 @@ const setup = (overrideProps) => {
}
describe('Datepicker component', () => {
+ beforeEach(() => {
+ MockDate.set('2024-01-01T01:00:00.000Z')
+ })
+
+ afterEach(() => {
+ MockDate.reset()
+ })
+
describe('on render', () => {
test('creates the custom buttons', () => {
setup()
@@ -112,7 +122,7 @@ describe('Datepicker component', () => {
await user.type(datePickerInput, '1')
})
- expect(requestAnimationFrameSpy).toHaveBeenCalledTimes(1)
+ expect(requestAnimationFrameSpy).toHaveBeenCalledTimes(2)
expect(requestAnimationFrameSpy).toHaveBeenCalledWith(expect.any(Function))
expect(closeCalendarSpy).toHaveBeenCalledTimes(1)
@@ -216,4 +226,134 @@ describe('Datepicker component', () => {
expect(navigateSpy).toHaveBeenCalledWith('month')
})
})
+
+ describe('when handling navigation arrows and month display', () => {
+ describe('in years viewMode', () => {
+ test('renders initial year range view correctly', async () => {
+ const { user } = setup({ viewMode: 'years' })
+
+ // Open the calendar
+ const input = screen.getByRole('textbox', { name: 'Date Time' })
+ await user.click(input)
+
+ // Verify year range header and navigation
+ const yearHeader = screen.getByRole('columnheader', { name: '2020-2029' })
+ expect(yearHeader).toBeInTheDocument()
+
+ const prevNav = screen.getByRole('columnheader', { name: '‹' })
+ const nextNav = screen.getByRole('columnheader', { name: '›' })
+ expect(prevNav).toBeVisible()
+ expect(nextNav).toBeVisible()
+ })
+
+ test('allows normal navigation between year ranges', async () => {
+ const { user } = setup({ viewMode: 'years' })
+
+ // Open the calendar
+ const input = screen.getByRole('textbox', { name: 'Date Time' })
+ await user.click(input)
+
+ const prevNav = screen.getByRole('columnheader', { name: '‹' })
+ await user.click(prevNav)
+
+ const prevDecadeHeader = screen.getByRole('columnheader', { name: '2010-2019' })
+ expect(prevDecadeHeader).toBeInTheDocument()
+
+ const nextNav = screen.getByRole('columnheader', { name: '›' })
+ await user.click(nextNav)
+
+ const currentDecadeHeader = screen.getByRole('columnheader', { name: '2020-2029' })
+ expect(currentDecadeHeader).toBeInTheDocument()
+ })
+ })
+
+ describe('in months viewMode', () => {
+ test('displays month selection without year and handles navigation visibility', async () => {
+ const { user } = setup({
+ viewMode: 'months',
+ value: '06-01 00:00:00',
+ format: 'MM-DD HH:mm:ss',
+ shouldValidate: false,
+ isValidDate: jest.fn().mockReturnValue(true)
+ })
+
+ // Open the calendar
+ const input = screen.getByRole('textbox', { name: 'Date Time' })
+ await user.click(input)
+
+ // Initial month selection view should have year and navigation
+ const [prevNav, monthSwitch, nextNav] = screen.getAllByRole('columnheader')
+ expect(monthSwitch).toHaveTextContent('2024')
+ expect(prevNav).toBeVisible()
+ expect(nextNav).toBeVisible()
+
+ // Verify June is selected
+ const juneCell = screen.getByRole('cell', { name: 'Jun' })
+ expect(juneCell).toHaveClass('rdtMonth', 'rdtActive')
+
+ // Click June to enter days view
+ await user.click(juneCell)
+
+ // Get fresh references after entering days view
+ const [currentPrevNav, currentMonthSwitch, currentNextNav] = screen
+ .getAllByRole('columnheader')
+ .filter((header) => header.className.includes('rdtPrev')
+ || header.className.includes('rdtSwitch')
+ || header.className.includes('rdtNext'))
+
+ // June state in days view
+ await waitFor(() => {
+ expect(currentMonthSwitch).toHaveTextContent('June')
+ })
+
+ expect(currentMonthSwitch).not.toHaveTextContent('2024')
+ expect(currentPrevNav).toBeVisible()
+ expect(currentNextNav).toBeVisible()
+
+ // Navigate to January using prev nav
+ await user.click(currentPrevNav) // May
+ await user.click(currentPrevNav) // April
+ await user.click(currentPrevNav) // March
+ await user.click(currentPrevNav) // February
+ await user.click(currentPrevNav) // January
+
+ // January state in days view
+ await waitFor(() => {
+ expect(currentMonthSwitch).toHaveTextContent('January')
+ })
+
+ await waitFor(() => {
+ expect(currentMonthSwitch).not.toHaveTextContent('2024')
+ })
+
+ expect(currentPrevNav).not.toBeVisible() // Hidden in January
+ expect(currentNextNav).toBeVisible()
+
+ // Navigate from February to December
+ await user.click(currentNextNav) // February
+ await user.click(currentNextNav) // March
+ await user.click(currentNextNav) // April
+ await user.click(currentNextNav) // May
+ await user.click(currentNextNav) // June
+ await user.click(currentNextNav) // July
+ await user.click(currentNextNav) // August
+ await user.click(currentNextNav) // September
+ await user.click(currentNextNav) // October
+ await user.click(currentNextNav) // November
+ await user.click(currentNextNav) // December
+
+ // December state in days view
+ await waitFor(() => {
+ expect(currentMonthSwitch).toHaveTextContent('December')
+ })
+
+ await waitFor(() => {
+ expect(currentMonthSwitch).not.toHaveTextContent('2024')
+ })
+
+ expect(currentPrevNav).toBeVisible()
+ expect(currentNextNav).not.toBeVisible() // Hidden in December
+ })
+ })
+ })
})
diff --git a/static/src/js/components/GranuleFilters/GranuleFiltersForm.jsx b/static/src/js/components/GranuleFilters/GranuleFiltersForm.jsx
index 0ffe0433fa..6b8d27369a 100644
--- a/static/src/js/components/GranuleFilters/GranuleFiltersForm.jsx
+++ b/static/src/js/components/GranuleFilters/GranuleFiltersForm.jsx
@@ -15,6 +15,7 @@ import { findGridByName } from '../../util/grid'
import { getTemporalDateFormat } from '../../../../../sharedUtils/edscDate'
import { getValueForTag } from '../../../../../sharedUtils/tags'
import { pluralize } from '../../util/pluralize'
+import { getApplicationConfig } from '../../../../../sharedUtils/config'
import SidebarFiltersItem from '../Sidebar/SidebarFiltersItem'
import SidebarFiltersList from '../Sidebar/SidebarFiltersList'
@@ -26,6 +27,7 @@ import './GranuleFiltersForm.scss'
/**
* Renders GranuleFiltersForm.
+ * @param {Object} props - The props passed into the component.
* @param {Object} props.collectionMetadata - The focused collections metadata.
* @param {Object} props.errors - Form errors provided by Formik.
* @param {Object} props.excludedGranuleIds - The list of excluded granules.
@@ -34,12 +36,8 @@ import './GranuleFiltersForm.scss'
* @param {Function} props.handleSubmit - Callback function passed from the container.
* @param {Function} props.setFieldTouched - Callback function provided by Formik.
* @param {Function} props.setFieldValue - Callback function provided by Formik.
- * @param {Object} props - The props passed into the component.
- * @param {Object} props.collectionMetadata - The focused collection metadata.
* @param {Object} props.onMetricsGranuleFilter - Callback function passed from actions.
* @param {Object} props.onUndoExcludeGranule - Callback function passed from actions.
- * @param {Function} props.setFieldTouched - Callback function provided by Formik.
- * @param {Function} props.setFieldValue - Callback function provided by Formik.
* @param {Object} props.touched - Form state provided by Formik.
* @param {Object} props.values - Form values provided by Formik.
*/
@@ -78,6 +76,15 @@ export const GranuleFiltersForm = (props) => {
// For recurring dates we don't show the year, it's displayed on the slider
const temporalDateFormat = getTemporalDateFormat(isRecurring)
+ const {
+ minimumTemporalDateString,
+ temporalDateFormatFull
+ } = getApplicationConfig()
+ const minDate = moment(
+ minimumTemporalDateString,
+ temporalDateFormatFull
+ )
+
const {
min: cloudCoverMin = '',
max: cloudCoverMax = ''
@@ -439,7 +446,15 @@ export const GranuleFiltersForm = (props) => {
size="sm"
format={temporalDateFormat}
temporal={temporal}
+ displayStartDate={temporal.startDate}
+ displayEndDate={temporal.endDate}
validate={false}
+ onSliderChange={
+ (value) => {
+ setFieldValue('temporal.startDate', moment(temporal.startDate).year(value.min).toISOString())
+ setFieldValue('temporal.endDate', moment(temporal.endDate).year(value.max).toISOString())
+ }
+ }
onRecurringToggle={
(event) => {
const isChecked = event.target.checked
@@ -447,17 +462,23 @@ export const GranuleFiltersForm = (props) => {
setFieldValue('temporal.isRecurring', isChecked)
setFieldTouched('temporal.isRecurring', isChecked)
- // If recurring is checked and values exist, set the recurringDay values
- if (isChecked) {
- const newStartDate = moment(temporal.startDate || undefined).utc()
+ if (isChecked && temporal) {
if (temporal.startDate) {
- setFieldValue('temporal.recurringDayStart', newStartDate.dayOfYear())
- }
+ const startDate = moment(temporal.startDate).utc()
+
+ if (temporal.endDate) {
+ const endDate = moment(temporal.endDate).utc()
- const newEndDate = moment(temporal.endDate || undefined).utc()
- if (temporal.endDate) {
- // Use the start year to calculate the end day of year. This avoids leap years potentially causing day mismatches
- setFieldValue('temporal.recurringDayEnd', newEndDate.year(newStartDate.year()).dayOfYear())
+ if (startDate.year() === endDate.year()) {
+ // Preserve original month/day while setting to minimum year
+ const newStartDate = moment(startDate).year(minDate.year())
+ setFieldValue('temporal.startDate', newStartDate.toISOString())
+ }
+
+ setFieldValue('temporal.recurringDayStart', startDate.dayOfYear())
+ // Use the start year to calculate the end day of year. This avoids leap years potentially causing day mismatches
+ setFieldValue('temporal.recurringDayEnd', endDate.year(startDate.year()).dayOfYear())
+ }
}
}
@@ -502,15 +523,33 @@ export const GranuleFiltersForm = (props) => {
}
onSubmitStart={
(startDate, shouldSubmit) => {
+ const { temporal: newTemporal } = values
+
+ // If the recurring toggle is toggled on, the format of the date drops the year, when
+ // converted into a moment object, this will erroneously set the year to the current year.
+ // To avoid this, we check if the temporal is recurring and set the year to the existing year in
+ // state.
+ if (newTemporal.isRecurring) {
+ const existingStartDate = moment(newTemporal.startDate)
+ if (existingStartDate.isValid()) {
+ const existingStartDateYear = existingStartDate.year()
+ startDate.year(existingStartDateYear)
+ }
+ }
+
const { input } = startDate.creationData()
const value = startDate.isValid() ? startDate.toISOString() : input
-
setFieldValue('temporal.startDate', value)
setFieldTouched('temporal.startDate')
- const { temporal: newTemporal } = values
- if (newTemporal.isRecurring) {
- setFieldValue('temporal.recurringDayStart', startDate.dayOfYear())
+ if (newTemporal.isRecurring && newTemporal.endDate && startDate.isValid()) {
+ const endDate = moment(newTemporal.endDate).utc()
+
+ if (startDate.year() === endDate.year()) {
+ // Preserve original month/day while setting to minimum year
+ startDate.year(minDate.year())
+ setFieldValue('temporal.startDate', startDate.toISOString())
+ }
}
// Only call handleSubmit if `onSubmitStart` was called
@@ -527,15 +566,32 @@ export const GranuleFiltersForm = (props) => {
}
onSubmitEnd={
(endDate, shouldSubmit) => {
+ const { temporal: newTemporal } = values
+
+ // Like with start date, if the recurring toggle is toggled on, the format of the date drops the year.
+ // To avoid this, we check if the temporal is recurring and set the year to the existing year in state.
+ if (newTemporal.isRecurring) {
+ const existingEndDate = moment(newTemporal.endDate)
+ if (existingEndDate.isValid()) {
+ const existingEndDateYear = existingEndDate.year()
+ endDate.year(existingEndDateYear)
+ }
+ }
+
const { input } = endDate.creationData()
const value = endDate.isValid() ? endDate.toISOString() : input
setFieldValue('temporal.endDate', value)
setFieldTouched('temporal.endDate')
- const { temporal: newTemporal } = values
- if (newTemporal.isRecurring) {
- setFieldValue('temporal.recurringDayEnd', endDate.dayOfYear())
+ if (newTemporal.isRecurring && newTemporal.startDate && endDate.isValid()) {
+ const startDate = moment(newTemporal.startDate).utc()
+
+ if (startDate.year() === endDate.year()) {
+ // Preserve original month/day while setting to minimum year
+ startDate.year(minDate.year())
+ setFieldValue('temporal.startDate', startDate.toISOString())
+ }
}
if (shouldSubmit && (endDate.isValid() || !input)) {
@@ -851,6 +907,14 @@ export const GranuleFiltersForm = (props) => {
size="sm"
format={temporalDateFormat}
temporal={equatorCrossingDate}
+ displayStartDate={equatorCrossingDate.startDate}
+ displayEndDate={equatorCrossingDate.endDate}
+ onSliderChange={
+ (value) => {
+ setFieldValue('temporal.startDate', moment(temporal.startDate).year(value.min).toISOString())
+ setFieldValue('temporal.endDate', moment(temporal.endDate).year(value.max).toISOString())
+ }
+ }
validate={false}
onSubmitStart={
(startDate, shouldSubmit) => {
diff --git a/static/src/js/components/GranuleFilters/__tests__/GranuleFiltersForm.test.jsx b/static/src/js/components/GranuleFilters/__tests__/GranuleFiltersForm.test.jsx
index daaf6c325f..c28e0cbb3d 100644
--- a/static/src/js/components/GranuleFilters/__tests__/GranuleFiltersForm.test.jsx
+++ b/static/src/js/components/GranuleFilters/__tests__/GranuleFiltersForm.test.jsx
@@ -41,7 +41,13 @@ const setup = (overrideProps) => {
setFieldValue,
setFieldTouched,
touched: {},
- values: {},
+ values: {
+ temporal: {
+ isRecurring: false,
+ startDate: '',
+ endDate: ''
+ }
+ },
...overrideProps
}
@@ -1545,4 +1551,136 @@ describe('GranuleFiltersForm component', () => {
expect(screen.getByText(gridCoordinatesMessage)).toBeVisible()
})
})
+
+ describe('Recurring date toggle behavior', () => {
+ test('when toggling recurring with same year dates, adjusts start date to minimum year', async () => {
+ const {
+ setFieldValue, setFieldTouched, handleSubmit, onMetricsGranuleFilter, user
+ } = setup({
+ values: {
+ temporal: {
+ startDate: '2024-03-01T00:00:00.000Z',
+ endDate: '2024-12-31T23:59:59.999Z',
+ isRecurring: false
+ }
+ }
+ })
+
+ const recurringCheckbox = screen.getByRole('checkbox', { name: 'Recurring?' })
+ await user.click(recurringCheckbox)
+
+ // Verify isRecurring was set
+ expect(setFieldValue).toHaveBeenCalledWith('temporal.isRecurring', true)
+ expect(setFieldTouched).toHaveBeenCalledWith('temporal.isRecurring', true)
+
+ // Verify start date was adjusted to minimum year while preserving month/day
+ expect(setFieldValue).toHaveBeenCalledWith('temporal.startDate', '1960-03-01T00:00:00.000Z')
+
+ // Verify recurringDay values were set correctly
+ expect(setFieldValue).toHaveBeenCalledWith('temporal.recurringDayStart', 61) // March 1st
+ expect(setFieldValue).toHaveBeenCalledWith('temporal.recurringDayEnd', 366) // December 31st
+
+ // Verify form was submitted
+ expect(handleSubmit).toHaveBeenCalled()
+
+ // Verify metrics were recorded
+ expect(onMetricsGranuleFilter).toHaveBeenCalledWith({
+ type: 'Set Recurring',
+ value: true
+ })
+ })
+
+ test('when toggling recurring with different year dates, preserves original start date year', async () => {
+ const { setFieldValue, user } = setup({
+ values: {
+ temporal: {
+ startDate: '2023-03-01T00:00:00.000Z',
+ endDate: '2024-12-31T23:59:59.999Z',
+ isRecurring: false
+ }
+ }
+ })
+
+ const recurringCheckbox = screen.getByRole('checkbox', { name: 'Recurring?' })
+ await user.click(recurringCheckbox)
+
+ // Verify start date was NOT adjusted since years are different
+ expect(setFieldValue).not.toHaveBeenCalledWith(
+ 'temporal.startDate',
+ expect.stringContaining('1960')
+ )
+ })
+ })
+
+ describe('Start date submission behavior', () => {
+ test('when submitting start date in same year as end date with recurring enabled, adjusts to minimum year', async () => {
+ MockDate.set('2024-03-15')
+
+ const {
+ setFieldValue, handleSubmit, onMetricsGranuleFilter, user
+ } = setup({
+ values: {
+ temporal: {
+ isRecurring: true,
+ startDate: '',
+ endDate: '2024-12-31T23:59:59.999Z'
+ }
+ }
+ })
+
+ // Click "Today" button for start date
+ const todayButton = screen.getAllByRole('button', { name: 'Today' })[0]
+ await user.click(todayButton)
+
+ // Verify start date was adjusted to minimum year while preserving month/day
+ expect(setFieldValue).toHaveBeenCalledWith(
+ 'temporal.startDate',
+ '1960-03-15T00:00:00.000Z'
+ )
+
+ expect(handleSubmit).toHaveBeenCalled()
+ expect(onMetricsGranuleFilter).toHaveBeenCalledWith({
+ type: 'Set Start Date',
+ value: '2024-03-15T00:00:00.000Z'
+ })
+
+ MockDate.reset()
+ })
+ })
+
+ describe('End date submission behavior', () => {
+ test.only('when submitting end date in same year as start date with recurring enabled, adjusts start date to minimum year', async () => {
+ MockDate.set('2024-12-15')
+
+ const {
+ setFieldValue, handleSubmit, onMetricsGranuleFilter, user
+ } = setup({
+ values: {
+ temporal: {
+ isRecurring: true,
+ startDate: '2024-03-15T00:00:00.000Z',
+ endDate: ''
+ }
+ }
+ })
+
+ // Click "Today" button for end date
+ const todayButton = screen.getAllByRole('button', { name: 'Today' })[1]
+ await user.click(todayButton)
+
+ // Verify start date was adjusted to minimum year while preserving month/day
+ expect(setFieldValue).toHaveBeenCalledWith(
+ 'temporal.startDate',
+ '1960-03-15T00:00:00.000Z'
+ )
+
+ expect(handleSubmit).toHaveBeenCalled()
+ expect(onMetricsGranuleFilter).toHaveBeenCalledWith({
+ type: 'Set End Date',
+ value: '2024-12-15T23:59:59.000Z'
+ })
+
+ MockDate.reset()
+ })
+ })
})
diff --git a/static/src/js/components/TemporalDisplay/TemporalSelectionDropdown.jsx b/static/src/js/components/TemporalDisplay/TemporalSelectionDropdown.jsx
index b5b5dd00e7..cc368bd58c 100644
--- a/static/src/js/components/TemporalDisplay/TemporalSelectionDropdown.jsx
+++ b/static/src/js/components/TemporalDisplay/TemporalSelectionDropdown.jsx
@@ -42,9 +42,18 @@ const TemporalSelectionDropdown = ({
recurringDayEnd,
isRecurring
})
+ const [datesSelected, setDatesSelected] = useState({
+ start: false,
+ end: false
+ })
useEffect(() => {
setTemporal(temporalSearch)
+
+ setDatesSelected({
+ start: !!temporalSearch.startDate,
+ end: !!temporalSearch.endDate
+ })
}, [temporalSearch])
/**
@@ -98,6 +107,11 @@ const TemporalSelectionDropdown = ({
* Clears the current temporal values internally and within the Redux store
*/
const onClearClick = () => {
+ setDatesSelected({
+ start: false,
+ end: false
+ })
+
setTemporal({
startDate: '',
endDate: '',
@@ -134,10 +148,67 @@ const TemporalSelectionDropdown = ({
})
}
- setTemporal({
- ...temporal,
- isRecurring: isChecked
- })
+ try {
+ if (isChecked) {
+ const {
+ startDate: existingStartDate,
+ endDate: existingEndDate
+ } = temporal
+ const { minimumTemporalDateString, temporalDateFormatFull } = getApplicationConfig()
+ const minDate = moment(minimumTemporalDateString, temporalDateFormatFull)
+
+ // When both dates exist and are in the same year, adjust start to min year
+ if (existingStartDate && existingEndDate) {
+ const startYear = moment(existingStartDate).utc().year()
+ const endYear = moment(existingEndDate).utc().year()
+ if (startYear === endYear) {
+ setTemporal({
+ ...temporal,
+ isRecurring: isChecked,
+ startDate: moment(existingStartDate).utc().year(minDate.year()).toISOString(),
+ endDate: existingEndDate
+ })
+
+ return
+ }
+ }
+
+ // When only start date exists and is in current year, use full range
+ if (existingStartDate && !existingEndDate) {
+ const startYear = moment.utc(existingStartDate).year()
+ const currentYear = moment().utc().year()
+ if (startYear === currentYear) {
+ setTemporal({
+ ...temporal,
+ isRecurring: isChecked,
+ startDate: moment(existingStartDate).utc().year(minDate.year()).toISOString(),
+ endDate: moment().utc().toISOString()
+ })
+
+ return
+ }
+ }
+
+ setTemporal({
+ ...temporal,
+ isRecurring: isChecked,
+ startDate: existingStartDate || minDate.utc().startOf('year').toISOString(),
+ endDate: existingEndDate || moment.utc().toISOString()
+ })
+
+ return
+ }
+
+ setTemporal({
+ ...temporal,
+ isRecurring: isChecked
+ })
+ } catch (error) {
+ setTemporal({
+ ...temporal,
+ isRecurring: isChecked
+ })
+ }
}
/**
@@ -194,6 +265,11 @@ const TemporalSelectionDropdown = ({
startDate: existingStartDate
} = temporal
+ setDatesSelected((prev) => ({
+ ...prev,
+ start: true
+ }))
+
if (shouldCallMetrics && onMetricsTemporalFilter) {
onMetricsTemporalFilter({
type: `Set Start Date - ${metricType}`,
@@ -229,6 +305,11 @@ const TemporalSelectionDropdown = ({
isRecurring: existingIsRecurring
} = temporal
+ setDatesSelected((prev) => ({
+ ...prev,
+ end: true
+ }))
+
if (shouldCallMetrics && onMetricsTemporalFilter) {
onMetricsTemporalFilter({
type: `Set End Date - ${metricType}`,
@@ -266,10 +347,22 @@ const TemporalSelectionDropdown = ({
onClearClick={onClearClick}
onInvalid={onInvalid}
onRecurringToggle={onRecurringToggle}
+ onSliderChange={
+ (value) => {
+ const { min, max } = value
+ setTemporal({
+ ...temporal,
+ startDate: moment(temporal.startDate).year(min).toISOString(),
+ endDate: moment(temporal.endDate).year(max).toISOString()
+ })
+ }
+ }
onValid={onValid}
setEndDate={setEndDate}
setStartDate={setStartDate}
temporal={temporal}
+ displayStartDate={datesSelected.start ? temporal.startDate : ''}
+ displayEndDate={datesSelected.end ? temporal.endDate : ''}
/>
)
}
diff --git a/static/src/js/components/TemporalDisplay/TemporalSelectionDropdownMenu.jsx b/static/src/js/components/TemporalDisplay/TemporalSelectionDropdownMenu.jsx
index 802616c96f..3ba8a47050 100644
--- a/static/src/js/components/TemporalDisplay/TemporalSelectionDropdownMenu.jsx
+++ b/static/src/js/components/TemporalDisplay/TemporalSelectionDropdownMenu.jsx
@@ -21,10 +21,13 @@ const TemporalSelectionDropdownMenu = ({
onChangeRecurring,
onInvalid,
onRecurringToggle,
+ onSliderChange,
onValid,
setEndDate,
setStartDate,
- temporal
+ temporal,
+ displayStartDate,
+ displayEndDate
}) => {
const classes = {
btnApply: classNames(
@@ -64,8 +67,11 @@ const TemporalSelectionDropdownMenu = ({
onChangeQuery={onChangeQuery}
onSubmitStart={setStartDate}
onSubmitEnd={setEndDate}
+ onSliderChange={onSliderChange}
onValid={onValid}
onInvalid={onInvalid}
+ displayStartDate={displayStartDate}
+ displayEndDate={displayEndDate}
/>