Skip to content
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

Show All Realtime Vehicles AT once #1281

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions lib/actions/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,6 @@ export const receivedVehiclePositionsError = createAction(
'REALTIME_VEHICLE_POSITIONS_ERROR'
)

export function getVehiclePositionsForRoute(routeId) {
return executeOTPAction('getVehiclePositionsForRoute', routeId)
export function getVehiclePositions(routeId) {
return executeOTPAction('getVehiclePositions', routeId)
}
4 changes: 2 additions & 2 deletions lib/actions/apiV1.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function findStopTimesForStop(params) {
}
}

const getVehiclePositionsForRoute = (routeId) =>
const getVehiclePositions = (routeId) =>
createQueryAction(
`index/routes/${routeId}/vehicles`,
receivedVehiclePositions,
Expand Down Expand Up @@ -166,7 +166,7 @@ export default {
findRoutes,
findStopTimesForStop,
findTrip,
getVehiclePositionsForRoute,
getVehiclePositions,
routingQuery,
vehicleRentalQuery
}
26 changes: 23 additions & 3 deletions lib/actions/apiV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -606,12 +606,12 @@ export const findStopTimesForStop = (params) =>
)
}

const getVehiclePositionsForRoute = (routeId) =>
const getVehiclePositions = (routeId) =>
function (dispatch, getState) {
return dispatch(
createGraphQLQueryAction(
`{
route(id: "${routeId}") {
route${routeId ? `(id: "${routeId}")` : 's'} {
patterns {
vehiclePositions {
vehicleId
Expand All @@ -629,6 +629,16 @@ const getVehiclePositionsForRoute = (routeId) =>
heading
lastUpdated
trip {
${
!routeId &&
`route {
shortName
longName
mode
color
textColor
}`
}
pattern {
id
}
Expand All @@ -643,6 +653,15 @@ const getVehiclePositionsForRoute = (routeId) =>
{
noThrottle: true,
rewritePayload: (payload) => {
if (payload.data?.routes) {
const vehicles = payload.data.routes.reduce((prev, cur) => {
return prev.concat(
cur.patterns.map((p) => p.vehiclePositions).flat()
)
}, [])

return { vehicles }
}
const vehicles = payload.data?.route?.patterns
.reduce((prev, cur) => {
return prev.concat(
Expand All @@ -664,6 +683,7 @@ const getVehiclePositionsForRoute = (routeId) =>
)
}, [])
.filter((vehicle) => !!vehicle)

return { routeId, vehicles }
}
}
Expand Down Expand Up @@ -1210,7 +1230,7 @@ export default {
findRoutes,
findStopTimesForStop,
findTrip,
getVehiclePositionsForRoute,
getVehiclePositions,
retrieveServiceTimeRangeIfNeeded,
routingQuery,
vehicleRentalQuery
Expand Down
54 changes: 54 additions & 0 deletions lib/components/map/connected-full-transit-vehicle-overlay.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { connect } from 'react-redux'

Check failure on line 1 in lib/components/map/connected-full-transit-vehicle-overlay.tsx

View workflow job for this annotation

GitHub Actions / test-build-release

Parameter 'obj' implicitly has an 'any' type.

Check failure on line 1 in lib/components/map/connected-full-transit-vehicle-overlay.tsx

View workflow job for this annotation

GitHub Actions / test-build-release

Parameter 'index' implicitly has an 'any' type.

Check failure on line 1 in lib/components/map/connected-full-transit-vehicle-overlay.tsx

View workflow job for this annotation

GitHub Actions / test-build-release

Parameter 'item' implicitly has an 'any' type.

Check failure on line 1 in lib/components/map/connected-full-transit-vehicle-overlay.tsx

View workflow job for this annotation

GitHub Actions / test-build-release

Parameter 'v' implicitly has an 'any' type.
import { injectIntl } from 'react-intl'
import React from 'react'
import TransitVehicleOverlay, {
Circle,
DefaultIconContainer,
RotatingCircle,
RouteNumberIcon,
withRouteColorBackground
} from '@opentripplanner/transit-vehicle-overlay'

import { DEFAULT_ROUTE_COLOR } from '../util/colors'

import { VehicleTooltip } from './connected-transit-vehicle-overlay'

const IconContainer = withRouteColorBackground(Circle)
// connect to the redux store
const mapStateToProps = (state: Record<string, any>) => {
const { viewedRoute } = state.otp.ui
// TODO: clever behavior for when route viewer is active

const vehicles = state.otp.transitIndex?.allVehicles
// TODO: CLEAN THIS UP
?.filter(
(obj, index) =>
state.otp.transitIndex?.allVehicles.findIndex(
(item) => item.vehicleId === obj.vehicleId
) === index
)
.map((v) => {
const { route } = v?.trip
v.routeType = route?.mode
v.routeColor =
route.color && !route.color.includes('#')
? '#' + route.color
: route?.color || DEFAULT_ROUTE_COLOR
// Try to populate this attribute, which is required for the vehicle popup to appear.
v.routeShortName = route?.shortName
v.routeLongName = v.routeLongName || route?.longName
v.textColor = route?.textColor
return v
})

// TODO: something funky is happening with the mode icon. Ferries are buses!
return {
IconContainer,
TooltipSlot: injectIntl(VehicleTooltip),
VehicleIcon: RouteNumberIcon,
vehicles
}
}

// @ts-expect-error state.js being typescripted will fix this error
export default injectIntl(connect(mapStateToProps)(TransitVehicleOverlay))
11 changes: 6 additions & 5 deletions lib/components/map/connected-transit-vehicle-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,21 @@
* 5) This overlay has a custom popup on vehicle hover
*/

import { connect } from 'react-redux'
import { FormattedMessage, FormattedNumber, injectIntl } from 'react-intl'
import React from 'react'
import TransitVehicleOverlay, {
Circle,
withCaret,
withRouteColorBackground
} from '@opentripplanner/transit-vehicle-overlay'

import { capitalizeFirst } from '../../util/ui'
import { connect } from 'react-redux'
import { DEFAULT_ROUTE_COLOR } from '../util/colors'
import { formatDuration } from '../util/formatted-duration'
import FormattedTransitVehicleStatus from '../util/formatted-transit-vehicle-status'

import React from 'react'

function VehicleTooltip(props) {
export function VehicleTooltip(props) {
const { intl, vehicle } = props

let vehicleLabel = vehicle?.label || vehicle?.vehicleId
Expand Down Expand Up @@ -65,7 +64,9 @@ function VehicleTooltip(props) {
{ id: 'common.time.durationAgo' },
{
duration: formatDuration(
Math.floor(Date.now() / 1000 - vehicle?.seconds),
Math.floor(
Date.now() / 1000 - (vehicle?.seconds || vehicle?.lastUpdated)
),
intl,
true
)
Expand Down
7 changes: 7 additions & 0 deletions lib/components/map/default-map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ import { MainPanelContent } from '../../actions/ui-constants'
import { setLocation, setMapPopupLocationAndGeocode } from '../../actions/map'
import { setViewedStop } from '../../actions/ui'
import { updateOverlayVisibility } from '../../actions/config'
import VehiclePositionRetriever from '../viewers/vehicle-position-retriever'

import ElevationPointMarker from './elevation-point-marker'
import EndpointsOverlay from './connected-endpoints-overlay'
import FullTransitVehicleOverlay from './connected-full-transit-vehicle-overlay'
import GeoJsonLayer from './connected-geojson-layer'
import ItinSummaryOverlay from './itinerary-summary-overlay'
import NearbyViewDotOverlay from './nearby-view-dot-overlay'
Expand Down Expand Up @@ -409,6 +411,8 @@ class DefaultMap extends Component {
viewedRouteStops,
config.companies
)
case 'realtime-vehicles':
return <FullTransitVehicleOverlay {...namedLayerProps} />
default:
return null
}
Expand All @@ -419,6 +423,9 @@ class DefaultMap extends Component {
<NavigationControl
position={navigationControlPosition || 'bottom-right'}
/>
{overlays.map((o) => o.type).includes('realtime-vehicles') && (
<VehiclePositionRetriever fetchAll />
)}
</BaseMap>
</MapContainer>
)
Expand Down
20 changes: 11 additions & 9 deletions lib/components/viewers/vehicle-position-retriever.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import { useCallback, useEffect, useState } from 'react'
import * as apiActions from '../../actions/api'

interface Props {
getVehiclePositionsForRoute: (id: string) => void
fetchAll?: boolean
getVehiclePositions: (id?: string) => void
refreshSeconds: number
routeId?: string
}
Expand All @@ -13,21 +14,22 @@ interface Props {
* Non-visual component that retrieves vehicle positions for the given route.
*/
const VehiclePositionRetriever = ({
getVehiclePositionsForRoute,
fetchAll,
getVehiclePositions,
refreshSeconds,
routeId
}: Props) => {
const [refreshTimer, setRefreshTimer] = useState<NodeJS.Timeout | null>(null)

const refreshVehiclePositions = useCallback(() => {
if (routeId) {
getVehiclePositionsForRoute(routeId)
if (routeId || fetchAll) {
getVehiclePositions(routeId)
}
}, [routeId, getVehiclePositionsForRoute])
}, [routeId, getVehiclePositions, fetchAll])

useEffect(() => {
// Fetch vehicle positions when initially mounting component and a route id is available.
if (routeId) {
if (routeId || fetchAll) {
refreshVehiclePositions()

if (!refreshTimer) {
Expand All @@ -45,7 +47,7 @@ const VehiclePositionRetriever = ({
setRefreshTimer(null)
}
}
}, [routeId, refreshVehiclePositions, refreshTimer, refreshSeconds])
}, [routeId, refreshVehiclePositions, refreshTimer, refreshSeconds, fetchAll])

// Component renders nothing.
return null
Expand All @@ -55,13 +57,13 @@ const VehiclePositionRetriever = ({
const mapStateToProps = (state: any) => {
return {
refreshSeconds:
state.otp.config.routeViewer?.vehiclePositionRefreshSeconds || 30,
state.otp.config.routeViewer?.vehiclePositionRefreshSeconds || 10,
routeId: state.otp.ui.viewedRoute?.routeId
}
}

const mapDispatchToProps = {
getVehiclePositionsForRoute: apiActions.getVehiclePositionsForRoute
getVehiclePositions: apiActions.getVehiclePositions
}

export default connect(
Expand Down
20 changes: 13 additions & 7 deletions lib/reducers/create-otp-reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -690,15 +690,21 @@ function createOtpReducer(config) {
case 'REALTIME_VEHICLE_POSITIONS_RESPONSE':
if (!action.payload?.vehicles) return state

return update(state, {
transitIndex: {
routes: {
[action.payload.routeId]: {
vehicles: { $set: action.payload.vehicles }
if (action.payload?.routeId) {
return update(state, {
transitIndex: {
routes: {
[action.payload.routeId]: {
vehicles: { $set: action.payload.vehicles }
}
}
}
}
})
})
} else {
return update(state, {
transitIndex: { allVehicles: { $set: action.payload.vehicles } }
})
}
case 'CLEAR_STOPS_OVERLAY':
return update(state, {
overlay: {
Expand Down
Loading