From 4eb4391d367978ad4b5f253010f5252fcba75d72 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 15 Dec 2024 16:24:59 +0200 Subject: [PATCH 1/9] fix: transfer analysis improvements - Compute transfer proceeding only when transfer walk has started - Get transfer duration from unmodified leg.duration, not from start and end times which change by realtime --- app/component/itinerary/navigator/NaviUtils.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 2567ee3392..0066293674 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -129,7 +129,7 @@ function findTransferProblems(legs, time, position, origin) { toLeg: next, }); } else { - const transferDuration = legTime(leg.end) - legTime(leg.start); + const transferDuration = leg.duration * 1000; // this is original duration // check if user is already at the next departure stop const atStop = position && distance(position, leg.to) <= DESTINATION_RADIUS; @@ -137,8 +137,17 @@ function findTransferProblems(legs, time, position, origin) { if (!atStop && slack < TRANSFER_SLACK) { // original transfer not possible let severity = 'WARNING'; - const toGo = getRemainingTraversal(leg, position, origin, time); - const timeLeft = (t2 - time) / 1000; + let toGo; + let timeLeft; + // has transit walk already started ? + if (time > legTime(leg.start)) { + // compute how transit is proceeding + toGo = getRemainingTraversal(leg, position, origin, time); + timeLeft = (t2 - time) / 1000; + } else { + toGo = 1.0; + timeLeft = (t2 - t1) / 1000; // should we consider also transfer slack here? + } if (toGo > 0 && timeLeft > 0) { const originalSpeed = leg.distance / leg.duration; const newSpeed = (toGo * leg.distance) / timeLeft; From 96ba55b9d8c81e8984f5d49f7875f50827d67f87 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 16 Dec 2024 10:03:30 +0200 Subject: [PATCH 2/9] fix: transit leg mode cannot be WALK --- app/component/itinerary/navigator/NaviUtils.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 0066293674..6d6525e7ad 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -204,9 +204,7 @@ export const getAdditionalMessages = (leg, time, intl, config, messages) => { export const getTransitLegState = (leg, intl, messages, time) => { const { start, realtimeState, from, mode, legId, route } = leg; const { scheduledTime, estimated } = start; - if (mode === 'WALK') { - return null; - } + const previousMessage = messages.get(legId); const prevSeverity = previousMessage ? previousMessage.severity : null; From fd2b54c81e71f8b4ca01e85e44318275fb6b75b3 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 16 Dec 2024 10:35:25 +0200 Subject: [PATCH 3/9] fix: refactor transit leg state logic - Card updates - Card does not reopen if user closes it --- .../itinerary/navigator/NaviCardContainer.js | 2 ++ .../itinerary/navigator/NaviUtils.js | 26 +++++++------------ 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index b680a0c72c..3dcd79e650 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -53,6 +53,8 @@ function NaviCardContainer( const cardRef = useRef(null); const handleRemove = index => { + const msg = messages.get(activeMessages[index].id); + msg.closed = true; // remember closing action setActiveMessages(activeMessages.filter((_, i) => i !== index)); }; diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 6d6525e7ad..507b86b399 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -205,10 +205,11 @@ export const getTransitLegState = (leg, intl, messages, time) => { const { start, realtimeState, from, mode, legId, route } = leg; const { scheduledTime, estimated } = start; - const previousMessage = messages.get(legId); - const prevSeverity = previousMessage ? previousMessage.severity : null; + if (messages.get(legId)?.closed) { + return []; + } - const late = + const notInSchedule = estimated?.delay > DISPLAY_MESSAGE_THRESHOLD || estimated?.delay < -DISPLAY_MESSAGE_THRESHOLD; const localizedMode = getLocalizedMode(mode, intl); @@ -216,24 +217,20 @@ export const getTransitLegState = (leg, intl, messages, time) => { let severity; const isRealTime = realtimeState === 'UPDATED'; - if (late && prevSeverity !== 'WARNING') { + if (notInSchedule) { const lMode = getLocalizedMode(mode, intl); const routeName = `${lMode} ${route.shortName}`; const { delay } = estimated; - const id = `navigation-mode-${delay > 0 ? 'late' : 'early'}`; + const translationId = `navigation-mode-${delay > 0 ? 'late' : 'early'}`; content = (
- +
); severity = 'WARNING'; - } else if ( - !isRealTime && - prevSeverity !== 'WARNING' && - legTime(start) - time < DISPLAY_MESSAGE_THRESHOLD - ) { + } else if (!isRealTime && legTime(start) - time < DISPLAY_MESSAGE_THRESHOLD) { severity = 'WARNING'; content = (
@@ -247,7 +244,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { />
); - } else if (isRealTime && prevSeverity !== 'INFO') { + } else if (isRealTime) { const { parentStation, name } = from.stop; const stopOrStation = parentStation ? intl.formatMessage({ id: 'from-station' }) @@ -270,10 +267,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { ); severity = 'INFO'; } - const state = severity - ? [{ severity, content, id: legId, expiresOn: legTime(start) }] - : []; - return state; + return [{ severity, content, id: legId, expiresOn: legTime(start) }]; }; export const getItineraryAlerts = ( From b928fa8776c60e7a971c06a7339b0b0dc0fcc22f Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 16 Dec 2024 10:47:30 +0200 Subject: [PATCH 4/9] fix: update messages also when waiting --- .../itinerary/navigator/NaviCardContainer.js | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 3dcd79e650..18cb893bf5 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -96,18 +96,17 @@ function NaviCardContainer( ), ); - if (currentLeg) { - if (nextLeg?.transitLeg) { - // Messages for NaviStack. - addMessages(incomingMessages, [ - ...getTransitLegState(nextLeg, intl, messages, time), - ...getAdditionalMessages(nextLeg, time, intl, config, messages), - ]); - } - if (legChanged) { - focusToLeg?.(currentLeg); - setCardExpanded(false); - } + if (nextLeg?.transitLeg) { + // Messages for NaviStack. + addMessages(incomingMessages, [ + ...getTransitLegState(nextLeg, intl, messages, time), + ...getAdditionalMessages(nextLeg, time, intl, config, messages), + ]); + } + + if (currentLeg && legChanged) { + focusToLeg?.(currentLeg); + setCardExpanded(false); } if (incomingMessages.size || legChanged) { // Handle messages when new messages arrives. From 7ddbd1de411c165e6528311da33cec618ae94e41 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 16 Dec 2024 10:54:51 +0200 Subject: [PATCH 5/9] fix: message replacement logic --- app/component/itinerary/navigator/NaviCardContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 18cb893bf5..a603c03984 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -118,7 +118,7 @@ function NaviCardContainer( // handle messages that are updated. const keptMessages = previousValidMessages.filter( - msg => !!incomingMessages.get(msg.id), + msg => !incomingMessages.get(msg.id), ); const newMessages = Array.from(incomingMessages.values()); setActiveMessages([...keptMessages, ...newMessages]); From 3378f9d0f05de39befe47f9d5e51ba67885bc8a2 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 16 Dec 2024 11:05:57 +0200 Subject: [PATCH 6/9] fix: correct expiration condition for transit leg card --- app/component/itinerary/navigator/NaviCardContainer.js | 2 +- app/component/itinerary/navigator/NaviUtils.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index a603c03984..59e9b8011e 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -113,7 +113,7 @@ function NaviCardContainer( // Current active messages. Filter away expired messages. const previousValidMessages = legChanged - ? activeMessages.filter(m => m.expiresOn < time) + ? activeMessages.filter(m => !m.expiresOn || m.expiresOn > time) : activeMessages; // handle messages that are updated. diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 507b86b399..933a61f7a5 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -181,8 +181,8 @@ export function getFirstLastLegs(legs) { } export const getAdditionalMessages = (leg, time, intl, config, messages) => { const msgs = []; - const ticketMsg = messages.get('ticket'); - if (!ticketMsg && legTime(leg.start) - time < DISPLAY_MESSAGE_THRESHOLD) { + const closed = messages.get('ticket')?.closed; + if (!closed && legTime(leg.start) - time < DISPLAY_MESSAGE_THRESHOLD) { // Todo: multiple fares? const fare = getFaresFromLegs([leg], config)[0]; msgs.push({ From eaa38105bdf9b3872e28ac9251dde751cd9cc0dd Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 16 Dec 2024 11:46:29 +0200 Subject: [PATCH 7/9] fix: transit leg card realtime in green --- app/component/itinerary/navigator/NaviUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 933a61f7a5..cc6c5919e0 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -258,7 +258,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { {timeStr(estimated.time)}, stopOrStation, stopName: name, }} From 61d9efac7c1aeed5caba33ef256021df2be8dde9 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 16 Dec 2024 11:55:22 +0200 Subject: [PATCH 8/9] fix: add route name to transit leg card messages --- app/component/itinerary/navigator/NaviUtils.js | 6 ++++-- app/translations.js | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index cc6c5919e0..49eb06fcd9 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -216,10 +216,11 @@ export const getTransitLegState = (leg, intl, messages, time) => { let content; let severity; const isRealTime = realtimeState === 'UPDATED'; + const shortName = route.shortName || ''; if (notInSchedule) { const lMode = getLocalizedMode(mode, intl); - const routeName = `${lMode} ${route.shortName}`; + const routeName = `${lMode} ${shortName}`; const { delay } = estimated; const translationId = `navigation-mode-${delay > 0 ? 'late' : 'early'}`; @@ -238,6 +239,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { {
Date: Mon, 16 Dec 2024 12:33:43 +0200 Subject: [PATCH 9/9] fix: use correct check for realtime availability No realtime state occurs when transit has departed from its first stop more than 2 minutes ago. --- app/component/itinerary/PlanConnection.js | 1 + app/component/itinerary/navigator/NaviUtils.js | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/app/component/itinerary/PlanConnection.js b/app/component/itinerary/PlanConnection.js index 8cff4082c8..6fb4afe5fb 100644 --- a/app/component/itinerary/PlanConnection.js +++ b/app/component/itinerary/PlanConnection.js @@ -133,6 +133,7 @@ const planConnection = graphql` gtfsId } scheduledDeparture + serviceDay } stoptimes { stop { diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 49eb06fcd9..a21da09687 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -231,7 +231,14 @@ export const getTransitLegState = (leg, intl, messages, time) => {
); severity = 'WARNING'; - } else if (!isRealTime && legTime(start) - time < DISPLAY_MESSAGE_THRESHOLD) { + } else if (!isRealTime) { + const departure = leg.trip.stoptimesForDate[0]; + const departed = + 1000 * (departure.serviceDay + departure.scheduledDeparture); + if (time - departed < DISPLAY_MESSAGE_THRESHOLD) { + // vehicle just departed, maybe no realtime yet + return []; + } severity = 'WARNING'; content = (
@@ -246,7 +253,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { />
); - } else if (isRealTime) { + } else { const { parentStation, name } = from.stop; const stopOrStation = parentStation ? intl.formatMessage({ id: 'from-station' })