From 67d3b603eea14f8e9c44668df4940f2787034599 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Tue, 27 Jun 2023 17:28:14 -0400 Subject: [PATCH 01/35] fix(actions/ui): Delete ui_itineraryView URL param if same as default. --- lib/actions/ui.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/actions/ui.js b/lib/actions/ui.js index 1da4359f2..76ac04f9f 100644 --- a/lib/actions/ui.js +++ b/lib/actions/ui.js @@ -308,7 +308,12 @@ export function setItineraryView(value) { // set the desired ui query param // and store the current view as previousItineraryView. if (value !== urlParams.ui_itineraryView) { - urlParams.ui_itineraryView = value + if (value !== ItineraryView.LIST) { + urlParams.ui_itineraryView = value + } else if (urlParams.ui_itineraryView) { + // Remove the ui_itineraryView param if it is set to LIST (default). + delete urlParams.ui_itineraryView + } dispatch(setUrlSearch(urlParams)) dispatch(setPreviousItineraryView(prevItineraryView)) From d7b242de78a66483f0907c13f7cf37d9e0d5d84a Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 28 Jun 2023 09:00:18 -0400 Subject: [PATCH 02/35] improvement(DepartureTimesList): Set time interaction based on allStarttimes+expanded prop. --- .../narrative/metro/departure-times-list.tsx | 139 +++++++++++------- .../narrative/metro/metro-itinerary.tsx | 7 +- lib/components/narrative/utils.tsx | 21 --- 3 files changed, 88 insertions(+), 79 deletions(-) diff --git a/lib/components/narrative/metro/departure-times-list.tsx b/lib/components/narrative/metro/departure-times-list.tsx index ac33038eb..be754892a 100644 --- a/lib/components/narrative/metro/departure-times-list.tsx +++ b/lib/components/narrative/metro/departure-times-list.tsx @@ -1,9 +1,8 @@ -import { FormattedList, FormattedTime, useIntl } from 'react-intl' +import { FormattedList, useIntl } from 'react-intl' import { Itinerary, Leg } from '@opentripplanner/types' -import React, { MouseEvent } from 'react' +import React, { MouseEvent, useCallback } from 'react' import { firstTransitLegIsRealtime } from '../../../util/viewer' -import { getDepartureLabelText } from '../utils' import { getFirstLegStartTime, getLastLegEndTime @@ -14,44 +13,86 @@ interface ItineraryWithIndex extends Itinerary { index: number } +interface StartTime { + itinerary: ItineraryWithIndex + legs: Leg[] + realtime: boolean +} + +export type SetActiveItineraryHandler = (payload: { index: number }) => void + type DepartureTimesProps = { + expanded?: boolean itinerary: ItineraryWithIndex & { - allStartTimes?: { - itinerary: ItineraryWithIndex - legs: Leg[] - realtime: boolean - }[] + allStartTimes?: StartTime[] } - setActiveItinerary: (payload: { index: number }) => void + setActiveItinerary: SetActiveItineraryHandler showArrivals?: boolean } -export const DepartureTimesList = ({ +interface TimeButtonProps { + active?: boolean + displayedTime: number + itinerary: ItineraryWithIndex + realTime?: boolean + setActiveItinerary?: SetActiveItineraryHandler +} + +const TimeButton = ({ + active, + displayedTime, + itinerary, + realTime, + setActiveItinerary +}: TimeButtonProps) => { + const intl = useIntl() + const classNames = [] + if (realTime) classNames.push('realtime') + if (active) classNames.push('active') + const timeString = intl.formatTime(displayedTime) + const realtimeStatus = realTime + ? intl.formatMessage({ id: 'components.StopTimeCell.realtime' }) + : intl.formatMessage({ id: 'components.StopTimeCell.scheduled' }) + const label = `${timeString} (${realtimeStatus})` + + const handleClick = useCallback( + (e: MouseEvent) => { + setActiveItinerary && setActiveItinerary(itinerary) + // Don't let MetroItinerary.handleClick execute, it will set another itinerary as active. + e.stopPropagation() + }, + [itinerary, setActiveItinerary] + ) + // If setActiveItinerary is set, use a button, otherwise render the time as span without interaction. + const Wrapper = setActiveItinerary ? 'button' : 'span' + + return ( + + {timeString} + ({realtimeStatus}) + + ) +} + +const DepartureTimesList = ({ + expanded, itinerary, setActiveItinerary, showArrivals }: DepartureTimesProps): JSX.Element => { - const intl = useIntl() - const isRealTime = firstTransitLegIsRealtime(itinerary) - const itineraryButtonLabel = getDepartureLabelText( - intl, - itinerary.startTime, - isRealTime - ) if (!itinerary.allStartTimes) { return ( - <> - - - - {itineraryButtonLabel} - + ) } @@ -60,36 +101,22 @@ export const DepartureTimesList = ({ type="disjunction" value={itinerary.allStartTimes.map((time, index) => { const { itinerary: itinOption, legs, realtime } = time - const classNames = [] - if (realtime) classNames.push('realtime') - if (itinOption.index === itinerary.index) classNames.push('active') - const singleItinLabel = getDepartureLabelText( - intl, - getFirstLegStartTime(legs), - realtime - ) + const displayedTime = showArrivals + ? getLastLegEndTime(legs) + : getFirstLegStartTime(legs) return ( - + ) })} /> ) } + +export default DepartureTimesList diff --git a/lib/components/narrative/metro/metro-itinerary.tsx b/lib/components/narrative/metro/metro-itinerary.tsx index bcf87d9fb..3e81f9d3d 100644 --- a/lib/components/narrative/metro/metro-itinerary.tsx +++ b/lib/components/narrative/metro/metro-itinerary.tsx @@ -28,12 +28,14 @@ import ItineraryBody from '../line-itin/connected-itinerary-body' import NarrativeItinerary from '../narrative-itinerary' import SimpleRealtimeAnnotation from '../simple-realtime-annotation' -import { DepartureTimesList } from './departure-times-list' import { getFirstTransitLegStop, getFlexAttirbutes, removeInsignifigantWalkLegs } from './attribute-utils' +import DepartureTimesList, { + SetActiveItineraryHandler +} from './departure-times-list' import MetroItineraryRoutes from './metro-itinerary-routes' import RouteBlock from './route-block' @@ -191,7 +193,7 @@ type Props = { intl: IntlShape itinerary: Itinerary mini?: boolean - setActiveItinerary: () => void + setActiveItinerary: SetActiveItineraryHandler setActiveLeg: (leg: Leg) => void setItineraryView: (view: string) => void showRealtimeAnnotation: () => void @@ -428,6 +430,7 @@ class MetroItinerary extends NarrativeItinerary { )}{' '} { - return `${intl.formatTime(time)} ${ - realTime - ? `(${intl.formatMessage({ id: 'components.StopTimeCell.realtime' })})` - : `(${intl.formatMessage({ id: 'components.StopTimeCell.scheduled' })})` - }` -} From 6a00e9a7a18af632204b9d9938572679334e60c9 Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:56:09 -0500 Subject: [PATCH 03/35] fix: restore walk icon to short trips --- lib/components/narrative/metro/metro-itinerary.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/components/narrative/metro/metro-itinerary.tsx b/lib/components/narrative/metro/metro-itinerary.tsx index c212ebc8a..32ff43113 100644 --- a/lib/components/narrative/metro/metro-itinerary.tsx +++ b/lib/components/narrative/metro/metro-itinerary.tsx @@ -29,11 +29,7 @@ import NarrativeItinerary from '../narrative-itinerary' import SimpleRealtimeAnnotation from '../simple-realtime-annotation' import { DepartureTimesList } from './departure-times-list' -import { - getFirstTransitLegStop, - getFlexAttirbutes, - removeInsignifigantWalkLegs -} from './attribute-utils' +import { getFirstTransitLegStop, getFlexAttirbutes } from './attribute-utils' import MetroItineraryRoutes from './metro-itinerary-routes' import RouteBlock from './route-block' @@ -308,7 +304,6 @@ class MetroItinerary extends NarrativeItinerary { ) const firstTransitStop = getFirstTransitLegStop(itinerary) - const routeLegs = itinerary.legs.filter(removeInsignifigantWalkLegs) const handleClick = () => { setActiveItinerary(itinerary) @@ -445,7 +440,7 @@ class MetroItinerary extends NarrativeItinerary { - {this._renderMainRouteBlock(routeLegs)} + {this._renderMainRouteBlock(itinerary.legs)} )} From e5a751a1003a8dc4f017462882d784abac3ffe07 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:57:26 -0400 Subject: [PATCH 04/35] fix(actions/narrative): Unset ui_itinearyView when changing the active itin. --- lib/actions/narrative.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/actions/narrative.js b/lib/actions/narrative.js index bc0057ae9..88418392c 100644 --- a/lib/actions/narrative.js +++ b/lib/actions/narrative.js @@ -12,6 +12,12 @@ export function setActiveItinerary(payload) { // Update URL params. const urlParams = coreUtils.query.getUrlParams() urlParams.ui_activeItinerary = payload.index + if (payload.index === -1 || payload.index === '-1') { + // Remove the ui_itineraryView param if changing to another itinerary. + // Note: set to undefined instead of deleting so that it merges with the other search params. + urlParams.ui_itineraryView = undefined + } + dispatch(setUrlSearch(urlParams)) } } From cf614f1e93482e437b36c356702c0088e995fb61 Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Wed, 28 Jun 2023 18:33:08 -0400 Subject: [PATCH 05/35] fix: time picker more expected behavior --- .../form/call-taker/date-time-picker.tsx | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/lib/components/form/call-taker/date-time-picker.tsx b/lib/components/form/call-taker/date-time-picker.tsx index 963da6548..fcfde0aac 100644 --- a/lib/components/form/call-taker/date-time-picker.tsx +++ b/lib/components/form/call-taker/date-time-picker.tsx @@ -102,6 +102,7 @@ const DateTimeOptions = ({ ) const [date, setDate] = useState(initialDate) const [time, setTime] = useState(initialTime) + const [typedTime, setTypedTime] = useState(initialTime) const intl = useIntl() @@ -134,7 +135,16 @@ const DateTimeOptions = ({ // Update state when external state is updated useEffect(() => { if (initialDate !== date) setDate(initialDate) - if (initialTime !== time) setTime(initialTime) + if (initialTime !== time) { + setTime(initialTime) + setTypedTime( + safeFormat(dateTime, timeFormat, { + timeZone: homeTimezone + }) || + // TODO: there doesn't seem to be an intl object present? + 'Invalid Time' + ) + } }, [initialTime, initialDate]) useEffect(() => { @@ -201,13 +211,9 @@ const DateTimeOptions = ({ className="datetime-slim" // TODO: Why does this no longer work when set as `value`? Is this a // date-fns issue? - defaultValue={ - time && time?.length > 1 - ? time || format(dateTime, 'H:mm', { timeZone: homeTimezone }) - : time - } onChange={(e) => { setTime(e.target.value) + setTypedTime(e.target.value) unsetNow() }} onFocus={(e) => e.target.select()} @@ -217,8 +223,9 @@ const DateTimeOptions = ({ lineHeight: '.8em', marginLeft: '3px', padding: '0px', - width: '50px' + width: '65px' }} + value={typedTime} /> Date: Wed, 28 Jun 2023 18:41:10 -0400 Subject: [PATCH 06/35] test: update snapshots --- .../__snapshots__/date-time-options.js.snap | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/__tests__/components/__snapshots__/date-time-options.js.snap b/__tests__/components/__snapshots__/date-time-options.js.snap index bd88def98..3b13e8182 100644 --- a/__tests__/components/__snapshots__/date-time-options.js.snap +++ b/__tests__/components/__snapshots__/date-time-options.js.snap @@ -78,7 +78,6 @@ exports[`components > form > call-taker > date time options should correctly han > form > call-taker > date time options should correctly han "lineHeight": ".8em", "marginLeft": "3px", "padding": "0px", - "width": "50px", + "width": "65px", } } + value="12a" /> form > call-taker > date time options should correctly han > form > call-taker > date time options should correctly han "lineHeight": ".8em", "marginLeft": "3px", "padding": "0px", - "width": "50px", + "width": "65px", } } + value="12p" /> form > call-taker > date time options should correctly han > form > call-taker > date time options should correctly han "lineHeight": ".8em", "marginLeft": "3px", "padding": "0px", - "width": "50px", + "width": "65px", } } + value="133" /> form > call-taker > date time options should correctly han > form > call-taker > date time options should correctly han "lineHeight": ".8em", "marginLeft": "3px", "padding": "0px", - "width": "50px", + "width": "65px", } } + value="133p" /> form > call-taker > date time options should correctly han > form > call-taker > date time options should correctly han "lineHeight": ".8em", "marginLeft": "3px", "padding": "0px", - "width": "50px", + "width": "65px", } } + value="135p" /> form > call-taker > date time options should correctly han > form > call-taker > date time options should correctly han "lineHeight": ".8em", "marginLeft": "3px", "padding": "0px", - "width": "50px", + "width": "65px", } } + value="1335" /> form > call-taker > date time options should render 1`] = > form > call-taker > date time options should render 1`] = "lineHeight": ".8em", "marginLeft": "3px", "padding": "0px", - "width": "50px", + "width": "65px", } } + value="12:34" /> Date: Thu, 29 Jun 2023 11:37:11 -0400 Subject: [PATCH 07/35] refactor(connect-location-field): support `suggestionCount` --- lib/components/form/connect-location-field.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/components/form/connect-location-field.js b/lib/components/form/connect-location-field.js index 74acd4b6e..d7091ee9b 100644 --- a/lib/components/form/connect-location-field.js +++ b/lib/components/form/connect-location-field.js @@ -94,6 +94,7 @@ export default function connectLocationField( sessionSearches, showUserSettings: getShowUserSettings(state), stopsIndex: transitIndex.stops, + suggestionCount: config.geocoder?.resultsCount, UserLocationIconComponent: UserLocationIcon, userLocationsAndRecentPlaces: [...userSavedLocations, ...recentPlaces] } From e3fb56e799c9ca9bba37406e68ed2278a5ceddc4 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 29 Jun 2023 12:50:06 -0700 Subject: [PATCH 08/35] fix(apiv2): adds 'headsign' to pattern request --- lib/actions/apiV2.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/actions/apiV2.js b/lib/actions/apiV2.js index 67436afe6..1470c41bd 100644 --- a/lib/actions/apiV2.js +++ b/lib/actions/apiV2.js @@ -609,6 +609,7 @@ export const findRoute = (params) => patterns { id + headsign name patternGeometry { points From 573656524293ecd87769f6529eb435967a074529 Mon Sep 17 00:00:00 2001 From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com> Date: Fri, 30 Jun 2023 06:53:47 -0400 Subject: [PATCH 09/35] fix(NarrativeItineraries): Display itinerary indicated in ui_activeItinerary. --- lib/components/narrative/narrative-itineraries.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js index 67e6f6c6e..be04aa9f4 100644 --- a/lib/components/narrative/narrative-itineraries.js +++ b/lib/components/narrative/narrative-itineraries.js @@ -368,6 +368,21 @@ class NarrativeItineraries extends Component { ) } + componentDidUpdate() { + // If set in URL, set the active itinerary in the state, once. + const { activeItinerary, activeSearch, setActiveItinerary } = this.props + const { ui_activeItinerary: uiActiveItinerary } = + coreUtils.query.getUrlParams() || {} + if ( + activeSearch && + uiActiveItinerary !== undefined && + uiActiveItinerary !== '-1' && + activeItinerary !== +uiActiveItinerary + ) { + setActiveItinerary({ index: +uiActiveItinerary }) + } + } + // eslint-disable-next-line complexity render() { const { From 7e7831b170c77c8bce54ca2772ae32ac75c5a7be Mon Sep 17 00:00:00 2001 From: amy-corson-ibigroup <115499534+amy-corson-ibigroup@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:22:57 -0500 Subject: [PATCH 10/35] a11y button fixes --- lib/components/narrative/trip-tools.js | 7 +++++++ lib/components/viewers/RouteRow.js | 1 + 2 files changed, 8 insertions(+) diff --git a/lib/components/narrative/trip-tools.js b/lib/components/narrative/trip-tools.js index 06f0cdbd6..f204e6aee 100644 --- a/lib/components/narrative/trip-tools.js +++ b/lib/components/narrative/trip-tools.js @@ -17,6 +17,7 @@ import React, { Component, useContext, useMemo } from 'react' import * as uiActions from '../../actions/ui' import { ComponentContext } from '../../util/contexts' import { IconWithText } from '../util/styledIcon' +import InvisibleA11yLabel from '../util/invisible-a11y-label' import PopupTriggerText from '../app/popup-trigger-text' import startOver from '../util/start-over' @@ -55,6 +56,12 @@ class CopyUrlButton extends Component { render() { return (
+ {/* Announces copy button status to AT */} + + {this.state.showCopied && ( + + )} +