diff --git a/lib/components/narrative/metro/attribute-utils.tsx b/lib/components/narrative/metro/attribute-utils.tsx index 36a12b90b..c48afd0c8 100644 --- a/lib/components/narrative/metro/attribute-utils.tsx +++ b/lib/components/narrative/metro/attribute-utils.tsx @@ -9,7 +9,7 @@ export const getFirstTransitLegStop = ( itinerary.legs?.find((leg: Leg) => leg?.from?.vertexType === 'TRANSIT')?.from ?.name -export const getFlexAttirbutes = ( +export const getFlexAttributes = ( itinerary: Itinerary ): { isCallAhead: boolean diff --git a/lib/components/narrative/metro/metro-itinerary.tsx b/lib/components/narrative/metro/metro-itinerary.tsx index e86a593e3..cbd0f7194 100644 --- a/lib/components/narrative/metro/metro-itinerary.tsx +++ b/lib/components/narrative/metro/metro-itinerary.tsx @@ -28,7 +28,7 @@ import ItineraryBody from '../line-itin/connected-itinerary-body' import NarrativeItinerary from '../narrative-itinerary' import SimpleRealtimeAnnotation from '../simple-realtime-annotation' -import { getFirstTransitLegStop, getFlexAttirbutes } from './attribute-utils' +import { getFlexAttributes } from './attribute-utils' import DepartureTimesList, { SetActiveItineraryHandler } from './departure-times-list' @@ -202,23 +202,17 @@ class MetroItinerary extends NarrativeItinerary { static ModesAndRoutes = MetroItineraryRoutes _onMouseEnter = () => { - const { active, index, setVisibleItinerary, visibleItinerary } = this.props + const { active, index, setVisibleItinerary, visible } = this.props // Set this itinerary as visible if not already visible. - const visibleNotSet = - visibleItinerary === null || visibleItinerary === undefined - const isVisible = - visibleItinerary === index || (active === index && visibleNotSet) + const isVisible = visible || active if (typeof setVisibleItinerary === 'function' && !isVisible) { setVisibleItinerary({ index }) } } _onMouseLeave = () => { - const { index, setVisibleItinerary, visibleItinerary } = this.props - if ( - typeof setVisibleItinerary === 'function' && - visibleItinerary === index - ) { + const { setVisibleItinerary, visible } = this.props + if (typeof setVisibleItinerary === 'function' && visible) { setVisibleItinerary({ index: null }) } } @@ -266,7 +260,7 @@ class MetroItinerary extends NarrativeItinerary { const { SvgIcon } = this.context const { isCallAhead, isContinuousDropoff, isFlexItinerary, phone } = - getFlexAttirbutes(itinerary) + getFlexAttributes(itinerary) const { fareCurrency, transitFare } = getFare(itinerary, defaultFareType) diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js index 30200a5cf..23d1d96fe 100644 --- a/lib/components/narrative/narrative-itineraries.js +++ b/lib/components/narrative/narrative-itineraries.js @@ -43,6 +43,15 @@ import Loading from './loading' import NarrativeItinerariesErrors from './narrative-itineraries-errors' import NarrativeItinerariesHeader from './narrative-itineraries-header' +/** Creates a start time object for the given itinerary. */ +function makeStartTime(itinerary) { + return { + itinerary, + legs: itinerary.legs, + realtime: firstTransitLegIsRealtime(itinerary) + } +} + function doMergeItineraries(itineraries) { const mergedItineraries = itineraries .reduce((prev, cur, curIndex) => { @@ -60,46 +69,51 @@ function doMergeItineraries(itineraries) { // Only process itineraries less than 24 hours in the future differenceInDays(updatedItinerary.startTime, Date.now()) < 1 ) { - const duplicateItin = updatedItineraries[duplicateIndex] + const duplicateFoundItin = updatedItineraries[duplicateIndex] // TODO: MERGE ROUTE NAMES - // Add only new start time to existing itinerary + // Add only new start time to existing itinerary. + // The existing itinerary is the earliest between + // this itinerary (updatedItinerary) and duplicateItin. + // This is because alternate routes are only added to the first non-duplicate itinerary, + // and we show alternate routes for the first (i.e. earliest) non-duplicate itinerary found. + let duplicateItin = duplicateFoundItin + let itinCopyToAdd = updatedItinerary + if (duplicateFoundItin.startTime > updatedItinerary.startTime) { + duplicateItin = updatedItinerary + duplicateItin.startTimes = duplicateFoundItin.allStartTimes + updatedItineraries[duplicateIndex] = updatedItinerary + itinCopyToAdd = duplicateFoundItin + } + if (!duplicateItin.allStartTimes) { - duplicateItin.allStartTimes = [ - { - itinerary: duplicateItin, - legs: duplicateItin.legs, - realtime: firstTransitLegIsRealtime(duplicateItin) - } - ] + duplicateItin.allStartTimes = [makeStartTime(duplicateItin)] } // Only add new time if it doesn't already exist. It would be better to use // the uniqueness feature of Set, but unfortunately objects are never equal if ( !duplicateItin.allStartTimes.find( - (time) => getFirstLegStartTime(time.legs) === cur.startTime + (time) => + getFirstLegStartTime(time.legs) === itinCopyToAdd.startTime ) ) { - duplicateItin.allStartTimes.push({ - itinerary: updatedItinerary, - legs: cur.legs, - realtime: firstTransitLegIsRealtime(cur) - }) + duplicateItin.allStartTimes.push(makeStartTime(itinCopyToAdd)) } // Some legs will be the same, but have a different route // This map catches those and stores the alternate routes so they can be displayed duplicateItin.legs = duplicateItin.legs.map((leg, index) => { const newLeg = clone(leg) - if (leg?.routeId !== cur.legs[index]?.routeId) { + const curLeg = itinCopyToAdd.legs[index] + const curLegRouteId = curLeg?.routeId + if (curLegRouteId && leg?.routeId && leg?.routeId !== curLegRouteId) { if (!newLeg.alternateRoutes) { newLeg.alternateRoutes = {} } - const { routeId } = cur.legs?.[index] - newLeg.alternateRoutes[routeId] = { + newLeg.alternateRoutes[curLegRouteId] = { // We save the entire leg to the alternateRoutes object so in // the future, we can draw the leg on the map as an alternate route - ...cur.legs?.[index] + ...curLeg } } return newLeg diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js index 14d3a486e..172ccb710 100644 --- a/lib/reducers/create-otp-reducer.js +++ b/lib/reducers/create-otp-reducer.js @@ -464,7 +464,8 @@ function createOtpReducer(config) { [state.activeSearchId]: { activeItinerary: { $set: action.payload.index }, activeLeg: { $set: null }, - activeStep: { $set: null } + activeStep: { $set: null }, + visibleItinerary: { $set: null } } } })