From c87c1a7e1f8e8d79bcd7337b680c61700f69c418 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 09:40:57 +0200 Subject: [PATCH 01/59] fix: bad translations and misleading ids --- app/translations.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/translations.js b/app/translations.js index f8c8113471..011ab42563 100644 --- a/app/translations.js +++ b/app/translations.js @@ -1304,6 +1304,7 @@ const translations = { 'navigation-abort-trip': 'TODO_Valitettavasti matkasi ei toteudu suunnitellusti.', 'navigation-description': 'Journey guidance', + 'navigation-get-mode': 'Get on the {mode}', 'navigation-header': 'Journey tracking', 'navigation-intro-begin': 'TODO_navigation-intro-begin_EN', 'navigation-intro-header': 'TODO_navigation-intro-login-prompt_EN', @@ -1326,7 +1327,6 @@ const translations = { 'navigation-ticket': 'Ticket', 'navigation-transfer-problem': 'TODO_Vaihto {route1} - {route2} ei onnistu', 'navigation-wait': 'Wait at the stop', - 'navigation-wait-mode': 'Nouse {mode}', 'navileg-arrive-at': 'TODO_{duration} min päästä klo {legTime}', 'navileg-bicycle': 'Cycle to', 'navileg-car': 'Drive to', @@ -1700,7 +1700,7 @@ const translations = { 'to-ferry': 'ferry', 'to-frontpage': 'To the front page', 'to-rail': 'train', - 'to-speedtram': 'TODO_pikaraitiovaunuun', + 'to-speedtram': 'light rail', 'to-subway': 'subway', 'to-tram': 'tram', today: 'Today', @@ -2579,6 +2579,7 @@ const translations = { 'navigation-abort-trip': 'Valitettavasti matkasi ei toteudu suunnitellusti.', 'navigation-description': 'Löydä perille ohjatusti', + 'navigation-get-mode': 'Nouse {mode}', 'navigation-header': 'Matkan seuranta', 'navigation-intro-begin': 'Aloita matka', 'navigation-intro-header': 'Mitä matkanseuranta tarjoaa?', @@ -2601,7 +2602,6 @@ const translations = { 'navigation-ticket': 'Lippu', 'navigation-transfer-problem': 'Vaihto {route1} - {route2} ei onnistu', 'navigation-wait': 'Odota pysäkillä', - 'navigation-wait-mode': 'Nouse {mode}', 'navileg-arrive-at': '{duration} min päästä klo {legTime}', 'navileg-bicycle': 'Pyöräile', 'navileg-car': 'Aja', @@ -2974,7 +2974,7 @@ const translations = { 'to-ferry': 'lauttaan', 'to-frontpage': 'Etusivulle', 'to-rail': 'junaan', - 'to-speedtram': 'TODO_pikaraitiovaunuun', + 'to-speedtram': 'pikaraitiovaunuun', 'to-subway': 'metroon', 'to-tram': 'raitiovaunuun', today: 'Tänään', @@ -5506,6 +5506,7 @@ const translations = { 'navigation-abort-trip': 'TODO_Valitettavasti matkasi ei toteudu suunnitellusti.', 'navigation-description': 'Hitta fram med vägledning.', + 'navigation-get-mode': 'Gå på {mode}', 'navigation-header': 'Följa', 'navigation-intro-begin': 'TODO_navigation-intro-begin_SV', 'navigation-intro-header': 'TODO_navigation-intro-login-prompt_SV', @@ -5528,7 +5529,6 @@ const translations = { 'navigation-ticket': 'Biljett', 'navigation-transfer-problem': 'TODO_Vaihto {route1} - {route2} ei onnistu', 'navigation-wait': 'Vänta på hållplatsen', - 'navigation-wait-mode': 'Odota {mode}', 'navileg-arrive-at': 'TODO_{duration} min päästä klo {legTime}', 'navileg-bicycle': 'Cycla till', 'navileg-car': 'Kör till', @@ -5904,7 +5904,7 @@ const translations = { 'to-ferry': 'färjan', 'to-frontpage': 'Till startsidan', 'to-rail': 'tåget', - 'to-speedtram': 'TODO_pikaraitiovaunuun', + 'to-speedtram': 'snabbspårvagnen', 'to-subway': 'metron', 'to-tram': 'spårvagnen', today: 'I dag', From 8a169cfa6e03e6d3d8cc91685976155ca2aeeba5 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 09:41:29 +0200 Subject: [PATCH 02/59] fix: proper formatting of 'get on the vehicle' messages --- .../itinerary/navigator/NaviInstructions.js | 17 ++++++++++------- app/component/itinerary/navigator/NaviUtils.js | 9 +++++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/component/itinerary/navigator/NaviInstructions.js b/app/component/itinerary/navigator/NaviInstructions.js index 54518aae52..14a2110bf8 100644 --- a/app/component/itinerary/navigator/NaviInstructions.js +++ b/app/component/itinerary/navigator/NaviInstructions.js @@ -6,7 +6,12 @@ import { displayDistance } from '../../../util/geo-utils'; import { legShape, configShape } from '../../../util/shapes'; import { legDestination, legTimeStr, legTime } from '../../../util/legUtils'; import RouteNumber from '../../RouteNumber'; -import { LEGTYPE, getLocalizedMode, getRemainingTraversal } from './NaviUtils'; +import { + LEGTYPE, + getLocalizedMode, + getToLocalizedMode, + getRemainingTraversal, +} from './NaviUtils'; import { durationToString } from '../../../util/timeUtils'; import { getRouteMode } from '../../../util/modeUtils'; @@ -45,7 +50,6 @@ export default function NaviInstructions( if (legType === LEGTYPE.WAIT && nextLeg.mode !== 'WALK') { const { mode, headsign, route, start } = nextLeg; const hs = headsign || nextLeg.trip?.tripHeadsign; - const localizedMode = getLocalizedMode(mode, intl); const remainingDuration = Math.max( Math.ceil((legTime(start) - time) / 60000), @@ -66,9 +70,9 @@ export default function NaviInstructions( <>
@@ -101,7 +105,6 @@ export default function NaviInstructions( const stopOrStation = leg.to.stop.parentStation ? intl.formatMessage({ id: 'navileg-from-station' }) : intl.formatMessage({ id: 'navileg-from-stop' }); - const localizedMode = getLocalizedMode(leg.mode, intl); const remainingDuration = Math.max(Math.ceil((t - time) / 60000), 0); // ms to minutes, >= 0 const values = { @@ -117,7 +120,7 @@ export default function NaviInstructions(
diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 8ba18fa2e7..79d152d353 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -191,12 +191,21 @@ function findTransferProblems(legs, time, position, origin) { } return problems; } + export const getLocalizedMode = (mode, intl) => { return intl.formatMessage({ id: `${mode.toLowerCase()}`, defaultMessage: `${mode}`, }); }; + +export const getToLocalizedMode = (mode, intl) => { + return intl.formatMessage({ + id: `to-${mode.toLowerCase()}`, + defaultMessage: `${mode}`, + }); +}; + export function getFirstLastLegs(legs) { const first = legs[0]; const last = legs[legs.length - 1]; From dfc9ffd1c0d27ddf66ad34c13ecaff7279991024 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 10:44:49 +0200 Subject: [PATCH 03/59] fix: add missing ferry pier translation, fix inverted translation ids --- app/translations.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/app/translations.js b/app/translations.js index 011ab42563..6974cb53e1 100644 --- a/app/translations.js +++ b/app/translations.js @@ -1328,10 +1328,11 @@ const translations = { 'navigation-transfer-problem': 'TODO_Vaihto {route1} - {route2} ei onnistu', 'navigation-wait': 'Wait at the stop', 'navileg-arrive-at': 'TODO_{duration} min päästä klo {legTime}', + 'navileg-at-ferrypier': 'ferry pier', + 'navileg-at-station': 'station', + 'navileg-at-stop': 'stop', 'navileg-bicycle': 'Cycle to', 'navileg-car': 'Drive to', - 'navileg-from-station': 'asemalla', - 'navileg-from-stop': 'pysäkillä', 'navileg-in-transit': 'TODO_{mode}matka', 'navileg-leave-at': 'Jää pois {stopOrStation} {stop} {duration} min päästä klo {legTime}', @@ -2603,10 +2604,11 @@ const translations = { 'navigation-transfer-problem': 'Vaihto {route1} - {route2} ei onnistu', 'navigation-wait': 'Odota pysäkillä', 'navileg-arrive-at': '{duration} min päästä klo {legTime}', + 'navileg-at-ferrypier': 'lauttalaiturilla', + 'navileg-at-station': 'asemalla', + 'navileg-at-stop': 'pysäkillä', 'navileg-bicycle': 'Pyöräile', 'navileg-car': 'Aja', - 'navileg-from-station': 'asemalla', - 'navileg-from-stop': 'pysäkillä', 'navileg-in-transit': '{mode}matka', 'navileg-leave-at': 'Jää pois {stopOrStation} {stop} {duration} min päästä klo {legTime}', @@ -5530,10 +5532,11 @@ const translations = { 'navigation-transfer-problem': 'TODO_Vaihto {route1} - {route2} ei onnistu', 'navigation-wait': 'Vänta på hållplatsen', 'navileg-arrive-at': 'TODO_{duration} min päästä klo {legTime}', + 'navileg-at-ferrypier': 'färjekajen', + 'navileg-at-station': 'station', + 'navileg-at-stop': 'hållplats', 'navileg-bicycle': 'Cycla till', 'navileg-car': 'Kör till', - 'navileg-from-station': 'TODO_asemalla', - 'navileg-from-stop': 'TODO_pysäkillä', 'navileg-in-transit': 'TODO_{mode}matka', 'navileg-leave-at': 'TODO_Jää pois {stopOrStation} {stop} {duration} min päästä klo {legTime}', From 28595fea4cb2ada28c40e82229755f3d78df73cd Mon Sep 17 00:00:00 2001 From: Simo Partinen Date: Fri, 27 Dec 2024 10:53:26 +0200 Subject: [PATCH 04/59] fix: prevent element flash on click --- app/component/itinerary/navigator/navigator.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/component/itinerary/navigator/navigator.scss b/app/component/itinerary/navigator/navigator.scss index f219d79de1..d7db39fb0b 100644 --- a/app/component/itinerary/navigator/navigator.scss +++ b/app/component/itinerary/navigator/navigator.scss @@ -72,6 +72,7 @@ $fixed-width-padding: 16px; letter-spacing: -0.3px; box-shadow: 0 2px 4px 0 rgba(51, 51, 51, 0.2); width: calc(100vw - #{$fixed-width-padding}); + cursor: default; &.expanded { max-height: unset; From 6357fdea5f079850199e581407032bcf28987001 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 10:57:05 +0200 Subject: [PATCH 05/59] fix: updated leave at instructions --- .../itinerary/navigator/NaviInstructions.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/component/itinerary/navigator/NaviInstructions.js b/app/component/itinerary/navigator/NaviInstructions.js index 14a2110bf8..d20e81484b 100644 --- a/app/component/itinerary/navigator/NaviInstructions.js +++ b/app/component/itinerary/navigator/NaviInstructions.js @@ -100,11 +100,15 @@ export default function NaviInstructions( if (legType === LEGTYPE.TRANSIT) { const rt = leg.realtimeState === 'UPDATED'; - const t = legTime(leg.end); - const stopOrStation = leg.to.stop.parentStation - ? intl.formatMessage({ id: 'navileg-from-station' }) - : intl.formatMessage({ id: 'navileg-from-stop' }); + + const destId = // eslint-disable-next-line no-nested-ternary + leg.mode === 'FERRY' + ? 'navileg-at-ferrypier' + : leg.to.stop.parentStation + ? 'navileg-at-station' + : 'navileg-at-stop'; + const stopOrStation = intl.formatMessage({ id: destId }); const remainingDuration = Math.max(Math.ceil((t - time) / 60000), 0); // ms to minutes, >= 0 const values = { From e6cad20c14c8e23cba241c06d993857798644cf9 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 11:12:18 +0200 Subject: [PATCH 06/59] fix: add ferry pier to 'leaves from' message --- app/component/itinerary/navigator/NaviUtils.js | 12 +++++++++--- app/translations.js | 3 +++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 79d152d353..ec209313a6 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -299,9 +299,15 @@ export const getTransitLegState = (leg, intl, messages, time) => { ); } else { const { parentStation, name } = from.stop; - const stopOrStation = parentStation - ? intl.formatMessage({ id: 'from-station' }) - : intl.formatMessage({ id: 'from-stop' }); + + const fromId = // eslint-disable-next-line no-nested-ternary + mode === 'FERRY' + ? 'from-ferrypier' + : parentStation + ? 'from-station' + : 'from-stop'; + const stopOrStation = intl.formatMessage({ id: fromId }); + content = (
Date: Fri, 27 Dec 2024 11:26:51 +0200 Subject: [PATCH 07/59] fix: show sheduled departure as info if realtime is not available Navi should show something when transit is departing from its first stop without realtime. --- app/component/itinerary/navigator/NaviUtils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index ec209313a6..9c25e670aa 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -281,9 +281,10 @@ export const getTransitLegState = (leg, intl, messages, time) => { 1000 * (departure.serviceDay + departure.scheduledDeparture); if (time - departed < DISPLAY_MESSAGE_THRESHOLD) { // vehicle just departed, maybe no realtime yet - return []; + severity = 'INFO'; + } else { + severity = 'WARNING'; } - severity = 'WARNING'; content = (
From 1f7cdd105eca256fd3ef59a8f5067c218bfd5575 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 11:45:10 +0200 Subject: [PATCH 08/59] chore: use 'from-ferrypier' also in itinerary Remove the word 'from' from mode expression --- app/component/itinerary/Itinerary.js | 7 ++++++- app/translations.js | 18 +++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/app/component/itinerary/Itinerary.js b/app/component/itinerary/Itinerary.js index 22eb769587..803bfd4217 100644 --- a/app/component/itinerary/Itinerary.js +++ b/app/component/itinerary/Itinerary.js @@ -652,7 +652,12 @@ const Itinerary = ( firstDeparture = compressedLegs.find(isTransitLeg); if (firstDeparture) { let firstDepartureStopType; - if (firstDeparture.mode === 'RAIL' || firstDeparture.mode === 'SUBWAY') { + if (firstDeparture.mode === 'FERRY') { + firstDepartureStopType = 'from-ferrypier'; + } else if ( + firstDeparture.mode === 'RAIL' || + firstDeparture.mode === 'SUBWAY' + ) { firstDepartureStopType = 'from-station'; } else { firstDepartureStopType = 'from-stop'; diff --git a/app/translations.js b/app/translations.js index 1c8f625cad..180b09d307 100644 --- a/app/translations.js +++ b/app/translations.js @@ -381,8 +381,8 @@ const translations = { ferry: 'Fähre', 'ferry-with-route-number': 'Fähre {routeNumber} {headSign}', 'fetch-new-route': 'Neue Verbindung anfragen', - 'from-station': 'von Bahnhof', - 'from-stop': 'von Halt', + 'from-station': 'Bahnhof', + 'from-stop': 'Halt', frontpage: 'Startseite', 'generic-error': 'Ein Fehler ist aufgetreten', 'geolocate-yourself': 'Lokalisieren', @@ -450,7 +450,7 @@ const translations = { 'itinerary-summary-row.first-departure': '{vehicle} fährt um {departureTime} von {stopName}.', 'itinerary-summary-row.first-leg-start-time': - 'Fährt ab um {firstDepartureTime} {firstDepartureStopType} {firstDepartureStop}', + 'Fährt ab um {firstDepartureTime} von {firstDepartureStopType} {firstDepartureStop}', 'itinerary-summary-row.first-leg-start-time-citybike': 'Abfahrt um {firstDepartureTime} von {firstDepartureStop} Leihrad-Station', 'itinerary-summary-row.no-transit-legs': 'Start jederzeit möglich', @@ -1090,8 +1090,8 @@ const translations = { 'from-ferrypier': 'ferry pier', 'from-rail': 'train', 'from-scooter-location': 'the scooter location', - 'from-station': 'from station', - 'from-stop': 'from stop', + 'from-station': 'station', + 'from-stop': 'stop', 'from-subway': 'subway', 'from-tram': 'tram', frontpage: 'Frontpage', @@ -1189,7 +1189,7 @@ const translations = { 'itinerary-summary-row.first-departure': '{vehicle} leaves at {departureTime} from stop {stopName}.', 'itinerary-summary-row.first-leg-start-time': - 'Leaves at {firstDepartureTime} {firstDepartureStopType} {firstDepartureStop}{firstDeparturePlatform}', + 'Leaves at {firstDepartureTime} from {firstDepartureStopType} {firstDepartureStop}{firstDeparturePlatform}', 'itinerary-summary-row.first-leg-start-time-citybike': 'Departure at {firstDepartureTime} from {firstDepartureStop} bike station', 'itinerary-summary-row.first-leg-start-time-scooter': @@ -5299,8 +5299,8 @@ const translations = { 'from-ferrypier': 'färjerkajen', 'from-rail': 'tåget', 'from-scooter-location': 'platsen för sparkcykel', - 'from-station': 'från stationen', - 'from-stop': 'från hållplats', + 'from-station': 'stationen', + 'from-stop': 'hållplats', 'from-subway': 'metron', 'from-tram': 'spårvagnen', frontpage: 'Framsidan', @@ -5396,7 +5396,7 @@ const translations = { 'itinerary-summary-row.first-departure': '{vehicle} avgår från station {stopName} klockan {departureTime}.', 'itinerary-summary-row.first-leg-start-time': - 'Avgår kl {firstDepartureTime} {firstDepartureStopType} {firstDepartureStop}{firstDeparturePlatform}', + 'Avgår kl {firstDepartureTime} från {firstDepartureStopType} {firstDepartureStop}{firstDeparturePlatform}', 'itinerary-summary-row.first-leg-start-time-citybike': 'Avgång kl {firstDepartureTime} från {firstDepartureStop} stadscykelstation', 'itinerary-summary-row.first-leg-start-time-scooter': From f65f5635c24bea32036747beb5b782083d96c1d3 Mon Sep 17 00:00:00 2001 From: Simo Partinen Date: Fri, 27 Dec 2024 13:35:42 +0200 Subject: [PATCH 09/59] fix: streamlined markup and classes --- app/component/itinerary/navigator/NaviCard.js | 77 +++++---- .../itinerary/navigator/NaviCardContainer.js | 24 ++- .../itinerary/navigator/navigator.scss | 158 +++++++++--------- 3 files changed, 129 insertions(+), 130 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCard.js b/app/component/itinerary/navigator/NaviCard.js index 75eaac285f..e60a560729 100644 --- a/app/component/itinerary/navigator/NaviCard.js +++ b/app/component/itinerary/navigator/NaviCard.js @@ -1,13 +1,13 @@ +import PropTypes from 'prop-types'; import React from 'react'; import { FormattedMessage } from 'react-intl'; -import PropTypes from 'prop-types'; -import { legShape, configShape } from '../../../util/shapes'; -import Icon from '../../Icon'; import { isRental } from '../../../util/legUtils'; -import NaviInstructions from './NaviInstructions'; +import { getRouteMode } from '../../../util/modeUtils'; +import { configShape, legShape } from '../../../util/shapes'; +import Icon from '../../Icon'; import NaviCardExtension from './NaviCardExtension'; +import NaviInstructions from './NaviInstructions'; import { LEGTYPE } from './NaviUtils'; -import { getRouteMode } from '../../../util/modeUtils'; const iconMap = { BICYCLE: 'icon-icon_cyclist', @@ -29,46 +29,44 @@ export default function NaviCard( { leg, nextLeg, legType, cardExpanded, startTime, time, position, origin }, { config }, ) { + let mainCardContent; if (legType === LEGTYPE.PENDING) { - return ( + mainCardContent = ( ); - } - if (legType === LEGTYPE.END) { - return ; - } - if (!leg && !nextLeg) { + } else if (legType === LEGTYPE.END) { + mainCardContent = ; + } else if (!leg && !nextLeg) { return null; - } - let iconColor = 'currentColor'; - let iconName; - let instructions = ''; - if (legType === LEGTYPE.TRANSIT) { - const m = getRouteMode(leg.route, config); - iconColor = config.colors.iconColors[`mode-${m}`] || leg.route.color; - iconName = iconMap[m.toUpperCase()]; + } else { + let iconColor = 'currentColor'; + let iconName; + let instructions = ''; + if (legType === LEGTYPE.TRANSIT) { + const m = getRouteMode(leg.route, config); + iconColor = config.colors.iconColors[`mode-${m}`] || leg.route.color; + iconName = iconMap[m.toUpperCase()]; - instructions = `navileg-in-transit`; - } else if (legType !== LEGTYPE.WAIT && isRental(leg, nextLeg)) { - if (leg.mode === 'WALK' && nextLeg?.mode === 'SCOOTER') { - instructions = `navileg-rent-scooter`; - } else { - instructions = 'rent-cycle-at'; + instructions = `navileg-in-transit`; + } else if (legType !== LEGTYPE.WAIT && isRental(leg, nextLeg)) { + if (leg.mode === 'WALK' && nextLeg?.mode === 'SCOOTER') { + instructions = `navileg-rent-scooter`; + } else { + instructions = 'rent-cycle-at'; + } + iconName = iconMap[leg.mode]; + } else if (legType === LEGTYPE.MOVE) { + instructions = `navileg-${leg?.mode.toLowerCase()}`; + iconName = iconMap.WALK; + } else if (legType === LEGTYPE.WAIT) { + iconName = iconMap.WAIT; } - iconName = iconMap[leg.mode]; - } else if (legType === LEGTYPE.MOVE) { - instructions = `navileg-${leg?.mode.toLowerCase()}`; - iconName = iconMap.WALK; - } else if (legType === LEGTYPE.WAIT) { - iconName = iconMap.WAIT; - } - return ( -
-
+ mainCardContent = ( + <>
-
+
-
+ + ); + } + return ( +
+
{mainCardContent}
{cardExpanded && ( {activeMessages.length > 0 && ( diff --git a/app/component/itinerary/navigator/navigator.scss b/app/component/itinerary/navigator/navigator.scss index d7db39fb0b..482711ceaa 100644 --- a/app/component/itinerary/navigator/navigator.scss +++ b/app/component/itinerary/navigator/navigator.scss @@ -61,7 +61,7 @@ $fixed-width-padding: 16px; } } -.navitop { +.navi-top-card-button { margin: 0 var(--space-s) 5px var(--space-s); border-radius: 8px; min-height: 70px; @@ -78,116 +78,114 @@ $fixed-width-padding: 16px; max-height: unset; } - .navitop-arrow { + .navi-top-card-arrow { .inverted { transform: rotate(180deg); } } - .content { + .main-card { width: 100%; + margin: var(--space-m) var(--space-l); - .navi-top-card { - margin: 16px 24px 16px; + .content { + display: flex; + flex-direction: row; + color: black; + justify-content: center; - .main-card { - display: flex; - flex-direction: row; + .mode { + width: 32px; + height: 32px; color: black; + margin-right: var(--space-s); + margin-top: var(--space-xxs); + } + } - .mode { - width: 32px; - height: 32px; - color: black; - margin-right: var(--space-s); - margin-top: var(--space-xxs); - } + .instructions { + display: flex; + flex-direction: column; + width: 100%; + font-size: $font-size-normal; + font-weight: $font-weight-medium; + + &.expanded { + margin-bottom: 0; } - .instructions { - display: flex; - flex-direction: column; - width: 100%; + .destination-header { font-size: $font-size-normal; - font-weight: $font-weight-medium; + font-weight: 500; + display: flex; + } - &.expanded { - margin-bottom: 0; - } + .vehicle-leg { + display: flex; + margin-top: var(--space-xs); + font-weight: $font-weight-book; + width: 80%; + text-align: left; + } - .destination-header { - font-size: $font-size-normal; - font-weight: 500; + .wait-leg { + display: flex; + margin-top: 3px; + flex-direction: column; + align-items: flex-start; + + .route-info { display: flex; + align-self: flex-start; + margin-bottom: var(--space-xcs); } - .vehicle-leg { - display: flex; - margin-top: var(--space-xs); + .wait-duration { font-weight: $font-weight-book; - width: 80%; - text-align: left; + margin-top: var(--space-xs); } - .wait-leg { - display: flex; - margin-top: 3px; - flex-direction: column; - align-items: flex-start; - - .route-info { - display: flex; - align-self: flex-start; - margin-bottom: var(--space-xcs); - } - - .wait-duration { - font-weight: $font-weight-book; - margin-top: var(--space-xs); - } - - .bar { - border-radius: $border-radius; - } - - .route-number { - .vcenter-children { - .vehicle-number { - color: white; - margin-top: 5px; - } + .bar { + border-radius: $border-radius; + } - display: flex; + .route-number { + .vcenter-children { + .vehicle-number { + color: white; + margin-top: 5px; } - } - .headsign { - margin-left: 10px; - font-size: $font-size-small; - font-weight: $font-weight-book; - max-width: 85%; - text-align: left; - align-content: center; + display: flex; } + } - .icon { - margin-top: 2px; - height: 25px; - width: 25px; - } + .headsign { + margin-left: 10px; + font-size: $font-size-small; + font-weight: $font-weight-book; + max-width: 85%; + text-align: left; + align-content: center; } - } - .duration { - &.fade-out { - animation: fadeOut 3s forwards; + .icon { + margin-top: 2px; + height: 25px; + width: 25px; } + } + } - font-size: $font-size-xsmall; - font-weight: $font-weight-book; - display: flex; - margin-top: 4px; + .duration { + &.fade-out { + animation: fadeOut 3s forwards; } + + font-size: $font-size-xsmall; + font-weight: $font-weight-book; + display: flex; + margin-top: 4px; } .extension { From 7909d0a8e488f59bb6a86e366765f2f95ef0ab58 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 15:00:53 +0200 Subject: [PATCH 10/59] fix: allow alerts to update --- 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 9c25e670aa..f567f9aa25 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -349,7 +349,7 @@ export const getItineraryAlerts = ( .filter(alert => { const { first } = getFirstLastLegs(legs); const startTime = legTime(first.start) / 1000; - if (messages.get(alert.id)) { + if (messages.get(alert.id)?.closed) { return false; } // show only alerts that are active when From 78e959d9b0d54a204de0b5c80242af3622bad436 Mon Sep 17 00:00:00 2001 From: Simo Partinen Date: Fri, 27 Dec 2024 16:33:13 +0200 Subject: [PATCH 11/59] feat: memoized planar leg calculation --- .../navigator/hooks/useRealtimeLegs.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js index 115ef46550..a3a4623b36 100644 --- a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js +++ b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js @@ -155,6 +155,16 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { [initialLegs[0]], ); + const planarLegs = useMemo(() => { + return initialLegs.map(leg => { + const geometry = polyUtil.decode(leg.legGeometry.points); + return { + ...leg, + geometry: geometry.map(p => GeodeticToEnu(p[0], p[1], origin)), + }; + }); + }, [initialLegs]); + const queryAndMapRealtimeLegs = useCallback( async legs => { if (!legs.length) { @@ -188,14 +198,6 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { return; } - const planarLegs = initialLegs.map(leg => { - const geometry = polyUtil.decode(leg.legGeometry.points); - return { - ...leg, - geometry: geometry.map(p => GeodeticToEnu(p[0], p[1], origin)), - }; - }); - const rtLegMap = await queryAndMapRealtimeLegs(planarLegs).catch(err => // eslint-disable-next-line no-console console.error('Failed to query and map real time legs', err), @@ -219,7 +221,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { // shift non-transit-legs to match possibly changed transit legs matchLegEnds(rtLegs); setRealTimeLegs(rtLegs); - }, [initialLegs, queryAndMapRealtimeLegs]); + }, [planarLegs, queryAndMapRealtimeLegs]); useEffect(() => { fetchAndSetRealtimeLegs(); From 12dcc5e0584a61d35356623faba6ea2e6c7f8f45 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 17:00:52 +0200 Subject: [PATCH 12/59] chore: refactor navi alerts - remove unncessary div and style - don't repeat code or pass static content as prop - don't render many alerts about triggering new itinerary search - better names --- .../itinerary/navigator/NaviUtils.js | 92 +++++++++---------- .../itinerary/navigator/navigator.scss | 27 ++---- 2 files changed, 53 insertions(+), 66 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index f567f9aa25..7f7bad54b5 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -8,7 +8,7 @@ import { getFaresFromLegs } from '../../../util/fareUtils'; import { ExtendedRouteTypes } from '../../../constants'; import { getItineraryPagePath } from '../../../util/path'; -const TRANSFER_SLACK = 60000; +const TRANSFER_SLACK = 600000; const DISPLAY_MESSAGE_THRESHOLD = 120 * 1000; // 2 minutes export const DESTINATION_RADIUS = 20; // meters @@ -340,10 +340,6 @@ export const getItineraryAlerts = ( location, router, ) => { - const canceled = legs.filter( - leg => leg.realtimeState === 'CANCELED' && legTime(leg.start) > time, - ); - let content; const alerts = legs.flatMap(leg => { return leg.alerts .filter(alert => { @@ -375,12 +371,13 @@ export const getItineraryAlerts = ( id: `${alert.effectiveStartDate}-${alert.alertDescriptionText}`, })); }); - const abortTrip = ; - const withShowRoutesBtn = children => ( -
+ + const withNewSearchBtn = children => ( +
{children} +
); - if (canceled) { + const canceled = legs.filter( + leg => leg.realtimeState === 'CANCELED' && legTime(leg.start) > time, + ); + + if (canceled.length) { // show routes button only for first canceled leg. canceled.forEach((leg, i) => { const { legId, mode, route } = leg; @@ -403,16 +404,13 @@ export const getItineraryAlerts = ( /> ); // we want to show the show routes button only for the first canceled leg. - if (i === 0) { - content = withShowRoutesBtn( -
- {m} - {abortTrip} -
, + const content = + i === 0 ? ( + withNewSearchBtn({ m }) + ) : ( +
{m}
); - } else { - content =
{m}
; - } + if (!messages.get(`canceled-${legId}`)) { alerts.push({ severity: 'ALERT', @@ -423,36 +421,32 @@ export const getItineraryAlerts = ( }); } }); - } - - const transferProblems = findTransferProblems(legs, time, position, origin); - if (transferProblems.length) { - let prob = transferProblems.find(p => p.severity === 'ALERT'); - if (!prob) { - // just take first - [prob] = transferProblems; - } - const transferId = `transfer-${prob.fromLeg.legId}-${prob.toLeg.legId}}`; - const alert = messages.get(transferId); - if (!alert || alert.severity !== prob.severity) { - content = withShowRoutesBtn( -
- - {abortTrip} -
, - ); - alerts.push({ - severity: prob.severity, - content, - id: transferId, - hideClose: prob.severity === 'ALERT', - }); + } else { + const transferProblems = findTransferProblems(legs, time, position, origin); + if (transferProblems.length) { + let prob = transferProblems.find(p => p.severity === 'ALERT'); + if (!prob) { + // just take first + [prob] = transferProblems; + } + const transferId = `transfer-${prob.fromLeg.legId}-${prob.toLeg.legId}}`; + const alert = messages.get(transferId); + if (!alert || alert.severity !== prob.severity) { + alerts.push({ + severity: prob.severity, + content: withNewSearchBtn( + , + ), + id: transferId, + hideClose: prob.severity === 'ALERT', + }); + } } } return alerts; diff --git a/app/component/itinerary/navigator/navigator.scss b/app/component/itinerary/navigator/navigator.scss index 482711ceaa..5f09e1c6f8 100644 --- a/app/component/itinerary/navigator/navigator.scss +++ b/app/component/itinerary/navigator/navigator.scss @@ -457,23 +457,16 @@ $fixed-width-padding: 16px; } } - .alt-btn { - display: flex; - flex-direction: column; - width: 100%; - - .show-options { - padding: var(--space-s, 16px) var(--space-xs, 8px) var(--space-s, 16px) - var(--space-s, 16px); - background: #0074bf; - color: #fff; - border-radius: 999px; // var(--radius-radius-medium, 8px); - margin-top: var(--space-xxs); - - /* box-shadow-card-s-strong */ - box-shadow: 0 2px 4px 0 - var(--color-shadow-strong, rgba(51, 51, 51, 0.2)); - } + .new-itinerary-search { + padding: var(--space-s, 16px) var(--space-xs, 8px) var(--space-s, 16px) + var(--space-s, 16px); + background: #0074bf; + color: #fff; + border-radius: 999px; // var(--radius-radius-medium, 8px); + margin-top: var(--space-xxs); + + /* box-shadow-card-s-strong */ + box-shadow: 0 2px 4px 0 var(--color-shadow-strong, rgba(51, 51, 51, 0.2)); } &.slide-out-right { From c5b3b26e7a73e0c5e2f5eff0dc561412667731d8 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 27 Dec 2024 17:43:49 +0200 Subject: [PATCH 13/59] chore: render search alert only when needed --- .../itinerary/navigator/NaviUtils.js | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 7f7bad54b5..29ab68cfaa 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -330,6 +330,22 @@ export const getTransitLegState = (leg, intl, messages, time) => { return [{ severity, content, id: legId, expiresOn: legTime(start) }]; }; +function withNewSearchBtn(router, to, children) { + return ( +
+ {children} + + +
+ ); +} + export const getItineraryAlerts = ( legs, time, @@ -372,20 +388,6 @@ export const getItineraryAlerts = ( })); }); - const withNewSearchBtn = children => ( -
- {children} - - -
- ); - const canceled = legs.filter( leg => leg.realtimeState === 'CANCELED' && legTime(leg.start) > time, ); @@ -406,7 +408,7 @@ export const getItineraryAlerts = ( // we want to show the show routes button only for the first canceled leg. const content = i === 0 ? ( - withNewSearchBtn({ m }) + withNewSearchBtn(router, { m }, location.to) ) : (
{m}
); @@ -435,6 +437,7 @@ export const getItineraryAlerts = ( alerts.push({ severity: prob.severity, content: withNewSearchBtn( + router, , + location.to, ), id: transferId, hideClose: prob.severity === 'ALERT', From 9a938a5b4e0e6647964f70b1f4b32670cdb73974 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sat, 28 Dec 2024 08:14:00 +0200 Subject: [PATCH 14/59] fix: parameter order --- 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 29ab68cfaa..a917a2caae 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -330,7 +330,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { return [{ severity, content, id: legId, expiresOn: legTime(start) }]; }; -function withNewSearchBtn(router, to, children) { +function withNewSearchBtn(router, children, to) { return (
{children} From 9536cb4118772f1782a2abe0d212bd5cf09a63fd Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 29 Dec 2024 12:01:02 +0200 Subject: [PATCH 15/59] feat: support OTP stop type in locationToUri --- app/util/otpStrings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/util/otpStrings.js b/app/util/otpStrings.js index ed1e0ec639..50921edaae 100644 --- a/app/util/otpStrings.js +++ b/app/util/otpStrings.js @@ -52,7 +52,7 @@ export function locationToUri(location) { if (!location.lat) { return '-'; } - let address = location.address || ''; + let address = location.address || location.name || ''; if (location.gtfsId) { address = `${address}**${location.gtfsId}`; } From 7dbd36c3a8e746289f144d560dc583f18aadc9b7 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 29 Dec 2024 12:02:50 +0200 Subject: [PATCH 16/59] feat: advanced rerouting - Search from next stop if in transit leg - Use existing position if available, instead of geolocator wrapper --- .../itinerary/navigator/NaviCardContainer.js | 14 ++++++-- .../itinerary/navigator/NaviUtils.js | 33 ++++++++++++++----- 2 files changed, 37 insertions(+), 10 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 97c7ac1b94..51b3433a96 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -11,6 +11,7 @@ import { getAdditionalMessages, getItineraryAlerts, getTransitLegState, + itinerarySearchPath, LEGTYPE, DESTINATION_RADIUS, } from './NaviUtils'; @@ -92,6 +93,16 @@ function NaviCardContainer( config, ); + const makeNewItinerarySearch = () => { + const path = itinerarySearchPath( + time, + currentLeg, + position, + match.params.location.to, + ); + router.push(path); + }; + useEffect(() => { updateClient(getNaviTopics(), context); }, []); @@ -116,8 +127,7 @@ function NaviCardContainer( origin, intl, messages, - match.params, - router, + makeNewItinerarySearch, ), ); diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index a917a2caae..1723c4e861 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -7,8 +7,9 @@ import { timeStr, epochToIso } from '../../../util/timeUtils'; import { getFaresFromLegs } from '../../../util/fareUtils'; import { ExtendedRouteTypes } from '../../../constants'; import { getItineraryPagePath } from '../../../util/path'; +import { locationToUri } from '../../../util/otpStrings'; -const TRANSFER_SLACK = 600000; +const TRANSFER_SLACK = 60000; const DISPLAY_MESSAGE_THRESHOLD = 120 * 1000; // 2 minutes export const DESTINATION_RADIUS = 20; // meters @@ -330,7 +331,24 @@ export const getTransitLegState = (leg, intl, messages, time) => { return [{ severity, content, id: legId, expiresOn: legTime(start) }]; }; -function withNewSearchBtn(router, children, to) { +export function itinerarySearchPath(time, leg, position, to) { + let from; + if (leg.transitLeg) { + from = leg.intermediatePlaces.find( + p => legTime(p.arrival) > time + TRANSFER_SLACK, + ); + if (!from) { + from = leg.to; + } + } else { + from = position || leg.to; + } + const location = from.stop || from.stop; // prefer stops + + return getItineraryPagePath(locationToUri(location), to); +} + +function withNewSearchBtn(children, searchCallback) { return (
{children} @@ -338,7 +356,7 @@ function withNewSearchBtn(router, children, to) { @@ -353,8 +371,7 @@ export const getItineraryAlerts = ( origin, intl, messages, - location, - router, + itinerarySearchCallback, ) => { const alerts = legs.flatMap(leg => { return leg.alerts @@ -399,6 +416,7 @@ export const getItineraryAlerts = ( const lMode = getLocalizedMode(mode, intl); const routeName = `${lMode} ${route.shortName}`; + const m = ( {m}
); @@ -437,7 +455,6 @@ export const getItineraryAlerts = ( alerts.push({ severity: prob.severity, content: withNewSearchBtn( - router, , - location.to, + itinerarySearchCallback, ), id: transferId, hideClose: prob.severity === 'ALERT', From 9136032aefc7655e911744bd96cf698c9a746eec Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 29 Dec 2024 13:49:21 +0200 Subject: [PATCH 17/59] fix: initial little bugs in new implementation --- app/component/itinerary/navigator/NaviCardContainer.js | 2 +- app/component/itinerary/navigator/NaviUtils.js | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 51b3433a96..75bea8d18c 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -98,7 +98,7 @@ function NaviCardContainer( time, currentLeg, position, - match.params.location.to, + match.params.to, ); router.push(path); }; diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 1723c4e861..7813a1ea7e 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -9,7 +9,7 @@ import { ExtendedRouteTypes } from '../../../constants'; import { getItineraryPagePath } from '../../../util/path'; import { locationToUri } from '../../../util/otpStrings'; -const TRANSFER_SLACK = 60000; +const TRANSFER_SLACK = 600000; const DISPLAY_MESSAGE_THRESHOLD = 120 * 1000; // 2 minutes export const DESTINATION_RADIUS = 20; // meters @@ -343,7 +343,10 @@ export function itinerarySearchPath(time, leg, position, to) { } else { from = position || leg.to; } - const location = from.stop || from.stop; // prefer stops + const location = { ...from }; + if (from.stop) { + location.gtfsId = from.stop.gtfsId; + } return getItineraryPagePath(locationToUri(location), to); } From 9b1deb226e72b5e0f69e329f626b9da2be0b2a8d Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 29 Dec 2024 13:54:41 +0200 Subject: [PATCH 18/59] fix: rerouting from waitleg or before the journey --- app/component/itinerary/navigator/NaviCardContainer.js | 1 + app/component/itinerary/navigator/NaviUtils.js | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 75bea8d18c..101324eefe 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -97,6 +97,7 @@ function NaviCardContainer( const path = itinerarySearchPath( time, currentLeg, + nextLeg, position, match.params.to, ); diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 7813a1ea7e..1a525206d3 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -331,9 +331,9 @@ export const getTransitLegState = (leg, intl, messages, time) => { return [{ severity, content, id: legId, expiresOn: legTime(start) }]; }; -export function itinerarySearchPath(time, leg, position, to) { +export function itinerarySearchPath(time, leg, nextLeg, position, to) { let from; - if (leg.transitLeg) { + if (leg?.transitLeg) { from = leg.intermediatePlaces.find( p => legTime(p.arrival) > time + TRANSFER_SLACK, ); @@ -341,7 +341,7 @@ export function itinerarySearchPath(time, leg, position, to) { from = leg.to; } } else { - from = position || leg.to; + from = position || leg?.to || nextLeg?.from; } const location = { ...from }; if (from.stop) { From 372c325f29f2882e21fe9f2d90e9dea7caed1991 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 08:36:23 +0200 Subject: [PATCH 19/59] fix: current leg should be undefined before itinerary starts --- .../navigator/hooks/useRealtimeLegs.js | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js index 115ef46550..4fb72efba8 100644 --- a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js +++ b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js @@ -91,7 +91,12 @@ function matchLegEnds(legs) { } } -function getLegsOfInterest(initialLegs, time, previousFinishedLeg) { +function getLegsOfInterest( + initialLegs, + time, + previousFinishedLeg, + itineraryStarted, +) { if (!initialLegs?.length) { return { firstLeg: undefined, @@ -100,7 +105,6 @@ function getLegsOfInterest(initialLegs, time, previousFinishedLeg) { nextLeg: undefined, }; } - const legs = initialLegs.reduce((acc, curr, i, arr) => { acc.push(curr); const next = arr[i + 1]; @@ -130,7 +134,8 @@ function getLegsOfInterest(initialLegs, time, previousFinishedLeg) { isAnyLegPropertyIdentical(currentLeg, previousFinishedLeg, [ 'legId', 'legGeometry.points', - ]) + ]) && + itineraryStarted // prev and current are both undefined before itinerary starts ) { previousLeg = currentLeg; currentLeg = nextLeg; @@ -149,6 +154,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { const [realTimeLegs, setRealTimeLegs] = useState(); const [time, setTime] = useState(Date.now()); const previousFinishedLeg = useRef(undefined); + const itineraryStarted = useRef(false); const origin = useMemo( () => GeodeticToEcef(initialLegs[0].from.lat, initialLegs[0].from.lon), @@ -233,10 +239,17 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { }, [fetchAndSetRealtimeLegs]); const { firstLeg, lastLeg, currentLeg, nextLeg, previousLeg } = - getLegsOfInterest(realTimeLegs, time, previousFinishedLeg.current); + getLegsOfInterest( + realTimeLegs, + time, + previousFinishedLeg.current, + itineraryStarted.current, + ); previousFinishedLeg.current = previousLeg; - + if (currentLeg) { + itineraryStarted.current = true; + } // return wait legs as undefined as they are not a global concept return { realTimeLegs, From cc5cdada141e1136eb3360fe63e8b8f37b00fe7f Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 08:49:42 +0200 Subject: [PATCH 20/59] fix: do not show transit realtime absence notifier too early If realtime is missing from a transit at its first stop, we should ignore it until there is only 2 minutes to the departure. --- app/component/itinerary/navigator/NaviUtils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 1a525206d3..9aee64389f 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -280,7 +280,10 @@ export const getTransitLegState = (leg, intl, messages, time) => { const departure = leg.trip.stoptimesForDate[0]; const departed = 1000 * (departure.serviceDay + departure.scheduledDeparture); - if (time - departed < DISPLAY_MESSAGE_THRESHOLD) { + if ( + time - departed < DISPLAY_MESSAGE_THRESHOLD && + time + DISPLAY_MESSAGE_THRESHOLD > legTime(leg.start) + ) { // vehicle just departed, maybe no realtime yet severity = 'INFO'; } else { From 7a6a88ab6bb88735e81f43c66f130e87744151e0 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 09:22:52 +0200 Subject: [PATCH 21/59] fix: intermediate stop details are needed for rerouting --- app/component/itinerary/navigator/NaviUtils.js | 4 +--- app/component/itinerary/queries/LegQuery.js | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 9aee64389f..32fb0f7f5e 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -337,9 +337,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { export function itinerarySearchPath(time, leg, nextLeg, position, to) { let from; if (leg?.transitLeg) { - from = leg.intermediatePlaces.find( - p => legTime(p.arrival) > time + TRANSFER_SLACK, - ); + from = leg.intermediatePlaces.find(p => legTime(p.arrival) > time + 60000); if (!from) { from = leg.to; } diff --git a/app/component/itinerary/queries/LegQuery.js b/app/component/itinerary/queries/LegQuery.js index be6e8e4ceb..f70c7fbbed 100644 --- a/app/component/itinerary/queries/LegQuery.js +++ b/app/component/itinerary/queries/LegQuery.js @@ -30,6 +30,12 @@ const legQuery = graphql` time } } + stop { + gtfsId + lat + lon + name + } } to { vehicleRentalStation { From 090d26ac700b0f1ee3fa3e3196265f668f996ee6 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 09:56:31 +0200 Subject: [PATCH 22/59] fix: stop merge which produces valid location --- app/component/itinerary/navigator/NaviUtils.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 32fb0f7f5e..d491ccfd84 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -344,10 +344,7 @@ export function itinerarySearchPath(time, leg, nextLeg, position, to) { } else { from = position || leg?.to || nextLeg?.from; } - const location = { ...from }; - if (from.stop) { - location.gtfsId = from.stop.gtfsId; - } + const location = { ...from, ...from.stop }; return getItineraryPagePath(locationToUri(location), to); } From 4bfe0cd017b653873d1843ae4642c8bddf9d283c Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 10:02:18 +0200 Subject: [PATCH 23/59] chore: rename --- .../itinerary/navigator/hooks/useRealtimeLegs.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js index 4fb72efba8..298e9d9288 100644 --- a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js +++ b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js @@ -92,12 +92,12 @@ function matchLegEnds(legs) { } function getLegsOfInterest( - initialLegs, + realTimeLegs, time, previousFinishedLeg, itineraryStarted, ) { - if (!initialLegs?.length) { + if (!realTimeLegs?.length) { return { firstLeg: undefined, lastLeg: undefined, @@ -105,7 +105,7 @@ function getLegsOfInterest( nextLeg: undefined, }; } - const legs = initialLegs.reduce((acc, curr, i, arr) => { + const legs = realTimeLegs.reduce((acc, curr, i, arr) => { acc.push(curr); const next = arr[i + 1]; @@ -146,7 +146,7 @@ function getLegsOfInterest( lastLeg: legs[legs.length - 1], previousLeg, currentLeg, - nextLeg: initialLegs.find(({ start }) => legTime(start) >= nextStart), + nextLeg: realTimeLegs.find(({ start }) => legTime(start) >= nextStart), }; } From 2cfca57577445d9f70389bb7a27664f1425edf54 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 10:07:27 +0200 Subject: [PATCH 24/59] fix: buggy alert identification --- app/component/itinerary/navigator/NaviUtils.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index d491ccfd84..40c6610200 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -365,6 +365,10 @@ function withNewSearchBtn(children, searchCallback) { ); } +function alertId(alert) { + return `${alert.effectiveStartDate}-${alert.alertDescriptionText}`; +} + export const getItineraryAlerts = ( legs, time, @@ -377,11 +381,11 @@ export const getItineraryAlerts = ( const alerts = legs.flatMap(leg => { return leg.alerts .filter(alert => { - const { first } = getFirstLastLegs(legs); - const startTime = legTime(first.start) / 1000; - if (messages.get(alert.id)?.closed) { + if (messages.get(alertId(alert))?.closed) { return false; } + const { first } = getFirstLastLegs(legs); + const startTime = legTime(first.start) / 1000; // show only alerts that are active when // the journey starts if (startTime < alert.effectiveStartDate) { @@ -402,7 +406,7 @@ export const getItineraryAlerts = ( {alert.alertHeaderText}
), - id: `${alert.effectiveStartDate}-${alert.alertDescriptionText}`, + id: alertId(alert), })); }); From b8ac9972509280519f2a0cf642b62977c7ba3c66 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 10:41:37 +0200 Subject: [PATCH 25/59] fix: focus without geolocation during a wait leg Navi focused on last leg if current leg was undefined --- app/component/itinerary/navigator/NaviCardContainer.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 101324eefe..31c2282d08 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -181,11 +181,10 @@ function NaviCardContainer( // handle initial focus when not tracking if (currentLeg) { focusToLeg(currentLeg); - destCountRef.current = 0; } else if (time < legTime(firstLeg.start)) { focusToLeg(firstLeg); } else { - focusToLeg(lastLeg); + focusToLeg(nextLeg || lastLeg); } focusRef.current = true; } From 3960390c341452338e2b66e027a89fd3f5929f05 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 10:44:56 +0200 Subject: [PATCH 26/59] chore: reset temporary test constants --- app/component/itinerary/navigator/NaviUtils.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 40c6610200..d258d9a5ba 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -9,7 +9,7 @@ import { ExtendedRouteTypes } from '../../../constants'; import { getItineraryPagePath } from '../../../util/path'; import { locationToUri } from '../../../util/otpStrings'; -const TRANSFER_SLACK = 600000; +const TRANSFER_SLACK = 60000; const DISPLAY_MESSAGE_THRESHOLD = 120 * 1000; // 2 minutes export const DESTINATION_RADIUS = 20; // meters @@ -337,7 +337,9 @@ export const getTransitLegState = (leg, intl, messages, time) => { export function itinerarySearchPath(time, leg, nextLeg, position, to) { let from; if (leg?.transitLeg) { - from = leg.intermediatePlaces.find(p => legTime(p.arrival) > time + 60000); + from = leg.intermediatePlaces.find( + p => legTime(p.arrival) > time + TRANSFER_SLACK, + ); if (!from) { from = leg.to; } From d6d94062c4e86b2419a377e022ed7df0f286c485 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 17:13:30 +0200 Subject: [PATCH 27/59] fix: transfer warnings/alerts should expire automatically --- app/component/itinerary/navigator/NaviUtils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index d258d9a5ba..b392f2ba47 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -473,6 +473,7 @@ export const getItineraryAlerts = ( ), id: transferId, hideClose: prob.severity === 'ALERT', + expiresOn: legTime(prob.toLeg.start) + TRANSFER_SLACK, }); } } From f3ad5c90c1e8f1097d126105d59d9185c592c661 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 30 Dec 2024 17:27:56 +0200 Subject: [PATCH 28/59] fix: more reliable way to prevent past legs from pushing current leg --- .../navigator/hooks/useRealtimeLegs.js | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js index 383239318d..d0cff11492 100644 --- a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js +++ b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js @@ -45,19 +45,21 @@ function scaleLegs(legs, i1, i2, k) { } } -function matchLegEnds(legs) { +function matchLegEnds(legs, first) { if (legs.length < 2) { return; } let transit; let gap; + transit = nextTransitIndex(legs, first); // shift first legs to match transit start - transit = nextTransitIndex(legs, 0); - if (transit > 0) { - gap = getLegGap(legs, transit - 1); - if (gap) { - shiftLegs(legs, 0, transit - 1, gap); + if (first === 0) { + if (transit > 0) { + gap = getLegGap(legs, transit - 1); + if (gap) { + shiftLegs(legs, 0, transit - 1, gap); + } } } @@ -155,6 +157,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { const [time, setTime] = useState(Date.now()); const previousFinishedLeg = useRef(undefined); const itineraryStarted = useRef(false); + const currentLegIndex = useRef(0); const origin = useMemo( () => GeodeticToEcef(initialLegs[0].from.lat, initialLegs[0].from.lon), @@ -178,7 +181,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { } const legQueries = legs - .filter(leg => leg.transitLeg && legTime(leg.end) > time) + .filter((leg, i) => leg.transitLeg && i >= currentLegIndex.current) .map(leg => fetchQuery( relayEnvironment, @@ -225,7 +228,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { return { ...l, start: { ...l.start }, end: { ...l.end } }; }); // shift non-transit-legs to match possibly changed transit legs - matchLegEnds(rtLegs); + matchLegEnds(rtLegs, currentLegIndex.current); setRealTimeLegs(rtLegs); }, [planarLegs, queryAndMapRealtimeLegs]); @@ -250,8 +253,10 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { previousFinishedLeg.current = previousLeg; if (currentLeg) { + currentLegIndex.current = realTimeLegs.indexOf(currentLeg); itineraryStarted.current = true; } + // return wait legs as undefined as they are not a global concept return { realTimeLegs, From 3807e955190226f9697702da22eb7352b8ef763a Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Tue, 31 Dec 2024 08:00:05 +0200 Subject: [PATCH 29/59] chore: rename leg index ref --- .../navigator/hooks/useRealtimeLegs.js | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js index d0cff11492..34c36b9ba2 100644 --- a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js +++ b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js @@ -54,12 +54,10 @@ function matchLegEnds(legs, first) { transit = nextTransitIndex(legs, first); // shift first legs to match transit start - if (first === 0) { - if (transit > 0) { - gap = getLegGap(legs, transit - 1); - if (gap) { - shiftLegs(legs, 0, transit - 1, gap); - } + if (first === 0 && transit > 0) { + gap = getLegGap(legs, transit - 1); + if (gap) { + shiftLegs(legs, 0, transit - 1, gap); } } @@ -157,7 +155,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { const [time, setTime] = useState(Date.now()); const previousFinishedLeg = useRef(undefined); const itineraryStarted = useRef(false); - const currentLegIndex = useRef(0); + const tailIndex = useRef(0); // transit legs before this are finished const origin = useMemo( () => GeodeticToEcef(initialLegs[0].from.lat, initialLegs[0].from.lon), @@ -181,7 +179,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { } const legQueries = legs - .filter((leg, i) => leg.transitLeg && i >= currentLegIndex.current) + .filter((leg, i) => leg.transitLeg && i >= tailIndex.current) .map(leg => fetchQuery( relayEnvironment, @@ -228,7 +226,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { return { ...l, start: { ...l.start }, end: { ...l.end } }; }); // shift non-transit-legs to match possibly changed transit legs - matchLegEnds(rtLegs, currentLegIndex.current); + matchLegEnds(rtLegs, tailIndex.current); setRealTimeLegs(rtLegs); }, [planarLegs, queryAndMapRealtimeLegs]); @@ -253,7 +251,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { previousFinishedLeg.current = previousLeg; if (currentLeg) { - currentLegIndex.current = realTimeLegs.indexOf(currentLeg); + tailIndex.current = realTimeLegs.indexOf(currentLeg); itineraryStarted.current = true; } From 167d08643a9872d35f1fcee971025d6988ba8925 Mon Sep 17 00:00:00 2001 From: Simo Partinen Date: Tue, 31 Dec 2024 12:16:18 +0200 Subject: [PATCH 30/59] feat: ticketsaleless Navigator bottom sheet --- .../itinerary/navigator/NaviBottom.js | 61 +++++++++++-------- .../itinerary/navigator/navigator.scss | 6 +- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/app/component/itinerary/navigator/NaviBottom.js b/app/component/itinerary/navigator/NaviBottom.js index 9d6507b155..40c070cad0 100644 --- a/app/component/itinerary/navigator/NaviBottom.js +++ b/app/component/itinerary/navigator/NaviBottom.js @@ -1,3 +1,4 @@ +import cx from 'classnames'; import PropTypes from 'prop-types'; import React from 'react'; import { FormattedMessage } from 'react-intl'; @@ -8,35 +9,47 @@ export default function NaviBottom( { setNavigation, arrival, time }, { config }, ) { + const handleClose = () => setNavigation(false); + const handleTicketButtonClick = e => e.stopPropagation(); + + const isTicketSaleActive = !!config?.ticketLink; const remainingDuration = Math.ceil((arrival - time) / 60000); // ms to minutes + + const controlsClasses = cx('navi-bottom-controls', { + 'ticket-link': isTicketSaleActive, + }); + + const closeButton = ( + + ); + + const durationDiv = remainingDuration >= 0 && ( +
+ + + + {epochToTime(arrival, config)} +
+ ); + + const [FirstElement, SecondElement] = isTicketSaleActive + ? [closeButton, durationDiv] + : [durationDiv, closeButton]; + return (
-
- - - {remainingDuration >= 0 && ( -
- - - - {epochToTime(arrival, config)} -
- )} - {config.ticketLink && ( +
+ {FirstElement} + {SecondElement} + {isTicketSaleActive && ( - {/* - - */}

); diff --git a/app/configurations/config.default.js b/app/configurations/config.default.js index f57312e0e3..9153fb4bc8 100644 --- a/app/configurations/config.default.js +++ b/app/configurations/config.default.js @@ -15,7 +15,6 @@ const STOP_TIMETABLES_URL = process.env.STOP_TIMETABLES_URL || 'https://dev.kartat.hsl.fi'; const APP_PATH = process.env.APP_CONTEXT || ''; const { - SENTRY_DSN, // AXE, NODE_ENV, API_SUBSCRIPTION_QUERY_PARAMETER_NAME, @@ -34,7 +33,6 @@ const realtime = require('./realtimeUtils').default; const REALTIME_PATCH = safeJsonParse(process.env.REALTIME_PATCH) || {}; export default { - SENTRY_DSN, PORT, // AXE, CONFIG, diff --git a/app/util/Raven.js b/app/util/Raven.js deleted file mode 100644 index f04d691a3b..0000000000 --- a/app/util/Raven.js +++ /dev/null @@ -1,18 +0,0 @@ -import { COMMIT_ID } from '../buildInfo'; - -export default function getRaven(sentryDsn) { - if (sentryDsn) { - /* eslint-disable global-require */ - const Raven = require('raven-js'); - Raven.addPlugin(require('raven-js/plugins/console')); - - Raven.config(sentryDsn, { - release: COMMIT_ID, - stacktrace: true, - sampleRate: 0.1, - }).install(); - - return Raven; - } - return undefined; -} diff --git a/server/server.js b/server/server.js index ae2c0c5f98..91f6555e2b 100644 --- a/server/server.js +++ b/server/server.js @@ -18,19 +18,11 @@ const proxy = require('express-http-proxy'); global.self = { fetch: global.fetch }; -let Raven; const devhost = ''; -if (process.env.NODE_ENV === 'production' && process.env.SENTRY_SECRET_DSN) { - Raven = require('raven'); - Raven.config(process.env.SENTRY_SECRET_DSN, { - captureUnhandledRejections: true, - }).install(); -} else { - process.on('unhandledRejection', (reason, p) => { - console.log('Unhandled Rejection at:', p, 'reason:', reason); - }); -} +process.on('unhandledRejection', (reason, p) => { + console.log('Unhandled Rejection at:', p, 'reason:', reason); +}); /* ********* Server ********* */ const express = require('express'); @@ -145,17 +137,7 @@ function onError(err, req, res) { res.end(err.message + err.stack); } -function setUpRaven() { - if (process.env.NODE_ENV === 'production' && process.env.SENTRY_SECRET_DSN) { - app.use(Raven.requestHandler()); - } -} - function setUpErrorHandling() { - if (process.env.NODE_ENV === 'production' && process.env.SENTRY_SECRET_DSN) { - app.use(Raven.errorHandler()); - } - app.use(onError); } @@ -458,7 +440,6 @@ function fetchCitybikeConfigurations() { if (process.env.OIDC_CLIENT_ID) { setUpOpenId(); } -setUpRaven(); setUpStaticFolders(); setUpMiddleware(); setUpRoutes(); From ac12e35fc6eed354c5264a1ebd140fbba793e334 Mon Sep 17 00:00:00 2001 From: Simo Partinen Date: Tue, 31 Dec 2024 15:50:31 +0200 Subject: [PATCH 32/59] fix: Fixed fare issue in envs without ticket sales --- .../itinerary/navigator/NaviCardContainer.js | 1 - .../itinerary/navigator/NaviUtils.js | 39 ++++++++++--------- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 31c2282d08..322198c61b 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -141,7 +141,6 @@ function NaviCardContainer( nextLeg, firstLeg, time, - intl, config, messages, ), diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index d258d9a5ba..ca607a9ee4 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -1,13 +1,13 @@ -import React from 'react'; import distance from '@digitransit-search-util/digitransit-search-util-distance'; +import React from 'react'; import { FormattedMessage } from 'react-intl'; +import { ExtendedRouteTypes } from '../../../constants'; +import { getFaresFromLegs } from '../../../util/fareUtils'; import { GeodeticToEnu } from '../../../util/geo-utils'; import { legTime, legTimeAcc } from '../../../util/legUtils'; -import { timeStr, epochToIso } from '../../../util/timeUtils'; -import { getFaresFromLegs } from '../../../util/fareUtils'; -import { ExtendedRouteTypes } from '../../../constants'; -import { getItineraryPagePath } from '../../../util/path'; import { locationToUri } from '../../../util/otpStrings'; +import { getItineraryPagePath } from '../../../util/path'; +import { epochToIso, timeStr } from '../../../util/timeUtils'; const TRANSFER_SLACK = 60000; const DISPLAY_MESSAGE_THRESHOLD = 120 * 1000; // 2 minutes @@ -217,7 +217,6 @@ export const getAdditionalMessages = ( nextLeg, firstLeg, time, - intl, config, messages, ) => { @@ -229,19 +228,21 @@ export const getAdditionalMessages = ( legTime(leg.end) - time < DISPLAY_MESSAGE_THRESHOLD ) { // Todo: multiple fares? - const fare = getFaresFromLegs([nextLeg], config)[0]; - msgs.push({ - severity: 'INFO', - content: ( -
- - - {fare.ticketName} {fare.price} € - -
- ), - id: 'ticket', - }); + const fares = getFaresFromLegs([nextLeg], config); + if (fares?.length) { + msgs.push({ + severity: 'INFO', + content: ( +
+ + + {fares[0].ticketName} {fares[0].price} € + +
+ ), + id: 'ticket', + }); + } } return msgs; }; From 53aa7db7a0d6293d2bb5380c1260e7faf128aa08 Mon Sep 17 00:00:00 2001 From: Simo Partinen Date: Tue, 31 Dec 2024 16:03:48 +0200 Subject: [PATCH 33/59] chore: removed unnecessary div --- .../itinerary/navigator/NaviBottom.js | 34 ++++--- .../itinerary/navigator/navigator.scss | 90 +++++++++---------- 2 files changed, 59 insertions(+), 65 deletions(-) diff --git a/app/component/itinerary/navigator/NaviBottom.js b/app/component/itinerary/navigator/NaviBottom.js index 40c070cad0..d87cbef12b 100644 --- a/app/component/itinerary/navigator/NaviBottom.js +++ b/app/component/itinerary/navigator/NaviBottom.js @@ -15,7 +15,7 @@ export default function NaviBottom( const isTicketSaleActive = !!config?.ticketLink; const remainingDuration = Math.ceil((arrival - time) / 60000); // ms to minutes - const controlsClasses = cx('navi-bottom-controls', { + const sheetClasses = cx('navi-bottom-sheet', { 'ticket-link': isTicketSaleActive, }); @@ -42,23 +42,21 @@ export default function NaviBottom( : [durationDiv, closeButton]; return ( -
- +
+ {FirstElement} + {SecondElement} + {isTicketSaleActive && ( + + )}
); } diff --git a/app/component/itinerary/navigator/navigator.scss b/app/component/itinerary/navigator/navigator.scss index 84b07d618d..aa92bafea9 100644 --- a/app/component/itinerary/navigator/navigator.scss +++ b/app/component/itinerary/navigator/navigator.scss @@ -540,62 +540,58 @@ $fixed-width-padding: 16px; } .navi-bottom-sheet { - .divider { - width: 100%; - height: 1px; - border-top: 1px solid #ddd; - margin-top: 10px; - } + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + font-size: $font-size-normal; + text-align: center; + margin: var(--space-m) var(--space-l); - .navi-bottom-controls { - display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - font-size: $font-size-normal; - text-align: center; - margin: var(--space-m) var(--space-l); + &.ticket-link { + margin: var(--space-l) var(--space-m); - &.ticket-link { - margin: var(--space-l) var(--space-m); + .navi-time { + align-items: inherit; } + } - .navi-close-button { - border-style: solid; - border-width: 1px; - border-radius: 20px; - width: 100px; - height: 40px; - text-align: center; - background-color: white; - border-color: $cancelation-red; - color: $cancelation-red; - } + .navi-close-button { + border-style: solid; + border-width: 1px; + border-radius: 20px; + width: 100px; + height: 40px; + text-align: center; + background-color: white; + border-color: $cancelation-red; + color: $cancelation-red; + } - .navi-time { - display: flex; - flex-direction: column; - color: $black; + .navi-time { + display: flex; + flex-direction: column; + align-items: flex-start; + color: $black; - .navi-daytime { - font-size: $font-size-xsmall; - font-weight: $font-weight-book; - } + .navi-daytime { + font-size: $font-size-xsmall; + font-weight: $font-weight-book; } + } - .navi-ticket-button { - border-radius: 20px; - width: 100px; - height: 40px; - text-align: center; - margin-left: 16px; - background-color: $primary-color; - color: white; + .navi-ticket-button { + border-radius: 20px; + width: 100px; + height: 40px; + text-align: center; + margin-left: 16px; + background-color: $primary-color; + color: white; - a { - color: white; - text-decoration: none; - } + a { + color: white; + text-decoration: none; } } } From 07c23ba5d1bb86fa51ce39df9e34313802ead71d Mon Sep 17 00:00:00 2001 From: Simo Partinen Date: Tue, 31 Dec 2024 16:05:43 +0200 Subject: [PATCH 34/59] chore: useCallbacked functions --- app/component/itinerary/navigator/NaviBottom.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviBottom.js b/app/component/itinerary/navigator/NaviBottom.js index d87cbef12b..d4b9140b40 100644 --- a/app/component/itinerary/navigator/NaviBottom.js +++ b/app/component/itinerary/navigator/NaviBottom.js @@ -1,6 +1,6 @@ import cx from 'classnames'; import PropTypes from 'prop-types'; -import React from 'react'; +import React, { useCallback } from 'react'; import { FormattedMessage } from 'react-intl'; import { configShape } from '../../../util/shapes'; import { epochToTime } from '../../../util/timeUtils'; @@ -9,8 +9,8 @@ export default function NaviBottom( { setNavigation, arrival, time }, { config }, ) { - const handleClose = () => setNavigation(false); - const handleTicketButtonClick = e => e.stopPropagation(); + const handleClose = useCallback(() => setNavigation(false), [setNavigation]); + const handleTicketButtonClick = useCallback(e => e.stopPropagation(), []); const isTicketSaleActive = !!config?.ticketLink; const remainingDuration = Math.ceil((arrival - time) / 60000); // ms to minutes From 5b20e0f0b1fb797684db63b9eea6dfd9fd3bd97b Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Tue, 31 Dec 2024 16:07:43 +0200 Subject: [PATCH 35/59] chore: reset unsuccesful leg fix attempts --- .../itinerary/navigator/hooks/useRealtimeLegs.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js index 34c36b9ba2..383239318d 100644 --- a/app/component/itinerary/navigator/hooks/useRealtimeLegs.js +++ b/app/component/itinerary/navigator/hooks/useRealtimeLegs.js @@ -45,16 +45,16 @@ function scaleLegs(legs, i1, i2, k) { } } -function matchLegEnds(legs, first) { +function matchLegEnds(legs) { if (legs.length < 2) { return; } let transit; let gap; - transit = nextTransitIndex(legs, first); // shift first legs to match transit start - if (first === 0 && transit > 0) { + transit = nextTransitIndex(legs, 0); + if (transit > 0) { gap = getLegGap(legs, transit - 1); if (gap) { shiftLegs(legs, 0, transit - 1, gap); @@ -155,7 +155,6 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { const [time, setTime] = useState(Date.now()); const previousFinishedLeg = useRef(undefined); const itineraryStarted = useRef(false); - const tailIndex = useRef(0); // transit legs before this are finished const origin = useMemo( () => GeodeticToEcef(initialLegs[0].from.lat, initialLegs[0].from.lon), @@ -179,7 +178,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { } const legQueries = legs - .filter((leg, i) => leg.transitLeg && i >= tailIndex.current) + .filter(leg => leg.transitLeg && legTime(leg.end) > time) .map(leg => fetchQuery( relayEnvironment, @@ -226,7 +225,7 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { return { ...l, start: { ...l.start }, end: { ...l.end } }; }); // shift non-transit-legs to match possibly changed transit legs - matchLegEnds(rtLegs, tailIndex.current); + matchLegEnds(rtLegs); setRealTimeLegs(rtLegs); }, [planarLegs, queryAndMapRealtimeLegs]); @@ -251,10 +250,8 @@ const useRealtimeLegs = (relayEnvironment, initialLegs = []) => { previousFinishedLeg.current = previousLeg; if (currentLeg) { - tailIndex.current = realTimeLegs.indexOf(currentLeg); itineraryStarted.current = true; } - // return wait legs as undefined as they are not a global concept return { realTimeLegs, From f786a8c5efa6d3ddff461fe4a89a2522f35d1c62 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Thu, 2 Jan 2025 09:16:33 +0200 Subject: [PATCH 36/59] chore: expire transfer alert as soon as transfer is over --- 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 b392f2ba47..ef79285c00 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -473,7 +473,7 @@ export const getItineraryAlerts = ( ), id: transferId, hideClose: prob.severity === 'ALERT', - expiresOn: legTime(prob.toLeg.start) + TRANSFER_SLACK, + expiresOn: legTime(prob.toLeg.start), }); } } From 81f648dfafd0b52f5bbe0291d29fa82b1b87bfb8 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Thu, 2 Jan 2025 11:36:39 +0200 Subject: [PATCH 37/59] chore: refactor geolocation actions and store Remove limited/outdated mock api and debug code --- app/action/MockGeolocationApi.js | 104 ------------------------------- app/action/PositionActions.js | 92 ++++++++++----------------- app/store/PositionStore.js | 33 ---------- 3 files changed, 32 insertions(+), 197 deletions(-) delete mode 100644 app/action/MockGeolocationApi.js diff --git a/app/action/MockGeolocationApi.js b/app/action/MockGeolocationApi.js deleted file mode 100644 index 1caa9c15bf..0000000000 --- a/app/action/MockGeolocationApi.js +++ /dev/null @@ -1,104 +0,0 @@ -// replacement for the browser geolocation api location mocking purposes -import d from 'debug'; -import range from 'lodash/range'; - -const debug = d('MockGeolocationApi.js'); - -export function init(permission, lat, lon) { - debug('Position mock activated'); - window.mock = { permission, data: {} }; - - window.mock.data.position = { - coords: { - latitude: lat || 60.1992, - longitude: lon || 24.9402, - heading: 0, - }, - }; - - let follow = false; - window.mock.geolocation = { - demo() { - const from = window.mock.data.position.coords; - - const to = { - latitude: 60.1716, - longitude: 24.9406, - }; - - const steps = 180; - const track = range(steps).map(i => { - const f = i / steps; - const variation = Math.random() * 0.0001 - 0.00005; - const latitude = f * to.latitude + (1 - f) * from.latitude + variation; - const longitude = - f * to.longitude + (1 - f) * from.longitude + variation; - - return { - latitude, - longitude, - }; - }); - - follow = { - track, - index: 0, - interval: setInterval(window.mock.geolocation.followTrack, 1000), - }; - }, - - followTrack() { - let position; - const i = follow.index || 0; - - if (follow.track && i < follow.track.length) { - position = follow.track[i]; - follow.index += 1; - window.mock.geolocation.setCurrentPosition( - position.latitude, - position.longitude, - ); - } else { - clearInterval(follow.interval); - follow = false; - } - }, - - move: (dlat, dlon, heading) => { - window.mock.data.position.coords.latitude += dlat; - window.mock.data.position.coords.longitude += dlon; - - if (heading) { - window.mock.data.position.coords.heading = heading; - } - }, - - setCurrentPosition: (latitude, longitude, heading) => { - window.mock.data.position.coords.latitude = latitude; - window.mock.data.position.coords.longitude = longitude; - - if (heading) { - window.mock.data.position.coords.heading = heading; - } - }, - }; -} - -export const api = { - watchPosition: success => { - debug('setting mock interval'); - let i = 0; - setInterval(() => { - if (window.mock) { - debug('broadcasting position', window.mock.data.position); - window.mock.permission = 'granted'; - // debounce does not seem to work within setInterval - // so disable debounce once every 5 seconds - success(window.mock.data.position, i % 10 === 0); - i += 1; - } else { - debug('window.mock is undefined'); - } - }, 2000); - }, -}; diff --git a/app/action/PositionActions.js b/app/action/PositionActions.js index 7fde4924f1..1297c6fc87 100644 --- a/app/action/PositionActions.js +++ b/app/action/PositionActions.js @@ -1,11 +1,8 @@ import debounce from 'lodash/debounce'; -import d from 'debug'; import { getJson } from '../util/xhrPromise'; import geolocationMessages from '../util/geolocationMessages'; import { addAnalyticsEvent } from '../util/analyticsUtils'; -const debug = d('PositionActions.js'); - let geoWatchId; function reverseGeocodeAddress(actionContext, location) { @@ -57,27 +54,18 @@ const debouncedRunReverseGeocodingAction = debounce( }, ); -function geoCallback(actionContext, { pos, disableDebounce }) { +function geoCallback(actionContext, pos) { actionContext.dispatch('StartReverseGeocoding'); actionContext.dispatch('GeolocationFound', { lat: pos.coords.latitude, lon: pos.coords.longitude, heading: pos.coords.heading, - disableFiltering: disableDebounce, }); - if (disableDebounce) { - runReverseGeocodingAction( - actionContext, - pos.coords.latitude, - pos.coords.longitude, - ); - } else { - debouncedRunReverseGeocodingAction( - actionContext, - pos.coords.latitude, - pos.coords.longitude, - ); - } + debouncedRunReverseGeocodingAction( + actionContext, + pos.coords.latitude, + pos.coords.longitude, + ); } function updateGeolocationMessage(actionContext, newId) { @@ -115,7 +103,6 @@ function dispatchGeolocationError(actionContext, error) { // set watcher for geolocation function watchPosition(actionContext) { - debug('watchPosition'); const quietTimeoutSeconds = 20; let timeout = setTimeout(() => { @@ -123,8 +110,8 @@ function watchPosition(actionContext) { updateGeolocationMessage(actionContext, 'timeout'); }, quietTimeoutSeconds * 1000); try { - geoWatchId = navigator.geoapi.watchPosition( - (position, disableDebounce) => { + geoWatchId = navigator.geolocation.watchPosition( + position => { updateGeolocationMessage(actionContext); if (timeout !== null) { clearTimeout(timeout); @@ -138,7 +125,7 @@ function watchPosition(actionContext) { lon !== undefined && !Number.isNaN(lon) ) { - geoCallback(actionContext, { pos: position, disableDebounce }); + geoCallback(actionContext, position); } }, error => { @@ -168,15 +155,9 @@ function watchPosition(actionContext) { /** * Small wrapper around permission api. * Returns a promise of checking positioning permission. - * resolving to null means there's no permission api. */ export function checkPositioningPermission() { const p = new Promise(resolve => { - if (typeof window !== 'undefined' && window.mock !== undefined) { - debug('mock permission'); - resolve({ state: window.mock.permission }); - return; - } if (!navigator.permissions) { resolve({ state: 'error' }); } else { @@ -201,44 +182,35 @@ export function checkPositioningPermission() { }); } }); - return p; } -function startPositioning(actionContext) { - checkPositioningPermission().then(status => { - debug('Examining permission', status); - switch (status.state) { - case 'granted': - actionContext.dispatch('GeolocationSearch'); - updateGeolocationMessage(actionContext); - watchPosition(actionContext); - break; - case 'denied': - actionContext.dispatch('GeolocationDenied'); - updateGeolocationMessage(actionContext, 'denied'); - break; - case 'prompt': - updateGeolocationMessage(actionContext, 'prompt'); - actionContext.dispatch('GeolocationSearch'); - watchPosition(actionContext); - break; - default: - // browsers not supporting permission api - actionContext.dispatch('GeolocationSearch'); - watchPosition(actionContext); - break; - } - }); -} - /* starts location watch */ export function startLocationWatch(actionContext) { if (typeof geoWatchId === 'undefined') { - debug('starting...'); - startPositioning(actionContext); // from geolocation.js - } else { - debug('already started...'); + checkPositioningPermission().then(status => { + switch (status.state) { + case 'granted': + actionContext.dispatch('GeolocationSearch'); + updateGeolocationMessage(actionContext); + watchPosition(actionContext); + break; + case 'denied': + actionContext.dispatch('GeolocationDenied'); + updateGeolocationMessage(actionContext, 'denied'); + break; + case 'prompt': + updateGeolocationMessage(actionContext, 'prompt'); + actionContext.dispatch('GeolocationSearch'); + watchPosition(actionContext); + break; + default: + // browsers not supporting permission api + actionContext.dispatch('GeolocationSearch'); + watchPosition(actionContext); + break; + } + }); } } diff --git a/app/store/PositionStore.js b/app/store/PositionStore.js index 9f3b8774c0..30b92007ff 100644 --- a/app/store/PositionStore.js +++ b/app/store/PositionStore.js @@ -1,12 +1,6 @@ import Store from 'fluxible/addons/BaseStore'; -import d from 'debug'; -import { api, init } from '../action/MockGeolocationApi'; -import { isBrowser } from '../util/browser'; -import { parseLatLon } from '../util/otpStrings'; import { getGeolocationState, setGeolocationState } from './localStorage'; -const debug = d('PositionStore.js'); - export default class PositionStore extends Store { static storeName = 'PositionStore'; @@ -33,33 +27,6 @@ export default class PositionStore extends Store { static REVERSE_GEOCODING_STATUS_IN_PROGRESS = 'reverse-geocoding-in-progress'; constructor(dispatcher) { - if ( - isBrowser && - window.location && - window.location.search.indexOf('mock') !== -1 - ) { - let permission = window.location.search.substring( - window.location.search.indexOf('mock') + 5, - ); - let lat; - let lon; - if (permission.length > 1) { - const latlon = parseLatLon(permission); - if (latlon) { - permission = 'granted'; - ({ lat, lon } = latlon); - } - } else { - // default mock permission = granted - permission = 'granted'; - } - - debug('replacing geolocation api with mock'); - navigator.geoapi = api; - init(permission, lat, lon); - } else { - navigator.geoapi = navigator.geolocation; - } super(dispatcher); this.lat = 0; this.lon = 0; From bb256cefd21914d9378e1fbee691ca8135fc5503 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Thu, 2 Jan 2025 12:16:58 +0200 Subject: [PATCH 38/59] fix: simplify multiple reverse geocoding wrappers --- app/action/PositionActions.js | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/app/action/PositionActions.js b/app/action/PositionActions.js index 1297c6fc87..63042a5d52 100644 --- a/app/action/PositionActions.js +++ b/app/action/PositionActions.js @@ -5,12 +5,12 @@ import { addAnalyticsEvent } from '../util/analyticsUtils'; let geoWatchId; -function reverseGeocodeAddress(actionContext, location) { +function reverseGeocodeAddress(actionContext, coords) { const language = actionContext.getStore('PreferencesStore').getLanguage(); const searchParams = { - 'point.lat': location.lat, - 'point.lon': location.lon, + 'point.lat': coords.latitude, + 'point.lon': coords.longitude, lang: language, size: 1, layers: 'address', @@ -20,6 +20,7 @@ function reverseGeocodeAddress(actionContext, location) { searchParams['boundary.country'] = actionContext.config.searchParams['boundary.country']; } + actionContext.dispatch('StartReverseGeocoding'); return getJson( actionContext.config.URL.PELIAS_REVERSE_GEOCODER, @@ -40,32 +41,17 @@ function reverseGeocodeAddress(actionContext, location) { }); } -const runReverseGeocodingAction = (actionContext, lat, lon) => - actionContext.executeAction(reverseGeocodeAddress, { - lat, - lon, - }); - -const debouncedRunReverseGeocodingAction = debounce( - runReverseGeocodingAction, - 10000, - { - leading: true, - }, -); +const debouncedReverseGeocoding = debounce(reverseGeocodeAddress, 10000, { + leading: true, +}); function geoCallback(actionContext, pos) { - actionContext.dispatch('StartReverseGeocoding'); actionContext.dispatch('GeolocationFound', { lat: pos.coords.latitude, lon: pos.coords.longitude, heading: pos.coords.heading, }); - debouncedRunReverseGeocodingAction( - actionContext, - pos.coords.latitude, - pos.coords.longitude, - ); + debouncedReverseGeocoding(actionContext, pos.coords); } function updateGeolocationMessage(actionContext, newId) { From db300f3e54183634e135fa4d253db12730bd50dc Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Thu, 2 Jan 2025 14:20:48 +0200 Subject: [PATCH 39/59] fix: do not start geolocationWatch multiple times --- app/action/PositionActions.js | 5 ++++- app/component/IndexPage.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/action/PositionActions.js b/app/action/PositionActions.js index 63042a5d52..ed59c4ab3c 100644 --- a/app/action/PositionActions.js +++ b/app/action/PositionActions.js @@ -171,9 +171,12 @@ export function checkPositioningPermission() { return p; } +let watchPending; + /* starts location watch */ export function startLocationWatch(actionContext) { - if (typeof geoWatchId === 'undefined') { + if (typeof geoWatchId === 'undefined' && !watchPending) { + watchPending = true; checkPositioningPermission().then(status => { switch (status.state) { case 'granted': diff --git a/app/component/IndexPage.js b/app/component/IndexPage.js index 534ee2c060..0b222b59b4 100644 --- a/app/component/IndexPage.js +++ b/app/component/IndexPage.js @@ -113,7 +113,7 @@ class IndexPage extends React.Component { this.context.executeAction(storeDestination, destination); } - if (this.context.config.startSearchFromUserLocation) { + if (this.context.config.startSearchFromUserLocation && !origin.lat) { checkPositioningPermission().then(permission => { if ( permission.state === 'granted' && From f0c68da7e59eaa2dd470f1dcac11a8bf8b0dde27 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Thu, 2 Jan 2025 14:28:02 +0200 Subject: [PATCH 40/59] fix: remove dead condition --- app/component/IndexPage.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/component/IndexPage.js b/app/component/IndexPage.js index 0b222b59b4..7efc29ed43 100644 --- a/app/component/IndexPage.js +++ b/app/component/IndexPage.js @@ -149,8 +149,7 @@ class IndexPage extends React.Component { const currentLocation = config.startSearchFromUserLocation && !this.props.origin.address && - this.props.locationState?.hasLocation && - this.props.locationState; + this.props.locationState?.hasLocation; if (currentLocation && !currentLocation.isReverseGeocodingInProgress) { const originPoint = [currentLocation.lon, currentLocation.lat]; if (inside(originPoint, config.areaPolygon)) { From b03ca8847a13d7f801360905ed58c3580feb162d Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Thu, 2 Jan 2025 14:45:20 +0200 Subject: [PATCH 41/59] Revert "fix: remove dead condition" This reverts commit f0c68da7e59eaa2dd470f1dcac11a8bf8b0dde27. --- app/component/IndexPage.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/component/IndexPage.js b/app/component/IndexPage.js index 7efc29ed43..0b222b59b4 100644 --- a/app/component/IndexPage.js +++ b/app/component/IndexPage.js @@ -149,7 +149,8 @@ class IndexPage extends React.Component { const currentLocation = config.startSearchFromUserLocation && !this.props.origin.address && - this.props.locationState?.hasLocation; + this.props.locationState?.hasLocation && + this.props.locationState; if (currentLocation && !currentLocation.isReverseGeocodingInProgress) { const originPoint = [currentLocation.lon, currentLocation.lat]; if (inside(originPoint, config.areaPolygon)) { From 927d3e8ead21bf62663c8f50e935a8622bf671e5 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Thu, 2 Jan 2025 15:13:11 +0200 Subject: [PATCH 42/59] chore: slightly higher speech bubble z index Map stations punch through the bubble which looks quite bad --- app/component/map/SpeechBubble.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/component/map/SpeechBubble.js b/app/component/map/SpeechBubble.js index eefd8b18f8..276c76f53e 100644 --- a/app/component/map/SpeechBubble.js +++ b/app/component/map/SpeechBubble.js @@ -48,5 +48,5 @@ SpeechBubble.propTypes = { SpeechBubble.defaultProps = { speechBubbleStyle: 'topRight', text: '', - zIndexOffset: undefined, + zIndexOffset: 400, }; From 24d2c295a057af04740d1331108ba9e1ba35dfc0 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 3 Jan 2025 07:50:59 +0200 Subject: [PATCH 43/59] chore: longer transfer slack, shorter in schedule threshold --- app/component/itinerary/navigator/NaviUtils.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index ef79285c00..5ac386fd6a 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -9,7 +9,7 @@ import { ExtendedRouteTypes } from '../../../constants'; import { getItineraryPagePath } from '../../../util/path'; import { locationToUri } from '../../../util/otpStrings'; -const TRANSFER_SLACK = 60000; +const TRANSFER_SLACK = 80000; const DISPLAY_MESSAGE_THRESHOLD = 120 * 1000; // 2 minutes export const DESTINATION_RADIUS = 20; // meters @@ -255,8 +255,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { } const notInSchedule = - estimated?.delay > DISPLAY_MESSAGE_THRESHOLD || - estimated?.delay < -DISPLAY_MESSAGE_THRESHOLD; + estimated?.delay > TRANSFER_SLACK || estimated?.delay < -TRANSFER_SLACK; const localizedMode = getLocalizedMode(mode, intl); let content; let severity; From 24191c0f542bdbc11ca5848cb70a9f977235823b Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 3 Jan 2025 07:56:38 +0200 Subject: [PATCH 44/59] chore: improve translations --- app/translations.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/translations.js b/app/translations.js index 180b09d307..2c8efc3409 100644 --- a/app/translations.js +++ b/app/translations.js @@ -1345,7 +1345,7 @@ const translations = { 'navileg-rent-scooter': 'Pick up scooter', 'navileg-scooter': 'Travel by scooter to', 'navileg-start-realtime': 'Lähtee klo {time} {stop} {stopName}', - 'navileg-start-schedule': '{mode}n {route} aikataulun muk. lähtö {time}', + 'navileg-start-schedule': '{mode} {route} aikataulun mukainen lähtö {time}', 'navileg-stops-remaining': 'TODO_{stopCount} pysähdystä ennen poistumista', 'navileg-walk': 'Walk to', nearest: '{ mode } near you', @@ -2622,7 +2622,8 @@ const translations = { 'navileg-rent-scooter': 'Nouda sähköpotkulauta', 'navileg-scooter': 'Potkulautaile', 'navileg-start-realtime': 'Lähtee klo {time} {stopOrStation} {stopName}', - 'navileg-start-schedule': '{mode}n {route} aikataulun muk. lähtö {time}', + 'navileg-start-schedule': + '{mode} {route} aikataulun mukainen lähtö {time}', 'navileg-stops-remaining': '{stopCount} pysähdystä ennen poistumista', 'navileg-walk': 'Kävele', nearest: 'Lähimmät {mode}', @@ -5551,7 +5552,7 @@ const translations = { 'navileg-rent-scooter': 'Hämta elsparkcykel', 'navileg-scooter': 'Åk elsparkcykel', 'navileg-start-realtime': 'Lähtee klo {time} {stop} {stopName}', - 'navileg-start-schedule': '{mode}n {route} aikataulun muk. lähtö {time}', + 'navileg-start-schedule': '{mode} {route} aikataulun mukainen lähtö {time}', 'navileg-stops-remaining': 'TODO_{stopCount} pysähdystä ennen poistumista', 'navileg-walk': 'Gå till', nearest: 'Närmaste { mode }', From bc5ec64c0804570131955603c1c4197011d3ea40 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Fri, 3 Jan 2025 09:45:01 +0200 Subject: [PATCH 45/59] chore: geolocation debugging card --- app/action/PositionActions.js | 1 + .../itinerary/navigator/NaviCardContainer.js | 23 +++++++++++++++++++ app/store/PositionStore.js | 6 ++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/action/PositionActions.js b/app/action/PositionActions.js index ed59c4ab3c..5a5efd12ac 100644 --- a/app/action/PositionActions.js +++ b/app/action/PositionActions.js @@ -125,6 +125,7 @@ function watchPosition(actionContext) { }, { enableHighAccuracy: true, timeout: 60000, maximumAge: 60000 }, ); + actionContext.dispatch('storeWatchId', geoWatchId); } catch (error) { if (timeout !== null) { clearTimeout(timeout); diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 322198c61b..0df50d1fba 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -132,6 +132,26 @@ function NaviCardContainer( ), ); + if (match.location.query?.debug !== undefined && position) { + const info1 = `lat: ${position.lat} lon: ${position.lon}`; + const info2 = `status: ${position.status}`; + const info3 = `locations: ${position.locationCount} watchId: ${position.watchId}`; + + addMessages(incomingMessages, [ + { + severity: 'INFO', + content: ( +
+ {info1} + {info2} + {info3} +
+ ), + id: 'debug', + }, + ]); + } + if (nextLeg?.transitLeg) { // Messages for NaviStack. addMessages(incomingMessages, [ @@ -253,6 +273,9 @@ NaviCardContainer.propTypes = { position: PropTypes.shape({ lat: PropTypes.number, lon: PropTypes.number, + status: PropTypes.string, + locationCount: PropTypes.number, + watchId: PropTypes.string, }), mapLayerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]) .isRequired, diff --git a/app/store/PositionStore.js b/app/store/PositionStore.js index 30b92007ff..6bb316820b 100644 --- a/app/store/PositionStore.js +++ b/app/store/PositionStore.js @@ -37,6 +37,7 @@ export default class PositionStore extends Store { this.layer = undefined; this.status = PositionStore.STATUS_NO_LOCATION; this.savedState = getGeolocationState(); + this.locationCount = 0; this.emitChange(); } @@ -99,7 +100,7 @@ export default class PositionStore extends Store { } this.heading = location.heading ? location.heading : this.heading; this.status = PositionStore.STATUS_FOUND_LOCATION; - + this.locationCount += 1; this.emitChange(); } @@ -133,6 +134,8 @@ export default class PositionStore extends Store { name: this.name, layer: this.layer, status: this.status, + locationCount: this.locationCount, + watchId: this.watchId, hasLocation: (this.status === PositionStore.STATUS_FOUND_ADDRESS || this.status === PositionStore.STATUS_FOUND_LOCATION) && @@ -181,5 +184,6 @@ export default class PositionStore extends Store { GeolocationWatchStarted: 'storeWatchId', GeolocationWatchStopped: 'clearWatchId', StartReverseGeocoding: 'startReverseGeocoding', + storeWatchId: 'storeWatchId', }; } From 5940c3c6c0be141f73e286b3cb4a4eba9e1e4578 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 5 Jan 2025 07:36:50 +0200 Subject: [PATCH 46/59] fix: buggy transit condition --- app/component/itinerary/navigator/NaviInstructions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/component/itinerary/navigator/NaviInstructions.js b/app/component/itinerary/navigator/NaviInstructions.js index d20e81484b..f67bb66cf3 100644 --- a/app/component/itinerary/navigator/NaviInstructions.js +++ b/app/component/itinerary/navigator/NaviInstructions.js @@ -47,7 +47,7 @@ export default function NaviInstructions( ); } - if (legType === LEGTYPE.WAIT && nextLeg.mode !== 'WALK') { + if (legType === LEGTYPE.WAIT && nextLeg.transitLeg) { const { mode, headsign, route, start } = nextLeg; const hs = headsign || nextLeg.trip?.tripHeadsign; From 24eb25a5adfea6ef1037f2fa39d89e68d1d34538 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 5 Jan 2025 08:42:24 +0200 Subject: [PATCH 47/59] Fix: remove unnecessary div --- .../itinerary/navigator/NaviBottom.js | 68 ++++++++------- .../itinerary/navigator/navigator.scss | 83 +++++++++---------- 2 files changed, 70 insertions(+), 81 deletions(-) diff --git a/app/component/itinerary/navigator/NaviBottom.js b/app/component/itinerary/navigator/NaviBottom.js index 9d6507b155..4400f19472 100644 --- a/app/component/itinerary/navigator/NaviBottom.js +++ b/app/component/itinerary/navigator/NaviBottom.js @@ -10,42 +10,40 @@ export default function NaviBottom( ) { const remainingDuration = Math.ceil((arrival - time) / 60000); // ms to minutes return ( -
-
- +
+ - {remainingDuration >= 0 && ( -
- - - - {epochToTime(arrival, config)} -
- )} - {config.ticketLink && ( - - )} -
+ {remainingDuration >= 0 && ( +
+ + + + {epochToTime(arrival, config)} +
+ )} + {config.ticketLink && ( + + )}
); } diff --git a/app/component/itinerary/navigator/navigator.scss b/app/component/itinerary/navigator/navigator.scss index 5f09e1c6f8..5716a9d74c 100644 --- a/app/component/itinerary/navigator/navigator.scss +++ b/app/component/itinerary/navigator/navigator.scss @@ -539,59 +539,50 @@ $fixed-width-padding: 16px; } } -.navi-bottom-sheet { - .divider { - width: 100%; - height: 1px; - border-top: 1px solid #ddd; - margin-top: 10px; +.navi-bottom-controls { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + font-size: $font-size-normal; + text-align: center; + margin: 20px 24px 10px 24px; + + .navi-close-button { + border-style: solid; + border-width: 1px; + border-radius: 20px; + width: 100px; + height: 40px; + text-align: center; + background-color: white; + border-color: $cancelation-red; + color: $cancelation-red; } - .navi-bottom-controls { + .navi-time { display: flex; - flex-direction: row; - align-items: center; - justify-content: space-between; - font-size: $font-size-normal; - text-align: center; - margin: 20px 24px 10px 24px; - - .navi-close-button { - border-style: solid; - border-width: 1px; - border-radius: 20px; - width: 100px; - height: 40px; - text-align: center; - background-color: white; - border-color: $cancelation-red; - color: $cancelation-red; - } - - .navi-time { - display: flex; - flex-direction: column; - color: $black; + flex-direction: column; + color: $black; - .navi-daytime { - font-size: $font-size-xsmall; - font-weight: $font-weight-book; - } + .navi-daytime { + font-size: $font-size-xsmall; + font-weight: $font-weight-book; } + } - .navi-ticket-button { - border-radius: 20px; - width: 100px; - height: 40px; - text-align: center; - margin-left: 16px; - background-color: $primary-color; - color: white; + .navi-ticket-button { + border-radius: 20px; + width: 100px; + height: 40px; + text-align: center; + margin-left: 16px; + background-color: $primary-color; + color: white; - a { - color: white; - text-decoration: none; - } + a { + color: white; + text-decoration: none; } } } From 6212e6afe3e7ea15428c394c75199961da1a8f43 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 5 Jan 2025 10:04:39 +0200 Subject: [PATCH 48/59] fix: common header style --- .../itinerary/navigator/NaviInstructions.js | 6 +++--- app/component/itinerary/navigator/navigator.scss | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/component/itinerary/navigator/NaviInstructions.js b/app/component/itinerary/navigator/NaviInstructions.js index f67bb66cf3..229fb2d4ea 100644 --- a/app/component/itinerary/navigator/NaviInstructions.js +++ b/app/component/itinerary/navigator/NaviInstructions.js @@ -34,7 +34,7 @@ export default function NaviInstructions( return ( <> -
+
  {legDestination(intl, leg, null, nextLeg)} @@ -68,7 +68,7 @@ export default function NaviInstructions( return ( <> -
+
-
+
Date: Sun, 5 Jan 2025 10:17:36 +0200 Subject: [PATCH 49/59] chore: rename style class --- app/component/itinerary/navigator/NaviCardContainer.js | 2 +- app/component/itinerary/navigator/navigator.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 31c2282d08..41bba812a5 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -225,7 +225,7 @@ function NaviCardContainer( >
); @@ -403,8 +414,8 @@ export const getItineraryAlerts = ( .map(alert => ({ severity: 'ALERT', content: ( -
- {alert.alertHeaderText} +
+ {alert.alertHeaderText}
), id: alertId(alert), @@ -424,17 +435,19 @@ export const getItineraryAlerts = ( const routeName = `${lMode} ${route.shortName}`; const m = ( - + + + ); // we want to show the show routes button only for the first canceled leg. const content = i === 0 ? ( withNewSearchBtn({ m }, itinerarySearchCallback) ) : ( -
{m}
+
{m}
); if (!messages.get(`canceled-${legId}`)) { @@ -461,13 +474,15 @@ export const getItineraryAlerts = ( alerts.push({ severity: prob.severity, content: withNewSearchBtn( - , + + + , itinerarySearchCallback, ), id: transferId, diff --git a/app/component/itinerary/navigator/navigator.scss b/app/component/itinerary/navigator/navigator.scss index 7c2ba31b02..a0c9fcd5f5 100644 --- a/app/component/itinerary/navigator/navigator.scss +++ b/app/component/itinerary/navigator/navigator.scss @@ -403,6 +403,8 @@ $fixed-width-padding: 16px; animation: slideDownFromTop 0.5s ease-out forwards, fadeIn 0.5s ease-out forwards; + font-size: $font-size-xsmall; + font-weight: $font-weight-book; .icon-container { display: flex; @@ -411,44 +413,24 @@ $fixed-width-padding: 16px; width: 16px; } + .navi-info-content { + display: flex; + flex-direction: column; + margin-left: 8px; + margin-right: 8px; + width: 100%; + } + &.info { background-color: #e5f2fa; } &.warning { background-color: #fff8e8; - - .navi-alert-content { - width: 100%; - margin: 0 8px; - display: flex; - flex-direction: column; - } } &.alert { background-color: #fdf3f6; - - .navi-alert-content { - display: flex; - flex-direction: column; - margin: 0 8px; - width: 100%; - - span:first-child { - font-weight: $font-weight-medium; - font-size: $font-size-normal; - } - - span:last-child { - font-size: $font-size-small; - font-weight: $font-weight-book; - } - - .header { - font-size: $font-size-small; - } - } } .new-itinerary-search { @@ -497,24 +479,6 @@ $fixed-width-padding: 16px; slideDownFromTop 0.5s ease-out forwards, fadeOut 0.5s ease-out forwards; } - - .navi-info-content { - display: flex; - flex-direction: column; - margin-left: 8px; - margin-right: 8px; - width: 100%; - - span:first-child { - font-weight: $font-weight-medium; - font-size: $font-size-normal; - } - - span:last-child { - font-size: $font-size-xsmall; - font-weight: $font-weight-book; - } - } } } From eac0b778f1b9ffafc7efa1868d7813b98b83e8ca Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Sun, 5 Jan 2025 14:16:37 +0200 Subject: [PATCH 53/59] fix: broken distance check from leg end --- app/component/itinerary/navigator/NaviCardContainer.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 41bba812a5..6cdd083a52 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -17,7 +17,7 @@ import { } from './NaviUtils'; import { updateClient, getTopics } from '../ItineraryPageUtils'; -const TIME_AT_DESTINATION = 3; // * 10 seconds +const COUNT_AT_LEG_END = 2; // update cycles within DESTINATION_RADIUS from leg.to const TOPBAR_PADDING = 8; // pixels const HIDE_TOPCARD_DURATION = 2000; // milliseconds @@ -27,13 +27,13 @@ function addMessages(incominMessages, newMessages) { }); } -const handleLegChange = (leg, firstLeg, time) => { +const handleLegChange = (leg, firstLeg, time, countAtLegEnd) => { let legType; if (time < legTime(firstLeg.start)) { legType = LEGTYPE.PENDING; } else if (leg) { if (!leg.transitLeg) { - if (leg.current >= TIME_AT_DESTINATION) { + if (countAtLegEnd >= COUNT_AT_LEG_END) { legType = LEGTYPE.WAIT; } else { legType = LEGTYPE.MOVE; @@ -206,7 +206,7 @@ function NaviCardContainer( // LegChange fires animation, we need to keep the old data until card goes out of the view. const l = legChanging ? previousLeg : currentLeg; - const legType = handleLegChange(l, firstLeg, time); + const legType = handleLegChange(l, firstLeg, time, destCountRef.current); const containerTopPosition = mapLayerRef.current.getBoundingClientRect().top + TOPBAR_PADDING; From 6d446188f170afeb65ed22397a59662d34a7884a Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 6 Jan 2025 11:24:34 +0200 Subject: [PATCH 54/59] chore: remove meaningless condition --- app/component/itinerary/navigator/NaviContainer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/component/itinerary/navigator/NaviContainer.js b/app/component/itinerary/navigator/NaviContainer.js index 889908f220..f480eeaed9 100644 --- a/app/component/itinerary/navigator/NaviContainer.js +++ b/app/component/itinerary/navigator/NaviContainer.js @@ -65,7 +65,7 @@ function NaviContainer( const arrivalTime = legTime(lastLeg.end); const isDestinationReached = - position && lastLeg && distance(position, lastLeg.to) <= DESTINATION_RADIUS; + position && distance(position, lastLeg.to) <= DESTINATION_RADIUS; const isPastExpectedArrival = time > arrivalTime + ADDITIONAL_ARRIVAL_TIME; From 57c22b46962c05dc5fbd992c2f64bbc834264316 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 6 Jan 2025 11:25:20 +0200 Subject: [PATCH 55/59] fix: apply leg end proximity logic only on intermediate legs, rename accordingly --- .../itinerary/navigator/NaviCardContainer.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 6cdd083a52..406f91c143 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -73,7 +73,7 @@ function NaviCardContainer( const legRef = useRef(currentLeg); const focusRef = useRef(false); // Destination counter. How long user has been at the destination. * 10 seconds - const destCountRef = useRef(0); + const legEndRef = useRef(0); const cardRef = useRef(null); const { intl, config, match, router } = context; const handleRemove = index => { @@ -193,12 +193,13 @@ function NaviCardContainer( if ( position && currentLeg && + nextLeg && // itinerary end has its own logic distance(position, currentLeg.to) <= DESTINATION_RADIUS ) { - destCountRef.current += 1; + legEndRef.current += 1; } else { // Todo: this works in transit legs, but do we need additional logic for bikes / scooters? - destCountRef.current = 0; + legEndRef.current = 0; } return () => clearTimeout(timeoutId); @@ -206,7 +207,7 @@ function NaviCardContainer( // LegChange fires animation, we need to keep the old data until card goes out of the view. const l = legChanging ? previousLeg : currentLeg; - const legType = handleLegChange(l, firstLeg, time, destCountRef.current); + const legType = handleLegChange(l, firstLeg, time, legEndRef.current); const containerTopPosition = mapLayerRef.current.getBoundingClientRect().top + TOPBAR_PADDING; @@ -267,10 +268,6 @@ NaviCardContainer.propTypes = { lastLeg: legShape, previousLeg: legShape, isJourneyCompleted: PropTypes.bool, - - /* - focusToPoint: PropTypes.func.isRequired, - */ }; NaviCardContainer.defaultProps = { From 64f6b59580ba8fcf2b53696c1e879cd9e1470f4f Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 6 Jan 2025 11:26:55 +0200 Subject: [PATCH 56/59] fix: leg type func has nothing to do with leg change, rename it --- app/component/itinerary/navigator/NaviCardContainer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/component/itinerary/navigator/NaviCardContainer.js b/app/component/itinerary/navigator/NaviCardContainer.js index 406f91c143..c51d2c27f6 100644 --- a/app/component/itinerary/navigator/NaviCardContainer.js +++ b/app/component/itinerary/navigator/NaviCardContainer.js @@ -27,7 +27,7 @@ function addMessages(incominMessages, newMessages) { }); } -const handleLegChange = (leg, firstLeg, time, countAtLegEnd) => { +const getLegType = (leg, firstLeg, time, countAtLegEnd) => { let legType; if (time < legTime(firstLeg.start)) { legType = LEGTYPE.PENDING; @@ -207,7 +207,7 @@ function NaviCardContainer( // LegChange fires animation, we need to keep the old data until card goes out of the view. const l = legChanging ? previousLeg : currentLeg; - const legType = handleLegChange(l, firstLeg, time, legEndRef.current); + const legType = getLegType(l, firstLeg, time, legEndRef.current); const containerTopPosition = mapLayerRef.current.getBoundingClientRect().top + TOPBAR_PADDING; From 0fa7ac2b94733982f78d053a150aadeaf8ba0928 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Tue, 7 Jan 2025 08:13:06 +0200 Subject: [PATCH 57/59] fix: ticket note header style --- app/component/itinerary/navigator/NaviUtils.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/component/itinerary/navigator/NaviUtils.js b/app/component/itinerary/navigator/NaviUtils.js index 49b0f0989f..55393440be 100644 --- a/app/component/itinerary/navigator/NaviUtils.js +++ b/app/component/itinerary/navigator/NaviUtils.js @@ -234,7 +234,9 @@ export const getAdditionalMessages = ( severity: 'INFO', content: (
- + + + {fares[0].ticketName} {fares[0].price} € From 43cbe249fdaf94b9f2f1bb3350728a5961150268 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Tue, 7 Jan 2025 09:01:27 +0200 Subject: [PATCH 58/59] chore: show permission state in debug mode --- app/component/IndexPage.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/component/IndexPage.js b/app/component/IndexPage.js index 0b222b59b4..bb21cc85e1 100644 --- a/app/component/IndexPage.js +++ b/app/component/IndexPage.js @@ -115,6 +115,9 @@ class IndexPage extends React.Component { if (this.context.config.startSearchFromUserLocation && !origin.lat) { checkPositioningPermission().then(permission => { + if (this.context.match.location?.query?.debug !== undefined) { + alert(permission.state); + } if ( permission.state === 'granted' && this.props.locationState.status === 'no-location' From 024dc621c99c49fb9aad9c6158e15b928d845a96 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Tue, 7 Jan 2025 09:25:39 +0200 Subject: [PATCH 59/59] chore: rename class name --- .../itinerary/navigator/NaviInstructions.js | 6 +++--- app/component/itinerary/navigator/NaviUtils.js | 18 +++++++++--------- .../itinerary/navigator/navigator.scss | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/app/component/itinerary/navigator/NaviInstructions.js b/app/component/itinerary/navigator/NaviInstructions.js index 229fb2d4ea..d4a59e86a6 100644 --- a/app/component/itinerary/navigator/NaviInstructions.js +++ b/app/component/itinerary/navigator/NaviInstructions.js @@ -34,7 +34,7 @@ export default function NaviInstructions( return ( <> -
+
  {legDestination(intl, leg, null, nextLeg)} @@ -68,7 +68,7 @@ export default function NaviInstructions( return ( <> -
+
-
+
- + @@ -273,7 +273,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { const translationId = `navigation-mode-${delay > 0 ? 'late' : 'early'}`; content = ( -
+
); @@ -293,7 +293,7 @@ export const getTransitLegState = (leg, intl, messages, time) => { } content = (
- + { content = (
- + - + @@ -413,7 +413,7 @@ export const getItineraryAlerts = ( severity: 'ALERT', content: (
- {alert.alertHeaderText} + {alert.alertHeaderText}
), id: alertId(alert), @@ -433,7 +433,7 @@ export const getItineraryAlerts = ( const routeName = `${lMode} ${route.shortName}`; const m = ( - + {m}
+
{m}
); if (!messages.get(`canceled-${legId}`)) { @@ -472,7 +472,7 @@ export const getItineraryAlerts = ( alerts.push({ severity: prob.severity, content: withNewSearchBtn( - +