Skip to content

Vehicle rental overlay graphql migration #1440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 30 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
7d35c98
chore(deps): Upgrade maplibre-gl and react-map-gl. Fix imports.
binh-dam-ibigroup Apr 18, 2025
d961b64
refactor(getFitBoundsPadding): Import from OTP-UI base-map ESM
binh-dam-ibigroup Apr 18, 2025
d2f2d22
refactor: Update imports for react-map-gl
binh-dam-ibigroup Apr 18, 2025
1d4090a
chore(deps): Use OTP-UI test packages
binh-dam-ibigroup Apr 23, 2025
0a4de65
chore(deps): Use tmp dependencies for test
binh-dam-ibigroup Jun 2, 2025
636d740
upgrade trip-form
miles-grant-ibigroup Jul 8, 2025
3c4a12c
Move bike rental query to graphQL
alec-georgoff Jul 8, 2025
95a31c5
Update bike rental response reducer
alec-georgoff Jul 8, 2025
5f66024
Remove comment
alec-georgoff Jul 10, 2025
175b0ea
chore(deps): Update OTP-UI trip-form
binh-dam-ibigroup Jul 10, 2025
f4d84e1
fix(ResponsiveWebApp): Sort from/to coordinates before calling map.fi…
binh-dam-ibigroup Jul 11, 2025
3be3901
fix(RoutePreviewOverlay): Sort coordinates before calling map.fitBounds
binh-dam-ibigroup Jul 11, 2025
b42f5ae
refactor(webapp,rtprvw): Extract method to fit map to endpoints
binh-dam-ibigroup Jul 11, 2025
12ef610
refactor(RoutePreviewOverlay): Improve typing
binh-dam-ibigroup Jul 11, 2025
1e70eef
refactor(RoutePreviewOverlay): Remove console statement
binh-dam-ibigroup Jul 11, 2025
814d420
Update car rental query and consolidate rental vehicle query logic
alec-georgoff Jul 14, 2025
915413f
Fix carRentalQuery
alec-georgoff Jul 14, 2025
e9bb584
Merge remote-tracking branch 'origin/dev' into vehicle-rental-overlay…
alec-georgoff Jul 14, 2025
52a30fe
chore(deps): Update maplibre to 5.6.1
binh-dam-ibigroup Jul 15, 2025
55b77a4
refactor(util): Reuse fitMapToPoints with bounds sorting from base-map.
binh-dam-ibigroup Jul 15, 2025
991f56d
Merge branch 'dev' into new-maplibre-nopublish
binh-dam-ibigroup Jul 15, 2025
84b55f0
chore(deps): Finish updating maplibre to 5.6.1.
binh-dam-ibigroup Jul 15, 2025
6fe7dd6
fix(NearbyView): Throttle mouseleave events (Firefox bug)
binh-dam-ibigroup Jul 15, 2025
d5f97ea
Update vehicle rental queries to use graphQL and new types
alec-georgoff Jul 16, 2025
b3cf826
Merge remote-tracking branch 'origin/dev' into vehicle-rental-overlay…
alec-georgoff Jul 16, 2025
5779115
Merge branch 'dev' into new-maplibre-nopublish
binh-dam-ibigroup Aug 6, 2025
8511d5c
Merge remote-tracking branch 'origin/new-maplibre-nopublish' into veh…
alec-georgoff Aug 7, 2025
a57cd26
Merge remote-tracking branch 'origin/dev' into vehicle-rental-overlay…
alec-georgoff Aug 7, 2025
fbd6599
Remove changes to package.json that introduced locally built tarballs
alec-georgoff Aug 8, 2025
348cb88
Remove local types version
alec-georgoff Aug 8, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 7 additions & 38 deletions lib/actions/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,50 +317,19 @@ export function parkAndRideQuery(

// bike rental station query

export const bikeRentalError = createAction('BIKE_RENTAL_ERROR')
export const bikeRentalResponse = createAction('BIKE_RENTAL_RESPONSE')

export function bikeRentalQuery(
params,
responseAction = bikeRentalResponse,
errorAction = bikeRentalError,
options = {}
) {
const paramsString = qs.stringify(params)
const endpoint = `bike_rental${paramsString ? `?${paramsString}` : ''}`
return createQueryAction(endpoint, responseAction, errorAction, options)
export function bikeRentalQuery() {
return executeOTPAction('findBikeRentalStations')
}

// Car rental (e.g. car2go) locations lookup query

export const carRentalResponse = createAction('CAR_RENTAL_RESPONSE')
export const carRentalError = createAction('CAR_RENTAL_ERROR')

export function carRentalQuery(params) {
return createQueryAction('car_rental', carRentalResponse, carRentalError)
export function carRentalQuery() {
return executeOTPAction('findCarRentalStations')
}

// Vehicle rental locations lookup query. For now, there are 3 separate
// "vehicle" rental endpoints - 1 for cars, 1 for bicycle rentals and another
// for micromobility. In the future, the hope is to consolidate these 3
// endpoints into one.

export const vehicleRentalResponse = createAction('VEHICLE_RENTAL_RESPONSE')
export const vehicleRentalError = createAction('VEHICLE_RENTAL_ERROR')

export function vehicleRentalQuery(
params,
responseAction = vehicleRentalResponse,
errorAction = vehicleRentalError,
options = {}
) {
return executeOTPAction(
'vehicleRentalQuery',
params,
responseAction,
errorAction,
options
)
// Free-floating rental vehicles lookup query
export function rentalVehicleQuery() {
return executeOTPAction('findRentalVehicles')
}

// Nearby view lookup query
Expand Down
181 changes: 125 additions & 56 deletions lib/actions/apiV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,60 +182,6 @@ const findTrip = (params) =>
}
)

export const vehicleRentalQuery = (
params,
responseAction,
errorAction,
options
) =>
// TODO: ErrorsByNetwork is missing
createGraphQLQueryAction(
`{
rentalVehicles {
vehicleId
id
name
lat
lon
allowPickupNow
vehicleType {
formFactor
}
network
}
}
`,
{},
responseAction,
errorAction,
{
noThrottle: true,
postprocess: (payload, dispatch) => {
if (payload.errors) {
return errorAction(payload.errors)
}
},
// TODO: most of this rewrites the OTP2 response to match OTP1.
// we should re-write the rest of the UI to match OTP's behavior instead
rewritePayload: (payload) => {
return {
stations: payload?.data?.rentalVehicles?.map((vehicle) => {
return {
allowPickup: vehicle.allowPickupNow,
id: vehicle.vehicleId,
isFloatingBike: vehicle?.vehicleType?.formFactor === 'BICYCLE',
isFloatingVehicle: vehicle?.vehicleType?.formFactor === 'SCOOTER',
name: vehicle.name,
networks: [vehicle.network],
x: vehicle.lon,
y: vehicle.lat
}
})
}
}
}
)

// TODO: numberOfDepartures needs to come from config!
const stopTimeGraphQLQuery = `
stopTimes: stoptimesForPatterns(numberOfDepartures: 3) {
Expand Down Expand Up @@ -685,6 +631,127 @@ const getVehiclePositionsForRoute = (routeId) =>
)
}

const vehicleRentalStationsQuery = `
query VehicleRentalStations {
vehicleRentalStations {
id
name
lat
lon
allowDropoff
allowPickup
rentalNetwork {
networkId
}
availableVehicles {
total
byType {
vehicleType {
formFactor
}
}
}
availableSpaces {
total
byType {
vehicleType {
formFactor
}
}
}
realtime
}
}`

const vehicleRentalStationFilter = (formFactor) => (station) =>
(station.availableVehicles &&
station.availableVehicles.byType.some(
(av) => av.vehicleType.formFactor === formFactor
)) ||
(station.availableSpaces &&
station.availableSpaces.byType.some(
(as) => as.vehicleType.formFactor === formFactor
))

const bikeRentalError = createAction('BIKE_RENTAL_ERROR')
const bikeRentalResponse = createAction('BIKE_RENTAL_RESPONSE')

export function findBikeRentalStations() {
return function (dispatch) {
dispatch(
createGraphQLQueryAction(
vehicleRentalStationsQuery,
{},
bikeRentalResponse,
bikeRentalError,
{
rewritePayload: (payload) =>
payload.data.vehicleRentalStations.filter(
vehicleRentalStationFilter('BICYCLE')
)
}
)
)
}
}

export const carRentalResponse = createAction('CAR_RENTAL_RESPONSE')
export const carRentalError = createAction('CAR_RENTAL_ERROR')

export function findCarRentalStations() {
return function (dispatch) {
dispatch(
createGraphQLQueryAction(
vehicleRentalStationsQuery,
{},
carRentalResponse,
carRentalError,
{
rewritePayload: (payload) =>
payload.data.vehicleRentalStations.filter(
vehicleRentalStationFilter('CAR')
)
}
)
)
}
}

const rentalVehiclesQuery = `
query RentalVehicles {
rentalVehicles {
allowPickupNow
id
lat
lon
name
operative
rentalNetwork {
networkId
}
vehicleType {
formFactor
}
}
}`

const vehicleRentalResponse = createAction('VEHICLE_RENTAL_RESPONSE')
const vehicleRentalError = createAction('VEHICLE_RENTAL_ERROR')

export function findRentalVehicles() {
return function (dispatch) {
dispatch(
createGraphQLQueryAction(
rentalVehiclesQuery,
{},
vehicleRentalResponse,
vehicleRentalError,
{}
)
)
}
}

export const findRoute = (params) =>
function (dispatch, getState) {
const { routeId } = params
Expand Down Expand Up @@ -1324,14 +1391,16 @@ const retrieveServiceTimeRangeIfNeeded = () =>

export default {
fetchNearby,
findBikeRentalStations,
findCarRentalStations,
findPatternsForRoute,
findRentalVehicles,
findRoute,
findRoutes,
findStopsWithinBBox,
findStopTimesForStop,
findTrip,
getVehiclePositionsForRoute,
retrieveServiceTimeRangeIfNeeded,
routingQuery,
vehicleRentalQuery
routingQuery
}
17 changes: 10 additions & 7 deletions lib/components/app/responsive-webapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { Col, Grid, Row } from 'react-bootstrap'
import { connect } from 'react-redux'
import { ConnectedRouter } from 'connected-react-router'
import { createHashHistory } from 'history'
import { getFitBoundsPadding } from '@opentripplanner/base-map/lib/util'
import { injectIntl, IntlProvider } from 'react-intl'
import { MapProvider } from 'react-map-gl'
import { MapProvider } from 'react-map-gl/maplibre'
import { QueryParamProvider } from 'use-query-params'
import { ReactRouter5Adapter } from 'use-query-params/adapters/react-router-5'
import { Route, Switch, withRouter } from 'react-router'
import { Toaster } from 'react-hot-toast'
import { util } from '@opentripplanner/base-map'
import coreUtils from '@opentripplanner/core-utils'
import isEqual from 'lodash.isequal'
import PropTypes from 'prop-types'
Expand Down Expand Up @@ -107,11 +107,14 @@ class ResponsiveWebapp extends Component {
autoFly !== false &&
activeItinerary === null
) {
if (query.from && query.to) {
map?.fitBounds([query.from, query.to], {
duration: 600,
padding: getFitBoundsPadding(map, 0.2)
})
if (
query.from &&
query.to &&
query.from !== prevProps.query.from &&
query.to !== prevProps.query.to &&
map
) {
util.fitMapToPoints(map, query.from, query.to, 0.2, 600)
} else if (query.from && !query.to) {
setMapCenter(map, query.from)
} else if (query.to && !query.from) {
Expand Down
Loading
Loading