From 5cb8ab57d67d8f7c72ef6dd98e1f4451dfccb057 Mon Sep 17 00:00:00 2001 From: Alec Georgoff Date: Wed, 6 Aug 2025 11:19:34 -0700 Subject: [PATCH 1/7] Select scooter mode when starting trip from scooter in nearby view --- lib/components/map/default-map.tsx | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/components/map/default-map.tsx b/lib/components/map/default-map.tsx index e88fa5211..46fe2d18c 100644 --- a/lib/components/map/default-map.tsx +++ b/lib/components/map/default-map.tsx @@ -5,10 +5,11 @@ import { connect } from 'react-redux' import { GeolocateControl, NavigationControl } from 'react-map-gl' import { getCurrentDate } from '@opentripplanner/core-utils/lib/time' import { injectIntl } from 'react-intl' +import { MapLocationActionArg } from '@opentripplanner/types' +import { QueryParamChangeEvent } from '@opentripplanner/trip-form/lib/types' import BaseMap from '@opentripplanner/base-map' import generateOTP2TileLayers from '@opentripplanner/otp2-tile-overlay' import React, { Component } from 'react' -import styled from 'styled-components' import { assembleBasePath, @@ -21,7 +22,9 @@ import { ComponentContext } from '../../util/contexts' import { getActiveItinerary, getActiveSearch } from '../../util/state' import { getCurrentPosition } from '../../actions/location' import { MainPanelContent } from '../../actions/ui-constants' +import { onSettingsUpdate } from '../form/util' import { setLocation, setMapPopupLocationAndGeocode } from '../../actions/map' +import { setQueryParam } from '../../actions/form' import { setViewedStop } from '../../actions/ui' import { updateOverlayVisibility } from '../../actions/config' import TransitOperatorIcons from '../util/connected-transit-operator-icons' @@ -278,6 +281,7 @@ class DefaultMap extends Component { carRentalQuery, carRentalStations, config, + currentQuery, getCurrentPosition, intl, itinerary, @@ -285,6 +289,7 @@ class DefaultMap extends Component { nearbyViewActive, pending, setLocation, + setQueryParam, setViewedStop, vehicleRentalQuery, vehicleRentalStations, @@ -319,6 +324,24 @@ class DefaultMap extends Component { const baseLayerUrls = baseLayersWithNames?.map((bl) => bl.url) const baseLayerNames = baseLayersWithNames?.map((bl) => bl.name) + const overlayTypes = overlays + ?.filter((overlay) => overlay?.type === 'otp2')?.[0] + ?.layers?.map((layer) => layer?.type) + const handleSetLocation = (location: MapLocationActionArg) => { + if (overlayTypes && overlayTypes.includes('rentalVehicles')) { + let selectedModeButtons = currentQuery.modeButtons ?? '' + // if selectedModeButtons is undefined, the mode buttons are in their default state, which includes transit + if (selectedModeButtons.length === 0) + selectedModeButtons = 'transit_bike_rent' + else if (!selectedModeButtons.includes('bike_rent')) + selectedModeButtons += '_bike_rent' + console.log('rentalVehicles detected! setting query params') + const evt: QueryParamChangeEvent = { modeButtons: selectedModeButtons } + onSettingsUpdate(setQueryParam)(evt) + } + setLocation(location) + } + const routeBasedTransitVehicleOverlayNameOverride = overlays?.find((o) => o.type === 'vehicles-one-route') || undefined @@ -435,7 +458,7 @@ class DefaultMap extends Component { name: getLayerName(l, config, intl) || l.network || l.type })), vectorTilesEndpoint, - setLocation, + handleSetLocation, setViewedStop, viewedRouteStops, config.companies, @@ -486,6 +509,7 @@ const mapStateToProps = (state) => { bikeRentalStations: state.otp.overlay.bikeRental.stations, carRentalStations: state.otp.overlay.carRental.stations, config: state.otp.config, + currentQuery: state.otp.currentQuery, itinerary: getActiveItinerary(state), mapConfig: state.otp.config.map, nearbyViewActive: @@ -504,6 +528,7 @@ const mapDispatchToProps = { getCurrentPosition, setLocation, setMapPopupLocationAndGeocode, + setQueryParam, setViewedStop, updateOverlayVisibility, vehicleRentalQuery From 85993ff549bb4f699145cd3a999ad5be0f4727f9 Mon Sep 17 00:00:00 2001 From: Alec Georgoff Date: Wed, 6 Aug 2025 11:28:22 -0700 Subject: [PATCH 2/7] Fix missing import --- lib/components/map/default-map.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/components/map/default-map.tsx b/lib/components/map/default-map.tsx index 46fe2d18c..52c0c51c8 100644 --- a/lib/components/map/default-map.tsx +++ b/lib/components/map/default-map.tsx @@ -10,6 +10,7 @@ import { QueryParamChangeEvent } from '@opentripplanner/trip-form/lib/types' import BaseMap from '@opentripplanner/base-map' import generateOTP2TileLayers from '@opentripplanner/otp2-tile-overlay' import React, { Component } from 'react' +import styled from 'styled-components' import { assembleBasePath, From 29d5d3f0623b07872b3d5cc15b7ca37e876af5e3 Mon Sep 17 00:00:00 2001 From: Alec Georgoff Date: Wed, 6 Aug 2025 11:28:39 -0700 Subject: [PATCH 3/7] Remove console log --- lib/components/map/default-map.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/components/map/default-map.tsx b/lib/components/map/default-map.tsx index 52c0c51c8..664019bfc 100644 --- a/lib/components/map/default-map.tsx +++ b/lib/components/map/default-map.tsx @@ -336,7 +336,6 @@ class DefaultMap extends Component { selectedModeButtons = 'transit_bike_rent' else if (!selectedModeButtons.includes('bike_rent')) selectedModeButtons += '_bike_rent' - console.log('rentalVehicles detected! setting query params') const evt: QueryParamChangeEvent = { modeButtons: selectedModeButtons } onSettingsUpdate(setQueryParam)(evt) } From 18a74a4dc9efef06d9b84981d1169c2d609ac25a Mon Sep 17 00:00:00 2001 From: Alec Georgoff Date: Wed, 20 Aug 2025 15:15:03 -0500 Subject: [PATCH 4/7] Implement findRequiredOptionsForTransportMode --- lib/components/map/default-map.tsx | 47 +++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/lib/components/map/default-map.tsx b/lib/components/map/default-map.tsx index 664019bfc..60168a917 100644 --- a/lib/components/map/default-map.tsx +++ b/lib/components/map/default-map.tsx @@ -2,6 +2,7 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import { connect } from 'react-redux' +import { findRequiredOptionsForTransportMode } from '@opentripplanner/trip-form' import { GeolocateControl, NavigationControl } from 'react-map-gl' import { getCurrentDate } from '@opentripplanner/core-utils/lib/time' import { injectIntl } from 'react-intl' @@ -20,10 +21,15 @@ import { vehicleRentalQuery } from '../../actions/api' import { ComponentContext } from '../../util/contexts' +import { decodeQueryParams } from 'serialize-query-params' import { getActiveItinerary, getActiveSearch } from '../../util/state' import { getCurrentPosition } from '../../actions/location' import { MainPanelContent } from '../../actions/ui-constants' -import { onSettingsUpdate } from '../form/util' +import { + modesQueryParamConfig, + onSettingsUpdate, + setModeButton +} from '../form/util' import { setLocation, setMapPopupLocationAndGeocode } from '../../actions/map' import { setQueryParam } from '../../actions/form' import { setViewedStop } from '../../actions/ui' @@ -282,7 +288,7 @@ class DefaultMap extends Component { carRentalQuery, carRentalStations, config, - currentQuery, + enabledModeButtons, getCurrentPosition, intl, itinerary, @@ -330,14 +336,26 @@ class DefaultMap extends Component { ?.layers?.map((layer) => layer?.type) const handleSetLocation = (location: MapLocationActionArg) => { if (overlayTypes && overlayTypes.includes('rentalVehicles')) { - let selectedModeButtons = currentQuery.modeButtons ?? '' - // if selectedModeButtons is undefined, the mode buttons are in their default state, which includes transit - if (selectedModeButtons.length === 0) - selectedModeButtons = 'transit_bike_rent' - else if (!selectedModeButtons.includes('bike_rent')) - selectedModeButtons += '_bike_rent' - const evt: QueryParamChangeEvent = { modeButtons: selectedModeButtons } - onSettingsUpdate(setQueryParam)(evt) + const requiredOptions: + | { modeButton: string; modeSetting?: string } + | undefined = findRequiredOptionsForTransportMode( + config.modes.modeButtons, + config.modes.modeSettingDefinitions, + { mode: 'SCOOTER', qualifier: 'RENT' } + ) + if (requiredOptions) { + const modeSetter = setModeButton( + enabledModeButtons, + onSettingsUpdate(setQueryParam) + ) + + modeSetter(requiredOptions.modeButton, true) + + if (requiredOptions.modeSetting) + onSettingsUpdate(setQueryParam)({ + [requiredOptions.modeSetting]: true + }) + } } setLocation(location) } @@ -504,12 +522,19 @@ const mapStateToProps = (state) => { ) ) : null + const urlSearchParams = new URLSearchParams(state.router.location.search) + const { modes } = state.otp.config return { bikeRentalStations: state.otp.overlay.bikeRental.stations, carRentalStations: state.otp.overlay.carRental.stations, config: state.otp.config, - currentQuery: state.otp.currentQuery, + enabledModeButtons: + decodeQueryParams(modesQueryParamConfig, { + modeButtons: urlSearchParams.get('modeButtons') + })?.modeButtons || + modes?.initialState?.enabledModeButtons || + {}, itinerary: getActiveItinerary(state), mapConfig: state.otp.config.map, nearbyViewActive: From c58f43f761b7f2a29a87c330912452a919e900ac Mon Sep 17 00:00:00 2001 From: Alec Georgoff Date: Wed, 20 Aug 2025 15:17:51 -0500 Subject: [PATCH 5/7] Use find instead of filter --- lib/components/map/default-map.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/map/default-map.tsx b/lib/components/map/default-map.tsx index 60168a917..6c648e77a 100644 --- a/lib/components/map/default-map.tsx +++ b/lib/components/map/default-map.tsx @@ -332,7 +332,7 @@ class DefaultMap extends Component { const baseLayerNames = baseLayersWithNames?.map((bl) => bl.name) const overlayTypes = overlays - ?.filter((overlay) => overlay?.type === 'otp2')?.[0] + ?.find((overlay) => overlay?.type === 'otp2') ?.layers?.map((layer) => layer?.type) const handleSetLocation = (location: MapLocationActionArg) => { if (overlayTypes && overlayTypes.includes('rentalVehicles')) { From 03028996127ecb3e4cdb0aa2df040e8bc02dc37e Mon Sep 17 00:00:00 2001 From: Alec Georgoff Date: Thu, 28 Aug 2025 11:28:46 -0700 Subject: [PATCH 6/7] Version bump trip form package --- lib/components/map/default-map.tsx | 18 ++++++++++-------- package.json | 2 +- yarn.lock | 28 +++++++++++++++++++++++----- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/lib/components/map/default-map.tsx b/lib/components/map/default-map.tsx index 6c648e77a..6670c227a 100644 --- a/lib/components/map/default-map.tsx +++ b/lib/components/map/default-map.tsx @@ -2,7 +2,10 @@ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-nocheck import { connect } from 'react-redux' -import { findRequiredOptionsForTransportMode } from '@opentripplanner/trip-form' +import { + findRequiredOptionsForTransportMode, + RequiredOptionsForTransportMode +} from '@opentripplanner/trip-form' import { GeolocateControl, NavigationControl } from 'react-map-gl' import { getCurrentDate } from '@opentripplanner/core-utils/lib/time' import { injectIntl } from 'react-intl' @@ -336,13 +339,12 @@ class DefaultMap extends Component { ?.layers?.map((layer) => layer?.type) const handleSetLocation = (location: MapLocationActionArg) => { if (overlayTypes && overlayTypes.includes('rentalVehicles')) { - const requiredOptions: - | { modeButton: string; modeSetting?: string } - | undefined = findRequiredOptionsForTransportMode( - config.modes.modeButtons, - config.modes.modeSettingDefinitions, - { mode: 'SCOOTER', qualifier: 'RENT' } - ) + const requiredOptions: RequiredOptionsForTransportMode = + findRequiredOptionsForTransportMode( + config.modes.modeButtons, + config.modes.modeSettingDefinitions, + { mode: 'SCOOTER', qualifier: 'RENT' } + ) if (requiredOptions) { const modeSetter = setModeButton( enabledModeButtons, diff --git a/package.json b/package.json index 4d7220a8d..adddb7498 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "@opentripplanner/transit-vehicle-overlay": "6.0.2", "@opentripplanner/transitive-overlay": "6.0.0", "@opentripplanner/trip-details": "^8.0.1", - "@opentripplanner/trip-form": "6.0.1", + "@opentripplanner/trip-form": "6.1.0", "@opentripplanner/trip-viewer-overlay": "4.0.1", "@opentripplanner/vehicle-rental-overlay": "4.0.2", "@styled-icons/fa-regular": "^10.34.0", diff --git a/yarn.lock b/yarn.lock index be65ea6b3..2918f049e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2733,6 +2733,24 @@ lodash.isequal "^4.5.0" qs "^6.9.1" +"@opentripplanner/core-utils@14.0.1": + version "14.0.1" + resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-14.0.1.tgz#8800c9cd50680ff09e5375b4a20d2f1c24fb4a8b" + integrity sha512-LfCNtl+YORiBxeutC4+SXL4yMIumrMdL3zNfcV+mghRtpRmus36xd5rCgnzXtv1d6Arbbk+zXixJg90j/tBmwA== + dependencies: + "@conveyal/lonlat" "^1.4.1" + "@mapbox/polyline" "^1.1.1" + "@opentripplanner/geocoder" "3.0.5" + "@styled-icons/foundation" "^10.34.0" + "@turf/along" "^6.0.1" + chroma-js "^2.4.2" + date-fns "^2.28.0" + date-fns-tz "^1.2.2" + graphql "^16.6.0" + lodash.clonedeep "^4.5.0" + lodash.isequal "^4.5.0" + qs "^6.9.1" + "@opentripplanner/endpoints-overlay@4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@opentripplanner/endpoints-overlay/-/endpoints-overlay-4.0.1.tgz#ecc62b729db876ed3e331b7cab1a638c77a9ebf5" @@ -2975,14 +2993,14 @@ flat "^5.0.2" react-animate-height "^3.0.4" -"@opentripplanner/trip-form@6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@opentripplanner/trip-form/-/trip-form-6.0.1.tgz#262079589e056bf49c285a5b38257c54c59f088f" - integrity sha512-7o8frpL7rhieQmkrSaAxj+kqp8ocHyxmyB2l2LH8jJmoGgGevtQ5VxEmXaVctwpGJ12Fi1P/yiqD08PqnPG49w== +"@opentripplanner/trip-form@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@opentripplanner/trip-form/-/trip-form-6.1.0.tgz#0238052e423436f25ecd0edc3d98c6c5b3429754" + integrity sha512-jeo6wPZBHaf5wBJI3msrjckc5C08WMj6VkRe5b+a2CqEoDwPInxRN658+H6qgxDeCxFzNiOehey3lQq35bTP/Q== dependencies: "@floating-ui/react" "^0.19.2" "@opentripplanner/building-blocks" "3.0.1" - "@opentripplanner/core-utils" "13.0.1" + "@opentripplanner/core-utils" "14.0.1" "@opentripplanner/icons" "4.0.0" "@styled-icons/bootstrap" "^10.34.0" "@styled-icons/boxicons-regular" "^10.38.0" From c9da892cb68156e78b84872f42618cbe56e86de3 Mon Sep 17 00:00:00 2001 From: danielhep Date: Wed, 27 Aug 2025 16:29:04 -0700 Subject: [PATCH 7/7] add an empty string handler for jest gql --- __tests__/test-utils/mock-data/empty-string.js | 1 + package.json | 1 + 2 files changed, 2 insertions(+) create mode 100644 __tests__/test-utils/mock-data/empty-string.js diff --git a/__tests__/test-utils/mock-data/empty-string.js b/__tests__/test-utils/mock-data/empty-string.js new file mode 100644 index 000000000..b0c50903a --- /dev/null +++ b/__tests__/test-utils/mock-data/empty-string.js @@ -0,0 +1 @@ +module.exports = '' diff --git a/package.json b/package.json index 4015645ac..5af80f8e9 100644 --- a/package.json +++ b/package.json @@ -210,6 +210,7 @@ "i18n/(.*)\\.yml$": "__tests__/test-utils/mock-data/empty-yml.js", "modeSettings.yml$": "__tests__/test-utils/mock-data/empty-yml.js", "i18n-loader": "__tests__/test-utils/mock-data/i18n-loader.js", + "\\.graphql$": "__tests__/test-utils/mock-data/empty-string.js", "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "__tests__/test-utils/mock-data/fileMock.js" }, "transform": {