- `.
- // These props are not relevant in modern browsers,
- // where `` already
- // formats the time|date according to the OS settings.
- // eslint-disable-next-line react/jsx-sort-props
- timeFormatLegacy={timeFormatLegacy}
- timeZone={homeTimezone}
- />
-
-
- )
- }
-}
-
-const mapStateToProps = (state) => {
- const { date, departArrive, time } = state.otp.currentQuery
- const config = state.otp.config
- return {
- config,
- date,
- // This prop is for legacy browsers (see render method above).
- dateFormatLegacy: coreUtils.time.getDateFormat(config),
- departArrive,
- time,
- // This prop is for legacy browsers (see render method above).
- timeFormatLegacy: coreUtils.time.getTimeFormat(config)
- }
-}
-
-const mapDispatchToProps = {
- setQueryParam
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(DateTimeModal)
diff --git a/lib/components/form/date-time-modal.tsx b/lib/components/form/date-time-modal.tsx
new file mode 100644
index 000000000..bf41b281a
--- /dev/null
+++ b/lib/components/form/date-time-modal.tsx
@@ -0,0 +1,107 @@
+import { connect } from 'react-redux'
+import { decodeQueryParams, StringParam } from 'serialize-query-params'
+import coreUtils from '@opentripplanner/core-utils'
+import React, { useCallback } from 'react'
+
+import { AppConfig } from '../../util/config-types'
+import { AppReduxState } from '../../util/state-types'
+import { setQueryParam } from '../../actions/form'
+
+import { StyledDateTimeSelector } from './styled'
+
+export type DepartArriveValue = 'NOW' | 'DEPART' | 'ARRIVE'
+
+type Props = {
+ config: AppConfig
+ date: any
+ dateFormatLegacy: string
+ departArrive: DepartArriveValue
+ setQueryParam: (params: any) => void
+ time: any
+ timeFormatLegacy: string
+}
+
+function DateTimeModal({
+ config,
+ date,
+ dateFormatLegacy,
+ departArrive,
+ setQueryParam,
+ time,
+ timeFormatLegacy
+}: Props) {
+ /**
+ * Stores parameters in both the Redux `currentQuery` and URL
+ * @param params Params to store
+ */
+ const _onSettingsUpdate = useCallback(
+ (params: any) => {
+ console.log('setting')
+ setQueryParam({ queryParamData: params, ...params })
+ },
+ [setQueryParam]
+ )
+
+ const { homeTimezone, isTouchScreenOnDesktop } = config
+ const touchClassName = isTouchScreenOnDesktop
+ ? 'with-desktop-touchscreen'
+ : ''
+
+ return (
+
+
+ `.
+ // These props are not relevant in modern browsers,
+ // where `` already
+ // formats the time|date according to the OS settings.
+ // eslint-disable-next-line react/jsx-sort-props
+ timeFormatLegacy={timeFormatLegacy}
+ timeZone={homeTimezone}
+ />
+
+
+ )
+}
+
+const queryParamConfig = {
+ date: StringParam,
+ departArrive: StringParam,
+ time: StringParam
+}
+
+const mapStateToProps = (state: AppReduxState) => {
+ const config = state.otp.config
+ const urlSearchParams = new URLSearchParams(state.router.location.search)
+ const { date, departArrive, time } = decodeQueryParams(queryParamConfig, {
+ date: urlSearchParams.get('date'),
+ departArrive: urlSearchParams.get('departArrive'),
+ time: urlSearchParams.get('time')
+ })
+
+ return {
+ config,
+ date: date || coreUtils.time.getCurrentDate(),
+ // This prop is for legacy browsers (see render method above).
+ // @ts-expect-error why do we have two config types?
+ dateFormatLegacy: coreUtils.time.getDateFormat(config),
+ departArrive: (departArrive as DepartArriveValue) || 'NOW',
+ time: time || coreUtils.time.getCurrentTime(),
+ // This prop is for legacy browsers (see render method above).
+ // @ts-expect-error why do we have two config types?
+ timeFormatLegacy: coreUtils.time.getTimeFormat(config)
+ }
+}
+
+const mapDispatchToProps = {
+ setQueryParam
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(DateTimeModal)
diff --git a/lib/components/form/date-time-preview.tsx b/lib/components/form/date-time-preview.tsx
index 55b19a837..4fa2faa95 100644
--- a/lib/components/form/date-time-preview.tsx
+++ b/lib/components/form/date-time-preview.tsx
@@ -1,13 +1,17 @@
import { CalendarAlt } from '@styled-icons/fa-solid/CalendarAlt'
import { Clock } from '@styled-icons/fa-regular/Clock'
import { connect } from 'react-redux'
+import { decodeQueryParams, StringParam } from 'serialize-query-params'
import { toDate } from 'date-fns-tz'
+import coreUtils from '@opentripplanner/core-utils'
import React from 'react'
import { IconWithText } from '../util/styledIcon'
import FormattedCalendarString from '../util/formatted-calendar-string'
import FormattedDateTimePreview from '../util/formatted-date-time-preview'
+import { DepartArriveValue } from './date-time-modal'
+
interface Props {
date: string
departArrive: string
@@ -38,13 +42,24 @@ const DateTimePreview = ({
)
}
+const queryParamConfig = {
+ date: StringParam,
+ departArrive: StringParam,
+ time: StringParam
+}
+
const mapStateToProps = (state: any) => {
- const { date, departArrive, time } = state.otp.currentQuery
const { homeTimezone: timeZone } = state.otp.config
+ const urlSearchParams = new URLSearchParams(state.router.location.search)
+ const { date, departArrive, time } = decodeQueryParams(queryParamConfig, {
+ date: urlSearchParams.get('date'),
+ departArrive: urlSearchParams.get('departArrive'),
+ time: urlSearchParams.get('time')
+ })
return {
- date,
- departArrive,
- time,
+ date: date || coreUtils.time.getCurrentDate(),
+ departArrive: (departArrive as DepartArriveValue) || 'NOW',
+ time: time || coreUtils.time.getCurrentTime(),
timeZone
}
}
diff --git a/lib/util/state-types.ts b/lib/util/state-types.ts
index 3daba23c6..f393871fa 100644
--- a/lib/util/state-types.ts
+++ b/lib/util/state-types.ts
@@ -12,6 +12,7 @@ export interface OtpState {
// TODO: Add other OTP states
activeSearchId?: string
config: AppConfig
+ currentQuery: any // TODO
filter: {
sort: {
type: string
diff --git a/percy/percy.test.js b/percy/percy.test.js
index 4c46528c4..b7ef7586c 100644
--- a/percy/percy.test.js
+++ b/percy/percy.test.js
@@ -105,7 +105,7 @@ async function executeTest(page, isMobile, isCallTaker) {
// Triggers mock.har graphql query #1 and #2 (bike-only query, twice).
// FIXME: Opening a url with non-default mode params triggers the plan query twice.
await page.goto(
- `http://localhost:${MOCK_SERVER_PORT}/#/?ui_activeSearch=fg33svlbf&ui_activeItinerary=-1&fromPlace=South%20Prado%20Northeast%2C%20Atlanta%2C%20GA%2C%20USA%3A%3A33.78946214120528%2C-84.37663414886111&toPlace=1%20Copenhill%20Avenue%20NE%2C%20Atlanta%2C%20GA%2C%20USA%3A%3A33.767060728439574%2C-84.35749390533111&date=2023-08-09&time=17%3A56&arriveBy=false&mode=BICYCLE&showIntermediateStops=true&walkSpeed=1.34&ignoreRealtimeUpdates=true&numItineraries=3&otherThanPreferredRoutesPenalty=900&modeButtons=walk_bike`
+ `http://localhost:${MOCK_SERVER_PORT}/#/?ui_activeSearch=fg33svlbf&ui_activeItinerary=-1&fromPlace=South%20Prado%20Northeast%2C%20Atlanta%2C%20GA%2C%20USA%3A%3A33.78946214120528%2C-84.37663414886111&toPlace=1%20Copenhill%20Avenue%20NE%2C%20Atlanta%2C%20GA%2C%20USA%3A%3A33.767060728439574%2C-84.35749390533111&date=2023-08-09&time=17%3A56&departArrive=DEPART&mode=BICYCLE&showIntermediateStops=true&walkSpeed=1.34&ignoreRealtimeUpdates=true&numItineraries=3&otherThanPreferredRoutesPenalty=900&modeButtons=walk_bike`
)
// FIXME: Network idle condition seems never met after navigating to above link.
// await page.waitForNavigation({ waitUntil: 'networkidle2' })