diff --git a/__tests__/components/viewers/__snapshots__/nearby-view.js.snap b/__tests__/components/viewers/__snapshots__/nearby-view.js.snap index d599a375e..46af4f668 100644 --- a/__tests__/components/viewers/__snapshots__/nearby-view.js.snap +++ b/__tests__/components/viewers/__snapshots__/nearby-view.js.snap @@ -4244,7 +4244,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` >

viewers > nearby view renders proper scooter dates 1`] = ` >

viewers > nearby view renders proper scooter dates 1`] = ` >

viewers > nearby view renders proper scooter dates 1`] = ` >

+ Roosevelt Station - Bay 2 @@ -11766,7 +12333,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

  • viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

      viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

    1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

        viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

      1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

          viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

          + Roosevelt @@ -18203,7 +19136,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

        1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

            viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

          1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

              viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

            1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                viewers > nearby view renders proper scooter dates 1`] = ` >

                viewers > nearby view renders proper scooter dates 1`] = ` >

                viewers > nearby view renders proper scooter dates 1`] = ` >

                viewers > nearby view renders proper scooter dates 1`] = ` >

                + Roosevelt Station - Bay 1 @@ -28467,7 +30044,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

              1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                  viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                    viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                  1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                      viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                    1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                        viewers > nearby view renders proper scooter dates 1`] = ` >

                        viewers > nearby view renders proper scooter dates 1`] = ` >

                        viewers > nearby view renders proper scooter dates 1`] = ` >

                        viewers > nearby view renders proper scooter dates 1`] = ` >

                        viewers > nearby view renders proper scooter dates 1`] = ` >

                        viewers > nearby view renders proper scooter dates 1`] = ` >

                        + Roosevelt Station Bay 5 - Bay 5 @@ -37584,7 +39527,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                      1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                          viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                        1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                            viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                          1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                              viewers > nearby view renders proper scooter dates 1`] = ` >

                              viewers > nearby view renders proper scooter dates 1`] = ` >

                              + Roosevelt @@ -46002,7 +48486,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                            1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                + Roosevelt Station - Bay 3 @@ -53643,7 +56771,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                              1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                  viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                    viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                  1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                      viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                    1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                        viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                      1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                          viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                        1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                            viewers > nearby view renders proper scooter dates 1`] = ` >

                                            viewers > nearby view renders proper scooter dates 1`] = ` >

                                            + NE 65th St & 14th Ave NE @@ -64829,7 +68524,7 @@ exports[`components > viewers > nearby view renders proper scooter dates 1`] = ` roundedTop={false} >

                                          1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                              viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                            1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                              1. viewers > nearby view renders proper scooter dates 1`] = ` className="departure-times" >

                                                  viewers > nearby view renders proper scooter dates 1`] = ` > viewers > nearby view renders proper scooter dates 1`] = ` iconViewBox="0 0 448 512" > viewers > nearby view renders proper scooter dates 1`] = ` >

                                                - - {transfers, plural, =0 {} one {# correspondance} other {# - correspondances}} linkOpensNewWindow: (Ouvre une nouvelle fenêtre) modes: bicycle_rent: En vélo en libre-service @@ -165,7 +161,6 @@ common: enterStartLocation: Entrez votre point de départ ou {mapAction} sur la carte… tap: appuyez time: - departureArrivalTimes: "{startTime, time, short}—{endTime, time, short}" duration: aFewSeconds: quelques secondes nDays: "{days, plural, =1 {un jour} other {# jours}}" @@ -286,7 +281,6 @@ components: ariaLabel: Navigation du formulaire ItinerarySummary: itineraryDetails: Détails du trajet - minMaxFare: "{minTotalFare} - {maxTotalFare}" LocationSearch: enterLocation: Entrez le lieu setDestination: Destination diff --git a/lib/actions/apiV2.js b/lib/actions/apiV2.js index 923cf6ef5..f42a6ec35 100644 --- a/lib/actions/apiV2.js +++ b/lib/actions/apiV2.js @@ -505,15 +505,13 @@ export const fetchNearby = (position, radius, currentServiceWeek) => { export const findStopTimesForStop = (params) => function (dispatch, getState) { dispatch(fetchingStopTimesForStop(params)) - const { date, stopId } = params + const { date, onlyRequestForOperators, stopId } = params const timeZone = getState().otp.config.homeTimezone // Create a service date timestamp from 3:30am local. const serviceDay = getServiceStart(date, timeZone).getTime() / 1000 - return dispatch( - createGraphQLQueryAction( - `query StopTimes( + const fullStopTimesQuery = `query StopTimes( $serviceDay: Long! $stopId: String! ) { @@ -573,7 +571,48 @@ export const findStopTimesForStop = (params) => } } } - }`, + }` + + const shorterStopTimesQueryForOperators = `query StopTimes( + $stopId: String! + ) { + stop(id: $stopId) { + gtfsId + code + routes { + id: gtfsId + agency { + gtfsId + name + } + patterns { + id + headsign + } + } + stoptimesForPatterns(numberOfDepartures: 100, omitNonPickups: true, omitCanceled: false) { + pattern { + desc: name + headsign + id: code + route { + agency { + gtfsId + } + gtfsId + } + } + } + } + }` + + const query = onlyRequestForOperators + ? shorterStopTimesQueryForOperators + : fullStopTimesQuery + + return dispatch( + createGraphQLQueryAction( + query, { serviceDay, stopId diff --git a/lib/actions/field-trip.js b/lib/actions/field-trip.js index 316978475..0b667dbf1 100644 --- a/lib/actions/field-trip.js +++ b/lib/actions/field-trip.js @@ -6,7 +6,7 @@ import { getRoutingParams, planParamsToQueryAsync } from '@opentripplanner/core-utils/lib/query' -import { isTransit } from '@opentripplanner/core-utils/lib/itinerary' +import { isTransitLeg } from '@opentripplanner/core-utils/lib/itinerary' import { OTP_API_DATE_FORMAT, OTP_API_TIME_FORMAT @@ -395,36 +395,34 @@ function makeSaveFieldTripItinerariesData(request, outbound, state) { } const gtfsTripsForItinerary = [] - itinerary.legs - .filter((leg) => isTransit(leg.mode)) - .forEach((leg) => { - let routeName = leg.routeShortName ? `(${leg.routeShortName}) ` : '' - routeName = `${routeName}${leg.routeLongName}` - const gtfsTrip = { - agencyAndId: leg.tripId, - // 'arrive' must be expressed in the agency's timezone - arrive: formatInTz(new Date(leg.endTime), FIELD_TRIP_TIME_FORMAT, { - timeZone: homeTimezone - }), - capacity: getFieldTripGroupCapacityForMode( - fieldTripModuleConfig, - leg.mode - ), - // 'depart' must be expressed in the agency's timezone - depart: formatInTz(new Date(leg.startTime), FIELD_TRIP_TIME_FORMAT, { - timeZone: homeTimezone - }), - fromStopIndex: leg.from.stopIndex, - fromStopName: leg.from.name, - headsign: leg.headsign, - routeName, - toStopIndex: leg.to.stopIndex, - toStopName: leg.to.name, - tripHash: tripHashLookup[leg.tripId] - } - if (leg.tripBlockId) gtfsTrip.blockId = leg.tripBlockId - gtfsTripsForItinerary.push(gtfsTrip) - }) + itinerary.legs.filter(isTransitLeg).forEach((leg) => { + let routeName = leg.routeShortName ? `(${leg.routeShortName}) ` : '' + routeName = `${routeName}${leg.routeLongName}` + const gtfsTrip = { + agencyAndId: leg.tripId, + // 'arrive' must be expressed in the agency's timezone + arrive: formatInTz(new Date(leg.endTime), FIELD_TRIP_TIME_FORMAT, { + timeZone: homeTimezone + }), + capacity: getFieldTripGroupCapacityForMode( + fieldTripModuleConfig, + leg.mode + ), + // 'depart' must be expressed in the agency's timezone + depart: formatInTz(new Date(leg.startTime), FIELD_TRIP_TIME_FORMAT, { + timeZone: homeTimezone + }), + fromStopIndex: leg.from.stopIndex, + fromStopName: leg.from.name, + headsign: leg.headsign, + routeName, + toStopIndex: leg.to.stopIndex, + toStopName: leg.to.name, + tripHash: tripHashLookup[leg.tripId] + } + if (leg.tripBlockId) gtfsTrip.blockId = leg.tripBlockId + gtfsTripsForItinerary.push(gtfsTrip) + }) data.itins.push(itineraryDataToSave) data.gtfsTrips.push(gtfsTripsForItinerary) @@ -616,7 +614,6 @@ function getMissingTripHashesForActiveItineraries() { }) ) } - return true } /** @@ -712,52 +709,50 @@ function checkValidityAndCapacity(state, request) { // check each individual trip to see if there aren't any trips in this // itinerary that are already in use by another field trip - itinerary.legs - .filter((leg) => isTransit(leg.mode)) - .forEach((leg) => { - const tripId = leg?.trip?.gtfsId - - // this variable is used to track how many other field trips are using a - // particular trip - let capacityInUse = 0 - - // iterate over trips that are already being used by other field trips - // NOTE: In the use case of re-planning trips, there is currently no way - // to discern whether a tripInUse belongs to the current direction of - // the field trip being planned. Therefore, this will result in the - // re-planning of trips avoiding it's own previously planned trips - // that it currently has saved - travelDateTripsInUse.forEach((tripInUse) => { - if (!tripsOverlap(leg, tripHashLookup, tripId, tripInUse)) return - - // ranges overlap! Add number of passengers on this other field trip - // to total capacity in use - capacityInUse += tripInUse.passengers - }) + itinerary.legs.filter(isTransitLeg).forEach((leg) => { + const tripId = leg?.trip?.gtfsId + + // this variable is used to track how many other field trips are using a + // particular trip + let capacityInUse = 0 + + // iterate over trips that are already being used by other field trips + // NOTE: In the use case of re-planning trips, there is currently no way + // to discern whether a tripInUse belongs to the current direction of + // the field trip being planned. Therefore, this will result in the + // re-planning of trips avoiding it's own previously planned trips + // that it currently has saved + travelDateTripsInUse.forEach((tripInUse) => { + if (!tripsOverlap(leg, tripHashLookup, tripId, tripInUse)) return + + // ranges overlap! Add number of passengers on this other field trip + // to total capacity in use + capacityInUse += tripInUse.passengers + }) - // check if the remaining capacity on this trip is enough to allow more - // field trip passengers on board - const legModeCapacity = getFieldTripGroupCapacityForMode( - fieldTripModuleConfig, - leg.mode - ) - let remainingTripCapacity = legModeCapacity - capacityInUse - if (remainingTripCapacity < minimumAllowableRemainingCapacity) { - // This trip is already too "full" to allow any addition field trips - // on board. Ban this trip in future searches and don't use this - // itinerary in final results (set trip and itinerary capacity to 0). - remainingTripCapacity = 0 - } + // check if the remaining capacity on this trip is enough to allow more + // field trip passengers on board + const legModeCapacity = getFieldTripGroupCapacityForMode( + fieldTripModuleConfig, + leg.mode + ) + let remainingTripCapacity = legModeCapacity - capacityInUse + if (remainingTripCapacity < minimumAllowableRemainingCapacity) { + // This trip is already too "full" to allow any addition field trips + // on board. Ban this trip in future searches and don't use this + // itinerary in final results (set trip and itinerary capacity to 0). + remainingTripCapacity = 0 + } - // always ban trips found in itineraries so that subsequent searches - // don't encounter them. - // TODO: a more advanced way of doing things might be to ban trip - // sequences to not find the same exact sequence, but also - // individual trips that are too full. - tripsToBanInSubsequentSearches.push(tripId) + // always ban trips found in itineraries so that subsequent searches + // don't encounter them. + // TODO: a more advanced way of doing things might be to ban trip + // sequences to not find the same exact sequence, but also + // individual trips that are too full. + tripsToBanInSubsequentSearches.push(tripId) - itineraryCapacity = Math.min(itineraryCapacity, remainingTripCapacity) - }) + itineraryCapacity = Math.min(itineraryCapacity, remainingTripCapacity) + }) if (itineraryCapacity > 0) { // itinerary has capacity, add to list and update remaining group size. diff --git a/lib/components/map/default-map.tsx b/lib/components/map/default-map.tsx index 38d7570e4..b2e7b899f 100644 --- a/lib/components/map/default-map.tsx +++ b/lib/components/map/default-map.tsx @@ -3,6 +3,7 @@ // @ts-nocheck 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 BaseMap from '@opentripplanner/base-map' import generateOTP2TileLayers from '@opentripplanner/otp2-tile-overlay' @@ -13,6 +14,7 @@ import { assembleBasePath, bikeRentalQuery, carRentalQuery, + findStopTimesForStop, vehicleRentalQuery } from '../../actions/api' import { ComponentContext } from '../../util/contexts' @@ -22,6 +24,7 @@ import { MainPanelContent } from '../../actions/ui-constants' import { setLocation, setMapPopupLocationAndGeocode } from '../../actions/map' import { setViewedStop } from '../../actions/ui' import { updateOverlayVisibility } from '../../actions/config' +import TransitOperatorIcons from '../util/connected-transit-operator-icons' import ElevationPointMarker from './elevation-point-marker' import EndpointsOverlay from './connected-endpoints-overlay' @@ -153,6 +156,17 @@ class DefaultMap extends Component { } } + // Generate operator logos to pass through OTP tile layer to map-popup + getEntityPrefix = (entity) => { + const stopId = entity.gtfsId + this.props.findStopTimesForStop({ + date: getCurrentDate(), + onlyRequestForOperators: true, + stopId + }) + return + } + /** * Checks whether the modes have changed between old and new queries and * whether to update the map overlays accordingly (e.g., to show rental vehicle @@ -407,7 +421,8 @@ class DefaultMap extends Component { setLocation, setViewedStop, viewedRouteStops, - config.companies + config.companies, + this.getEntityPrefix ) default: return null @@ -468,6 +483,7 @@ const mapStateToProps = (state) => { const mapDispatchToProps = { bikeRentalQuery, carRentalQuery, + findStopTimesForStop, getCurrentPosition, setLocation, setMapPopupLocationAndGeocode, diff --git a/lib/components/narrative/default/default-itinerary.js b/lib/components/narrative/default/default-itinerary.js index 89219244f..ba67d24da 100644 --- a/lib/components/narrative/default/default-itinerary.js +++ b/lib/components/narrative/default/default-itinerary.js @@ -36,7 +36,7 @@ const { isAdvanceBookingRequired, isCoordinationRequired, isFlex, - isTransit + isTransitLeg } = coreUtils.itinerary // Styled components @@ -164,7 +164,7 @@ const ITINERARY_ATTRIBUTES = [ order: 3, render: (itinerary, options) => { const leg = clone(itinerary.legs[0]) - if (isTransit(leg.mode)) { + if (isTransitLeg(leg)) { leg.mode = 'WALK' } diff --git a/lib/components/narrative/default/itinerary-description.tsx b/lib/components/narrative/default/itinerary-description.tsx index d26e348f5..9e2f1327a 100644 --- a/lib/components/narrative/default/itinerary-description.tsx +++ b/lib/components/narrative/default/itinerary-description.tsx @@ -9,7 +9,7 @@ import FormattedMode from '../../util/formatted-mode' const { isRideshareLeg } = coreUtils.itinerary -const { isBicycle, isMicromobility, isTransit } = coreUtils.itinerary +const { isBicycle, isMicromobility, isTransitLeg } = coreUtils.itinerary type Props = { combineTransitModes?: boolean @@ -32,10 +32,7 @@ export function getMainItineraryModes({ let transitMode itinerary.legs.forEach((leg, i) => { const { duration, mode, rentedBike, rentedVehicle } = leg - if ( - (leg.transitLeg || isTransit(mode)) && - duration > primaryTransitDuration - ) { + if (isTransitLeg(leg) && duration > primaryTransitDuration) { primaryTransitDuration = duration transitMode = getFormattedMode( combineTransitModes ? 'transit' : mode.toLowerCase(), @@ -68,7 +65,7 @@ export function ItineraryDescription({ itinerary }: Props): JSX.Element { let transitMode itinerary.legs.forEach((leg) => { const { duration, mode, rentedBike, rentedVehicle } = leg - if (isTransit(mode) && duration > primaryTransitDuration) { + if (isTransitLeg(leg) && duration > primaryTransitDuration) { primaryTransitDuration = duration // If custom TransitModes have been defined for the given mode/leg, attempt to use them, diff --git a/lib/components/narrative/default/itinerary-summary.js b/lib/components/narrative/default/itinerary-summary.js index 5ff8dcc8f..5d327407b 100644 --- a/lib/components/narrative/default/itinerary-summary.js +++ b/lib/components/narrative/default/itinerary-summary.js @@ -1,7 +1,10 @@ /* eslint-disable @typescript-eslint/no-use-before-define */ import { connect } from 'react-redux' -import { getCompanyFromLeg } from '@opentripplanner/core-utils/lib/itinerary' +import { + getCompanyFromLeg, + isTransitLeg +} from '@opentripplanner/core-utils/lib/itinerary' import PropTypes from 'prop-types' import React, { Component } from 'react' import styled from 'styled-components' @@ -93,16 +96,16 @@ export default class ItinerarySummary extends Component { if ( i > 0 && i < itinerary.legs.length - 1 && - !leg.transitLeg && - itinerary.legs[i - 1].transitLeg && - itinerary.legs[i + 1].transitLeg + !isTransitLeg(leg) && + isTransitLeg(itinerary.legs[i - 1]) && + isTransitLeg(itinerary.legs[i + 1]) ) { return null } // Add the mode icon let title = leg.mode - if (leg.transitLeg) { + if (isTransitLeg(leg)) { title = leg.routeShortName ? `${leg.routeShortName}${ leg.routeLongName ? ` - ${leg.routeLongName}` : '' diff --git a/lib/components/narrative/line-itin/LegIconWithA11y.tsx b/lib/components/narrative/line-itin/LegIconWithA11y.tsx index ab5e8dacc..283fe7ace 100644 --- a/lib/components/narrative/line-itin/LegIconWithA11y.tsx +++ b/lib/components/narrative/line-itin/LegIconWithA11y.tsx @@ -1,22 +1,24 @@ -import { getFormattedMode } from '../../../util/i18n' -import coreUtils from '@opentripplanner/core-utils' -import InvisibleA11yLabel from '../../util/invisible-a11y-label' - -import React, { useContext } from 'react' +import { isTransitLeg } from '@opentripplanner/core-utils/lib/itinerary' +import { Leg } from '@opentripplanner/types' +import { useIntl } from 'react-intl' import { ComponentContext } from '../../../util/contexts' +import { getFormattedMode } from '../../../util/i18n' +import React, { useContext } from 'react' -import { useIntl } from 'react-intl' +import InvisibleA11yLabel from '../../util/invisible-a11y-label' -const { isTransit } = coreUtils.itinerary +type Props = { + leg: Leg +} -const LegIconWithA11y = (props: any) => { +const LegIconWithA11y = (props: Props): JSX.Element => { // @ts-expect-error No type on ComponentContext const { LegIcon } = useContext(ComponentContext) const intl = useIntl() const { leg } = props const { mode } = leg - const ariaLabel = isTransit(mode) ? getFormattedMode(mode, intl) : null + const ariaLabel = isTransitLeg(leg) ? getFormattedMode(mode, intl) : null return ( <> diff --git a/lib/components/narrative/line-itin/itin-summary.tsx b/lib/components/narrative/line-itin/itin-summary.tsx deleted file mode 100644 index 482aa9a72..000000000 --- a/lib/components/narrative/line-itin/itin-summary.tsx +++ /dev/null @@ -1,247 +0,0 @@ -import { connect } from 'react-redux' -import { FareProductSelector, Itinerary, Leg } from '@opentripplanner/types' -import { FormattedMessage, FormattedNumber } from 'react-intl' -import coreUtils from '@opentripplanner/core-utils' -import React, { Component } from 'react' -import styled from 'styled-components' - -import { AppReduxState } from '../../../util/state-types' -import { ComponentContext } from '../../../util/contexts' -import { getFare } from '../../../util/itinerary' -import { GREY_ON_WHITE } from '../../util/colors' -import FormattedDuration from '../../util/formatted-duration' - -// TODO: make this a prop -const defaultRouteColor = '#008' - -const Container = styled.div` - display: ${() => (coreUtils.ui.isMobile() ? 'table' : 'none')}; - height: 60px; - margin-bottom: 15px; - padding-right: 5px; - width: 100%; -` - -const Detail = styled.div` - color: ${GREY_ON_WHITE}; - font-size: 13px; -` - -const Details = styled.div` - display: table-cell; - vertical-align: top; -` - -const Header = styled.div` - font-size: 18px; - font-weight: bold; - margin-top: -3px; -` - -const LegIconContainer = styled.div` - height: 30px; - width: 30px; -` - -const NonTransitSpacer = styled.div` - height: 30px; - overflow: hidden; -` - -const RoutePreview = styled.div` - display: inline-block; - margin-left: 8px; - vertical-align: top; -` - -const Routes = styled.div` - display: table-cell; - text-align: right; -` - -const ShortName = styled.div<{ leg: Leg }>` - background-color: ${(props) => getRouteColorForBadge(props.leg)}; - border-radius: 15px; - border: 2px solid white; - box-shadow: 0 0 0.5em #000; - color: white; - font-size: 15px; - font-weight: 500; - height: 30px; - margin-top: 6px; - overflow: hidden; - padding-top: 4px; - text-align: center; - text-overflow: ellipsis; - white-space: nowrap; - width: 30px; -` - -type Props = { - currency?: string - defaultFareType?: FareProductSelector - itinerary: Itinerary - onClick: () => void -} - -export class ItinerarySummary extends Component { - static contextType = ComponentContext - - _onSummaryClicked = (): void => { - if (typeof this.props.onClick === 'function') this.props.onClick() - } - - render(): JSX.Element { - const { defaultFareType, itinerary } = this.props - const { LegIcon } = this.context - - const { fareCurrency, maxTNCFare, minTNCFare, transitFare } = getFare( - itinerary, - defaultFareType - ) - - const minTotalFare = minTNCFare * 100 + (transitFare || 0) - const maxTotalFare = maxTNCFare * 100 + (transitFare || 0) - - const { endTime, startTime } = itinerary - - const { caloriesBurned } = - coreUtils.itinerary.calculatePhysicalActivity(itinerary) - - const minTotalFareFormatted = minTotalFare > 0 && ( - - ) - - return ( - -
                                                - {/* Travel time in hrs/mins */} -
                                                - -
                                                - - {/* Duration as time range */} - - - - - {/* Fare / Calories */} - - {minTotalFare > 0 && ( - - {minTotalFare === maxTotalFare ? ( - minTotalFareFormatted - ) : ( - - ), - minTotalFare: minTotalFareFormatted - }} - /> - )} - - - )} - - - - {/* Number of transfers, if applicable */} - - - -
                                                - - {itinerary.legs - .filter((leg: Leg) => { - return !(leg.mode === 'WALK' && itinerary.transitTime > 0) - }) - .map((leg: Leg, k: number) => { - return ( - - - - - {coreUtils.itinerary.isTransit(leg.mode) ? ( - {getRouteNameForBadge(leg)} - ) : ( - - )} - - ) - })} - -
                                                - ) - } -} - -// Helper functions - -// Leg is any for now until types package is updated with correct Leg type -function getRouteLongName(leg: any) { - return leg.routes && leg.routes.length > 0 - ? leg.routes[0].longName - : leg.routeLongName -} - -function getRouteNameForBadge(leg: any) { - const shortName = - leg.routes && leg.routes.length > 0 - ? leg.routes[0].shortName - : leg.routeShortName - - const longName = getRouteLongName(leg) - - // check for max - if (longName && longName.toLowerCase().startsWith('max')) return null - - // check for streetcar - if (longName && longName.startsWith('Portland Streetcar')) - return longName.split('-')[1].trim().split(' ')[0] - - return shortName || longName -} - -function getRouteColorForBadge(leg: Leg): string { - return leg.routeColor ? '#' + leg.routeColor : defaultRouteColor -} - -const mapStateToProps = (state: AppReduxState) => { - return { - defaultFareType: state.otp.config.itinerary?.defaultFareType - } -} - -export default connect(mapStateToProps)(ItinerarySummary) diff --git a/lib/components/narrative/line-itin/realtime-time-column.tsx b/lib/components/narrative/line-itin/realtime-time-column.tsx index 2e14834a8..303a700d9 100644 --- a/lib/components/narrative/line-itin/realtime-time-column.tsx +++ b/lib/components/narrative/line-itin/realtime-time-column.tsx @@ -1,5 +1,5 @@ import { FormattedTime } from 'react-intl' -import { isTransit } from '@opentripplanner/core-utils/lib/itinerary' +import { isTransitLeg } from '@opentripplanner/core-utils/lib/itinerary' import { Leg } from '@opentripplanner/types' import React, { ReactElement } from 'react' import styled from 'styled-components' @@ -33,11 +33,10 @@ function RealtimeTimeColumn({ isDestination, leg }: Props): ReactElement { } const timeMillis = isDestination ? leg.endTime : leg.startTime - const isTransitLeg = isTransit(leg.mode) - const isRealtimeTransitLeg = isTransitLeg && leg.realTime + const isRealtimeTransitLeg = isTransitLeg(leg) && leg.realTime // For non-transit legs show only the scheduled time. - if (!isTransitLeg) { + if (!isTransitLeg(leg)) { return (
                                                diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js index 7d9faded6..e86007221 100644 --- a/lib/components/narrative/narrative-itineraries.js +++ b/lib/components/narrative/narrative-itineraries.js @@ -2,7 +2,7 @@ import { connect } from 'react-redux' import { differenceInDays } from 'date-fns' import { FormattedMessage, injectIntl } from 'react-intl' -import { isFlex, isTransit } from '@opentripplanner/core-utils/lib/itinerary' +import { isFlex, isTransitLeg } from '@opentripplanner/core-utils/lib/itinerary' import clone from 'clone' import coreUtils from '@opentripplanner/core-utils' import memoize from 'lodash.memoize' @@ -423,9 +423,7 @@ class NarrativeItineraries extends Component { }) // Identify whether an itinerary uses transit & sort into appropriate bucket - const transitLegs = cur.legs.filter( - (leg) => isTransit(leg.mode) | leg.transitLeg - ) + const transitLegs = cur.legs.filter(isTransitLeg) const modeContainer = transitLegs.length > 0 ? modeItinMap.multi : modeItinMap.single diff --git a/lib/components/user/monitored-trip/trip-notifications-pane.tsx b/lib/components/user/monitored-trip/trip-notifications-pane.tsx index 197275a4a..d02bbf52c 100644 --- a/lib/components/user/monitored-trip/trip-notifications-pane.tsx +++ b/lib/components/user/monitored-trip/trip-notifications-pane.tsx @@ -2,7 +2,7 @@ import { Alert, FormControl } from 'react-bootstrap' import { ExclamationTriangle } from '@styled-icons/fa-solid/ExclamationTriangle' import { FormattedList, FormattedMessage } from 'react-intl' import { FormikProps } from 'formik' -import { Leg } from '@opentripplanner/types' +import { isTransitLeg } from '@opentripplanner/core-utils/lib/itinerary' import React, { Component, FormEvent } from 'react' import styled from 'styled-components' @@ -74,9 +74,7 @@ class TripNotificationsPane extends Component { values.arrivalVarianceMinutesThreshold, values.departureVarianceMinutesThreshold ) - const hasTransit = values.itinerary?.legs?.some( - (leg: Leg) => leg.transitLeg - ) + const hasTransit = values.itinerary?.legs?.some(isTransitLeg) let notificationSettingsContent if (areNotificationsDisabled) { diff --git a/lib/components/util/connected-transit-operator-icons.tsx b/lib/components/util/connected-transit-operator-icons.tsx new file mode 100644 index 000000000..0475e54e4 --- /dev/null +++ b/lib/components/util/connected-transit-operator-icons.tsx @@ -0,0 +1,38 @@ +import { connect } from 'react-redux' +import { TransitOperator } from '@opentripplanner/types' +import React from 'react' + +import { AppReduxState } from '../../util/state-types' +import { FETCH_STATUS } from '../../util/constants' + +import { StopData } from './types' +import TransitOperatorLogos from './transit-operator-icons' + +interface Props { + stopData?: StopData + transitOperators: TransitOperator[] +} + +function TransitOperatorIcons({ stopData, transitOperators }: Props) { + const loading = stopData?.fetchStatus === FETCH_STATUS.FETCHING + return ( + + ) +} + +const mapStateToProps = ( + state: AppReduxState, + ownProps: Props & { stopId: string } +) => { + const stops = state.otp.transitIndex.stops + return { + stopData: stops?.[ownProps.stopId], + transitOperators: state.otp.config.transitOperators || [] + } +} + +export default connect(mapStateToProps)(TransitOperatorIcons) diff --git a/lib/components/util/operator-logo.tsx b/lib/components/util/operator-logo.tsx index 420e37ce7..f88f6d51a 100644 --- a/lib/components/util/operator-logo.tsx +++ b/lib/components/util/operator-logo.tsx @@ -2,20 +2,32 @@ import { TransitOperator } from '@opentripplanner/types' import React from 'react' import styled from 'styled-components' -const OperatorImg = styled.img` +const OperatorImg = styled.img<{ marginRight?: number; maxHeight?: number }>` &:not(:last-of-type) { margin-right: 0.5ch; } width: 25px; ` +const StyledOperatorImg = styled(OperatorImg)` + margin-right: 0.5ch; + max-height: 1em; + // Make sure icons stay square + max-width: 1em; +` + type Props = { alt?: string operator?: TransitOperator + styled?: boolean } -const OperatorLogo = ({ alt, operator }: Props): JSX.Element | null => { +const OperatorLogo = ({ alt, operator, styled }: Props): JSX.Element | null => { if (!operator?.logo) return null + if (styled) { + return + } + return } diff --git a/lib/components/util/transit-operator-icons.tsx b/lib/components/util/transit-operator-icons.tsx new file mode 100644 index 000000000..7f40fe11c --- /dev/null +++ b/lib/components/util/transit-operator-icons.tsx @@ -0,0 +1,83 @@ +import { MapPin } from '@styled-icons/fa-solid' +import { useIntl } from 'react-intl' +import React from 'react' +import Skeleton from 'react-loading-skeleton' +import type { TransitOperator } from '@opentripplanner/types' + +import InvisibleA11yLabel from './invisible-a11y-label' +import OperatorLogo from './operator-logo' +import type { StopData } from './types' + +const Operator = ({ operator }: { operator?: TransitOperator }) => { + const intl = useIntl() + + if (!operator) { + return null + } else { + const operatorLogoAriaLabel = intl.formatMessage( + { + id: 'components.StopViewer.operatorLogoAriaLabel' + }, + { + operatorName: operator.name + } + ) + return operator.logo ? ( + // Span with agency classname allows optional contrast/customization in user + // config for logos with poor contrast. Class name is hyphenated agency name + // e.g. "sound-transit" + + + + ) : ( + // If operator exists but logo is missing, + // we still need to announce the operator name to screen readers. + <> + + {operatorLogoAriaLabel} + + ) + } +} + +const TransitOperatorLogos = ({ + loading = false, + stopData, + transitOperators +}: { + loading?: boolean + stopData?: StopData + transitOperators?: TransitOperator[] +}): JSX.Element => { + const agencies = + (stopData && + stopData.stoptimesForPatterns?.reduce>((prev, cur) => { + // @ts-expect-error The agency type is not yet compatible with OTP2 + const agencyGtfsId = cur.pattern.route.agency?.gtfsId + return agencyGtfsId ? prev.add(agencyGtfsId) : prev + }, new Set())) || + new Set() + + return ( + <> + {loading ? ( + + ) : ( + transitOperators + ?.filter((to) => Array.from(agencies).includes(to.agencyId)) + // Second pass to remove duplicates based on name + .filter( + (to, index, arr) => + index === arr.findIndex((t) => t?.name === to?.name) + ) + .map((to) => ) + )} + + ) +} + +export default TransitOperatorLogos diff --git a/lib/components/viewers/nearby/stop-card-header.tsx b/lib/components/viewers/nearby/stop-card-header.tsx index 045616e60..d161ba7d6 100644 --- a/lib/components/viewers/nearby/stop-card-header.tsx +++ b/lib/components/viewers/nearby/stop-card-header.tsx @@ -1,6 +1,5 @@ import { connect } from 'react-redux' import { FormattedMessage, useIntl } from 'react-intl' -import { MapPin } from '@styled-icons/fa-solid' import { Search } from '@styled-icons/fa-solid/Search' import { TransitOperator } from '@opentripplanner/types' import React, { ComponentType } from 'react' @@ -10,8 +9,8 @@ import { Icon, IconWithText } from '../../util/styledIcon' import { StopData } from '../../util/types' import InvisibleA11yLabel from '../../util/invisible-a11y-label' import Link from '../../util/link' -import OperatorLogo from '../../util/operator-logo' import Strong from '../../util/strong-text' +import TransitOperatorLogos from '../../util/transit-operator-icons' import { CardBody, CardHeader, CardTitle } from './styled' import DistanceDisplay from './distance-display' @@ -28,41 +27,6 @@ type Props = { transitOperators?: TransitOperator[] } -const Operator = ({ operator }: { operator?: TransitOperator }) => { - const intl = useIntl() - if (!operator) { - return null - } else { - const operatorLogoAriaLabel = intl.formatMessage( - { - id: 'components.StopViewer.operatorLogoAriaLabel' - }, - { - operatorName: operator.name - } - ) - return operator.logo ? ( - // Span with agency classname allows optional contrast/customization in user - // config for logos with poor contrast. Class name is hyphenated agency name - // e.g. "sound-transit" - - - - ) : ( - // If operator exists but logo is missing, - // we still need to announce the operator name to screen readers. - <> - - {operatorLogoAriaLabel} - - ) - } -} - const StopCardHeader = ({ actionIcon, actionParams, @@ -75,12 +39,7 @@ const StopCardHeader = ({ transitOperators }: Props): JSX.Element => { const intl = useIntl() - const agencies = - stopData.stoptimesForPatterns?.reduce>((prev, cur) => { - // @ts-expect-error The agency type is not yet compatible with OTP2 - const agencyGtfsId = cur.pattern.route.agency?.gtfsId - return agencyGtfsId ? prev.add(agencyGtfsId) : prev - }, new Set()) || new Set() + const zoomButtonText = onZoomClick ? intl.formatMessage({ id: 'components.StopViewer.zoomToStop' @@ -92,16 +51,10 @@ const StopCardHeader = ({ {/* @ts-expect-error The 'as' prop in styled-components is not listed for TypeScript. */} - {transitOperators - ?.filter((to) => Array.from(agencies).includes(to.agencyId)) - // Second pass to remove duplicates based on name - .filter( - (to, index, arr) => - index === arr.findIndex((t) => t?.name === to?.name) - ) - .map((to) => ( - - ))} + {stopData.name} diff --git a/lib/components/viewers/nearby/styled.tsx b/lib/components/viewers/nearby/styled.tsx index 1ffd1dc76..d088ebbfe 100644 --- a/lib/components/viewers/nearby/styled.tsx +++ b/lib/components/viewers/nearby/styled.tsx @@ -48,7 +48,6 @@ export const CardTitle = styled.p` display: flex; font-size: 22px; font-weight: 600; - gap: 0.5ch; grid-column: 1; margin: 0; /* Prevent svg and images to be taller than the text. */ diff --git a/lib/util/itinerary.tsx b/lib/util/itinerary.tsx index 6cebee5b3..a8f2d1a2b 100644 --- a/lib/util/itinerary.tsx +++ b/lib/util/itinerary.tsx @@ -1,4 +1,5 @@ import { differenceInMinutes } from 'date-fns' +import { isTransitLeg } from '@opentripplanner/core-utils/lib/itinerary' import { Itinerary, Leg, Place } from '@opentripplanner/types' import { toDate, utcToZonedTime } from 'date-fns-tz' import coreUtils from '@opentripplanner/core-utils' @@ -81,7 +82,7 @@ export function getMinutesUntilItineraryStart(itinerary: Itinerary): number { * Gets the first transit leg of the given itinerary, or null if none found. */ function getFirstTransitLeg(itinerary: Itinerary) { - return itinerary?.legs?.find((leg) => leg.transitLeg) + return itinerary?.legs?.find(isTransitLeg) } /** @@ -373,7 +374,7 @@ export function getTotalFare( ) { hasBikeshare = true } - if (coreUtils.itinerary.isTransit(leg.mode) && transitFare == null) { + if (isTransitLeg(leg) && transitFare == null) { transitFareNotProvided = true } }) diff --git a/lib/util/viewer.js b/lib/util/viewer.js index faa994560..d407b356c 100644 --- a/lib/util/viewer.js +++ b/lib/util/viewer.js @@ -4,6 +4,7 @@ import { getMostReadableTextColor } from '@opentripplanner/core-utils/lib/route' import tinycolor from 'tinycolor2' import { DARK_TEXT_GREY } from '../components/util/colors' +import { isTransitLeg } from '@opentripplanner/core-utils/lib/itinerary' import { checkForRouteModeOverride } from './config' import { getOperatorAndRoute } from './state' @@ -265,7 +266,7 @@ export function getTripStatus( * has realtime info */ export function firstTransitLegIsRealtime(itinerary) { - const firstTransitLeg = itinerary.legs.find((leg) => !!leg.transitLeg) + const firstTransitLeg = itinerary.legs.find((leg) => !!isTransitLeg(leg)) return firstTransitLeg?.realTime } diff --git a/package.json b/package.json index 34e1e7c8f..7b69da5c0 100644 --- a/package.json +++ b/package.json @@ -50,11 +50,11 @@ "@opentripplanner/geocoder": "^3.0.2", "@opentripplanner/humanize-distance": "^1.2.0", "@opentripplanner/icons": "3.0.0", - "@opentripplanner/itinerary-body": "6.0.0", + "@opentripplanner/itinerary-body": "6.0.1", "@opentripplanner/location-field": "3.0.0", "@opentripplanner/location-icon": "^1.4.1", - "@opentripplanner/map-popup": "5.0.0", - "@opentripplanner/otp2-tile-overlay": "2.0.0", + "@opentripplanner/map-popup": "5.1.0", + "@opentripplanner/otp2-tile-overlay": "2.1.0", "@opentripplanner/park-and-ride-overlay": "3.0.0", "@opentripplanner/printable-itinerary": "3.0.0", "@opentripplanner/route-viewer-overlay": "3.0.0", diff --git a/yarn.lock b/yarn.lock index 599332b3e..1a65ef7a9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2383,7 +2383,7 @@ dependencies: "@octokit/openapi-types" "^10.0.0" -"@opentripplanner/base-map@4.0.0": +"@opentripplanner/base-map@4.0.0", "@opentripplanner/base-map@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@opentripplanner/base-map/-/base-map-4.0.0.tgz#56ffa1d833673282cc3a0b7a17f388fc5dbd31e3" integrity sha512-pWTKXxnzUQk43woPMc40uYfGIcGqHV8GoCvRwrIu2pqNw7QAV4rxjZfca0pm5hnbbJ+G83sRzYboILEbEUwMcw== @@ -2403,7 +2403,7 @@ maplibre-gl "^2.1.9" react-map-gl "^7.0.15" -"@opentripplanner/building-blocks@2.0.0": +"@opentripplanner/building-blocks@2.0.0", "@opentripplanner/building-blocks@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@opentripplanner/building-blocks/-/building-blocks-2.0.0.tgz#8282c01dff7db5c7e809f6ea91cb52df559a2f9d" integrity sha512-N07rDaZL8fp552eI9/0j1udKjc0uOpvO0Wv1P19Ge0a4roques463MJgWJ026fbopRCi3uwbc/gYTlh4/ske9A== @@ -2413,7 +2413,7 @@ resolved "https://registry.yarnpkg.com/@opentripplanner/building-blocks/-/building-blocks-1.2.3.tgz#404e8f9038867d66d55f51adf8855b1326c51ed5" integrity sha512-I0AxiZrTZu+e7+av4u0tHW2ijqpxH0AkLHrhf75BHf1Ep2FOGxaul/v+8UT18mNYiM5eHNstOX3XiXaDjtCUaw== -"@opentripplanner/core-utils@12.0.0": +"@opentripplanner/core-utils@12.0.0", "@opentripplanner/core-utils@^12.0.0": version "12.0.0" resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-12.0.0.tgz#cc40af92620b207f4dce817d08f99def0cdaea7a" integrity sha512-udLF8XU+k7gxZ+yyyw7ASz6/4D540zYIv8a9GbUL61TF8HmgGhcMk3XOgBnm5jdOukuaNNpOFE4J3oJc5QsSBQ== @@ -2461,7 +2461,7 @@ "@styled-icons/fa-solid" "^10.34.0" flat "^5.0.2" -"@opentripplanner/from-to-location-picker@3.0.0": +"@opentripplanner/from-to-location-picker@3.0.0", "@opentripplanner/from-to-location-picker@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@opentripplanner/from-to-location-picker/-/from-to-location-picker-3.0.0.tgz#048a596c2f854825e0058e03dac67dcad7eb5864" integrity sha512-jRXaY9jKg+PXUL7Z2SkHRyO88xG1t7iG3U449LPiCm/6flxsY+Wlxg+nyMsAP5gQMjOU0wsGLdH83lGgrpSF4A== @@ -2493,7 +2493,7 @@ resolved "https://registry.yarnpkg.com/@opentripplanner/humanize-distance/-/humanize-distance-1.2.0.tgz#71cf5d5d1b756adef15300edbba0995ccd4b35ee" integrity sha512-x0QRXMDhypFeazZ6r6vzrdU8vhiV56nZ/WX6zUbxpgp6T9Oclw0gwR2Zdw6DZiiFpSYVNeVNxVzZwsu6NRGjcA== -"@opentripplanner/icons@3.0.0": +"@opentripplanner/icons@3.0.0", "@opentripplanner/icons@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@opentripplanner/icons/-/icons-3.0.0.tgz#f7293fd4dd2625eace3a4c82ecd573d6000d85d3" integrity sha512-naSCdCsPwSyEiP7Vf6oN6dpgwpFIkeQFXfTJG7lp1Dg9emLTAYzRx/f+45e9Bh0zP0aA4DsN4VgHBQllyu82qQ== @@ -2509,14 +2509,14 @@ "@opentripplanner/core-utils" "^11.4.4" prop-types "^15.7.2" -"@opentripplanner/itinerary-body@6.0.0": - version "6.0.0" - resolved "https://registry.yarnpkg.com/@opentripplanner/itinerary-body/-/itinerary-body-6.0.0.tgz#e261bcccd0d7a786f7f17be987a52ba1dc940229" - integrity sha512-j79byCefyEZuomvDlvBZJVZJ92+X6U4ivth3M62RKGmw1x8qW4nsbEKnzeQxXzGJcy3M+91eeIpcJnj98KHlRw== +"@opentripplanner/itinerary-body@6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@opentripplanner/itinerary-body/-/itinerary-body-6.0.1.tgz#74139536b34083af5b324fb94e69be267ea6bbeb" + integrity sha512-6Z+ZEW28MwtteOwZZUjkPkTnYQ0Aq1lMpfKMZW7F+OD6hfKhFBUx4NLMExTffXHswXQ3faYaHScOHxpalX73UQ== dependencies: - "@opentripplanner/core-utils" "^11.4.4" + "@opentripplanner/core-utils" "^12.0.0" "@opentripplanner/humanize-distance" "^1.2.0" - "@opentripplanner/icons" "^2.0.12" + "@opentripplanner/icons" "^3.0.0" "@opentripplanner/location-icon" "^1.4.1" "@styled-icons/fa-solid" "^10.34.0" "@styled-icons/foundation" "^10.34.0" @@ -2566,15 +2566,15 @@ "@styled-icons/fa-regular" "^10.34.0" "@styled-icons/fa-solid" "^10.34.0" -"@opentripplanner/map-popup@5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@opentripplanner/map-popup/-/map-popup-5.0.0.tgz#cf360845704ed54222c8bf19581ed1253d3dcf14" - integrity sha512-cuIzZm/cZbjY2tAVLSDpBK63efR+YsEsXVPBx4VAHlGhJoY1yooipFlq+3/51VSsFOJPp6gcsKaizfdICDJlYA== +"@opentripplanner/map-popup@5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@opentripplanner/map-popup/-/map-popup-5.1.0.tgz#cf6374bf7b69af69c026ec414a84719078c56e9e" + integrity sha512-EShoMyFZa7Zb2ZZrJhEsJfuCAvs2jfQe5QstU+AEk5Jm1zc8LzU6PsXmizQ/RMVi6zIYLhlBoZ3u458tTA3VQA== dependencies: - "@opentripplanner/base-map" "^3.2.2" - "@opentripplanner/building-blocks" "^1.2.2" - "@opentripplanner/core-utils" "^11.4.4" - "@opentripplanner/from-to-location-picker" "^2.1.14" + "@opentripplanner/base-map" "^4.0.0" + "@opentripplanner/building-blocks" "^2.0.0" + "@opentripplanner/core-utils" "^12.0.0" + "@opentripplanner/from-to-location-picker" "^3.0.0" flat "^5.0.2" "@opentripplanner/map-popup@^4.0.0": @@ -2588,12 +2588,23 @@ "@opentripplanner/from-to-location-picker" "^2.1.14" flat "^5.0.2" -"@opentripplanner/otp2-tile-overlay@2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@opentripplanner/otp2-tile-overlay/-/otp2-tile-overlay-2.0.0.tgz#6af1a9113a8baaebb226a5e747e8e523f6da249b" - integrity sha512-Yc0VsfxS6xIw4+1i9lpvQyCXobkTubZWYYu+6bDWkk77D4J4WaSoWE/qWT39vc2/h1ZY4afUZL59d7kc8V0PLg== +"@opentripplanner/map-popup@^v3.2.0-alpha.1": + version "3.2.0-alpha.1" + resolved "https://registry.yarnpkg.com/@opentripplanner/map-popup/-/map-popup-3.2.0-alpha.1.tgz#dcad38c103500f7c5ad3c632398204849ed5885e" + integrity sha512-Z0RsyC7wkYU/aOLYQFsJI5tBhzooEE/sQZROX2WODkDWAv4Qfj95ppS8pvNkpoZ0N4fioFcj5aM2VGXVMSy0EA== dependencies: - "@opentripplanner/map-popup" "^4.0.0" + "@opentripplanner/base-map" "^3.2.2" + "@opentripplanner/building-blocks" "^1.2.2" + "@opentripplanner/core-utils" "^11.4.4" + "@opentripplanner/from-to-location-picker" "^2.1.14" + flat "^5.0.2" + +"@opentripplanner/otp2-tile-overlay@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@opentripplanner/otp2-tile-overlay/-/otp2-tile-overlay-2.1.0.tgz#745cb6c80dbde767a0b5ac7b0b866193a18ec984" + integrity sha512-gkKS5OT/Ayc/987vcdSkFcGSH/YyvEBN9bZFWBHKRN5nbRykBRZu2GNFVfN5ITLoshrFw+YasIk9omfTKVJtRg== + dependencies: + "@opentripplanner/map-popup" "^v3.2.0-alpha.1" "@opentripplanner/park-and-ride-overlay@3.0.0": version "3.0.0"