From b7cfc5a5b43a6f1224a8aafc26bed58425d9e816 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 8 Jun 2023 23:45:45 -0700 Subject: [PATCH 01/40] feat(core-utils): adds function for converting GQL response to REST --- packages/core-utils/src/itinerary.ts | 45 ++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/core-utils/src/itinerary.ts b/packages/core-utils/src/itinerary.ts index b8f6f4742..b68ccc424 100644 --- a/packages/core-utils/src/itinerary.ts +++ b/packages/core-utils/src/itinerary.ts @@ -629,3 +629,48 @@ export function getItineraryCost( { cents: 0, currency: null } ); } + +const pickupDropoffTypeToOtp1 = otp2Type => { + switch (otp2Type) { + case "COORDINATE_WITH_DRIVER": + return "coordinateWithDriver"; + case "CALL_AGENCY": + return "mustPhone"; + case "SCHEDULED": + return "scheduled"; + case "NONE": + return "none"; + default: + return null; + } +}; + +export const convertGraphQLResponseToLegacy = (leg: any): any => ({ + ...leg, + agencyBrandingUrl: leg.agency?.url, + agencyName: leg.agency?.name, + agencyUrl: leg.agency?.url, + alightRule: pickupDropoffTypeToOtp1(leg.dropoffType), + boardRule: pickupDropoffTypeToOtp1(leg.pickupType), + dropOffBookingInfo: { + latestBookingTime: leg.dropOffBookingInfo + }, + from: { + ...leg.from, + stopCode: leg.from.stop?.code, + stopId: leg.from.stop?.gtfsId + }, + route: leg.route?.shortName, + routeColor: leg.route?.color, + routeId: leg.route?.id, + routeLongName: leg.route?.longName, + routeShortName: leg.route?.shortName, + routeTextColor: leg.route?.textColor, + to: { + ...leg.to, + stopCode: leg.to.stop?.code, + stopId: leg.to.stop?.gtfsId + }, + tripHeadsign: leg.trip?.tripHeadsign, + tripId: leg.trip?.gtfsId +}); From bb3b33439d063d348e048e233669f21d4c214065 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 8 Jun 2023 23:47:53 -0700 Subject: [PATCH 02/40] fix(core-utils): convert fare functions to consume GQL data BREAKING CHANGE: Removes old getTransitFare() function --- packages/core-utils/src/itinerary.ts | 65 +++++++--------------------- 1 file changed, 16 insertions(+), 49 deletions(-) diff --git a/packages/core-utils/src/itinerary.ts b/packages/core-utils/src/itinerary.ts index b68ccc424..744053dbe 100644 --- a/packages/core-utils/src/itinerary.ts +++ b/packages/core-utils/src/itinerary.ts @@ -4,7 +4,6 @@ import { Config, ElevationProfile, FlexBookingInfo, - Itinerary, ItineraryOnlyLegsRequired, LatLngArray, Leg, @@ -460,27 +459,6 @@ export function calculateTncFares( ); } -/** - * For a given fare component (either total fare or component parts), returns - * an object with the fare value (in cents). - */ -export function getTransitFare( - fareComponent: Money -): { - currencyCode: string; - transitFare: number; -} { - return fareComponent - ? { - currencyCode: fareComponent.currency.currencyCode, - transitFare: fareComponent.cents - } - : { - currencyCode: "USD", - transitFare: 0 - }; -} - /** * Sources: * - https://www.itf-oecd.org/sites/default/files/docs/environmental-performance-new-mobility.pdf @@ -563,20 +541,6 @@ export function getDisplayedStopId(placeOrStop: Place | Stop): string { return stopCode || stopId?.split(":")[1] || stopId; } -/** - * Adds the fare product info to each leg in an itinerary, from the itinerary's fare property - * @param itinerary Itinerary with legProducts in fare object - * @returns Itinerary with legs that have fare products attached to them - */ -export function getLegsWithFares(itinerary: Itinerary): Leg[] { - return itinerary.legs.map((leg, i) => ({ - ...leg, - fareProducts: itinerary.fare?.legProducts - ?.filter(lp => lp?.legIndices?.includes(i)) - .flatMap(lp => lp.products) - })); -} - /** * Extracts useful data from the fare products on a leg, such as the leg cost and transfer info. * @param leg Leg with fare products (must have used getLegsWithFares) @@ -586,23 +550,26 @@ export function getLegsWithFares(itinerary: Itinerary): Leg[] { */ export function getLegCost( leg: Leg, - category: string, - container: string -): { price?: Money; transferAmount?: number } { + mediumId: string, + riderCategoryId: string +): { price: Money; transferAmount?: Money | undefined } { if (!leg.fareProducts) return { price: undefined }; - - const relevantFareProducts = leg.fareProducts.filter( - fp => fp.category.name === category && fp.container.name === container - ); - const totalCost = relevantFareProducts.find(fp => fp.name === "rideCost") - ?.amount; + const relevantFareProducts = leg.fareProducts.filter(({ product }) => { + return ( + product.riderCategory.id === riderCategoryId && + product.medium.id === mediumId + ); + }); + const totalCost = relevantFareProducts.find( + fp => fp.product.name === "rideCost" + )?.product?.price; const transferFareProduct = relevantFareProducts.find( - fp => fp.name === "transfer" + fp => fp.product.name === "transfer" ); return { price: totalCost, - transferAmount: transferFareProduct?.amount?.cents + transferAmount: transferFareProduct?.product.price }; } @@ -623,10 +590,10 @@ export function getItineraryCost( .map(leg => getLegCost(leg, category, container).price) .reduce( (prev, cur) => ({ - cents: prev.cents + cur?.cents || 0, + amount: prev.amount + cur?.amount || 0, currency: prev.currency ?? cur?.currency }), - { cents: 0, currency: null } + { amount: 0, currency: null } ); } From c456013a1b8315304633d1d2eca295253ceff4f6 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 8 Jun 2023 23:53:21 -0700 Subject: [PATCH 03/40] feat(itinerary-body): removes REST style fare data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fare data is now stored on the legs themselves, so it’s not necessary to pass it around on its own --- .../src/ItineraryBody/index.tsx | 6 ----- .../src/ItineraryBody/place-row.tsx | 2 -- .../src/TransitLegBody/index.tsx | 25 +++---------------- .../src/stories/OtpRrItineraryBody.story.tsx | 7 ++---- .../src/stories/OtpUiItineraryBody.story.tsx | 4 +-- packages/itinerary-body/src/types.ts | 5 ---- 6 files changed, 7 insertions(+), 42 deletions(-) diff --git a/packages/itinerary-body/src/ItineraryBody/index.tsx b/packages/itinerary-body/src/ItineraryBody/index.tsx index 73f40333e..8052c3878 100755 --- a/packages/itinerary-body/src/ItineraryBody/index.tsx +++ b/packages/itinerary-body/src/ItineraryBody/index.tsx @@ -35,7 +35,6 @@ const ItineraryBody = ({ showElevationProfile, showLegIcon, showMapButtonColumn = true, - showRouteFares, showViewTripButton, TimeColumnContent, toRouteAbbreviation = defaultRouteAbbr, @@ -50,7 +49,6 @@ const ItineraryBody = ({ const rows = []; let followsTransit = false; let lastLeg; - const { fare } = itinerary; itinerary.legs.forEach((leg, i) => { function createPlaceRow(isDestination) { // Create a row containing this leg's start place and leg traversal details @@ -64,10 +62,6 @@ const ItineraryBody = ({ key={i + (isDestination ? 1 : 0)} config={config} diagramVisible={diagramVisible} - // Itinerary fare is only passed as prop if showRouteFares is enabled. - // The fare details will be processed in the TransitLeg component and - // shown for all legs. - fare={showRouteFares ? fare : null} followsTransit={followsTransit} frameLeg={frameLeg} isDestination={isDestination} diff --git a/packages/itinerary-body/src/ItineraryBody/place-row.tsx b/packages/itinerary-body/src/ItineraryBody/place-row.tsx index 6cee10637..5a2bf95a6 100755 --- a/packages/itinerary-body/src/ItineraryBody/place-row.tsx +++ b/packages/itinerary-body/src/ItineraryBody/place-row.tsx @@ -22,7 +22,6 @@ export default function PlaceRow({ alwaysCollapseAlerts, config, diagramVisible, - fare, followsTransit, frameLeg, isDestination, @@ -135,7 +134,6 @@ export default function PlaceRow({ AlertBodyIcon={AlertBodyIcon} AlertToggleIcon={AlertToggleIcon} alwaysCollapseAlerts={alwaysCollapseAlerts} - fare={fare} leg={leg} LegIcon={LegIcon} legIndex={legIndex} diff --git a/packages/itinerary-body/src/TransitLegBody/index.tsx b/packages/itinerary-body/src/TransitLegBody/index.tsx index 65785c783..77e86ecc3 100644 --- a/packages/itinerary-body/src/TransitLegBody/index.tsx +++ b/packages/itinerary-body/src/TransitLegBody/index.tsx @@ -1,6 +1,5 @@ import coreUtils from "@opentripplanner/core-utils"; import { - Fare, FlexBookingInfo, Leg, LegIconComponent, @@ -8,12 +7,7 @@ import { } from "@opentripplanner/types"; import React, { Component, FunctionComponent, ReactElement } from "react"; import AnimateHeight from "react-animate-height"; -import { - FormattedMessage, - FormattedNumber, - injectIntl, - IntlShape -} from "react-intl"; +import { FormattedMessage, injectIntl, IntlShape } from "react-intl"; import { Duration } from "../defaults"; import * as S from "../styled"; @@ -34,7 +28,6 @@ interface Props { AlertBodyIcon?: FunctionComponent; AlertToggleIcon?: FunctionComponent; alwaysCollapseAlerts: boolean; - fare?: Fare; intl: IntlShape; leg: Leg; LegIcon: LegIconComponent; @@ -108,16 +101,6 @@ class TransitLegBody extends Component { }; } - getFareForLeg = (leg: Leg, fare: Fare) => { - let fareForLeg; - fare?.details?.regular?.forEach(fareComponent => { - if (fareComponent.routes?.includes(leg.routeId)) { - fareForLeg = coreUtils.itinerary.getTransitFare(fareComponent.price); - } - }); - return fareForLeg; - }; - onToggleStopsClick = () => { const { stopsExpanded } = this.state; this.setState({ stopsExpanded: !stopsExpanded }); @@ -138,7 +121,6 @@ class TransitLegBody extends Component { AlertToggleIcon = S.DefaultAlertToggleIcon, AlertBodyIcon, alwaysCollapseAlerts, - fare, intl, leg, LegIcon, @@ -177,7 +159,6 @@ class TransitLegBody extends Component { const shouldOnlyShowAlertsExpanded = !(shouldCollapseDueToAlertCount || alwaysCollapseAlerts) || !leg.alerts; const expandAlerts = alertsExpanded || shouldOnlyShowAlertsExpanded; - const fareForLeg = this.getFareForLeg(leg, fare); return ( <> @@ -337,7 +318,7 @@ class TransitLegBody extends Component { > - {fareForLeg && ( + {/* {leg.fareProducts && ( { }} /> - )} + )} */} diff --git a/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx b/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx index 7f545819f..0954aaaa9 100644 --- a/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx +++ b/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx @@ -22,7 +22,7 @@ const bikeRentalTransitBikeRentalItinerary = require("../__mocks__/itineraries/b const bikeTransitBikeItinerary = require("../__mocks__/itineraries/bike-transit-bike.json"); const eScooterRentalItinerary = require("../__mocks__/itineraries/e-scooter-rental.json"); const eScooterRentalTransiteScooterRentalItinerary = require("../__mocks__/itineraries/e-scooter-transit-e-scooter.json"); -const fareComponentsItinerary = require("../__mocks__/itineraries/fare-components.json"); +const fareProductsItinerary = require("../__mocks__/itineraries/leg-fare-products.json"); const parkAndRideItinerary = require("../__mocks__/itineraries/park-and-ride.json"); const tncTransitTncItinerary = require("../__mocks__/itineraries/tnc-transit-tnc.json"); const walkInterlinedTransitItinerary = require("../__mocks__/itineraries/walk-interlined-transit-walk.json"); @@ -148,10 +148,7 @@ export const OTP2FlexItinerary = (): ReactElement => ( ); export const IndividualLegFareComponents = (): ReactElement => ( - + ); export const CustomTimeColumn = (): ReactElement => ( diff --git a/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx b/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx index b7350d5b1..0f9882d44 100644 --- a/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx +++ b/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx @@ -24,7 +24,7 @@ const walkInterlinedTransitItinerary = require("../__mocks__/itineraries/walk-in const walkOnlyItinerary = require("../__mocks__/itineraries/walk-only.json"); const walkTransitWalkItinerary = require("../__mocks__/itineraries/walk-transit-walk.json"); const walkTransitWalkTransitWalkItinerary = require("../__mocks__/itineraries/walk-transit-walk-transit-walk.json"); -const fareComponentsItinerary = require("../__mocks__/itineraries/fare-components.json"); +const fareProductsItinerary = require("../__mocks__/itineraries/leg-fare-products.json"); const walkTransitWalkTransitWalkA11yItinerary = require("../__mocks__/itineraries/walk-transit-walk-transit-walk-with-accessibility-scores.json"); const otp2ScooterItinerary = require("../__mocks__/itineraries/otp2-scooter.json"); const flexItinerary = require("../__mocks__/itineraries/flex-itinerary.json"); @@ -148,7 +148,7 @@ export const OTP2FlexItinerary = (): ReactElement => ( export const IndividualLegFareComponents = (): ReactElement => ( ); diff --git a/packages/itinerary-body/src/types.ts b/packages/itinerary-body/src/types.ts index 681b31a0d..cc76a5213 100644 --- a/packages/itinerary-body/src/types.ts +++ b/packages/itinerary-body/src/types.ts @@ -2,7 +2,6 @@ import { FunctionComponent } from "react"; import { Config, - Fare, GradationMap, Itinerary, Leg, @@ -184,8 +183,6 @@ interface ItineraryBodySharedProps { showLegIcon?: boolean; /** If true, will show the right column with the map button */ showMapButtonColumn?: boolean; - /** If true, will show fare information in transit leg bodies */ - showRouteFares?: boolean; /** If true, shows the view trip button in transit leg bodies */ showViewTripButton?: boolean; /** @@ -216,8 +213,6 @@ interface ItineraryBodySharedProps { export interface PlaceRowProps extends ItineraryBodySharedProps, LegSharedProps { - /** The fare information to be displayed for the corresponding leg. */ - fare: Fare; /** Indicates whether this leg directly follows a transit leg */ followsTransit?: boolean; } From 96eae0803bf9856d9022aeead43111f63fac32b7 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 8 Jun 2023 23:55:25 -0700 Subject: [PATCH 04/40] test(itinerary-body): add new mock --- .../itineraries/leg-fare-products.json | 1283 +++++++++++++++++ 1 file changed, 1283 insertions(+) create mode 100644 packages/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json diff --git a/packages/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json b/packages/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json new file mode 100644 index 000000000..0387113e8 --- /dev/null +++ b/packages/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json @@ -0,0 +1,1283 @@ +{ + "duration": 6952, + "endTime": 1685146739000, + "startTime": 1685139787000, + "waitingTime": 184, + "walkTime": 2436, + "accessibilityScore": null, + "legs": [ + { + "fareProducts": [], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": false, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 825.81, + "duration": 641, + "endTime": 1685140428000, + "mode": "WALK", + "realTime": false, + "realtimeState": null, + "startTime": 1685139787000, + "transitLeg": false, + "accessibilityScore": null, + "trip": null, + "agency": null, + "legGeometry": { + "length": 16, + "points": "}zrbHnykiV@GHk@Dg@dC@j@BhDh@AlD?tCCzKGfV?T?NO?a@???" + }, + "intermediateStops": null, + "route": null, + "from": { + "lat": 47.7791977, + "lon": -122.2903181, + "name": "47.7792, -122.29032", + "vertexType": "NORMAL", + "rentalVehicle": null, + "stop": null + }, + "to": { + "lat": 47.7776833, + "lon": -122.297684, + "name": "48th Ave W & 244th St SW", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206ODI0MDU", + "code": "82405", + "gtfsId": "kcm:82405", + "alerts": [] + } + }, + "steps": [ + { + "distance": 36.61, + "lat": 47.7791959, + "lon": -122.290319, + "relativeDirection": "DEPART", + "absoluteDirection": "EAST", + "stayOn": false, + "streetName": "242nd Street Southwest", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 194.04, + "lat": 47.7791005, + "lon": -122.2898502, + "relativeDirection": "RIGHT", + "absoluteDirection": "SOUTH", + "stayOn": false, + "streetName": "Cedar Way", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 567.32, + "lat": 47.7773669, + "lon": -122.2900921, + "relativeDirection": "RIGHT", + "absoluteDirection": "WEST", + "stayOn": false, + "streetName": "Northeast 205th Street - 244th Street Southwest", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 27.83, + "lat": 47.7774331, + "lon": -122.2976837, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTH", + "stayOn": false, + "streetName": "path", + "area": false, + "alerts": [], + "elevationProfile": [] + } + ] + }, + { + "fareProducts": [ + { + "id": "3ff3d12d-6747-3b47-842a-92c7bf167015", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 2.75 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "77a8ba05-8081-301f-9fe4-777dcd10ae02", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 2.75 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "0740913d-0e0a-34ab-9518-014f2025b1a8", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "16ac6750-91b2-347c-b991-e63f8c483de9", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "cf501333-167f-31b1-b99a-0e9b17d4a16c", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1.5 + }, + "riderCategory": { + "id": "orca:special", + "name": "special" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "1b2d9477-8ce5-3eec-a63d-7d2534fa3bef", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "105e04d3-a575-3f65-96c1-e33d5199f339", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + } + ], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": null, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 12180.55, + "duration": 2112, + "endTime": 1685142540000, + "mode": "BUS", + "realTime": false, + "realtimeState": null, + "startTime": 1685140428000, + "transitLeg": true, + "accessibilityScore": null, + "trip": { + "id": "VHJpcDprY206NTQxNDgwODUz", + "gtfsId": "kcm:541480853", + "tripHeadsign": "Northgate Station Ridgecrest" + }, + "agency": { + "name": "Metro Transit", + "id": "QWdlbmN5OmtjbTox", + "timezone": "America/Los_Angeles", + "url": "https://kingcounty.gov/en/dept/metro", + "alerts": [] + }, + "legGeometry": { + "length": 262, + "points": "oqrbH~fmiVp@??fEC|DCjE?fN?h@??AfEAvCAxA@n@AdCAhD?tAAtCA~@???hDAfF?bBAn@???ZA`A?`@Av@Ax@AhB?R@NBNFLLPVXN@T?R?l@A??fCGnCEzBE??hBErAApIM??nGKX?R?L?N@XFLBFBJ@LFLHPHPJTNXV^ZTPRRrAl@F@??d@Jb@DT?TCxCIVCl@Ab@CTEHCTGNGTKb@Sp@c@TINIPC??FCPEVAVAV?b@?V@^A\\IZEZKf@UrAq@|@a@d@W`@_@f@_@NM??x@m@b@Cz@M\\C^?z@Px@XZPZXn@r@r@f@ZLb@Rb@FZFb@?z@???tA?rF@|I?AjD??CbJA|FA|C??AtBEpOEtOxCC??Z?|BAzEGdECf@???dIEhJG`DE??jAAfFEzCE??J?zA?xACdDE??N?pDCpDE`BCp@A??pFG~CC^A^???fBAbEEvCE\\?X???bCA|@F`E?f@?@mG???C@yGFwO@qG@gF???]DyOtAC??tGAt@???vHEn@???~HE|HA??n@?|G?tC?xA?~D@Z???lI?p@???rHBB?pAC??vGIp@???xHI|@C??|CCt@?ZBRJRNRR`@h@LTpFhI??~@xAbD~E`A|A|AzB\\Z^Vf@Rx@R~CArAC?fB??CvLA|OnA???hDEbFGx@???|DErDAvDA?jB??AfCA`HA~G?pB?P|A?lA?" + }, + "intermediateStops": [ + { + "lat": 47.7775421, + "lon": -122.303215, + "name": "NE 205th St & 52nd Ave W", + "stopCode": "82410", + "stopId": "U3RvcDprY206ODI0MTA", + "locationType": "STOP" + }, + { + "lat": 47.7775955, + "lon": -122.308685, + "name": "NE 205th St & 56th Ave W", + "stopCode": "82430", + "stopId": "U3RvcDprY206ODI0MzA", + "locationType": "STOP" + }, + { + "lat": 47.7776146, + "lon": -122.311432, + "name": "NE 205th St & 58th Pl W", + "stopCode": "82440", + "stopId": "U3RvcDprY206ODI0NDA", + "locationType": "STOP" + }, + { + "lat": 47.7768135, + "lon": -122.31382, + "name": "15th Ave NE & Ballinger Way NE", + "stopCode": "77400", + "stopId": "U3RvcDprY206Nzc0MDA", + "locationType": "STOP" + }, + { + "lat": 47.7747955, + "lon": -122.313721, + "name": "15th Ave NE & Forest Park Dr NE", + "stopCode": "77410", + "stopId": "U3RvcDprY206Nzc0MTA", + "locationType": "STOP" + }, + { + "lat": 47.7721519, + "lon": -122.313614, + "name": "15th Ave NE & NE 200th Ct", + "stopCode": "77418", + "stopId": "U3RvcDprY206Nzc0MTg", + "locationType": "STOP" + }, + { + "lat": 47.768734, + "lon": -122.314636, + "name": "15th Ave NE & NE 192nd St", + "stopCode": "77940", + "stopId": "U3RvcDprY206Nzc5NDA", + "locationType": "STOP" + }, + { + "lat": 47.7656479, + "lon": -122.313995, + "name": "15th Ave NE & NE Perkins Way", + "stopCode": "77440", + "stopId": "U3RvcDprY206Nzc0NDA", + "locationType": "STOP" + }, + { + "lat": 47.7626801, + "lon": -122.312752, + "name": "15th Ave NE & 24th Ave NE", + "stopCode": "77450", + "stopId": "U3RvcDprY206Nzc0NTA", + "locationType": "STOP" + }, + { + "lat": 47.7591515, + "lon": -122.31356, + "name": "15th Ave NE & NE 180th St", + "stopCode": "77460", + "stopId": "U3RvcDprY206Nzc0NjA", + "locationType": "STOP" + }, + { + "lat": 47.7558212, + "lon": -122.314339, + "name": "NE 175th St & 15th Ave NE", + "stopCode": "77738", + "stopId": "U3RvcDprY206Nzc3Mzg", + "locationType": "STOP" + }, + { + "lat": 47.7558632, + "lon": -122.318176, + "name": "NE 175th St & 10th Ave NE", + "stopCode": "77737", + "stopId": "U3RvcDprY206Nzc3Mzc", + "locationType": "STOP" + }, + { + "lat": 47.7550964, + "lon": -122.324158, + "name": "5th Ave NE & NE 174th St", + "stopCode": "81246", + "stopId": "U3RvcDprY206ODEyNDY", + "locationType": "STOP" + }, + { + "lat": 47.752037, + "lon": -122.324104, + "name": "5th Ave NE & NE 170th St", + "stopCode": "81248", + "stopId": "U3RvcDprY206ODEyNDg", + "locationType": "STOP" + }, + { + "lat": 47.7477875, + "lon": -122.324013, + "name": "5th Ave NE & NE 163rd St", + "stopCode": "77560", + "stopId": "U3RvcDprY206Nzc1NjA", + "locationType": "STOP" + }, + { + "lat": 47.7454681, + "lon": -122.323944, + "name": "5th Ave NE & NE 161st St", + "stopCode": "77570", + "stopId": "U3RvcDprY206Nzc1NzA", + "locationType": "STOP" + }, + { + "lat": 47.7436676, + "lon": -122.323883, + "name": "5th Ave NE & NE 158th St", + "stopCode": "77580", + "stopId": "U3RvcDprY206Nzc1ODA", + "locationType": "STOP" + }, + { + "lat": 47.741066, + "lon": -122.323792, + "name": "5th Ave NE & NE 155th St", + "stopCode": "81252", + "stopId": "U3RvcDprY206ODEyNTI", + "locationType": "STOP" + }, + { + "lat": 47.7387314, + "lon": -122.323723, + "name": "5th Ave NE & NE 152nd St", + "stopCode": "81254", + "stopId": "U3RvcDprY206ODEyNTQ", + "locationType": "STOP" + }, + { + "lat": 47.7361908, + "lon": -122.323654, + "name": "5th Ave NE & NE 148th St", + "stopCode": "81256", + "stopId": "U3RvcDprY206ODEyNTY", + "locationType": "STOP" + }, + { + "lat": 47.7339783, + "lon": -122.322235, + "name": "NE 145th St & 6th Ave NE", + "stopCode": "82200", + "stopId": "U3RvcDprY206ODIyMDA", + "locationType": "STOP" + }, + { + "lat": 47.7339096, + "lon": -122.315598, + "name": "NE 145th St & 12th Ave NE", + "stopCode": "82220", + "stopId": "U3RvcDprY206ODIyMjA", + "locationType": "STOP" + }, + { + "lat": 47.7335167, + "lon": -122.312851, + "name": "15th Ave NE & NE 145th St", + "stopCode": "38830", + "stopId": "U3RvcDprY206Mzg4MzA", + "locationType": "STOP" + }, + { + "lat": 47.7318573, + "lon": -122.31282, + "name": "15th Ave NE & NE 143rd St", + "stopCode": "38840", + "stopId": "U3RvcDprY206Mzg4NDA", + "locationType": "STOP" + }, + { + "lat": 47.7300568, + "lon": -122.312798, + "name": "15th Ave NE & NE 140th St", + "stopCode": "38850", + "stopId": "U3RvcDprY206Mzg4NTA", + "locationType": "STOP" + }, + { + "lat": 47.7268677, + "lon": -122.312752, + "name": "15th Ave NE & NE 135th St", + "stopCode": "38870", + "stopId": "U3RvcDprY206Mzg4NzA", + "locationType": "STOP" + }, + { + "lat": 47.7228928, + "lon": -122.312767, + "name": "15th Ave NE & NE 130th St", + "stopCode": "38890", + "stopId": "U3RvcDprY206Mzg4OTA", + "locationType": "STOP" + }, + { + "lat": 47.7209663, + "lon": -122.312782, + "name": "15th Ave NE & NE 127th St", + "stopCode": "38900", + "stopId": "U3RvcDprY206Mzg5MDA", + "locationType": "STOP" + }, + { + "lat": 47.7190018, + "lon": -122.312767, + "name": "15th Ave NE & NE 125th St", + "stopCode": "38910", + "stopId": "U3RvcDprY206Mzg5MTA", + "locationType": "STOP" + }, + { + "lat": 47.71735, + "lon": -122.312714, + "name": "15th Ave NE & NE 123rd St", + "stopCode": "38920", + "stopId": "U3RvcDprY206Mzg5MjA", + "locationType": "STOP" + }, + { + "lat": 47.7154694, + "lon": -122.312645, + "name": "15th Ave NE & NE 120th St", + "stopCode": "38930", + "stopId": "U3RvcDprY206Mzg5MzA", + "locationType": "STOP" + }, + { + "lat": 47.7125664, + "lon": -122.314827, + "name": "Pinehurst Way NE & NE 115th St", + "stopCode": "38962", + "stopId": "U3RvcDprY206Mzg5NjI", + "locationType": "STOP" + }, + { + "lat": 47.7086334, + "lon": -122.318367, + "name": "NE Northgate Way & Roosevelt Way NE", + "stopCode": "82198", + "stopId": "U3RvcDprY206ODIxOTg", + "locationType": "STOP" + }, + { + "lat": 47.7081947, + "lon": -122.323364, + "name": "5th Ave NE & NE Northgate Way", + "stopCode": "23230", + "stopId": "U3RvcDprY206MjMyMzA", + "locationType": "STOP" + }, + { + "lat": 47.7059097, + "lon": -122.323296, + "name": "5th Ave NE & Northgate Mall", + "stopCode": "23250", + "stopId": "U3RvcDprY206MjMyNTA", + "locationType": "STOP" + }, + { + "lat": 47.7032166, + "lon": -122.323692, + "name": "NE 103rd St & 5th Ave NE", + "stopCode": "35290", + "stopId": "U3RvcDprY206MzUyOTA", + "locationType": "STOP" + } + ], + "route": { + "shortName": "347", + "longName": null, + "color": null, + "textColor": null, + "id": "Um91dGU6a2NtOjEwMDIwNA", + "type": 3, + "alerts": [] + }, + "from": { + "lat": 47.7776833, + "lon": -122.297684, + "name": "48th Ave W & 244th St SW", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206ODI0MDU", + "code": "82405", + "gtfsId": "kcm:82405", + "alerts": [] + } + }, + "to": { + "lat": 47.7023087, + "lon": -122.328026, + "name": "Northgate Station - Bay 4", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206MzUzMTg", + "code": "35318", + "gtfsId": "kcm:35318", + "alerts": [] + } + }, + "steps": [] + }, + { + "fareProducts": [], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": false, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 60.87, + "duration": 56, + "endTime": 1685142596000, + "mode": "WALK", + "realTime": false, + "realtimeState": null, + "startTime": 1685142540000, + "transitLeg": false, + "accessibilityScore": null, + "trip": null, + "agency": null, + "legGeometry": { + "length": 9, + "points": "kzcbHdesiV?Ce@?Q??L?V?RO??B" + }, + "intermediateStops": null, + "route": null, + "from": { + "lat": 47.7023087, + "lon": -122.328026, + "name": "Northgate Station - Bay 4", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206MzUzMTg", + "code": "35318", + "gtfsId": "kcm:35318", + "alerts": [] + } + }, + "to": { + "lat": 47.702662, + "lon": -122.32832, + "name": "Northgate Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo5OTAwMDU", + "code": "N11-T1", + "gtfsId": "40:990005", + "alerts": [] + } + }, + "steps": [ + { + "distance": 60.87, + "lat": 47.7023088, + "lon": -122.3280018, + "relativeDirection": "DEPART", + "absoluteDirection": "NORTH", + "stayOn": false, + "streetName": "path", + "area": false, + "alerts": [], + "elevationProfile": [] + } + ] + }, + { + "fareProducts": [ + { + "id": "0f76bb4a-7491-34b9-95ce-5d6f4e6b4d53", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 3 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "ab8213b7-eddd-3d20-9b2d-a5ed8d8573a4", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0.25 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "75fef4dc-142b-3589-ac62-d484f5b41143", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 2.75 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "69bafcef-e2ee-3a6c-a355-0883f3d5561f", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "b0026496-8eea-31c8-8468-a67b00abc2b5", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "8e77f7c7-7eda-32a8-ad44-23372b079942", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:special", + "name": "special" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "e8e69341-c5f3-3833-9a0a-de3118460842", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1.5 + }, + "riderCategory": { + "id": "orca:special", + "name": "special" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "7ab667f5-3bb1-3973-b065-46ac5bffe3a4", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "b3ff8f6e-f55f-3098-bb23-2bc49441d81f", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "2fe47d57-d05f-3f51-9d4b-4d060a68abd9", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + } + ], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": null, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 23087.2, + "duration": 2220, + "endTime": 1685145000000, + "mode": "TRAM", + "realTime": false, + "realtimeState": null, + "startTime": 1685142780000, + "transitLeg": true, + "accessibilityScore": null, + "trip": { + "id": "VHJpcDo0MDpMTFJfMjAyMy0wMy0xOC0yMDIzLTA5LTA0X1dlZWtkYXlfMjA4Ng", + "gtfsId": "40:LLR_2023-03-18-2023-09-04_Weekday_2086", + "tripHeadsign": "Angle Lake" + }, + "agency": { + "name": "Sound Transit", + "id": "QWdlbmN5OjQwOjQw", + "timezone": "America/Los_Angeles", + "url": "https://www.soundtransit.org", + "alerts": [] + }, + "legGeometry": { + "length": 509, + "points": "s|cbHhgsiVJ?dA?pAApA@nAHnANnALnANnALnALpAFnABpACpAGnAKr@G^CnAKpAEnA?pA@pA?nA@pA@pA@nA@pA@pA?nACpAKlASlAWjA]fAc@fAi@`Ak@`Aq@z@u@z@w@v@{@r@{@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@}@v@{@x@w@~@s@bAk@fAe@hA_@nAWnAMnACpAApAAnA?V???x@ApACnAGnAKpAMnAMnAKnAMnAMnAMnAMpAKnAMnAMnAMnAKnAMnAMpAMnAKnAMnAMnAMnAMnAKpAMnAKnAIpAInAEpAGnACpAApAApA?nA?pA@pA@nABpA@h@???f@@nAAnAQfAc@~@q@v@{@j@cAd@gAZkARmANoAJqAJoAHoAJqAJoAJoALoALoARoATmAZkA^kA`@iAf@eAj@cAp@aAt@{@x@w@~@q@dAk@hAa@jAYnAOpAEnAApAApAAnAApAAbDAb@Cb@???H?p@Ar@?|FGx@?hA?rA@pADzAHtAHrALrARrAPzAV`BZxA^`Bd@rBn@|Aj@lBx@lBz@|Ax@fB`AhBlAbBlAfE`DrB~Avh@da@bHlFbDdCjEfDdK~HrB~A~@r@n@d@bAh@|@d@jAd@jA^tAVpAR~@HfADtA?n@A????vFC~A?x@?|@HbAPbAZbA`@x@b@dAz@v@r@~@jAr@dAp@rAd@fA`@jAd@bBZxAVbBRfBH~AFtA@|AAdBGpAIzAOdBWzASxAKx@Ix@?f@?n@@l@Dr@Jx@Hf@Jh@JZjAnDb@tAhBzFXvAhB|FnBlG??@?FTj@fABBRh@PVNRLHLDR@N?VGXMNInJoIlC_Cp@o@RQ????t@s@lCaC|GcGnCcClCaC\\[nBgBlBgB@???VUVURWVc@Xe@PYpBeDx@sAx@mAV_@TQ\\Sp@MzCA|FF@@??N@RFNFN@LB~BCF?D?fCAF?N?NCN?NALAHCJAJAHCNEPC^KxDeAxCy@NGJAJCJALAL?h@CrC???nHBrB?V?X@R@VBn@HVDP@T@z@?b@?z@?vp@B??@?zG?L?N?JCF?JAHEDABCF?@CDABCDCBCBEDCBEBCBGBEBC@EBGBEBG@E@E@GBE@G@E?CBM?IBI@K?I?SDeAFeBBqAJ_D@q@@o@?y@?s@?qAAgI@y@@o@Ds@JiBXkE@s@Bm@?{@Aw@Ey@Gy@Gg@Gi@Ie@Ke@UaAoDiNa@aBc@kBkAwF???AoAcGKg@Ii@Ge@Gg@Ee@Ek@Am@Ak@Ak@@k@Bg@Bk@@e@Dk@Fc@Hk@Js@Rw@zDsPNs@Lm@RqAPqAHgAf@kHLiBDc@BWFWDUFUHUJUJULUJONSNKPQtCmB??~BcBb@Ud@STEVGVCVA^?pHDvOFjLCx@?pDH`@Bb@Cb@?^Ib@G^I\\M\\O\\Qhg@oX~@e@????|L{GjDgB|@c@f@QtE_BpAe@lO}FbJkDdQwGrFyBt[{LnSqI?A" + }, + "intermediateStops": [ + { + "lat": 47.676107, + "lon": -122.316041, + "name": "Roosevelt Station", + "stopCode": "N09-T1", + "stopId": "U3RvcDo0MDo5OTAwMDM", + "locationType": "STOP" + }, + { + "lat": 47.659875, + "lon": -122.314194, + "name": "U District Station", + "stopCode": "N07-T1", + "stopId": "U3RvcDo0MDo5OTAwMDE", + "locationType": "STOP" + }, + { + "lat": 47.649349, + "lon": -122.303795, + "name": "Univ of Washington Station", + "stopCode": "N05-T1", + "stopId": "U3RvcDo0MDo5OTYwNA", + "locationType": "STOP" + }, + { + "lat": 47.61956, + "lon": -122.320389, + "name": "Capitol Hill Station", + "stopCode": "N03-T1", + "stopId": "U3RvcDo0MDo5OTYxMA", + "locationType": "STOP" + }, + { + "lat": 47.61145, + "lon": -122.337532, + "name": "Westlake Station", + "stopCode": "C03-T1", + "stopId": "U3RvcDo0MDoxMTA4", + "locationType": "STOP" + }, + { + "lat": 47.607246, + "lon": -122.335754, + "name": "University St Station", + "stopCode": "C05-T1", + "stopId": "U3RvcDo0MDo0NTU", + "locationType": "STOP" + }, + { + "lat": 47.602139, + "lon": -122.331055, + "name": "Pioneer Square Station", + "stopCode": "C07-T1", + "stopId": "U3RvcDo0MDo1MDE", + "locationType": "STOP" + }, + { + "lat": 47.59766, + "lon": -122.328217, + "name": "Int'l Dist/Chinatown Station", + "stopCode": "C09-T1", + "stopId": "U3RvcDo0MDo2MjM", + "locationType": "STOP" + }, + { + "lat": 47.591824, + "lon": -122.327354, + "name": "Stadium Station", + "stopCode": "C13-T1", + "stopId": "U3RvcDo0MDo5OTEwMQ", + "locationType": "STOP" + }, + { + "lat": 47.579952, + "lon": -122.327522, + "name": "SODO Station", + "stopCode": "C15-T1", + "stopId": "U3RvcDo0MDo5OTExMQ", + "locationType": "STOP" + }, + { + "lat": 47.579124, + "lon": -122.311279, + "name": "Beacon Hill Station", + "stopCode": "C19-T1", + "stopId": "U3RvcDo0MDo5OTEyMQ", + "locationType": "STOP" + }, + { + "lat": 47.576439, + "lon": -122.297737, + "name": "Mount Baker Station", + "stopCode": "C23-T1", + "stopId": "U3RvcDo0MDo1NTk0OQ", + "locationType": "STOP" + }, + { + "lat": 47.559025, + "lon": -122.292389, + "name": "Columbia City Station", + "stopCode": "C25-T1", + "stopId": "U3RvcDo0MDo1NjAzOQ", + "locationType": "STOP" + } + ], + "route": { + "shortName": "1-Line", + "longName": "Northgate - Angle Lake", + "color": "28813F", + "textColor": "FFFFFF", + "id": "Um91dGU6NDA6MTAwNDc5", + "type": 0, + "alerts": [] + }, + "from": { + "lat": 47.702662, + "lon": -122.32832, + "name": "Northgate Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo5OTAwMDU", + "code": "N11-T1", + "gtfsId": "40:990005", + "alerts": [] + } + }, + "to": { + "lat": 47.537529, + "lon": -122.281471, + "name": "Othello Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo1NjE1OQ", + "code": "C27-T1", + "gtfsId": "40:56159", + "alerts": [] + } + }, + "steps": [] + }, + { + "fareProducts": [], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": false, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 2167.47, + "duration": 1739, + "endTime": 1685146739000, + "mode": "WALK", + "realTime": false, + "realtimeState": null, + "startTime": 1685145000000, + "transitLeg": false, + "accessibilityScore": null, + "trip": null, + "agency": null, + "legGeometry": { + "length": 135, + "points": "otcaHfbjiV?BXMF\\\\??fC?NJ?@|@BbC?R?TAB?|A?t@@f@?L@B?V?TA@@D?D?vA?h@?X?TAXCXANCPCPKd@ERCLCH@@HFLJ@@@?@@@@B@F?F?D?DAENDAHCFCFNPTDBD?RIl@Wb@Qn@c@h@[ZONGPCD?LEFAL@Ad@@vF?pAApA?nH@\\@J@DBPJLEFIFI^ENQf@EBCFHJP^BL@J@PAhFA|A?bAArB?hA@JBFDDDHl@b@RHTFXD\\@P@PCjB[hB[h@M`A]lAk@vBoAlAu@h@YLCPAJ@J@LFLHHJHJFNHTv@dGFb@@NK@KCOCM@{Ad@e@F_@LM@" + }, + "intermediateStops": null, + "route": null, + "from": { + "lat": 47.537529, + "lon": -122.281471, + "name": "Othello Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo1NjE1OQ", + "code": "C27-T1", + "gtfsId": "40:56159", + "alerts": [] + } + }, + "to": { + "lat": 47.5312889, + "lon": -122.2958113, + "name": "New Light Christian Church, Seattle, WA, USA", + "vertexType": "NORMAL", + "rentalVehicle": null, + "stop": null + }, + "steps": [ + { + "distance": 14.92, + "lat": 47.5375246, + "lon": -122.2814907, + "relativeDirection": "DEPART", + "absoluteDirection": "SOUTH", + "stayOn": false, + "streetName": "Martin Luther King Junior Way South", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 12.32, + "lat": 47.5373972, + "lon": -122.2814286, + "relativeDirection": "RIGHT", + "absoluteDirection": "SOUTHWEST", + "stayOn": false, + "streetName": "service road", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 79.38, + "lat": 47.537352, + "lon": -122.2815784, + "relativeDirection": "LEFT", + "absoluteDirection": "SOUTH", + "stayOn": true, + "streetName": "parking aisle", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 186.19, + "lat": 47.5371499, + "lon": -122.2823392, + "relativeDirection": "RIGHT", + "absoluteDirection": "WEST", + "stayOn": true, + "streetName": "sidewalk", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 185.66, + "lat": 47.5371051, + "lon": -122.2847952, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTHWEST", + "stayOn": true, + "streetName": "sidewalk", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 223.22, + "lat": 47.5369894, + "lon": -122.2868292, + "relativeDirection": "HARD_RIGHT", + "absoluteDirection": "NORTHWEST", + "stayOn": true, + "streetName": "path", + "area": false, + "alerts": [null], + "elevationProfile": [] + }, + { + "distance": 316.7, + "lat": 47.535227, + "lon": -122.2863141, + "relativeDirection": "RIGHT", + "absoluteDirection": "WEST", + "stayOn": false, + "streetName": "South Webster Street", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 55.15, + "lat": 47.5351293, + "lon": -122.2904874, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTHWEST", + "stayOn": false, + "streetName": "path", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 259.82, + "lat": 47.5354239, + "lon": -122.2910651, + "relativeDirection": "LEFT", + "absoluteDirection": "SOUTHWEST", + "stayOn": false, + "streetName": "South Webster Street", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 57.96, + "lat": 47.5352763, + "lon": -122.2944348, + "relativeDirection": "SLIGHTLY_LEFT", + "absoluteDirection": "SOUTHWEST", + "stayOn": false, + "streetName": "29th Avenue South", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 644.09, + "lat": 47.5348545, + "lon": -122.2948441, + "relativeDirection": "CONTINUE", + "absoluteDirection": "SOUTH", + "stayOn": false, + "streetName": "Military Road South", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 132.1, + "lat": 47.5301402, + "lon": -122.2953592, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTH", + "stayOn": false, + "streetName": "service road", + "area": false, + "alerts": [], + "elevationProfile": [] + } + ] + } + ] +} From e941d671ecd981ac0f918762c8fed1ea459be71b Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 8 Jun 2023 23:55:33 -0700 Subject: [PATCH 05/40] test(core-utils): add new mock --- .../__mocks__/fare-products-itinerary.json | 1283 +++++++++++++++++ 1 file changed, 1283 insertions(+) create mode 100644 packages/core-utils/src/__tests__/__mocks__/fare-products-itinerary.json diff --git a/packages/core-utils/src/__tests__/__mocks__/fare-products-itinerary.json b/packages/core-utils/src/__tests__/__mocks__/fare-products-itinerary.json new file mode 100644 index 000000000..0387113e8 --- /dev/null +++ b/packages/core-utils/src/__tests__/__mocks__/fare-products-itinerary.json @@ -0,0 +1,1283 @@ +{ + "duration": 6952, + "endTime": 1685146739000, + "startTime": 1685139787000, + "waitingTime": 184, + "walkTime": 2436, + "accessibilityScore": null, + "legs": [ + { + "fareProducts": [], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": false, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 825.81, + "duration": 641, + "endTime": 1685140428000, + "mode": "WALK", + "realTime": false, + "realtimeState": null, + "startTime": 1685139787000, + "transitLeg": false, + "accessibilityScore": null, + "trip": null, + "agency": null, + "legGeometry": { + "length": 16, + "points": "}zrbHnykiV@GHk@Dg@dC@j@BhDh@AlD?tCCzKGfV?T?NO?a@???" + }, + "intermediateStops": null, + "route": null, + "from": { + "lat": 47.7791977, + "lon": -122.2903181, + "name": "47.7792, -122.29032", + "vertexType": "NORMAL", + "rentalVehicle": null, + "stop": null + }, + "to": { + "lat": 47.7776833, + "lon": -122.297684, + "name": "48th Ave W & 244th St SW", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206ODI0MDU", + "code": "82405", + "gtfsId": "kcm:82405", + "alerts": [] + } + }, + "steps": [ + { + "distance": 36.61, + "lat": 47.7791959, + "lon": -122.290319, + "relativeDirection": "DEPART", + "absoluteDirection": "EAST", + "stayOn": false, + "streetName": "242nd Street Southwest", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 194.04, + "lat": 47.7791005, + "lon": -122.2898502, + "relativeDirection": "RIGHT", + "absoluteDirection": "SOUTH", + "stayOn": false, + "streetName": "Cedar Way", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 567.32, + "lat": 47.7773669, + "lon": -122.2900921, + "relativeDirection": "RIGHT", + "absoluteDirection": "WEST", + "stayOn": false, + "streetName": "Northeast 205th Street - 244th Street Southwest", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 27.83, + "lat": 47.7774331, + "lon": -122.2976837, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTH", + "stayOn": false, + "streetName": "path", + "area": false, + "alerts": [], + "elevationProfile": [] + } + ] + }, + { + "fareProducts": [ + { + "id": "3ff3d12d-6747-3b47-842a-92c7bf167015", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 2.75 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "77a8ba05-8081-301f-9fe4-777dcd10ae02", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 2.75 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "0740913d-0e0a-34ab-9518-014f2025b1a8", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "16ac6750-91b2-347c-b991-e63f8c483de9", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "cf501333-167f-31b1-b99a-0e9b17d4a16c", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1.5 + }, + "riderCategory": { + "id": "orca:special", + "name": "special" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "1b2d9477-8ce5-3eec-a63d-7d2534fa3bef", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "105e04d3-a575-3f65-96c1-e33d5199f339", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + } + ], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": null, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 12180.55, + "duration": 2112, + "endTime": 1685142540000, + "mode": "BUS", + "realTime": false, + "realtimeState": null, + "startTime": 1685140428000, + "transitLeg": true, + "accessibilityScore": null, + "trip": { + "id": "VHJpcDprY206NTQxNDgwODUz", + "gtfsId": "kcm:541480853", + "tripHeadsign": "Northgate Station Ridgecrest" + }, + "agency": { + "name": "Metro Transit", + "id": "QWdlbmN5OmtjbTox", + "timezone": "America/Los_Angeles", + "url": "https://kingcounty.gov/en/dept/metro", + "alerts": [] + }, + "legGeometry": { + "length": 262, + "points": "oqrbH~fmiVp@??fEC|DCjE?fN?h@??AfEAvCAxA@n@AdCAhD?tAAtCA~@???hDAfF?bBAn@???ZA`A?`@Av@Ax@AhB?R@NBNFLLPVXN@T?R?l@A??fCGnCEzBE??hBErAApIM??nGKX?R?L?N@XFLBFBJ@LFLHPHPJTNXV^ZTPRRrAl@F@??d@Jb@DT?TCxCIVCl@Ab@CTEHCTGNGTKb@Sp@c@TINIPC??FCPEVAVAV?b@?V@^A\\IZEZKf@UrAq@|@a@d@W`@_@f@_@NM??x@m@b@Cz@M\\C^?z@Px@XZPZXn@r@r@f@ZLb@Rb@FZFb@?z@???tA?rF@|I?AjD??CbJA|FA|C??AtBEpOEtOxCC??Z?|BAzEGdECf@???dIEhJG`DE??jAAfFEzCE??J?zA?xACdDE??N?pDCpDE`BCp@A??pFG~CC^A^???fBAbEEvCE\\?X???bCA|@F`E?f@?@mG???C@yGFwO@qG@gF???]DyOtAC??tGAt@???vHEn@???~HE|HA??n@?|G?tC?xA?~D@Z???lI?p@???rHBB?pAC??vGIp@???xHI|@C??|CCt@?ZBRJRNRR`@h@LTpFhI??~@xAbD~E`A|A|AzB\\Z^Vf@Rx@R~CArAC?fB??CvLA|OnA???hDEbFGx@???|DErDAvDA?jB??AfCA`HA~G?pB?P|A?lA?" + }, + "intermediateStops": [ + { + "lat": 47.7775421, + "lon": -122.303215, + "name": "NE 205th St & 52nd Ave W", + "stopCode": "82410", + "stopId": "U3RvcDprY206ODI0MTA", + "locationType": "STOP" + }, + { + "lat": 47.7775955, + "lon": -122.308685, + "name": "NE 205th St & 56th Ave W", + "stopCode": "82430", + "stopId": "U3RvcDprY206ODI0MzA", + "locationType": "STOP" + }, + { + "lat": 47.7776146, + "lon": -122.311432, + "name": "NE 205th St & 58th Pl W", + "stopCode": "82440", + "stopId": "U3RvcDprY206ODI0NDA", + "locationType": "STOP" + }, + { + "lat": 47.7768135, + "lon": -122.31382, + "name": "15th Ave NE & Ballinger Way NE", + "stopCode": "77400", + "stopId": "U3RvcDprY206Nzc0MDA", + "locationType": "STOP" + }, + { + "lat": 47.7747955, + "lon": -122.313721, + "name": "15th Ave NE & Forest Park Dr NE", + "stopCode": "77410", + "stopId": "U3RvcDprY206Nzc0MTA", + "locationType": "STOP" + }, + { + "lat": 47.7721519, + "lon": -122.313614, + "name": "15th Ave NE & NE 200th Ct", + "stopCode": "77418", + "stopId": "U3RvcDprY206Nzc0MTg", + "locationType": "STOP" + }, + { + "lat": 47.768734, + "lon": -122.314636, + "name": "15th Ave NE & NE 192nd St", + "stopCode": "77940", + "stopId": "U3RvcDprY206Nzc5NDA", + "locationType": "STOP" + }, + { + "lat": 47.7656479, + "lon": -122.313995, + "name": "15th Ave NE & NE Perkins Way", + "stopCode": "77440", + "stopId": "U3RvcDprY206Nzc0NDA", + "locationType": "STOP" + }, + { + "lat": 47.7626801, + "lon": -122.312752, + "name": "15th Ave NE & 24th Ave NE", + "stopCode": "77450", + "stopId": "U3RvcDprY206Nzc0NTA", + "locationType": "STOP" + }, + { + "lat": 47.7591515, + "lon": -122.31356, + "name": "15th Ave NE & NE 180th St", + "stopCode": "77460", + "stopId": "U3RvcDprY206Nzc0NjA", + "locationType": "STOP" + }, + { + "lat": 47.7558212, + "lon": -122.314339, + "name": "NE 175th St & 15th Ave NE", + "stopCode": "77738", + "stopId": "U3RvcDprY206Nzc3Mzg", + "locationType": "STOP" + }, + { + "lat": 47.7558632, + "lon": -122.318176, + "name": "NE 175th St & 10th Ave NE", + "stopCode": "77737", + "stopId": "U3RvcDprY206Nzc3Mzc", + "locationType": "STOP" + }, + { + "lat": 47.7550964, + "lon": -122.324158, + "name": "5th Ave NE & NE 174th St", + "stopCode": "81246", + "stopId": "U3RvcDprY206ODEyNDY", + "locationType": "STOP" + }, + { + "lat": 47.752037, + "lon": -122.324104, + "name": "5th Ave NE & NE 170th St", + "stopCode": "81248", + "stopId": "U3RvcDprY206ODEyNDg", + "locationType": "STOP" + }, + { + "lat": 47.7477875, + "lon": -122.324013, + "name": "5th Ave NE & NE 163rd St", + "stopCode": "77560", + "stopId": "U3RvcDprY206Nzc1NjA", + "locationType": "STOP" + }, + { + "lat": 47.7454681, + "lon": -122.323944, + "name": "5th Ave NE & NE 161st St", + "stopCode": "77570", + "stopId": "U3RvcDprY206Nzc1NzA", + "locationType": "STOP" + }, + { + "lat": 47.7436676, + "lon": -122.323883, + "name": "5th Ave NE & NE 158th St", + "stopCode": "77580", + "stopId": "U3RvcDprY206Nzc1ODA", + "locationType": "STOP" + }, + { + "lat": 47.741066, + "lon": -122.323792, + "name": "5th Ave NE & NE 155th St", + "stopCode": "81252", + "stopId": "U3RvcDprY206ODEyNTI", + "locationType": "STOP" + }, + { + "lat": 47.7387314, + "lon": -122.323723, + "name": "5th Ave NE & NE 152nd St", + "stopCode": "81254", + "stopId": "U3RvcDprY206ODEyNTQ", + "locationType": "STOP" + }, + { + "lat": 47.7361908, + "lon": -122.323654, + "name": "5th Ave NE & NE 148th St", + "stopCode": "81256", + "stopId": "U3RvcDprY206ODEyNTY", + "locationType": "STOP" + }, + { + "lat": 47.7339783, + "lon": -122.322235, + "name": "NE 145th St & 6th Ave NE", + "stopCode": "82200", + "stopId": "U3RvcDprY206ODIyMDA", + "locationType": "STOP" + }, + { + "lat": 47.7339096, + "lon": -122.315598, + "name": "NE 145th St & 12th Ave NE", + "stopCode": "82220", + "stopId": "U3RvcDprY206ODIyMjA", + "locationType": "STOP" + }, + { + "lat": 47.7335167, + "lon": -122.312851, + "name": "15th Ave NE & NE 145th St", + "stopCode": "38830", + "stopId": "U3RvcDprY206Mzg4MzA", + "locationType": "STOP" + }, + { + "lat": 47.7318573, + "lon": -122.31282, + "name": "15th Ave NE & NE 143rd St", + "stopCode": "38840", + "stopId": "U3RvcDprY206Mzg4NDA", + "locationType": "STOP" + }, + { + "lat": 47.7300568, + "lon": -122.312798, + "name": "15th Ave NE & NE 140th St", + "stopCode": "38850", + "stopId": "U3RvcDprY206Mzg4NTA", + "locationType": "STOP" + }, + { + "lat": 47.7268677, + "lon": -122.312752, + "name": "15th Ave NE & NE 135th St", + "stopCode": "38870", + "stopId": "U3RvcDprY206Mzg4NzA", + "locationType": "STOP" + }, + { + "lat": 47.7228928, + "lon": -122.312767, + "name": "15th Ave NE & NE 130th St", + "stopCode": "38890", + "stopId": "U3RvcDprY206Mzg4OTA", + "locationType": "STOP" + }, + { + "lat": 47.7209663, + "lon": -122.312782, + "name": "15th Ave NE & NE 127th St", + "stopCode": "38900", + "stopId": "U3RvcDprY206Mzg5MDA", + "locationType": "STOP" + }, + { + "lat": 47.7190018, + "lon": -122.312767, + "name": "15th Ave NE & NE 125th St", + "stopCode": "38910", + "stopId": "U3RvcDprY206Mzg5MTA", + "locationType": "STOP" + }, + { + "lat": 47.71735, + "lon": -122.312714, + "name": "15th Ave NE & NE 123rd St", + "stopCode": "38920", + "stopId": "U3RvcDprY206Mzg5MjA", + "locationType": "STOP" + }, + { + "lat": 47.7154694, + "lon": -122.312645, + "name": "15th Ave NE & NE 120th St", + "stopCode": "38930", + "stopId": "U3RvcDprY206Mzg5MzA", + "locationType": "STOP" + }, + { + "lat": 47.7125664, + "lon": -122.314827, + "name": "Pinehurst Way NE & NE 115th St", + "stopCode": "38962", + "stopId": "U3RvcDprY206Mzg5NjI", + "locationType": "STOP" + }, + { + "lat": 47.7086334, + "lon": -122.318367, + "name": "NE Northgate Way & Roosevelt Way NE", + "stopCode": "82198", + "stopId": "U3RvcDprY206ODIxOTg", + "locationType": "STOP" + }, + { + "lat": 47.7081947, + "lon": -122.323364, + "name": "5th Ave NE & NE Northgate Way", + "stopCode": "23230", + "stopId": "U3RvcDprY206MjMyMzA", + "locationType": "STOP" + }, + { + "lat": 47.7059097, + "lon": -122.323296, + "name": "5th Ave NE & Northgate Mall", + "stopCode": "23250", + "stopId": "U3RvcDprY206MjMyNTA", + "locationType": "STOP" + }, + { + "lat": 47.7032166, + "lon": -122.323692, + "name": "NE 103rd St & 5th Ave NE", + "stopCode": "35290", + "stopId": "U3RvcDprY206MzUyOTA", + "locationType": "STOP" + } + ], + "route": { + "shortName": "347", + "longName": null, + "color": null, + "textColor": null, + "id": "Um91dGU6a2NtOjEwMDIwNA", + "type": 3, + "alerts": [] + }, + "from": { + "lat": 47.7776833, + "lon": -122.297684, + "name": "48th Ave W & 244th St SW", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206ODI0MDU", + "code": "82405", + "gtfsId": "kcm:82405", + "alerts": [] + } + }, + "to": { + "lat": 47.7023087, + "lon": -122.328026, + "name": "Northgate Station - Bay 4", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206MzUzMTg", + "code": "35318", + "gtfsId": "kcm:35318", + "alerts": [] + } + }, + "steps": [] + }, + { + "fareProducts": [], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": false, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 60.87, + "duration": 56, + "endTime": 1685142596000, + "mode": "WALK", + "realTime": false, + "realtimeState": null, + "startTime": 1685142540000, + "transitLeg": false, + "accessibilityScore": null, + "trip": null, + "agency": null, + "legGeometry": { + "length": 9, + "points": "kzcbHdesiV?Ce@?Q??L?V?RO??B" + }, + "intermediateStops": null, + "route": null, + "from": { + "lat": 47.7023087, + "lon": -122.328026, + "name": "Northgate Station - Bay 4", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDprY206MzUzMTg", + "code": "35318", + "gtfsId": "kcm:35318", + "alerts": [] + } + }, + "to": { + "lat": 47.702662, + "lon": -122.32832, + "name": "Northgate Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo5OTAwMDU", + "code": "N11-T1", + "gtfsId": "40:990005", + "alerts": [] + } + }, + "steps": [ + { + "distance": 60.87, + "lat": 47.7023088, + "lon": -122.3280018, + "relativeDirection": "DEPART", + "absoluteDirection": "NORTH", + "stayOn": false, + "streetName": "path", + "area": false, + "alerts": [], + "elevationProfile": [] + } + ] + }, + { + "fareProducts": [ + { + "id": "0f76bb4a-7491-34b9-95ce-5d6f4e6b4d53", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 3 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "ab8213b7-eddd-3d20-9b2d-a5ed8d8573a4", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0.25 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "75fef4dc-142b-3589-ac62-d484f5b41143", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 2.75 + }, + "riderCategory": { + "id": "orca:regular", + "name": "regular" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "69bafcef-e2ee-3a6c-a355-0883f3d5561f", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "b0026496-8eea-31c8-8468-a67b00abc2b5", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "8e77f7c7-7eda-32a8-ad44-23372b079942", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:special", + "name": "special" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "e8e69341-c5f3-3833-9a0a-de3118460842", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1.5 + }, + "riderCategory": { + "id": "orca:special", + "name": "special" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "7ab667f5-3bb1-3973-b065-46ac5bffe3a4", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:youth", + "name": "youth" + }, + "medium": { + "id": "orca:cash", + "name": "cash" + } + } + }, + { + "id": "b3ff8f6e-f55f-3098-bb23-2bc49441d81f", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 0 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + }, + { + "id": "2fe47d57-d05f-3f51-9d4b-4d060a68abd9", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "currency": { + "code": "USD", + "digits": 2 + }, + "amount": 1 + }, + "riderCategory": { + "id": "orca:senior", + "name": "senior" + }, + "medium": { + "id": "orca:electronic", + "name": "electronic" + } + } + } + ], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": null, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 23087.2, + "duration": 2220, + "endTime": 1685145000000, + "mode": "TRAM", + "realTime": false, + "realtimeState": null, + "startTime": 1685142780000, + "transitLeg": true, + "accessibilityScore": null, + "trip": { + "id": "VHJpcDo0MDpMTFJfMjAyMy0wMy0xOC0yMDIzLTA5LTA0X1dlZWtkYXlfMjA4Ng", + "gtfsId": "40:LLR_2023-03-18-2023-09-04_Weekday_2086", + "tripHeadsign": "Angle Lake" + }, + "agency": { + "name": "Sound Transit", + "id": "QWdlbmN5OjQwOjQw", + "timezone": "America/Los_Angeles", + "url": "https://www.soundtransit.org", + "alerts": [] + }, + "legGeometry": { + "length": 509, + "points": "s|cbHhgsiVJ?dA?pAApA@nAHnANnALnANnALnALpAFnABpACpAGnAKr@G^CnAKpAEnA?pA@pA?nA@pA@pA@nA@pA@pA?nACpAKlASlAWjA]fAc@fAi@`Ak@`Aq@z@u@z@w@v@{@r@{@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@_Ar@}@r@}@r@}@v@{@x@w@~@s@bAk@fAe@hA_@nAWnAMnACpAApAAnA?V???x@ApACnAGnAKpAMnAMnAKnAMnAMnAMnAMpAKnAMnAMnAMnAKnAMnAMpAMnAKnAMnAMnAMnAMnAKpAMnAKnAIpAInAEpAGnACpAApAApA?nA?pA@pA@nABpA@h@???f@@nAAnAQfAc@~@q@v@{@j@cAd@gAZkARmANoAJqAJoAHoAJqAJoAJoALoALoARoATmAZkA^kA`@iAf@eAj@cAp@aAt@{@x@w@~@q@dAk@hAa@jAYnAOpAEnAApAApAAnAApAAbDAb@Cb@???H?p@Ar@?|FGx@?hA?rA@pADzAHtAHrALrARrAPzAV`BZxA^`Bd@rBn@|Aj@lBx@lBz@|Ax@fB`AhBlAbBlAfE`DrB~Avh@da@bHlFbDdCjEfDdK~HrB~A~@r@n@d@bAh@|@d@jAd@jA^tAVpAR~@HfADtA?n@A????vFC~A?x@?|@HbAPbAZbA`@x@b@dAz@v@r@~@jAr@dAp@rAd@fA`@jAd@bBZxAVbBRfBH~AFtA@|AAdBGpAIzAOdBWzASxAKx@Ix@?f@?n@@l@Dr@Jx@Hf@Jh@JZjAnDb@tAhBzFXvAhB|FnBlG??@?FTj@fABBRh@PVNRLHLDR@N?VGXMNInJoIlC_Cp@o@RQ????t@s@lCaC|GcGnCcClCaC\\[nBgBlBgB@???VUVURWVc@Xe@PYpBeDx@sAx@mAV_@TQ\\Sp@MzCA|FF@@??N@RFNFN@LB~BCF?D?fCAF?N?NCN?NALAHCJAJAHCNEPC^KxDeAxCy@NGJAJCJALAL?h@CrC???nHBrB?V?X@R@VBn@HVDP@T@z@?b@?z@?vp@B??@?zG?L?N?JCF?JAHEDABCF?@CDABCDCBCBEDCBEBCBGBEBC@EBGBEBG@E@E@GBE@G@E?CBM?IBI@K?I?SDeAFeBBqAJ_D@q@@o@?y@?s@?qAAgI@y@@o@Ds@JiBXkE@s@Bm@?{@Aw@Ey@Gy@Gg@Gi@Ie@Ke@UaAoDiNa@aBc@kBkAwF???AoAcGKg@Ii@Ge@Gg@Ee@Ek@Am@Ak@Ak@@k@Bg@Bk@@e@Dk@Fc@Hk@Js@Rw@zDsPNs@Lm@RqAPqAHgAf@kHLiBDc@BWFWDUFUHUJUJULUJONSNKPQtCmB??~BcBb@Ud@STEVGVCVA^?pHDvOFjLCx@?pDH`@Bb@Cb@?^Ib@G^I\\M\\O\\Qhg@oX~@e@????|L{GjDgB|@c@f@QtE_BpAe@lO}FbJkDdQwGrFyBt[{LnSqI?A" + }, + "intermediateStops": [ + { + "lat": 47.676107, + "lon": -122.316041, + "name": "Roosevelt Station", + "stopCode": "N09-T1", + "stopId": "U3RvcDo0MDo5OTAwMDM", + "locationType": "STOP" + }, + { + "lat": 47.659875, + "lon": -122.314194, + "name": "U District Station", + "stopCode": "N07-T1", + "stopId": "U3RvcDo0MDo5OTAwMDE", + "locationType": "STOP" + }, + { + "lat": 47.649349, + "lon": -122.303795, + "name": "Univ of Washington Station", + "stopCode": "N05-T1", + "stopId": "U3RvcDo0MDo5OTYwNA", + "locationType": "STOP" + }, + { + "lat": 47.61956, + "lon": -122.320389, + "name": "Capitol Hill Station", + "stopCode": "N03-T1", + "stopId": "U3RvcDo0MDo5OTYxMA", + "locationType": "STOP" + }, + { + "lat": 47.61145, + "lon": -122.337532, + "name": "Westlake Station", + "stopCode": "C03-T1", + "stopId": "U3RvcDo0MDoxMTA4", + "locationType": "STOP" + }, + { + "lat": 47.607246, + "lon": -122.335754, + "name": "University St Station", + "stopCode": "C05-T1", + "stopId": "U3RvcDo0MDo0NTU", + "locationType": "STOP" + }, + { + "lat": 47.602139, + "lon": -122.331055, + "name": "Pioneer Square Station", + "stopCode": "C07-T1", + "stopId": "U3RvcDo0MDo1MDE", + "locationType": "STOP" + }, + { + "lat": 47.59766, + "lon": -122.328217, + "name": "Int'l Dist/Chinatown Station", + "stopCode": "C09-T1", + "stopId": "U3RvcDo0MDo2MjM", + "locationType": "STOP" + }, + { + "lat": 47.591824, + "lon": -122.327354, + "name": "Stadium Station", + "stopCode": "C13-T1", + "stopId": "U3RvcDo0MDo5OTEwMQ", + "locationType": "STOP" + }, + { + "lat": 47.579952, + "lon": -122.327522, + "name": "SODO Station", + "stopCode": "C15-T1", + "stopId": "U3RvcDo0MDo5OTExMQ", + "locationType": "STOP" + }, + { + "lat": 47.579124, + "lon": -122.311279, + "name": "Beacon Hill Station", + "stopCode": "C19-T1", + "stopId": "U3RvcDo0MDo5OTEyMQ", + "locationType": "STOP" + }, + { + "lat": 47.576439, + "lon": -122.297737, + "name": "Mount Baker Station", + "stopCode": "C23-T1", + "stopId": "U3RvcDo0MDo1NTk0OQ", + "locationType": "STOP" + }, + { + "lat": 47.559025, + "lon": -122.292389, + "name": "Columbia City Station", + "stopCode": "C25-T1", + "stopId": "U3RvcDo0MDo1NjAzOQ", + "locationType": "STOP" + } + ], + "route": { + "shortName": "1-Line", + "longName": "Northgate - Angle Lake", + "color": "28813F", + "textColor": "FFFFFF", + "id": "Um91dGU6NDA6MTAwNDc5", + "type": 0, + "alerts": [] + }, + "from": { + "lat": 47.702662, + "lon": -122.32832, + "name": "Northgate Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo5OTAwMDU", + "code": "N11-T1", + "gtfsId": "40:990005", + "alerts": [] + } + }, + "to": { + "lat": 47.537529, + "lon": -122.281471, + "name": "Othello Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo1NjE1OQ", + "code": "C27-T1", + "gtfsId": "40:56159", + "alerts": [] + } + }, + "steps": [] + }, + { + "fareProducts": [], + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED", + "pickupBookingInfo": null, + "rentedBike": false, + "interlineWithPreviousLeg": false, + "departureDelay": 0, + "arrivalDelay": 0, + "distance": 2167.47, + "duration": 1739, + "endTime": 1685146739000, + "mode": "WALK", + "realTime": false, + "realtimeState": null, + "startTime": 1685145000000, + "transitLeg": false, + "accessibilityScore": null, + "trip": null, + "agency": null, + "legGeometry": { + "length": 135, + "points": "otcaHfbjiV?BXMF\\\\??fC?NJ?@|@BbC?R?TAB?|A?t@@f@?L@B?V?TA@@D?D?vA?h@?X?TAXCXANCPCPKd@ERCLCH@@HFLJ@@@?@@@@B@F?F?D?DAENDAHCFCFNPTDBD?RIl@Wb@Qn@c@h@[ZONGPCD?LEFAL@Ad@@vF?pAApA?nH@\\@J@DBPJLEFIFI^ENQf@EBCFHJP^BL@J@PAhFA|A?bAArB?hA@JBFDDDHl@b@RHTFXD\\@P@PCjB[hB[h@M`A]lAk@vBoAlAu@h@YLCPAJ@J@LFLHHJHJFNHTv@dGFb@@NK@KCOCM@{Ad@e@F_@LM@" + }, + "intermediateStops": null, + "route": null, + "from": { + "lat": 47.537529, + "lon": -122.281471, + "name": "Othello Station", + "vertexType": "TRANSIT", + "rentalVehicle": null, + "stop": { + "id": "U3RvcDo0MDo1NjE1OQ", + "code": "C27-T1", + "gtfsId": "40:56159", + "alerts": [] + } + }, + "to": { + "lat": 47.5312889, + "lon": -122.2958113, + "name": "New Light Christian Church, Seattle, WA, USA", + "vertexType": "NORMAL", + "rentalVehicle": null, + "stop": null + }, + "steps": [ + { + "distance": 14.92, + "lat": 47.5375246, + "lon": -122.2814907, + "relativeDirection": "DEPART", + "absoluteDirection": "SOUTH", + "stayOn": false, + "streetName": "Martin Luther King Junior Way South", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 12.32, + "lat": 47.5373972, + "lon": -122.2814286, + "relativeDirection": "RIGHT", + "absoluteDirection": "SOUTHWEST", + "stayOn": false, + "streetName": "service road", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 79.38, + "lat": 47.537352, + "lon": -122.2815784, + "relativeDirection": "LEFT", + "absoluteDirection": "SOUTH", + "stayOn": true, + "streetName": "parking aisle", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 186.19, + "lat": 47.5371499, + "lon": -122.2823392, + "relativeDirection": "RIGHT", + "absoluteDirection": "WEST", + "stayOn": true, + "streetName": "sidewalk", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 185.66, + "lat": 47.5371051, + "lon": -122.2847952, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTHWEST", + "stayOn": true, + "streetName": "sidewalk", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 223.22, + "lat": 47.5369894, + "lon": -122.2868292, + "relativeDirection": "HARD_RIGHT", + "absoluteDirection": "NORTHWEST", + "stayOn": true, + "streetName": "path", + "area": false, + "alerts": [null], + "elevationProfile": [] + }, + { + "distance": 316.7, + "lat": 47.535227, + "lon": -122.2863141, + "relativeDirection": "RIGHT", + "absoluteDirection": "WEST", + "stayOn": false, + "streetName": "South Webster Street", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 55.15, + "lat": 47.5351293, + "lon": -122.2904874, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTHWEST", + "stayOn": false, + "streetName": "path", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 259.82, + "lat": 47.5354239, + "lon": -122.2910651, + "relativeDirection": "LEFT", + "absoluteDirection": "SOUTHWEST", + "stayOn": false, + "streetName": "South Webster Street", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 57.96, + "lat": 47.5352763, + "lon": -122.2944348, + "relativeDirection": "SLIGHTLY_LEFT", + "absoluteDirection": "SOUTHWEST", + "stayOn": false, + "streetName": "29th Avenue South", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 644.09, + "lat": 47.5348545, + "lon": -122.2948441, + "relativeDirection": "CONTINUE", + "absoluteDirection": "SOUTH", + "stayOn": false, + "streetName": "Military Road South", + "area": false, + "alerts": [], + "elevationProfile": [] + }, + { + "distance": 132.1, + "lat": 47.5301402, + "lon": -122.2953592, + "relativeDirection": "RIGHT", + "absoluteDirection": "NORTH", + "stayOn": false, + "streetName": "service road", + "area": false, + "alerts": [], + "elevationProfile": [] + } + ] + } + ] +} From 97d46a874cfc3f0f6152331e8ccf01f697373164 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Fri, 9 Jun 2023 00:02:29 -0700 Subject: [PATCH 06/40] feat(trip-details): convert FareTable to use Fare Product data BREAKING CHANGE: removes support for REST data in FareTable --- .../trip-details/src/TripDetails.story.tsx | 125 ++++-------- packages/trip-details/src/fare-table.tsx | 142 ++++++-------- packages/trip-details/src/index.tsx | 179 +++++++++--------- packages/trip-details/src/types.ts | 58 +++--- packages/trip-details/src/utils.tsx | 75 +------- 5 files changed, 216 insertions(+), 363 deletions(-) diff --git a/packages/trip-details/src/TripDetails.story.tsx b/packages/trip-details/src/TripDetails.story.tsx index b615acf8c..3f6b9c313 100644 --- a/packages/trip-details/src/TripDetails.story.tsx +++ b/packages/trip-details/src/TripDetails.story.tsx @@ -9,6 +9,7 @@ import { } from "@storybook/react"; import styled from "styled-components"; // The below eslint-disable is due to https://github.com/storybookjs/storybook/issues/13408 +import { convertGraphQLResponseToLegacy } from "@opentripplanner/core-utils/lib/itinerary"; // eslint-disable-next-line import/no-named-as-default import TripDetails, { FareLegTable } from "."; import * as TripDetailsClasses from "./styled"; @@ -17,7 +18,6 @@ import { DepartureDetailsProps, FareDetailsProps, FareTableLayout, - FareTableText, TripDetailsProps } from "./types"; @@ -37,10 +37,10 @@ const walkInterlinedTransitItinerary = require("@opentripplanner/itinerary-body/ const walkOnlyItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-only.json"); const walkTransitWalkItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-transit-walk.json"); const walkTransitWalkTransitWalkItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-transit-walk-transit-walk.json"); -const fareComponentsItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/fare-components.json"); +const fareProductsItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json"); const flexItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/flex-itinerary.json"); const otp2ScooterItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/otp2-scooter.json"); -const otp2FareProducts = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/otp2-with-fareproducts.json"); +const otp2FareProducts = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json"); const flattenedEnglishMessages = flatten(customEnglishMessages); const flattenedFrenchMessages = flatten(customFrenchMessages); @@ -59,97 +59,52 @@ const StyledTripDetails = styled(TripDetails)` const otp2FareByLegLayout: FareTableLayout[] = [ { - header: "regular" as FareTableText, + headerKey: "regular", cols: [ { - header: "cash" as FareTableText, - riderCategory: "regular", - fareContainer: "cash" + columnHeaderKey: "cash", + riderCategoryId: "orca:regular", + mediumId: "orca:cash" }, { - header: "electronic" as FareTableText, - riderCategory: "regular", - fareContainer: "electronic" + columnHeaderKey: "electronic", + riderCategoryId: "orca:regular", + mediumId: "orca:electronic" }, { - header: "special" as FareTableText, - riderCategory: "special", - fareContainer: "electronic" + columnHeaderKey: "special", + riderCategoryId: "orca:special", + mediumId: "orca:electronic" } ] }, { - header: "youth" as FareTableText, + headerKey: "youth", cols: [ { - header: "cash" as FareTableText, - riderCategory: "youth", - fareContainer: "cash" + columnHeaderKey: "cash", + riderCategoryId: "orca:youth", + mediumId: "orca:cash" }, { - header: "electronic" as FareTableText, - riderCategory: "youth", - fareContainer: "electronic" + columnHeaderKey: "electronic", + riderCategoryId: "orca:youth", + mediumId: "orca:electronic" } ] }, { - header: "senior" as FareTableText, + headerKey: "senior", cols: [ { - header: "cash" as FareTableText, - riderCategory: "senior", - fareContainer: "cash" + columnHeaderKey: "cash", + riderCategoryId: "orca:senior", + mediumId: "orca:cash" }, { - header: "electronic" as FareTableText, - riderCategory: "senior", - fareContainer: "electronic" - } - ] - } -]; -const fareByLegLayout: FareTableLayout[] = [ - { - header: "regular" as FareTableText, - cols: [ - { - header: "cash" as FareTableText, - key: "regular" - }, - { - header: "electronic" as FareTableText, - key: "electronicRegular" - }, - { - header: "special" as FareTableText, - key: "electronicSpecial" - } - ] - }, - { - header: "youth" as FareTableText, - cols: [ - { - header: "cash" as FareTableText, - key: "youth" - }, - { - header: "electronic" as FareTableText, - key: "electronicYouth" - } - ] - }, - { - header: "senior" as FareTableText, - cols: [ - { - header: "cash" as FareTableText, - key: "cash" - }, - { - header: "electronic" as FareTableText, - key: "electronic" + columnHeaderKey: "electronic", + riderCategoryId: "orca:senior", + mediumId: "orca:electronic" } ] } @@ -313,8 +268,8 @@ export const BikeTransitBikeItinerary = makeStory({ export const WalkInterlinedTransitItinerary = makeStory( { - defaultFareKey: "electronicRegular", - fareDetailsLayout: fareByLegLayout, + // defaultFareKey: "electronicRegular", + // fareDetailsLayout: fareByLegLayout, itinerary: walkInterlinedTransitItinerary }, { @@ -373,7 +328,11 @@ export const TncTransitItinerary = makeStory( export const TncTransitItineraryWithCustomMessages = makeStory( { TimeActiveDetails: CustomTimeActiveDetails, - defaultFareKey: "electronicRegular", + defaultFareType: { + headerKey: "electronicRegular", + mediumId: "orca:electronic", + riderCategoryId: "orca:regular" + }, DepartureDetails: CustomDepartureDetails, itinerary: tncTransitTncItinerary }, @@ -392,22 +351,12 @@ export const TncTransitItineraryWithCustomMessages = makeStory( ); export const FareComponentsItinerary = makeStory({ - itinerary: fareComponentsItinerary + itinerary: fareProductsItinerary }); export const OTP2FlexItinerary = makeStory({ itinerary: flexItinerary }); -export const FareLegTableStory = (): ReactElement => { - return ( - - ); -}; - export const FareLegTableStoryLegProducts = (): ReactElement => { - return ( - - ); + const otp1legs = otp2FareProducts.legs.map(convertGraphQLResponseToLegacy); + return ; }; diff --git a/packages/trip-details/src/fare-table.tsx b/packages/trip-details/src/fare-table.tsx index 289bcaa4f..26a40135b 100644 --- a/packages/trip-details/src/fare-table.tsx +++ b/packages/trip-details/src/fare-table.tsx @@ -1,16 +1,15 @@ -import { Leg, Money } from "@opentripplanner/types"; +import { Leg } from "@opentripplanner/types"; import React from "react"; import styled from "styled-components"; import { Transfer } from "@styled-icons/boxicons-regular/Transfer"; import { getItineraryCost, - getLegCost, - getLegsWithFares + getLegCost } from "@opentripplanner/core-utils/lib/itinerary"; import { useIntl } from "react-intl"; import { flatten } from "flat"; -import { boldText, getFormattedTextForConfigKey, renderFare } from "./utils"; +import { boldText, renderFare } from "./utils"; import { FareLegTableProps, FareTableLayout } from "./types"; @@ -23,14 +22,8 @@ import defaultEnglishMessages from "../i18n/en-US.yml"; // - the yaml loader for jest returns messages with flattened ids. const defaultMessages: Record = flatten(defaultEnglishMessages); -type LegAndFare = Leg & { - fares: Record; -}; - interface FareTypeTableProps extends FareTableLayout { - fareTotals: Record; - legs: LegAndFare[]; - hasLegProducts?: boolean; + legs: Leg[]; } const TableHeader = styled.thead` @@ -73,63 +66,73 @@ const TransferIcon = styled(Transfer)` padding-left: 4px; `; +const useGetHeaderString = (headerKey: string): string => { + const intl = useIntl(); + return intl.formatMessage({ + id: `otpUi.TripDetails.FareTable.${headerKey}`, + description: `Fare leg table header for key ${headerKey}`, + defaultMessage: + defaultEnglishMessages[`otpUi.TripDetails.FareTable.${headerKey}`] + }); +}; + const FareTypeTable = ({ cols, - fareTotals, - header, - legs, - hasLegProducts + headerKey, + legs }: FareTypeTableProps): JSX.Element => { - const colsToRender = cols.filter(col => - hasLegProducts - ? getItineraryCost(legs, col.riderCategory, col.fareContainer) - : fareTotals[col.key] - ); - const intl = useIntl(); + // FIXME: Is there a nicer way to do this? + const colsToRender = cols + .filter(col => getItineraryCost(legs, col.riderCategoryId, col.mediumId)) + .map(col => ({ + ...col, + total: getItineraryCost(legs, col.riderCategoryId, col.mediumId) + })); + const headerString = useGetHeaderString(headerKey); + + const filteredLegs = legs.filter(leg => leg.fareProducts?.length > 0); if (colsToRender.length) { return ( {colsToRender.map(col => { - const fare = hasLegProducts - ? getItineraryCost(legs, col.riderCategory, col.fareContainer) - : fareTotals[col.key]; + const fare = col.total; return ( ); })} - {legs.map((leg, index) => ( + {filteredLegs.map((leg, index) => ( {colsToRender.map(col => { - const fare = hasLegProducts - ? getLegCost(leg, col.riderCategory, col.fareContainer) - : leg.fares[col.key]; - + const fare = getLegCost(leg, col.mediumId, col.riderCategoryId); return ( ); @@ -174,53 +179,20 @@ const FareTypeTable = ({ return null; }; -const FareLegDetails = ({ - layout, - itinerary -}: FareLegTableProps): JSX.Element => { - const hasLegProducts = !!itinerary?.fare?.legProducts; - const fareKeys = Object.keys(itinerary?.fare?.details); - - let legsWithFares; - - if (!hasLegProducts) { - // OTP1 Logic - legsWithFares = itinerary.legs - .map((leg, index) => { - const fares = fareKeys.reduce((prev, key) => { - const fareForKey = itinerary.fare.details[key]?.find( - detail => detail.legIndex === index - ); - if (fareForKey) { - prev[key] = fareForKey; - } - return prev; - }, {}); - return { - ...leg, - fares - }; - }) - .filter(leg => leg.transitLeg); - } else { - // OTP2 Logic using core-utils function - legsWithFares = getLegsWithFares(itinerary).filter(leg => leg.transitLeg); - } - +const FareLegTable = ({ layout, legs }: FareLegTableProps): JSX.Element => { + // the layout argument contains an object for every table to be displayed return (
{layout.map(config => ( ))}
); }; -export default FareLegDetails; +export default FareLegTable; diff --git a/packages/trip-details/src/index.tsx b/packages/trip-details/src/index.tsx index 7543b77f8..157e6135a 100644 --- a/packages/trip-details/src/index.tsx +++ b/packages/trip-details/src/index.tsx @@ -1,4 +1,3 @@ -import flatten from "flat"; import coreUtils from "@opentripplanner/core-utils"; import React, { ReactElement } from "react"; import { FormattedMessage, FormattedNumber } from "react-intl"; @@ -8,16 +7,14 @@ import { MoneyBillAlt } from "@styled-icons/fa-solid/MoneyBillAlt"; import { Leaf } from "@styled-icons/fa-solid/Leaf"; import { Route } from "@styled-icons/fa-solid/Route"; +import { getItineraryCost } from "@opentripplanner/core-utils/lib/itinerary"; +import { flatten } from "flat"; import * as S from "./styled"; import TripDetail from "./trip-detail"; import FareLegTable from "./fare-table"; import { boldText, renderFare } from "./utils"; -import { - TimeActiveDetailsProps, - TransitFareProps, - TripDetailsProps -} from "./types"; +import { FareType, TimeActiveDetailsProps, TripDetailsProps } from "./types"; // Load the default messages. import defaultEnglishMessages from "../i18n/en-US.yml"; @@ -63,54 +60,17 @@ function DefaultTimeActiveDetails({ ); } -/** - * Helper component that renders a transit fare entry. - */ -const TransitFare = ({ - fareKey, - fareNameFallback, - fareKeyNameMap, - transitFares -}: TransitFareProps): ReactElement => { - const currentFare = transitFares[fareKey]; - - // TODO: Is this needed? Every implementation of TransitFare does a check for currentFare's existence, although not the cents field - if (typeof currentFare?.cents !== "number") { - return ( - - ); - } - - return ( - - - - ); -}; - /** * Renders trip details such as departure instructions, fare amount, and minutes active. */ export function TripDetails({ className = "", co2Config, - defaultFareKey = "regular", + defaultFareType = { + headerKey: "cash-regular", + mediumId: "cash", + riderCategoryId: "regular" + }, DepartureDetails = null, displayTimeActive = true, FareDetails = null, @@ -122,63 +82,106 @@ export function TripDetails({ // process the transit fare const fareResult = coreUtils.itinerary.calculateTncFares(itinerary); const { currencyCode, maxTNCFare, minTNCFare } = fareResult; - const transitFares = itinerary?.fare?.fare; - - let companies = ""; - itinerary.legs.forEach(leg => { - if (leg.tncData) { - companies = leg.tncData.company; - } - }); - let fare; - const fareKeys = transitFares && Object.keys(transitFares).sort(); - - if (transitFares && fareKeys.length > 0) { - let defaultFare = defaultFareKey; - if (!transitFares[defaultFareKey]) { - defaultFare = "regular"; - } + const { companies, fareTypes } = itinerary.legs.reduce<{ + companies: string; + fareTypes: FareType[]; + }>( + (prev, leg) => { + if (leg.tncData) { + prev.companies = leg.tncData.company; + } + if (leg.fareProducts) { + leg.fareProducts.forEach(fp => { + const mediumId = fp.product.medium.id; + const riderCategoryId = fp.product.riderCategory.id; + if ( + prev.fareTypes.find( + ft => + !( + ft.mediumId === mediumId && + ft.riderCategoryId === riderCategoryId + ) + ) + ) { + prev.fareTypes.push({ mediumId, riderCategoryId }); + } + }); + } + return prev; + }, + { companies: "", fareTypes: [] } + ); + let fare; + if (fareTypes.length > 0) { + const defaultFareTotal = getItineraryCost( + itinerary.legs, + defaultFareType.riderCategoryId, + defaultFareType.mediumId + ); // Depending on if there are additional fares to display either render a or a
const TransitFareWrapper = - transitFares && fareKeys.length > 1 ? S.TransitFare : S.TransitFareSingle; + fareTypes.length > 1 ? S.TransitFare : S.TransitFareSingle; - fare = transitFares?.[defaultFare] && ( + const fareNameFallback = ( + + ); + + fare = defaultFareTotal.amount && ( - 1 ? "list-item" : "" }}> - + 1 ? "list-item" : "" }}> + {fareDetailsLayout ? ( // Show full ƒare details by leg - + ) : ( // Just show the fares for each payment type - fareKeys.map(fareKey => { + fareTypes.map(fareType => { // Don't show the default fare twice! - if (fareKey === defaultFare) { + if (fareType) { return null; } return ( - ); }) @@ -289,7 +292,7 @@ export function TripDetails({ ) } diff --git a/packages/trip-details/src/types.ts b/packages/trip-details/src/types.ts index 7a180ca2c..dd00eff80 100644 --- a/packages/trip-details/src/types.ts +++ b/packages/trip-details/src/types.ts @@ -1,6 +1,6 @@ // Prettier does not recognize the import type syntax. // eslint-disable-next-line prettier/prettier -import type { MassUnitOption, Fare, Itinerary, Money } from "@opentripplanner/types"; +import type { MassUnitOption, Itinerary, Money, Leg } from "@opentripplanner/types"; import type { ReactElement } from "react"; export interface TimeActiveDetailsProps { @@ -19,48 +19,48 @@ export interface DepartureDetailsProps { departureDate: Date; } -export enum FareTableText { - regular = "regular", - youth = "youth", - senior = "senior", - special = "special", - cash = "cash", - electronic = "electronic" +export interface FareType { + riderCategoryId: string; + mediumId: string; } +/** + * This is the interface used to define the layout for a particular fare table. + * The table with be rendered with the columsn defined here, + * with each row being an individual transit leg from the itinerary. + */ export interface FareTableLayout { - cols: { - header: FareTableText; - key?: string; - riderCategory?: string; - fareContainer?: string; - }[]; - header: FareTableText; + cols: (FareType & { + columnHeaderKey: string; + })[] + headerKey: string; } -export interface TransitFareData { - [key: string]: Money -} - -export interface FareDetailsProps { - maxTNCFare: number; - minTNCFare: number; - transitFares: TransitFareData; -} - export interface FareLegTableProps { layout?: FareTableLayout[]; - itinerary: Itinerary; + legs: Leg[]; } +// Total fare amount corresponding to a fare key +export type FareTotals = (FareType & { price: Money })[] + export interface TransitFareProps { - fareKey: string; + headerKey: string; + fareMediumId: string + riderCategoryId: string fareNameFallback?: ReactElement; fareKeyNameMap: { [key: string]: string; }; - transitFares: Fare; + fareTotals: FareTotals; } +export interface FareDetailsProps { + maxTNCFare: number; + minTNCFare: number; + legs: Leg[]; +} + + export interface TripDetailsProps { /** * Used for additional styling with styled components for example. @@ -73,7 +73,7 @@ export interface TripDetailsProps { /** * Determines which transit fare should be displayed by default, should there be multiple transit fare types. */ - defaultFareKey?: string; + defaultFareType?: { headerKey: string } & FareType; /** * Slot for a custom component to render the expandable section for departure. */ diff --git a/packages/trip-details/src/utils.tsx b/packages/trip-details/src/utils.tsx index 809c596c1..48f88c23c 100644 --- a/packages/trip-details/src/utils.tsx +++ b/packages/trip-details/src/utils.tsx @@ -1,21 +1,10 @@ import React, { ReactElement } from "react"; -import { FormattedMessage, FormattedNumber } from "react-intl"; -import { flatten } from "flat"; -import { FareTableText } from "./types"; - -// Load the default messages. -import defaultEnglishMessages from "../i18n/en-US.yml"; - -// HACK: We should flatten the messages loaded above because -// the YAML loaders behave differently between webpack and our version of jest: -// - the yaml loader for webpack returns a nested object, -// - the yaml loader for jest returns messages with flattened ids. -const defaultMessages: Record = flatten(defaultEnglishMessages); +import { FormattedNumber } from "react-intl"; /** * Format text bold (used with FormattedMessage). */ -export function boldText(contents: ReactElement): ReactElement { +export function boldText(contents: ReactElement | string): ReactElement { return {contents}; } @@ -39,63 +28,3 @@ export function renderFare(currencyCode: string, fare: number): ReactElement { /> ); } - -export const getFormattedTextForConfigKey = (textKey: FareTableText) => { - switch (textKey) { - case FareTableText.cash: - return ( - - ); - case FareTableText.electronic: - return ( - - ); - case FareTableText.youth: - return ( - - ); - case FareTableText.senior: - return ( - - ); - case FareTableText.special: - return ( - - ); - case FareTableText.regular: - default: - return ( - - ); - } -}; From 2a95a9365c1bbe791a7831a234f44bbee73b67a4 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 12 Jun 2023 15:05:23 -0700 Subject: [PATCH 07/40] test: add test for getlegfare --- .../core-utils/src/__tests__/itinerary.js | 77 +++++++++++++------ 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/packages/core-utils/src/__tests__/itinerary.js b/packages/core-utils/src/__tests__/itinerary.js index 2a6b8bc2f..09bdcc3bf 100644 --- a/packages/core-utils/src/__tests__/itinerary.js +++ b/packages/core-utils/src/__tests__/itinerary.js @@ -2,7 +2,7 @@ import { calculateTncFares, getCompanyFromLeg, getDisplayedStopId, - getTransitFare, + getLegCost, isTransit } from "../itinerary"; @@ -35,30 +35,6 @@ describe("util > itinerary", () => { }); }); - describe("getTransitFare", () => { - it("should return defaults with missing fare", () => { - const { transitFare } = getTransitFare(null); - // transit fare value should be zero - expect(transitFare).toMatchSnapshot(); - }); - - it("should work with valid fare component", () => { - const fareComponent = { - currency: { - currency: "USD", - defaultFractionDigits: 2, - currencyCode: "USD", - symbol: "$" - }, - cents: 575 - }; - const { currencyCode, transitFare } = getTransitFare(fareComponent); - expect(currencyCode).toEqual(fareComponent.currency.currencyCode); - // Snapshot tests - expect(transitFare).toMatchSnapshot(); - }); - }); - describe("calculateTncFares", () => { it("should return the correct amounts and currency for an itinerary with TNC", () => { const fareResult = calculateTncFares(tncItinerary, true); @@ -111,4 +87,55 @@ describe("util > itinerary", () => { expect(getDisplayedStopId(basePlace)).toBeFalsy(); }); }); + + describe("getLegCost", () => { + it("should return the total cost for a leg", () => { + const leg = { + fareProducts: [ + { + product: { + medium: { id: "cash" }, + riderCategory: { id: "regular" }, + name: "rideCost", + price: { amount: 200, currency: "USD" } + } + } + ] + }; + const result = getLegCost(leg, "cash", "regular"); + expect(result.price).toEqual({ amount: 200, currency: "USD" }); + }); + + it("should return the transfer discount amount if a transfer was used", () => { + const leg = { + fareProducts: [ + { + product: { + medium: { id: "cash" }, + riderCategory: { id: "regular" }, + name: "rideCost", + price: { amount: 200, currency: "USD" } + } + }, + { + product: { + name: "transfer", + price: { amount: 50, currency: "USD" }, + medium: { id: "cash" }, + riderCategory: { id: "regular" } + } + } + ] + }; + const result = getLegCost(leg, "cash", "regular"); + expect(result.price).toEqual({ amount: 200, currency: "USD" }); + expect(result.transferAmount).toEqual({ amount: 50, currency: "USD" }); + }); + + it("should return undefined if no fare products exist on the leg", () => { + const leg = {}; + const result = getLegCost(leg, "cash", "regular"); + expect(result.price).toBeUndefined(); + }); + }); }); From d1025105774caa3e9e2ddfd25dc6367ac0e537d3 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 12 Jun 2023 16:39:07 -0700 Subject: [PATCH 08/40] feat(types): Remove old fare info, add GraphQL style FareProducts to legs --- packages/types/src/index.ts | 60 +++++-------------------------------- 1 file changed, 7 insertions(+), 53 deletions(-) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index bdbac3260..b6a29dd68 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -187,11 +187,6 @@ export type Config = { transitOperators?: TransitOperator[]; }; -type FeedScopedId = { - agencyId?: string; - id?: string; -}; - export type EncodedPolyline = { length: number; points: string; @@ -336,55 +331,20 @@ export type Leg = { tripBlockId?: string; tripId?: string; walkingBike?: boolean; - /** - * Below this are extra properties added in OTP-RR - * They are not returned in the API response - */ - fareProducts?: Array; + fareProducts?: Array<{ id: string; product: FareProduct }>; }; /** * Describes the cost of an itinerary leg. */ export type Money = { - cents: number; + amount: number; currency: { - defaultFractionDigits: number; - currencyCode: string; - symbol: string; - currency: string; + code: string; + digits: number; }; }; -/** - * Describes a fare id or route to which a fare applies. - */ -type ApplicableId = string | FeedScopedId; - -export type FareDetail = { - fareId?: ApplicableId; - isTransfer?: boolean; - legIndex?: number; - price: Money; - routes?: ApplicableId[]; -}; - -export type FareDetails = Record; - -/** - * Represents the fare component of an itinerary of an OTP plan response. See - * detailed documentation in OTP webservice documentation here: - * http://otp-docs.ibi-transit.com/api/json_Fare.html - * - * NOTE: so far the fare includes ONLY a fare encountered on public transit and - * not any bike rental or TNC rental fees. - */ -export type Fare = { - details?: FareDetails; - fare?: Record; - legProducts?: Array; -}; - /** * Represents an itinerary of an OTP plan response. See detailed documentation * in OTP webservice documentation here: @@ -397,7 +357,6 @@ export type Itinerary = { elevationGained: number; elevationLost: number; endTime: number; - fare?: Fare; legs: Leg[]; startTime: number; tooSloped?: boolean; @@ -771,24 +730,19 @@ export type ModeButtonDefinition = { }; export type FareProduct = { - amount: Money; + price: Money; id: string; name: string; - category: { + riderCategory?: { id: string; name: string; }; - container: { + medium?: { id: string; name: string; }; }; -export type LegProduct = { - legIndices: Array; - products: Array; -}; - /** * Options for units of mass (used in CO₂ calculation config) */ From c7b7cad0aef6cb2a5933de56a11ed0fb6fe309a4 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 12 Jun 2023 18:21:23 -0700 Subject: [PATCH 09/40] refactor(itinerary-body): re-add showRouteFares --- packages/itinerary-body/src/types.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/itinerary-body/src/types.ts b/packages/itinerary-body/src/types.ts index cc76a5213..b57fff757 100644 --- a/packages/itinerary-body/src/types.ts +++ b/packages/itinerary-body/src/types.ts @@ -183,6 +183,8 @@ interface ItineraryBodySharedProps { showLegIcon?: boolean; /** If true, will show the right column with the map button */ showMapButtonColumn?: boolean; + /** If true, will show fare information in transit leg bodies */ + showRouteFares?: boolean; /** If true, shows the view trip button in transit leg bodies */ showViewTripButton?: boolean; /** From 0ca75a4891a1e60fe6c947c896bf510a362c7c85 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 12 Jun 2023 18:29:16 -0700 Subject: [PATCH 10/40] fix(core-utils): adds new FareProducts API to query --- packages/core-utils/src/planQuery.graphql | 57 ++++++++++++++++------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/packages/core-utils/src/planQuery.graphql b/packages/core-utils/src/planQuery.graphql index f65355cbe..bf15a05ee 100644 --- a/packages/core-utils/src/planQuery.graphql +++ b/packages/core-utils/src/planQuery.graphql @@ -1,18 +1,18 @@ query Plan( - $fromPlace: String! - $toPlace: String! - $modes: [TransportMode] - $time: String - $date: String - $wheelchair: Boolean - $bikeReluctance: Float - $carReluctance: Float - $walkReluctance: Float - $arriveBy: Boolean - $intermediatePlaces: [InputCoordinates] - $preferred: InputPreferred - $unpreferred: InputUnpreferred - $banned: InputBanned + $fromPlace: String!, + $toPlace: String!, + $modes: [TransportMode], + $time: String, + $date: String, + $wheelchair: Boolean, + $bikeReluctance: Float, + $carReluctance: Float, + $walkReluctance: Float, + $arriveBy: Boolean, + $intermediatePlaces: [InputCoordinates], + $preferred: InputPreferred, + $unpreferred: InputUnpreferred, + $banned: InputBanned, $numItineraries: Int ) { plan( @@ -23,7 +23,6 @@ query Plan( date: $date fromPlace: $fromPlace intermediatePlaces: $intermediatePlaces - # Currently only supporting EN locale, used for times and text locale: "en" numItineraries: $numItineraries preferred: $preferred @@ -38,7 +37,7 @@ query Plan( accessibilityScore duration endTime - legs { + legs { accessibilityScore agency { alerts { @@ -59,6 +58,28 @@ query Plan( dropoffType duration endTime + fareProducts { + id + product { + id + medium { + id + name + } + name + price { + amount + currency { + code + digits + } + } + riderCategory { + id + name + } + } + } from { lat lon @@ -137,7 +158,7 @@ query Plan( } lat lon - relativeDirection + relativeDirection stayOn streetName } @@ -180,4 +201,4 @@ query Plan( inputField } } -} +} \ No newline at end of file From 7a5652f5e37d98637f8f40bcf47322161adb53c2 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Tue, 13 Jun 2023 13:41:34 -0700 Subject: [PATCH 11/40] refactor(itinerary-body): update legprodct mock --- .../itineraries/otp2-with-fareproducts.json | 2302 ++++++++++------- 1 file changed, 1332 insertions(+), 970 deletions(-) diff --git a/packages/itinerary-body/src/__mocks__/itineraries/otp2-with-fareproducts.json b/packages/itinerary-body/src/__mocks__/itineraries/otp2-with-fareproducts.json index 177302f1b..5fb61c392 100644 --- a/packages/itinerary-body/src/__mocks__/itineraries/otp2-with-fareproducts.json +++ b/packages/itinerary-body/src/__mocks__/itineraries/otp2-with-fareproducts.json @@ -1,1130 +1,1492 @@ { - "duration": 3583, - "startTime": 1674505485000, - "endTime": 1674509068000, - "walkTime": 930, - "transitTime": 2340, - "waitingTime": 313, - "walkDistance": 1157.33, - "walkLimitExceeded": false, - "generalizedCost": 5616, - "elevationLost": 0, - "elevationGained": 0, - "transfers": 1, - "fare": { - "fare": { - "senior": { - "cents": 225, - "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" - } + "accessibilityScore": null, + "duration": 5710, + "endTime": 1686626346000, + "legs": [ + { + "accessibilityScore": null, + "fareProducts": [], + "agency": null, + "arrivalDelay": 0, + "departureDelay": 0, + "distance": 1563.5, + "dropoffType": "SCHEDULED", + "duration": 1264, + "endTime": 1686621900000, + "from": { + "lat": 47.8308509, + "lon": -122.3177839, + "name": "47.83085, -122.31778", + "rentalVehicle": null, + "stop": null, + "vertexType": "NORMAL" }, - "electronicSpecial": { - "cents": 150, - "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" - } + "interlineWithPreviousLeg": false, + "intermediateStops": null, + "legGeometry": { + "length": 49, + "points": "e~|bHdeqiV@xJpA?~A?H?|A?n@@jC@N?L?xAAdDCrB@bA?pDAL?rBA~@AhD?xBCV?|@?t@?d@@X?Z?V?H@V?T?J?N??U@sA?{@?c@@Q?}@@qBF?DkF?WBmC@IDI@CL@\\V@A" }, - "electronicSenior": { - "cents": 125, - "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "mode": "WALK", + "pickupBookingInfo": null, + "pickupType": "SCHEDULED", + "realTime": false, + "realtimeState": null, + "rentedBike": false, + "route": null, + "startTime": 1686620636000, + "steps": [ + { + "absoluteDirection": "WEST", + "alerts": [], + "area": false, + "distance": 141.18, + "elevationProfile": [], + "lat": 47.8309108, + "lon": -122.3177846, + "relativeDirection": "DEPART", + "stayOn": false, + "streetName": "185th Place Southwest" + }, + { + "absoluteDirection": "SOUTH", + "alerts": [], + "area": false, + "distance": 1080.61, + "elevationProfile": [], + "lat": 47.830901, + "lon": -122.3196758, + "relativeDirection": "LEFT", + "stayOn": false, + "streetName": "64th Avenue West" + }, + { + "absoluteDirection": "EAST", + "alerts": [], + "area": false, + "distance": 148.37, + "elevationProfile": [], + "lat": 47.8211832, + "lon": -122.3196493, + "relativeDirection": "LEFT", + "stayOn": false, + "streetName": "196th Street Southwest" + }, + { + "absoluteDirection": "SOUTH", + "alerts": [], + "area": false, + "distance": 5.26, + "elevationProfile": [], + "lat": 47.8211587, + "lon": -122.3176623, + "relativeDirection": "RIGHT", + "stayOn": false, + "streetName": "service road" + }, + { + "absoluteDirection": "EAST", + "alerts": [], + "area": false, + "distance": 188.06, + "elevationProfile": [], + "lat": 47.8211115, + "lon": -122.3176665, + "relativeDirection": "LEFT", + "stayOn": true, + "streetName": "sidewalk" } + ], + "to": { + "lat": 47.820787, + "lon": -122.315656, + "name": "Crossroads SB Station at 196th St SW", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "2764", + "gtfsId": "CommTrans:2764", + "id": "U3RvcDpDb21tVHJhbnM6Mjc2NA" + }, + "vertexType": "TRANSIT" }, - "electronicYouth": { - "cents": 0, - "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "transitLeg": false, + "trip": null + }, + { + "accessibilityScore": null, + "fareProducts": [ + { + "id": "ea135a2b-9d68-3a39-904c-9e60a8688e9c", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 1.25, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "senior", + "id": "orca:senior" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "5134f5c4-6055-3250-977c-62c1c7611a44", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 0, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "youth", + "id": "orca:youth" + }, + "medium": { + "name": "cash", + "id": "orca:cash" + } + } + }, + { + "id": "c3cd5fea-fc52-3368-85e5-97ac250cdba3", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 1.25, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "special", + "id": "orca:special" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "6a93fabf-1515-3f43-af14-f8803568504c", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 2.5, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "regular", + "id": "orca:regular" + }, + "medium": { + "name": "cash", + "id": "orca:cash" + } + } + }, + { + "id": "095bed9e-c459-361e-bc5a-b944196874b6", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 0, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "youth", + "id": "orca:youth" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "2505a198-c406-3ebd-aa77-ac2b8094bcc8", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 2.5, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "regular", + "id": "orca:regular" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "8b25f594-46f2-3d5e-ae92-ac7f28d8b043", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 1.25, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "senior", + "id": "orca:senior" + }, + "medium": { + "name": "cash", + "id": "orca:cash" + } + } } + ], + "agency": { + "alerts": [], + "id": "QWdlbmN5OkNvbW1UcmFuczoyOQ", + "name": "Community Transit", + "timezone": "America/Los_Angeles", + "url": "http://www.communitytransit.org/" }, - "electronicRegular": { - "cents": 250, - "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" - } + "arrivalDelay": 0, + "departureDelay": 0, + "distance": 6117.26, + "dropoffType": "SCHEDULED", + "duration": 1140, + "endTime": 1686623040000, + "from": { + "lat": 47.820787, + "lon": -122.315656, + "name": "Crossroads SB Station at 196th St SW", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "2764", + "gtfsId": "CommTrans:2764", + "id": "U3RvcDpDb21tVHJhbnM6Mjc2NA" + }, + "vertexType": "TRANSIT" }, - "youth": { - "cents": 0, - "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "interlineWithPreviousLeg": false, + "intermediateStops": [ + { + "lat": 47.813736, + "locationType": "STOP", + "lon": -122.321744, + "name": "College SB Station at 204th St SW", + "stopCode": "2760", + "stopId": "U3RvcDpDb21tVHJhbnM6Mjc2MA" + }, + { + "lat": 47.802879, + "locationType": "STOP", + "lon": -122.329612, + "name": "216th St SW SB Station", + "stopCode": "2754", + "stopId": "U3RvcDpDb21tVHJhbnM6Mjc1NA" + }, + { + "lat": 47.782854, + "locationType": "STOP", + "lon": -122.344036, + "name": "238th St SW SB Station", + "stopCode": "2748", + "stopId": "U3RvcDpDb21tVHJhbnM6Mjc0OA" } + ], + "legGeometry": { + "length": 272, + "points": "o~zbH|vpiVv@n@LJh@b@dA|@TPHFXT|@t@ZVPNl@f@f@`@LJ`@Zl@h@n@h@t@l@\\VlB~Ab@^f@`@VTNLNJnAbArAhATR\\XHF\\XLJf@`@LJTRzAnAf@^RNHF??DBNJ`@ZLHh@`@JHRLf@\\LHdAp@PLf@Zr@d@PJv@f@HFb@XXRrAz@`@Vv@f@\\TXRLHLHLHJFn@b@LHJHb@Xp@b@NJfAp@HF\\TRLl@^\\TTN\\Td@XXPv@f@xA`Aj@^PJn@b@p@b@TN|BxADBLHb@ZTNHFl@^HFVNXP\\T^Th@\\\\TfAt@FD??p@b@HF`@VNHTNZRj@^d@ZjAv@bAn@bAn@FDxBvAt@d@bAn@JFNJNHvA~@hAt@t@d@NJ^T`@VTNXPn@b@r@f@LHHF|@j@ZTv@f@vA|@NJVNZRd@Zb@XTNXPf@\\TLb@XdAr@zA`ARLj@`@PLh@\\VNf@\\hAt@RLTLTNTNLHLHRLPLTNdAp@h@\\xA~@b@XLHZR~@l@^V`BdANJd@Z`An@VNZR^V\\TZRjBjAfAr@d@Z`GxD^VXPNJh@Zt@d@z@j@b@XJHlAv@`Al@VPFD??LHZRTNPLHFJHNJNLPLLJ\\VLJt@l@b@\\RP`@Z\\VXRXPd@VPJTJRHPFZJVHXHVFPDRD`@FXB\\@X@^?T?hAEz@GdAILA|@Eb@ANAjACr@Cr@AX?R?P?VAX?l@?T?f@?T?|AAH?BqBAg@?{A?m@?c@?iB?u@?yCe@?Eu@Fw@?sF" }, - "regular": { - "cents": 250, - "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" - } + "mode": "BUS", + "pickupBookingInfo": null, + "pickupType": "SCHEDULED", + "realTime": false, + "realtimeState": null, + "rentedBike": null, + "route": { + "alerts": [], + "color": "006aff", + "id": "Um91dGU6Q29tbVRyYW5zOjcwMQ", + "longName": "Everett - Aurora Village", + "shortName": "Swift Blue", + "textColor": "ffffff", + "type": 3 + }, + "startTime": 1686621900000, + "steps": [], + "to": { + "lat": 47.774297, + "lon": -122.341069, + "name": "Aurora Village Station", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "2742", + "gtfsId": "CommTrans:2742", + "id": "U3RvcDpDb21tVHJhbnM6Mjc0Mg" + }, + "vertexType": "TRANSIT" + }, + "transitLeg": true, + "trip": { + "gtfsId": "CommTrans:11084840__MCOB-DO:123:0:Weekday:1:23MAR:67020:12345", + "id": "VHJpcDpDb21tVHJhbnM6MTEwODQ4NDBfX01DT0ItRE86MTIzOjA6V2Vla2RheToxOjIzTUFSOjY3MDIwOjEyMzQ1", + "tripHeadsign": "Aurora Village" } }, - "details": { - "senior": [], - "electronicSpecial": [], - "electronicSenior": [], - "electronicYouth": [], - "electronicRegular": [], - "youth": [], - "regular": [] + { + "accessibilityScore": null, + "fareProducts": [], + "agency": null, + "arrivalDelay": 0, + "departureDelay": 0, + "distance": 138.12, + "dropoffType": "SCHEDULED", + "duration": 131, + "endTime": 1686623171000, + "from": { + "lat": 47.774297, + "lon": -122.341069, + "name": "Aurora Village Station", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "2742", + "gtfsId": "CommTrans:2742", + "id": "U3RvcDpDb21tVHJhbnM6Mjc0Mg" + }, + "vertexType": "TRANSIT" + }, + "interlineWithPreviousLeg": false, + "intermediateStops": null, + "legGeometry": { + "length": 15, + "points": "i|qbHtvuiVE??t@?zBJ??tB@L@C?A@C?C?ACI?O@?" + }, + "mode": "WALK", + "pickupBookingInfo": null, + "pickupType": "SCHEDULED", + "realTime": false, + "realtimeState": null, + "rentedBike": false, + "route": null, + "startTime": 1686623040000, + "steps": [ + { + "absoluteDirection": "WEST", + "alerts": [], + "area": false, + "distance": 65.97, + "elevationProfile": [], + "lat": 47.7743217, + "lon": -122.3410691, + "relativeDirection": "DEPART", + "stayOn": false, + "streetName": "open area" + }, + { + "absoluteDirection": "SOUTH", + "alerts": [], + "area": false, + "distance": 6.04, + "elevationProfile": [], + "lat": 47.774323, + "lon": -122.341952, + "relativeDirection": "LEFT", + "stayOn": true, + "streetName": "path" + }, + { + "absoluteDirection": "WEST", + "alerts": [], + "area": false, + "distance": 49.38, + "elevationProfile": [], + "lat": 47.7742687, + "lon": -122.3419519, + "relativeDirection": "RIGHT", + "stayOn": true, + "streetName": "sidewalk" + }, + { + "absoluteDirection": "SOUTHEAST", + "alerts": [], + "area": true, + "distance": 16.73, + "elevationProfile": [], + "lat": 47.7742565, + "lon": -122.3426111, + "relativeDirection": "HARD_LEFT", + "stayOn": true, + "streetName": "open area" + } + ], + "to": { + "lat": 47.7742424, + "lon": -122.342407, + "name": "Aurora Village Transit Center - Bay 10", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "16100", + "gtfsId": "kcm:16100", + "id": "U3RvcDprY206MTYxMDA" + }, + "vertexType": "TRANSIT" + }, + "transitLeg": false, + "trip": null }, - "legProducts": [ - { - "legIndices": [1], - "products": [ - { - "id": "orcaFares:farePayment", + { + "accessibilityScore": null, + "fareProducts": [ + { + "id": "ca24dfed-196e-38f8-941e-88de142005df", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 0, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "senior", + "id": "orca:senior" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "e4c53703-37ce-3cc2-851f-3db7f40882d8", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "amount": 1.25, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "senior", + "id": "orca:senior" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "2f8986c1-2552-345a-a020-57506f70838f", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 0, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "youth", + "id": "orca:youth" + }, + "medium": { + "name": "cash", + "id": "orca:cash" + } + } + }, + { + "id": "2d3b06e8-6521-338e-b674-f8ce3c09d1ed", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 0.25, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "special", + "id": "orca:special" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "6b5bae4b-d495-3133-9924-f199ef1f1a72", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "amount": 1.25, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "special", + "id": "orca:special" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "f87203f1-9dba-3dd0-90c0-18cc2ed361a2", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 0, + "price": { + "amount": 2.75, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "regular", + "id": "orca:regular" }, - "category": { - "id": "orcaFares", - "name": "youth" + "medium": { + "name": "cash", + "id": "orca:cash" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "c58a11c1-00d2-3093-bada-28543482a861", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 125, + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "cash" + "riderCategory": { + "name": "youth", + "id": "orca:youth" }, - "category": { - "id": "orcaFares", - "name": "senior" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "65becef9-10d7-3e6c-8a6b-f8037ae57aec", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 0, + "price": { + "amount": 0.25, + "currency": { + "code": "USD", + "digits": 2 + } + }, + "riderCategory": { + "name": "regular", + "id": "orca:regular" + }, + "medium": { + "name": "electronic", + "id": "orca:electronic" + } + } + }, + { + "id": "6e098f71-365a-3540-af1a-398a083028de", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "amount": 2.5, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "cash" + "riderCategory": { + "name": "regular", + "id": "orca:regular" }, - "category": { - "id": "orcaFares", - "name": "youth" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "5ba0d2b6-2539-36ad-b808-85ba1957e260", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 125, + "price": { + "amount": 1, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "senior", + "id": "orca:senior" }, - "category": { - "id": "orcaFares", - "name": "special" + "medium": { + "name": "cash", + "id": "orca:cash" } - }, - { - "id": "orcaFares:farePayment", + } + } + ], + "agency": { + "alerts": [], + "id": "QWdlbmN5OmtjbTox", + "name": "Metro Transit", + "timezone": "America/Los_Angeles", + "url": "https://kingcounty.gov/en/dept/metro" + }, + "arrivalDelay": 0, + "departureDelay": 0, + "distance": 9663.15, + "dropoffType": "SCHEDULED", + "duration": 1260, + "endTime": 1686624720000, + "from": { + "lat": 47.7742424, + "lon": -122.342407, + "name": "Aurora Village Transit Center - Bay 10", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "16100", + "gtfsId": "kcm:16100", + "id": "U3RvcDprY206MTYxMDA" + }, + "vertexType": "TRANSIT" + }, + "interlineWithPreviousLeg": false, + "intermediateStops": [ + { + "lat": 47.7737427, + "locationType": "STOP", + "lon": -122.346207, + "name": "Aurora Ave N & N 200th St", + "stopCode": "75700", + "stopId": "U3RvcDprY206NzU3MDA" + }, + { + "lat": 47.7672043, + "locationType": "STOP", + "lon": -122.3461, + "name": "Aurora Ave N & N 192nd St", + "stopCode": "75730", + "stopId": "U3RvcDprY206NzU3MzA" + }, + { + "lat": 47.7628479, + "locationType": "STOP", + "lon": -122.346184, + "name": "Aurora Ave N & N 185th St", + "stopCode": "75740", + "stopId": "U3RvcDprY206NzU3NDA" + }, + { + "lat": 47.7594452, + "locationType": "STOP", + "lon": -122.346237, + "name": "Aurora Ave N & N 180th St", + "stopCode": "75750", + "stopId": "U3RvcDprY206NzU3NTA" + }, + { + "lat": 47.7552986, + "locationType": "STOP", + "lon": -122.345856, + "name": "Aurora Ave N & N 175th St", + "stopCode": "75760", + "stopId": "U3RvcDprY206NzU3NjA" + }, + { + "lat": 47.7520294, + "locationType": "STOP", + "lon": -122.345741, + "name": "Aurora Ave N & N 170th St", + "stopCode": "75770", + "stopId": "U3RvcDprY206NzU3NzA" + }, + { + "lat": 47.7483559, + "locationType": "STOP", + "lon": -122.345688, + "name": "Aurora Ave N & N 165th St", + "stopCode": "75780", + "stopId": "U3RvcDprY206NzU3ODA" + }, + { + "lat": 47.7446899, + "locationType": "STOP", + "lon": -122.34565, + "name": "Aurora Ave N & N 160th St", + "stopCode": "75790", + "stopId": "U3RvcDprY206NzU3OTA" + }, + { + "lat": 47.7408867, + "locationType": "STOP", + "lon": -122.345497, + "name": "Aurora Ave N & N 155th St", + "stopCode": "75800", + "stopId": "U3RvcDprY206NzU4MDA" + }, + { + "lat": 47.7386818, + "locationType": "STOP", + "lon": -122.345428, + "name": "Aurora Ave N & N 152nd St", + "stopCode": "75810", + "stopId": "U3RvcDprY206NzU4MTA" + }, + { + "lat": 47.7335701, + "locationType": "STOP", + "lon": -122.345268, + "name": "Aurora Ave N & N 145th St", + "stopCode": "6950", + "stopId": "U3RvcDprY206Njk1MA" + }, + { + "lat": 47.726429, + "locationType": "STOP", + "lon": -122.3451, + "name": "Aurora Ave N & N 135th St", + "stopCode": "6990", + "stopId": "U3RvcDprY206Njk5MA" + }, + { + "lat": 47.7229614, + "locationType": "STOP", + "lon": -122.345078, + "name": "Aurora Ave N & N 130th St", + "stopCode": "7000", + "stopId": "U3RvcDprY206NzAwMA" + }, + { + "lat": 47.719902, + "locationType": "STOP", + "lon": -122.345047, + "name": "Aurora Ave N & N 125th St", + "stopCode": "7010", + "stopId": "U3RvcDprY206NzAxMA" + }, + { + "lat": 47.7119751, + "locationType": "STOP", + "lon": -122.34491, + "name": "Aurora Ave N & N 115th St", + "stopCode": "7040", + "stopId": "U3RvcDprY206NzA0MA" + }, + { + "lat": 47.7046356, + "locationType": "STOP", + "lon": -122.344856, + "name": "Aurora Ave N & N 105th St", + "stopCode": "7080", + "stopId": "U3RvcDprY206NzA4MA" + }, + { + "lat": 47.701088, + "locationType": "STOP", + "lon": -122.34481, + "name": "Aurora Ave N & N 100th St", + "stopCode": "7100", + "stopId": "U3RvcDprY206NzEwMA" + }, + { + "lat": 47.6974945, + "locationType": "STOP", + "lon": -122.344704, + "name": "Aurora Ave N & N 95th St", + "stopCode": "7120", + "stopId": "U3RvcDprY206NzEyMA" + }, + { + "lat": 47.6939621, + "locationType": "STOP", + "lon": -122.344734, + "name": "Aurora Ave N & N 90th St", + "stopCode": "7140", + "stopId": "U3RvcDprY206NzE0MA" + } + ], + "legGeometry": { + "length": 168, + "points": "q{qbH`_viV?`AB~R?b@\\Cr@???dB?rBE~@A`HA|IElGArBC??f@?`DBpA?fB?pA@r@BhDBdB@lA???~@BbDDr@?|BBxAB|@?v@?PCb@?HA??v@AtAIjBInBGn@AvAGhES~BM??TA`AE`AA`B?hACbDCfB?|@C??v@AxDCnAAhA?bB?pA?xAA`AA??l@?n@?r@?|@CxAAj@?pB@vA?vB?dAA??|CEv@?fAE`CIhA?~CEnBC??~JIt@A??vBEz@AZCrAApAEfBEvFCvDCrBA??d@?RM~DA|FAlB?hJCfJGxA???pB?~EAlHCt@???dCArD?THxBAJKlCA??bA?r]OJL`HELMxCCbA???jPIbFAlFA|@CjBALLpDCrAA??|@?nCAnC?pCCnC?dAA??nB?`DCRItDC\\?rC?~@???pACpC?pCArA?NHh@?pCCj@???bB?jA?JKx@?fAAhA?~A?LH`@?pCAfC?" + }, + "mode": "BUS", + "pickupBookingInfo": null, + "pickupType": "SCHEDULED", + "realTime": false, + "realtimeState": null, + "rentedBike": null, + "route": { + "alerts": [], + "color": null, + "id": "Um91dGU6a2NtOjEwMjYxNQ", + "longName": null, + "shortName": "E Line", + "textColor": null, + "type": 3 + }, + "startTime": 1686623460000, + "steps": [], + "to": { + "lat": 47.6898766, + "lon": -122.344681, + "name": "Aurora Ave N & N 85th St", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "7160", + "gtfsId": "kcm:7160", + "id": "U3RvcDprY206NzE2MA" + }, + "vertexType": "TRANSIT" + }, + "transitLeg": true, + "trip": { + "gtfsId": "kcm:585679864", + "id": "VHJpcDprY206NTg1Njc5ODY0", + "tripHeadsign": "Downtown Seattle" + } + }, + { + "accessibilityScore": null, + "fareProducts": [], + "agency": null, + "arrivalDelay": 0, + "departureDelay": 0, + "distance": 69.62, + "dropoffType": "SCHEDULED", + "duration": 62, + "endTime": 1686624782000, + "from": { + "lat": 47.6898766, + "lon": -122.344681, + "name": "Aurora Ave N & N 85th St", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "7160", + "gtfsId": "kcm:7160", + "id": "U3RvcDprY206NzE2MA" + }, + "vertexType": "TRANSIT" + }, + "interlineWithPreviousLeg": false, + "intermediateStops": null, + "legGeometry": { + "length": 19, + "points": "ulabHhmviV?BE?AAS?A@W?AAM?G?E?I?M?C?A@ABACE??D" + }, + "mode": "WALK", + "pickupBookingInfo": null, + "pickupType": "SCHEDULED", + "realTime": false, + "realtimeState": null, + "rentedBike": false, + "route": null, + "startTime": 1686624720000, + "steps": [ + { + "absoluteDirection": "NORTH", + "alerts": [], + "area": false, + "distance": 69.62, + "elevationProfile": [], + "lat": 47.6898767, + "lon": -122.3447008, + "relativeDirection": "DEPART", + "stayOn": false, + "streetName": "sidewalk" + } + ], + "to": { + "lat": 47.6904907, + "lon": -122.344734, + "name": "N 85th St & Aurora Ave N", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "5370", + "gtfsId": "kcm:5370", + "id": "U3RvcDprY206NTM3MA" + }, + "vertexType": "TRANSIT" + }, + "transitLeg": false, + "trip": null + }, + { + "accessibilityScore": null, + "fareProducts": [ + { + "id": "2db1b8be-49cd-3e32-8e21-6a2731f7e006", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 125, + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "senior", + "id": "orca:senior" }, - "category": { - "id": "orcaFares", - "name": "senior" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", - "name": "rideCost", - "amount": { - "cents": 250, + } + }, + { + "id": "7cf53db2-09ff-3b98-b9ef-b3278dc3ab04", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "amount": 1.25, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "senior", + "id": "orca:senior" }, - "category": { - "id": "orcaFares", - "name": "regular" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "710d3a35-1450-3130-b93d-c67a8be4b527", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 250, + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "cash" + "riderCategory": { + "name": "youth", + "id": "orca:youth" }, - "category": { - "id": "orcaFares", - "name": "regular" + "medium": { + "name": "cash", + "id": "orca:cash" } } - ] - }, - { - "legIndices": [3], - "products": [ - { - "id": "orcaFares:farePayment", + }, + { + "id": "f5b38df6-10a0-35c1-92d6-679eddfce6ff", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 0, + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "special", + "id": "orca:special" }, - "category": { - "id": "orcaFares", - "name": "youth" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", - "name": "rideCost", - "amount": { - "cents": 100, + } + }, + { + "id": "d74b0553-a50d-3f52-9572-74aae1033a6a", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "amount": 1.5, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "cash" + "riderCategory": { + "name": "special", + "id": "orca:special" }, - "category": { - "id": "orcaFares", - "name": "senior" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "5dcb16dc-64f5-3ab3-99b1-29cf0d74c4d5", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 0, + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "cash" + "riderCategory": { + "name": "regular", + "id": "orca:regular" }, - "category": { - "id": "orcaFares", - "name": "youth" + "medium": { + "name": "cash", + "id": "orca:cash" } - }, - { - "id": "orcaFares:farePayment", - "name": "rideCost", - "amount": { - "cents": 25, + } + }, + { + "id": "e38356c5-9559-3a39-a691-4fce5ef857d9", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "amount": 2.75, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "regular", + "id": "orca:regular" }, - "category": { - "id": "orcaFares", - "name": "special" + "medium": { + "name": "cash", + "id": "orca:cash" } - }, - { - "id": "orcaFares:farePayment", - "name": "transfer", - "amount": { - "cents": 125, + } + }, + { + "id": "462c8831-4aa6-3ab8-92d3-e5610bdc9815", + "product": { + "id": "orca:farePayment", + "name": "rideCost", + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "youth", + "id": "orca:youth" }, - "category": { - "id": "orcaFares", - "name": "special" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "36578739-9027-38f3-9891-76fcb1d0218e", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 0, + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "regular", + "id": "orca:regular" }, - "category": { - "id": "orcaFares", - "name": "senior" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "f6abeea9-9870-31f8-a19f-2a2b7f7afda5", + "product": { + "id": "orca:farePayment", "name": "transfer", - "amount": { - "cents": 125, + "price": { + "amount": 2.75, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "regular", + "id": "orca:regular" }, - "category": { - "id": "orcaFares", - "name": "senior" + "medium": { + "name": "electronic", + "id": "orca:electronic" } - }, - { - "id": "orcaFares:farePayment", + } + }, + { + "id": "3bd1b287-bfcc-3ef8-8736-eeeca140dbff", + "product": { + "id": "orca:farePayment", "name": "rideCost", - "amount": { - "cents": 0, + "price": { + "amount": 0, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "electronic" + "riderCategory": { + "name": "senior", + "id": "orca:senior" }, - "category": { - "id": "orcaFares", - "name": "regular" + "medium": { + "name": "cash", + "id": "orca:cash" } - }, - { - "id": "orcaFares:farePayment", - "name": "rideCost", - "amount": { - "cents": 0, + } + }, + { + "id": "5fab13fb-3029-3033-bde8-c2c2e29fa1de", + "product": { + "id": "orca:farePayment", + "name": "transfer", + "price": { + "amount": 1, "currency": { - "currency": "USD", - "defaultFractionDigits": 2, - "currencyCode": "USD", - "symbol": "$" + "code": "USD", + "digits": 2 } }, - "container": { - "id": "orcaFares", - "name": "cash" + "riderCategory": { + "name": "senior", + "id": "orca:senior" }, - "category": { - "id": "orcaFares", - "name": "regular" + "medium": { + "name": "cash", + "id": "orca:cash" } } - ] - } - ] - }, - "legs": [ - { - "startTime": 1674505485000, - "endTime": 1674506100000, - "departureDelay": 0, - "arrivalDelay": 0, - "realTime": false, - "distance": 802.9, - "generalizedCost": 1204, - "pathway": false, - "mode": "WALK", - "transitLeg": false, - "route": "", - "agencyTimeZoneOffset": -28800000, - "interlineWithPreviousLeg": false, - "from": { - "name": "47.83549, -122.31293", - "lon": -122.3129313, - "lat": 47.8354853, - "departure": 1674505485000, - "vertexType": "NORMAL" - }, - "to": { - "name": "Hwy 99 & 180th St SW", - "stopId": "CommTrans:1521", - "stopCode": "1521", - "lon": -122.303382, - "lat": 47.834973, - "arrival": 1674506100000, - "departure": 1674506100000, - "vertexType": "TRANSIT" - }, - "legGeometry": { - "points": "u{}bHxfpiV?q@@eE?wG?_D?Y@o@?kCBqF?{D@qI?qA?c@?qA?i@?IZWB?d@ZBAPa@b@^EL", - "length": 23 - }, - "steps": [ - { - "distance": 717.88, - "relativeDirection": "DEPART", - "streetName": "180th Street Southwest", - "absoluteDirection": "EAST", - "stayOn": false, - "area": false, - "bogusName": false, - "lon": -122.3129292, - "lat": 47.8356351, - "elevation": "", - "walkingBike": false - }, - { - "distance": 62.21, - "relativeDirection": "RIGHT", - "streetName": "service road", - "absoluteDirection": "SOUTHEAST", - "stayOn": false, - "area": false, - "bogusName": true, - "lon": -122.3033119, - "lat": 47.8355803, - "elevation": "", - "walkingBike": false - }, - { - "distance": 22.81, - "relativeDirection": "RIGHT", - "streetName": "Highway 99", - "absoluteDirection": "SOUTHWEST", - "stayOn": false, - "area": false, - "bogusName": false, - "lon": -122.3031554, - "lat": 47.8351213, - "elevation": "", - "walkingBike": false - } - ], - "rentedBike": false, - "walkingBike": false, - "duration": 615 - }, - { - "startTime": 1674506100000, - "endTime": 1674507660000, - "departureDelay": 0, - "arrivalDelay": 0, - "realTime": false, - "distance": 7813.43, - "generalizedCost": 2160, - "pathway": false, - "mode": "BUS", - "transitLeg": true, - "route": "Mariner P&R - Aurora Village", - "agencyName": "Community Transit", - "agencyUrl": "http://www.communitytransit.org/", - "agencyTimeZoneOffset": -28800000, - "routeColor": "0070c0", - "routeType": 3, - "routeId": "CommTrans:101", - "routeTextColor": "ffffff", - "interlineWithPreviousLeg": false, - "tripBlockId": "MCOB-DO:123:0:Weekday:1:22SEP:41028:12345", - "headsign": "Aurora Village", - "agencyId": "CommTrans:29", - "tripId": "CommTrans:10499096__MCOB-DO:123:0:Weekday:1:22SEP:41028:12345", - "serviceDate": "2023-01-23", - "from": { - "name": "Hwy 99 & 180th St SW", - "stopId": "CommTrans:1521", - "stopCode": "1521", - "lon": -122.303382, - "lat": 47.834973, - "arrival": 1674506100000, - "departure": 1674506100000, - "stopIndex": 16, - "stopSequence": 17, - "vertexType": "TRANSIT" - }, - "to": { - "name": "Aurora Village Transit Center", - "stopId": "CommTrans:2877", - "stopCode": "2877", - "lon": -122.34277, - "lat": 47.77435, - "arrival": 1674507660000, - "departure": 1674507660000, - "stopIndex": 30, - "stopSequence": 31, - "vertexType": "TRANSIT" - }, - "intermediateStops": [ - { - "name": "Hwy 99 & 188th St SW", - "stopId": "CommTrans:1502", - "stopCode": "1502", - "lon": -122.309711, - "lat": 47.827669, - "arrival": 1674506220000, - "departure": 1674506220000, - "stopIndex": 17, - "stopSequence": 18, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 60th Ave W", - "stopId": "CommTrans:1495", - "stopCode": "1495", - "lon": -122.312185, - "lat": 47.824801, - "arrival": 1674506280000, - "departure": 1674506280000, - "stopIndex": 18, - "stopSequence": 19, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 196th St SW", - "stopId": "CommTrans:1503", - "stopCode": "1503", - "lon": -122.31592, - "lat": 47.820482, - "arrival": 1674506340000, - "departure": 1674506340000, - "stopIndex": 19, - "stopSequence": 20, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 200th St SW", - "stopId": "CommTrans:1504", - "stopCode": "1504", - "lon": -122.318702, - "lat": 47.81725, - "arrival": 1674506340000, - "departure": 1674506340000, - "stopIndex": 20, - "stopSequence": 21, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 202nd St SW", - "stopId": "CommTrans:1505", - "stopCode": "1505", - "lon": -122.320426, - "lat": 47.815264, - "arrival": 1674506400000, - "departure": 1674506400000, - "stopIndex": 21, - "stopSequence": 22, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 208th St SW", - "stopId": "CommTrans:1506", - "stopCode": "1506", - "lon": -122.324693, - "lat": 47.809703, - "arrival": 1674506520000, - "departure": 1674506520000, - "stopIndex": 22, - "stopSequence": 23, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 212th St SW", - "stopId": "CommTrans:1507", - "stopCode": "1507", - "lon": -122.327809, - "lat": 47.805379, - "arrival": 1674506580000, - "departure": 1674506580000, - "stopIndex": 23, - "stopSequence": 24, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 216th St SW", - "stopId": "CommTrans:1508", - "stopCode": "1508", - "lon": -122.329866, - "lat": 47.802523, - "arrival": 1674506640000, - "departure": 1674506640000, - "stopIndex": 24, - "stopSequence": 25, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 220th St SW", - "stopId": "CommTrans:1509", - "stopCode": "1509", - "lon": -122.332468, - "lat": 47.798918, - "arrival": 1674506700000, - "departure": 1674506700000, - "stopIndex": 25, - "stopSequence": 26, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 224th St SW", - "stopId": "CommTrans:1510", - "stopCode": "1510", - "lon": -122.334893, - "lat": 47.795549, - "arrival": 1674506820000, - "departure": 1674506820000, - "stopIndex": 26, - "stopSequence": 27, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 230th St SW", - "stopId": "CommTrans:1511", - "stopCode": "1511", - "lon": -122.338743, - "lat": 47.790207, - "arrival": 1674507000000, - "departure": 1674507000000, - "stopIndex": 27, - "stopSequence": 28, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & 238th St SW", - "stopId": "CommTrans:1517", - "stopCode": "1517", - "lon": -122.343432, - "lat": 47.783697, - "arrival": 1674507240000, - "departure": 1674507240000, - "stopIndex": 28, - "stopSequence": 29, - "vertexType": "TRANSIT" - }, - { - "name": "Hwy 99 & N 205th St", - "stopId": "CommTrans:2089", - "stopCode": "2089", - "lon": -122.346379, - "lat": 47.777264, - "arrival": 1674507420000, - "departure": 1674507420000, - "stopIndex": 29, - "stopSequence": 30, - "vertexType": "TRANSIT" } ], - "legGeometry": { - "points": "ew}bHfjniVj@d@JHLJPNTRb@^h@b@XThA~@n@h@j@d@l@f@VTd@^v@n@RPZVNLVRZVLJrAfAd@`@z@r@^Zf@`@LJbAz@dCrBj@d@ZV~ApA`BtATP\\X??NLNJ^ZPNb@\\HFRPl@f@NL`@^NLn@f@`@\\RPf@`@jA`Ad@^t@l@@@??t@n@JHRP^ZZVHFNLNLb@\\PNJHTRPLd@^TPd@^VRPNVTXTd@^n@h@^Zb@^fA|@bAz@pAdABB??HFh@b@dA|@TPHFXT|@t@ZVPNl@f@f@`@LJ`@Zl@h@n@h@t@l@\\Vn@h@??|@t@b@^f@`@VTNLNJnAbArAhATRNL??LJHF\\XLJf@`@LJTRzAnAf@^RNNJNJ`@ZLHh@`@JHRLf@\\LHdAp@PLf@Zr@d@PJv@f@HFb@XXRrAz@`@Vv@f@\\TXRLHLHLHFD??B@n@b@LHJHb@Xp@b@NJfAp@HF\\TRLl@^\\TTN\\Td@XXPv@f@xA`Aj@^PJn@b@p@b@TN`@V??zA`ADBLHb@ZTNHFl@^HFVNXP\\T^Th@\\\\TfAt@x@h@HFHF??VNNHTNZRj@^d@ZjAv@bAn@bAn@FDxBvAt@d@bAn@JFNJNHh@^??l@^hAt@t@d@NJ^T`@VTNXPn@b@r@f@LHHF|@j@ZTv@f@vA|@JF??BBVNZRd@Zb@XTNXPf@\\TLb@XdAr@zA`ARLj@`@PLh@\\VNf@\\hAt@RLTLTNTNLHLHRLPLTNdAp@h@\\pAx@??FDb@XLHZR~@l@^V`BdANJd@Z`An@VNZR^V\\TZRjBjAfAr@d@Z`GxD^VXPNJh@Zt@d@z@j@b@XJHDB??fAr@`Al@VPTNZRTNPLHFJHNJNLPLLJ\\VLJt@l@b@\\RP`@Z\\VXRXPd@VPJTJRHPFZJVHXHVFPDRD`@FXB\\@X@^?T?hAEz@GdAILATA??f@Cb@ANAjACr@Cr@AX?R?P?VAX?l@?T?f@?T?|AAH?BqBAg@?{A?m@?c@?iB?u@?yCe@??K", - "length": 368 + "agency": { + "alerts": [], + "id": "QWdlbmN5OmtjbTox", + "name": "Metro Transit", + "timezone": "America/Los_Angeles", + "url": "https://kingcounty.gov/en/dept/metro" }, - "steps": [], - "routeLongName": "Mariner P&R - Aurora Village", - "duration": 1560 - }, - { - "startTime": 1674507660000, - "endTime": 1674507707000, - "departureDelay": 0, "arrivalDelay": 0, - "realTime": false, - "distance": 38.11, - "generalizedCost": 67, - "pathway": false, - "mode": "WALK", - "transitLeg": false, - "route": "", - "agencyTimeZoneOffset": -28800000, - "interlineWithPreviousLeg": false, + "departureDelay": 0, + "distance": 4454.61, + "dropoffType": "SCHEDULED", + "duration": 967, + "endTime": 1686625941000, "from": { - "name": "Aurora Village Transit Center", - "stopId": "CommTrans:2877", - "stopCode": "2877", - "lon": -122.34277, - "lat": 47.77435, - "arrival": 1674507660000, - "departure": 1674507660000, - "vertexType": "TRANSIT" - }, - "to": { - "name": "Aurora Village Transit Center - Bay 10", - "stopId": "kcm:16100", - "stopCode": "16100", - "lon": -122.342407, - "lat": 47.7742424, - "arrival": 1674507707000, - "departure": 1674508020000, - "zoneId": "18", + "lat": 47.6904907, + "lon": -122.344734, + "name": "N 85th St & Aurora Ave N", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "5370", + "gtfsId": "kcm:5370", + "id": "U3RvcDprY206NTM3MA" + }, "vertexType": "TRANSIT" }, - "legGeometry": { - "points": "u|qbHhaviV??R??]@C?A@C?C?ACI?O@?", - "length": 12 - }, - "steps": [ + "interlineWithPreviousLeg": false, + "intermediateStops": [ { - "distance": 10.22, - "relativeDirection": "DEPART", - "streetName": "service road", - "absoluteDirection": "SOUTH", - "stayOn": false, - "area": false, - "bogusName": true, - "lon": -122.3427609, - "lat": 47.77435, - "elevation": "", - "walkingBike": false + "lat": 47.6904716, + "locationType": "STOP", + "lon": -122.341507, + "name": "N 85th St & Stone Ave N", + "stopCode": "5380", + "stopId": "U3RvcDprY206NTM4MA" }, { - "distance": 11.17, - "relativeDirection": "LEFT", - "streetName": "path", - "absoluteDirection": "EAST", - "stayOn": true, - "area": false, - "bogusName": true, - "lon": -122.3427605, - "lat": 47.7742581, - "elevation": "", - "walkingBike": false + "lat": 47.6904449, + "locationType": "STOP", + "lon": -122.336601, + "name": "N 85th St & Wallingford Ave N", + "stopCode": "5400", + "stopId": "U3RvcDprY206NTQwMA" }, { - "distance": 16.73, - "relativeDirection": "RIGHT", - "streetName": "open area", - "absoluteDirection": "SOUTHEAST", - "stayOn": true, - "area": true, - "bogusName": true, - "lon": -122.3426111, - "lat": 47.7742565, - "elevation": "", - "walkingBike": false - } - ], - "rentedBike": false, - "walkingBike": false, - "duration": 47 - }, - { - "startTime": 1674508020000, - "endTime": 1674508800000, - "departureDelay": 0, - "arrivalDelay": 0, - "realTime": false, - "distance": 4792.95, - "generalizedCost": 1693, - "pathway": false, - "mode": "BUS", - "transitLeg": true, - "agencyName": "Metro Transit", - "agencyUrl": "http://metro.kingcounty.gov", - "agencyTimeZoneOffset": -28800000, - "routeType": 3, - "routeId": "kcm:102615", - "interlineWithPreviousLeg": false, - "tripShortName": "LOCAL", - "tripBlockId": "6649263", - "headsign": "Downtown Seattle", - "agencyId": "kcm:1", - "tripId": "kcm:585679422", - "serviceDate": "2023-01-23", - "from": { - "name": "Aurora Village Transit Center - Bay 10", - "stopId": "kcm:16100", - "stopCode": "16100", - "lon": -122.342407, - "lat": 47.7742424, - "arrival": 1674507707000, - "departure": 1674508020000, - "zoneId": "18", - "stopIndex": 0, - "stopSequence": 1, - "vertexType": "TRANSIT" - }, - "to": { - "name": "Aurora Ave N & N 145th St", - "stopId": "kcm:6950", - "stopCode": "6950", - "lon": -122.345268, - "lat": 47.7335701, - "arrival": 1674508800000, - "departure": 1674508800000, - "zoneId": "20", - "stopIndex": 11, - "stopSequence": 84, - "vertexType": "TRANSIT" - }, - "intermediateStops": [ + "lat": 47.68853, + "locationType": "STOP", + "lon": -122.33651, + "name": "Wallingford Ave N & N 82nd St", + "stopCode": "17070", + "stopId": "U3RvcDprY206MTcwNzA" + }, { - "name": "Aurora Ave N & N 200th St", - "stopId": "kcm:75700", - "stopCode": "75700", - "lon": -122.346207, - "lat": 47.7737427, - "arrival": 1674508073000, - "departure": 1674508073000, - "zoneId": "18", - "stopIndex": 1, - "stopSequence": 6, - "vertexType": "TRANSIT" + "lat": 47.6870499, + "locationType": "STOP", + "lon": -122.336494, + "name": "Wallingford Ave N & N 80th St", + "stopCode": "17080", + "stopId": "U3RvcDprY206MTcwODA" }, { - "name": "Aurora Ave N & N 192nd St", - "stopId": "kcm:75730", - "stopCode": "75730", - "lon": -122.3461, - "lat": 47.7672043, - "arrival": 1674508191000, - "departure": 1674508191000, - "zoneId": "18", - "stopIndex": 2, - "stopSequence": 13, - "vertexType": "TRANSIT" + "lat": 47.6857948, + "locationType": "STOP", + "lon": -122.336861, + "name": "Wallingford Ave N & East Green Lake Dr N", + "stopCode": "17081", + "stopId": "U3RvcDprY206MTcwODE" }, { - "name": "Aurora Ave N & N 185th St", - "stopId": "kcm:75740", - "stopCode": "75740", - "lon": -122.346184, - "lat": 47.7628479, - "arrival": 1674508270000, - "departure": 1674508270000, - "zoneId": "18", - "stopIndex": 3, - "stopSequence": 22, - "vertexType": "TRANSIT" + "lat": 47.682682, + "locationType": "STOP", + "lon": -122.332932, + "name": "East Green Lake Dr N & Meridian Ave N", + "stopCode": "35691", + "stopId": "U3RvcDprY206MzU2OTE" }, { - "name": "Aurora Ave N & N 180th St", - "stopId": "kcm:75750", - "stopCode": "75750", - "lon": -122.346237, - "lat": 47.7594452, - "arrival": 1674508331000, - "departure": 1674508331000, - "zoneId": "18", - "stopIndex": 4, - "stopSequence": 32, - "vertexType": "TRANSIT" + "lat": 47.6812057, + "locationType": "STOP", + "lon": -122.326973, + "name": "East Green Lake Dr N & 4th Ave NE", + "stopCode": "35721", + "stopId": "U3RvcDprY206MzU3MjE" }, { - "name": "Aurora Ave N & N 175th St", - "stopId": "kcm:75760", - "stopCode": "75760", - "lon": -122.345856, - "lat": 47.7552986, - "arrival": 1674508407000, - "departure": 1674508407000, - "zoneId": "18", - "stopIndex": 5, - "stopSequence": 40, - "vertexType": "TRANSIT" + "lat": 47.6784592, + "locationType": "STOP", + "lon": -122.32486, + "name": "NE Ravenna Blvd & Woodlawn Ave NE", + "stopCode": "16390", + "stopId": "U3RvcDprY206MTYzOTA" }, { - "name": "Aurora Ave N & N 170th St", - "stopId": "kcm:75770", - "stopCode": "75770", - "lon": -122.345741, - "lat": 47.7520294, - "arrival": 1674508466000, - "departure": 1674508466000, - "zoneId": "18", - "stopIndex": 6, - "stopSequence": 48, - "vertexType": "TRANSIT" + "lat": 47.6773109, + "locationType": "STOP", + "lon": -122.323807, + "name": "NE Ravenna Blvd & NE 68th St", + "stopCode": "16400", + "stopId": "U3RvcDprY206MTY0MDA" }, { - "name": "Aurora Ave N & N 165th St", - "stopId": "kcm:75780", - "stopCode": "75780", - "lon": -122.345688, - "lat": 47.7483559, - "arrival": 1674508532000, - "departure": 1674508532000, - "zoneId": "18", - "stopIndex": 7, - "stopSequence": 56, - "vertexType": "TRANSIT" + "lat": 47.6757851, + "locationType": "STOP", + "lon": -122.320129, + "name": "NE 65th St & 8th Ave NE", + "stopCode": "16416", + "stopId": "U3RvcDprY206MTY0MTY" }, { - "name": "Aurora Ave N & N 160th St", - "stopId": "kcm:75790", - "stopCode": "75790", - "lon": -122.34565, - "lat": 47.7446899, - "arrival": 1674508599000, - "departure": 1674508599000, - "zoneId": "18", - "stopIndex": 8, - "stopSequence": 66, - "vertexType": "TRANSIT" + "lat": 47.6757507, + "locationType": "STOP", + "lon": -122.316673, + "name": "Roosevelt Station - Bay 1", + "stopCode": "16430", + "stopId": "U3RvcDprY206MTY0MzA" }, { - "name": "Aurora Ave N & N 155th St", - "stopId": "kcm:75800", - "stopCode": "75800", - "lon": -122.345497, - "lat": 47.7408867, - "arrival": 1674508668000, - "departure": 1674508668000, - "zoneId": "18", - "stopIndex": 9, - "stopSequence": 73, - "vertexType": "TRANSIT" + "lat": 47.6757202, + "locationType": "STOP", + "lon": -122.312683, + "name": "NE 65th St & 14th Ave NE", + "stopCode": "37359", + "stopId": "U3RvcDprY206MzczNTk" }, { - "name": "Aurora Ave N & N 152nd St", - "stopId": "kcm:75810", - "stopCode": "75810", - "lon": -122.345428, - "lat": 47.7386818, - "arrival": 1674508707000, - "departure": 1674508707000, - "zoneId": "18", - "stopIndex": 10, - "stopSequence": 75, - "vertexType": "TRANSIT" + "lat": 47.6706772, + "locationType": "STOP", + "lon": -122.313133, + "name": "University Way NE & NE Ravenna Blvd", + "stopCode": "38022", + "stopId": "U3RvcDprY206MzgwMjI" } ], "legGeometry": { - "points": "q{qbH`_viV?`AB~R?b@\\Cr@???dB?rBE~@A`HA|IElGArBC??f@?`DBpA?fB?pA@r@BhDBdB@lA???~@BbDDr@?|BBxAB|@?v@?PCb@?HA??v@AtAIjBInBGn@AvAGhES~BM??TA`AE`AA`B?hACbDCfB?|@C??v@AxDCnAAhA?bB?pA?xAA`AA??l@?n@?r@?|@CxAAj@?pB@vA?vB?dAA??|CEv@?fAE`CIhA?~CEnBC??~JIt@A??vBEz@AZCrAApAEfBEvFCvDCrBA", - "length": 94 + "length": 151, + "points": "_qabHnmviV@YAY@iE@sE?mB?aA???g@BcD?s@?yE@uE?U?_@?}B?oB???_@hJE`@???jCA|C???F?H@FDHDJJRXRL`DD??b@?Ny@To@HQHQV]Z]LMzB}BfCeCRWVUVWV[R]R]Nc@Re@Ja@Ha@??BCFe@Ho@Fs@@e@@i@Ae@Ae@Ca@Ce@Cq@C]?WAW@m@B_@Bg@Bi@Ha@Fe@Je@Jg@L_@JUL[Na@R[Tg@t@sAjAwB??Xi@Ta@NUNUPSLKPQTOROTMNENGRETAV?XQTIVOhCeBp@m@??bEmDb@c@??dHsG@}A?mB@wB?s@?_A???K?gCBgC?gC?cC@iC??@iE@uC?oB?{B@wB@yA???]?{A?[rB?tACrA?hA?vJAx@hA~A|BNNHDNDZ?|@???vFCpD?D?h@?" }, + "mode": "BUS", + "pickupBookingInfo": null, + "pickupType": "SCHEDULED", + "realTime": false, + "realtimeState": null, + "rentedBike": null, + "route": { + "alerts": [], + "color": null, + "id": "Um91dGU6a2NtOjEwMDIyNQ", + "longName": null, + "shortName": "45", + "textColor": null, + "type": 3 + }, + "startTime": 1686624974000, "steps": [], - "routeShortName": "E Line", - "duration": 780 + "to": { + "lat": 47.6683159, + "lon": -122.313126, + "name": "University Way NE & NE 55th St", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "38024", + "gtfsId": "kcm:38024", + "id": "U3RvcDprY206MzgwMjQ" + }, + "vertexType": "TRANSIT" + }, + "transitLeg": true, + "trip": { + "gtfsId": "kcm:583679024", + "id": "VHJpcDprY206NTgzNjc5MDI0", + "tripHeadsign": "University District Roosevelt Station" + } }, { - "startTime": 1674508800000, - "endTime": 1674509068000, - "departureDelay": 0, + "accessibilityScore": null, + "fareProducts": [], + "agency": null, "arrivalDelay": 0, - "realTime": false, - "distance": 316.32, - "generalizedCost": 490, - "pathway": false, - "mode": "WALK", - "transitLeg": false, - "route": "", - "agencyTimeZoneOffset": -28800000, - "interlineWithPreviousLeg": false, + "departureDelay": 0, + "distance": 492.88, + "dropoffType": "SCHEDULED", + "duration": 405, + "endTime": 1686626346000, "from": { - "name": "Aurora Ave N & N 145th St", - "stopId": "kcm:6950", - "stopCode": "6950", - "lon": -122.345268, - "lat": 47.7335701, - "arrival": 1674508800000, - "departure": 1674508800000, - "zoneId": "20", + "lat": 47.6683159, + "lon": -122.313126, + "name": "University Way NE & NE 55th St", + "rentalVehicle": null, + "stop": { + "alerts": [], + "code": "38024", + "gtfsId": "kcm:38024", + "id": "U3RvcDprY206MzgwMjQ" + }, "vertexType": "TRANSIT" }, - "to": { - "name": "1318 North 145th Street, Seattle, WA, USA", - "lon": -122.3420287, - "lat": 47.7342206, - "arrival": 1674509068000, - "vertexType": "NORMAL" - }, + "interlineWithPreviousLeg": false, + "intermediateStops": null, "legGeometry": { - "points": "y}ibH|pviV@Be@?I??Q]?O?Q??c@?W?qB?aA?kA@e@AiEQ??Q@K?o@", - "length": 19 + "length": 41, + "points": "}e}aH`hpiV?F[??C?AAQ?Y@CAC@qA@{A?C?O?OAE?_B?}A?G?I?G?G?aB?aB?E?G?e@?G?I?eB?{A?G?K?G?G?cBA{A?E?K?I?E?u@" }, + "mode": "WALK", + "pickupBookingInfo": null, + "pickupType": "SCHEDULED", + "realTime": false, + "realtimeState": null, + "rentedBike": false, + "route": null, + "startTime": 1686625941000, "steps": [ { - "distance": 26.16, - "relativeDirection": "DEPART", - "streetName": "sidewalk", - "absoluteDirection": "NORTH", - "stayOn": false, - "area": false, - "bogusName": true, - "lon": -122.3452855, - "lat": 47.73357, - "elevation": "", - "walkingBike": false - }, - { - "distance": 7.06, - "relativeDirection": "RIGHT", - "streetName": "service road", - "absoluteDirection": "EAST", - "stayOn": true, - "area": false, - "bogusName": true, - "lon": -122.3452885, - "lat": 47.7338053, - "elevation": "", - "walkingBike": false - }, - { - "distance": 35.59, - "relativeDirection": "LEFT", - "streetName": "Aurora Avenue North", - "absoluteDirection": "NORTH", - "stayOn": false, - "area": false, - "bogusName": false, - "lon": -122.3451941, - "lat": 47.7338066, - "elevation": "", - "walkingBike": false - }, - { - "distance": 207.88, - "relativeDirection": "RIGHT", - "streetName": "North 145th Street", - "absoluteDirection": "EAST", - "stayOn": false, - "area": false, - "bogusName": false, - "lon": -122.3451971, - "lat": 47.7341266, - "elevation": "", - "walkingBike": false - }, - { - "distance": 10.3, - "relativeDirection": "LEFT", - "streetName": "Stone Avenue North", "absoluteDirection": "NORTH", - "stayOn": false, + "alerts": [], "area": false, - "bogusName": false, - "lon": -122.3424174, - "lat": 47.7341208, - "elevation": "", - "walkingBike": false - }, - { - "distance": 29.32, - "relativeDirection": "RIGHT", - "streetName": "path", - "absoluteDirection": "EAST", + "distance": 492.91, + "elevationProfile": [], + "lat": 47.6683162, + "lon": -122.3131688, + "relativeDirection": "DEPART", "stayOn": false, - "area": false, - "bogusName": true, - "lon": -122.3424186, - "lat": 47.7342134, - "elevation": "", - "walkingBike": false + "streetName": "sidewalk" } ], - "rentedBike": false, - "walkingBike": false, - "duration": 268 + "to": { + "lat": 47.6683393, + "lon": -122.3067976, + "name": "47.66834, -122.3068", + "rentalVehicle": null, + "stop": null, + "vertexType": "NORMAL" + }, + "transitLeg": false, + "trip": null } ], - "tooSloped": false, - "arrivedAtDestinationWithRentedBicycle": false + "startTime": 1686620636000, + "waitingTime": 481, + "walkTime": 1862 } From 1113b6bf85fce6c37be99f203c7ea3f701811f7d Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Thu, 15 Jun 2023 14:55:17 -0700 Subject: [PATCH 12/40] undo some regressions --- packages/core-utils/src/planQuery.graphql | 29 ++++++++++++----------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/core-utils/src/planQuery.graphql b/packages/core-utils/src/planQuery.graphql index bf15a05ee..79a46e7b4 100644 --- a/packages/core-utils/src/planQuery.graphql +++ b/packages/core-utils/src/planQuery.graphql @@ -1,18 +1,18 @@ query Plan( - $fromPlace: String!, - $toPlace: String!, - $modes: [TransportMode], - $time: String, - $date: String, - $wheelchair: Boolean, - $bikeReluctance: Float, - $carReluctance: Float, - $walkReluctance: Float, - $arriveBy: Boolean, - $intermediatePlaces: [InputCoordinates], - $preferred: InputPreferred, - $unpreferred: InputUnpreferred, - $banned: InputBanned, + $fromPlace: String! + $toPlace: String! + $modes: [TransportMode] + $time: String + $date: String + $wheelchair: Boolean + $bikeReluctance: Float + $carReluctance: Float + $walkReluctance: Float + $arriveBy: Boolean + $intermediatePlaces: [InputCoordinates] + $preferred: InputPreferred + $unpreferred: InputUnpreferred + $banned: InputBanned $numItineraries: Int ) { plan( @@ -23,6 +23,7 @@ query Plan( date: $date fromPlace: $fromPlace intermediatePlaces: $intermediatePlaces + # Currently only supporting EN locale, used for times and text locale: "en" numItineraries: $numItineraries preferred: $preferred From 6ee769c9a52a2859a4a428465f33242975b48996 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 19 Jun 2023 15:37:37 -0700 Subject: [PATCH 13/40] fix(core-utils): correct bug with argument order --- .../src/__tests__/__snapshots__/itinerary.js.snap | 9 ++++++--- packages/core-utils/src/__tests__/itinerary.js | 14 ++++++++++++++ packages/core-utils/src/itinerary.ts | 8 ++++---- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/packages/core-utils/src/__tests__/__snapshots__/itinerary.js.snap b/packages/core-utils/src/__tests__/__snapshots__/itinerary.js.snap index 0d2e2bc79..c1ff0d6a3 100644 --- a/packages/core-utils/src/__tests__/__snapshots__/itinerary.js.snap +++ b/packages/core-utils/src/__tests__/__snapshots__/itinerary.js.snap @@ -1,5 +1,8 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`util > itinerary getTransitFare should return defaults with missing fare 1`] = `0`; - -exports[`util > itinerary getTransitFare should work with valid fare component 1`] = `575`; +exports[`util > itinerary getItineraryCost should calculate the total cost of an itinerary 1`] = ` +Object { + "code": "USD", + "digits": 2, +} +`; diff --git a/packages/core-utils/src/__tests__/itinerary.js b/packages/core-utils/src/__tests__/itinerary.js index 09bdcc3bf..90181adfb 100644 --- a/packages/core-utils/src/__tests__/itinerary.js +++ b/packages/core-utils/src/__tests__/itinerary.js @@ -2,12 +2,14 @@ import { calculateTncFares, getCompanyFromLeg, getDisplayedStopId, + getItineraryCost, getLegCost, isTransit } from "../itinerary"; const bikeRentalItinerary = require("./__mocks__/bike-rental-itinerary.json"); const tncItinerary = require("./__mocks__/tnc-itinerary.json"); +const fareProductItinerary = require("./__mocks__/fare-products-itinerary.json"); const basePlace = { lat: 0, @@ -138,4 +140,16 @@ describe("util > itinerary", () => { expect(result.price).toBeUndefined(); }); }); + + describe("getItineraryCost", () => { + it("should calculate the total cost of an itinerary", () => { + const result = getItineraryCost( + fareProductItinerary.legs, + "orca:cash", + "orca:regular" + ); + expect(result.amount).toEqual(5.75); + expect(result.currency).toMatchSnapshot(); + }); + }); }); diff --git a/packages/core-utils/src/itinerary.ts b/packages/core-utils/src/itinerary.ts index 744053dbe..937413f25 100644 --- a/packages/core-utils/src/itinerary.ts +++ b/packages/core-utils/src/itinerary.ts @@ -582,12 +582,12 @@ export function getLegCost( */ export function getItineraryCost( legs: Leg[], - category: string, - container: string + mediumId: string, + riderCategoryId: string ): Money { return legs - .filter(leg => !!leg.fareProducts) - .map(leg => getLegCost(leg, category, container).price) + .filter(leg => leg.fareProducts?.length > 0) + .map(leg => getLegCost(leg, mediumId, riderCategoryId).price) .reduce( (prev, cur) => ({ amount: prev.amount + cur?.amount || 0, From 0a1ba981a871cc088bf9705bedcf79651608fa26 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 19 Jun 2023 15:46:06 -0700 Subject: [PATCH 14/40] fix(trip-details): bug fixes --- .../trip-details/src/TripDetails.story.tsx | 14 ++++++++++++ packages/trip-details/src/fare-table.tsx | 17 ++++++-------- packages/trip-details/src/index.tsx | 22 +++++++------------ 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/packages/trip-details/src/TripDetails.story.tsx b/packages/trip-details/src/TripDetails.story.tsx index 3f6b9c313..44ee67fc3 100644 --- a/packages/trip-details/src/TripDetails.story.tsx +++ b/packages/trip-details/src/TripDetails.story.tsx @@ -110,6 +110,12 @@ const otp2FareByLegLayout: FareTableLayout[] = [ } ]; +const otp2defaultFareType = { + headerKey: "cash-regular", + mediumId: "orca:cash", + riderCategoryId: "orca:regular" +}; + const englishFareKeyMap = { regular: "Transit Fare", student: "Student Fare", @@ -186,6 +192,7 @@ function createTripDetailsTemplate( DepartureDetails, FareDetails, fareDetailsLayout, + defaultFareType, itinerary }: TripDetailsProps, { globals, parameters }: StoryContext @@ -206,6 +213,7 @@ function createTripDetailsTemplate( fareKeyNameMap={fareKeyNameMap} itinerary={itinerary} co2Config={defaultCo2Config} + defaultFareType={defaultFareType} /> ); }; @@ -266,6 +274,12 @@ export const BikeTransitBikeItinerary = makeStory({ itinerary: bikeTransitBikeItinerary }); +export const LegFareProductsItinerary = makeStory({ + itinerary: otp2FareProducts, + fareDetailsLayout: otp2FareByLegLayout, + defaultFareType: otp2defaultFareType +}); + export const WalkInterlinedTransitItinerary = makeStory( { // defaultFareKey: "electronicRegular", diff --git a/packages/trip-details/src/fare-table.tsx b/packages/trip-details/src/fare-table.tsx index 26a40135b..72395757c 100644 --- a/packages/trip-details/src/fare-table.tsx +++ b/packages/trip-details/src/fare-table.tsx @@ -84,7 +84,7 @@ const FareTypeTable = ({ const intl = useIntl(); // FIXME: Is there a nicer way to do this? const colsToRender = cols - .filter(col => getItineraryCost(legs, col.riderCategoryId, col.mediumId)) + .filter(col => getItineraryCost(legs, col.mediumId, col.riderCategoryId)) .map(col => ({ ...col, total: getItineraryCost(legs, col.riderCategoryId, col.mediumId) @@ -112,10 +112,7 @@ const FareTypeTable = ({ > {boldText(useGetHeaderString(col.columnHeaderKey))}
- {renderFare( - fare?.currency?.code, - (fare?.amount || 0) / 10 ** fare?.currency?.digits - )} + {renderFare(fare?.currency?.code, fare?.amount || 0)} ); })} @@ -123,10 +120,12 @@ const FareTypeTable = ({ {filteredLegs.map((leg, index) => (
{colsToRender.map(col => { const fare = getLegCost(leg, col.mediumId, col.riderCategoryId); + console.log(fare); + return ( {colsToRender.map(col => { const fare = getLegCost(leg, col.mediumId, col.riderCategoryId); - console.log(fare); - return ( @@ -255809,30 +251449,15 @@ exports[`Storyshots TripDetails Fare Leg Table Story 2`] = ` +
- {boldText(getFormattedTextForConfigKey(header))} + {boldText(headerString)} - {boldText(getFormattedTextForConfigKey(col.header))} + {boldText(useGetHeaderString(col.columnHeaderKey))}
{renderFare( - fare?.currency?.currencyCode, - (fare?.cents || 0) / 100 + fare?.currency?.code, + (fare?.amount || 0) / 10 ** fare?.currency?.digits )}
{leg.routeShortName || leg.route || leg.routeLongName} 0 && intl.formatMessage( { defaultMessage: @@ -142,9 +145,10 @@ const FareTypeTable = ({ }, { transferAmount: intl.formatNumber( - fare.transferAmount / 100, + fare?.transferAmount?.amount / + 10 ** fare?.transferAmount?.currency.digits, { - currency: fare?.price?.currency?.currencyCode, + currency: fare?.price?.currency?.code, currencyDisplay: "narrowSymbol", style: "currency" } @@ -153,15 +157,16 @@ const FareTypeTable = ({ ) } > - {(("isTransfer" in fare && fare?.isTransfer) || - ("transferAmount" in fare && fare?.transferAmount)) && ( - <> - {" "} - - )} + {"transferAmount" in fare && + fare?.transferAmount?.amount > 0 && ( + <> + {" "} + + )} {renderFare( - fare?.price?.currency?.currencyCode, - (fare?.price?.cents || 0) / 100 + fare?.price?.currency?.code, + (fare?.price?.amount || 0) / + 10 ** fare?.price?.currency?.digits )}
- {leg.routeShortName || leg.route || leg.routeLongName} + {leg.routeShortName || leg.routeLongName} ); diff --git a/packages/trip-details/src/index.tsx b/packages/trip-details/src/index.tsx index 157e6135a..cf56d8269 100644 --- a/packages/trip-details/src/index.tsx +++ b/packages/trip-details/src/index.tsx @@ -66,11 +66,7 @@ function DefaultTimeActiveDetails({ export function TripDetails({ className = "", co2Config, - defaultFareType = { - headerKey: "cash-regular", - mediumId: "cash", - riderCategoryId: "regular" - }, + defaultFareType, DepartureDetails = null, displayTimeActive = true, FareDetails = null, @@ -96,12 +92,10 @@ export function TripDetails({ const mediumId = fp.product.medium.id; const riderCategoryId = fp.product.riderCategory.id; if ( - prev.fareTypes.find( + !prev.fareTypes.find( ft => - !( - ft.mediumId === mediumId && - ft.riderCategoryId === riderCategoryId - ) + ft.mediumId === mediumId && + ft.riderCategoryId === riderCategoryId ) ) { prev.fareTypes.push({ mediumId, riderCategoryId }); @@ -114,11 +108,11 @@ export function TripDetails({ ); let fare; - if (fareTypes.length > 0) { + if (fareTypes.length > 0 && defaultFareType) { const defaultFareTotal = getItineraryCost( itinerary.legs, - defaultFareType.riderCategoryId, - defaultFareType.mediumId + defaultFareType.mediumId, + defaultFareType.riderCategoryId ); // Depending on if there are additional fares to display either render a or a
const TransitFareWrapper = @@ -284,7 +278,7 @@ export function TripDetails({ } /> - {fare && ( + {!!fare && ( Date: Tue, 20 Jun 2023 12:39:05 -0700 Subject: [PATCH 15/40] fix(trip-details): fix fare product table bug --- packages/trip-details/src/fare-table.tsx | 8 +++----- packages/trip-details/src/index.tsx | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/trip-details/src/fare-table.tsx b/packages/trip-details/src/fare-table.tsx index 72395757c..d516be8a4 100644 --- a/packages/trip-details/src/fare-table.tsx +++ b/packages/trip-details/src/fare-table.tsx @@ -84,11 +84,11 @@ const FareTypeTable = ({ const intl = useIntl(); // FIXME: Is there a nicer way to do this? const colsToRender = cols - .filter(col => getItineraryCost(legs, col.mediumId, col.riderCategoryId)) .map(col => ({ ...col, - total: getItineraryCost(legs, col.riderCategoryId, col.mediumId) - })); + total: getItineraryCost(legs, col.mediumId, col.riderCategoryId) + })) + .filter(col => col.total); const headerString = useGetHeaderString(headerKey); @@ -124,8 +124,6 @@ const FareTypeTable = ({
From 4c1ed6e09b38f3b0f36d1e9fadc2fe7b91696305 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Tue, 20 Jun 2023 14:39:48 -0700 Subject: [PATCH 16/40] fix(i18n): add correct translations --- packages/trip-details/i18n/en-US.yml | 7 +++++++ packages/trip-details/i18n/fr.yml | 13 +++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/trip-details/i18n/en-US.yml b/packages/trip-details/i18n/en-US.yml index c4b11ef5c..dfeea2732 100644 --- a/packages/trip-details/i18n/en-US.yml +++ b/packages/trip-details/i18n/en-US.yml @@ -1,5 +1,12 @@ otpUi: TripDetails: + FareTable: + cash: Cash + electronic: Electronic + regular: Adult + senior: Senior + special: Special + youth: Youth co2: "CO₂ Emitted: {co2}" co2description: >- CO₂ intensity is calculated by multiplying the distance of each leg of a diff --git a/packages/trip-details/i18n/fr.yml b/packages/trip-details/i18n/fr.yml index 82d2520b0..93798c0c2 100644 --- a/packages/trip-details/i18n/fr.yml +++ b/packages/trip-details/i18n/fr.yml @@ -1,5 +1,12 @@ otpUi: TripDetails: + FareTable: + cash: Espèces + electronic: Électronique + regular: Normal + senior: Séniors + special: Spécial + youth: Jeunes co2: "CO₂ émis : {co2}" co2description: >- L'intensité carbone est calculée en multipliant la distance de chaque @@ -16,8 +23,7 @@ otpUi: special: Spécial youth: Jeunes hideDetail: Masquer les détails - minutesActive: "Activité physique : {minutes, plural, one {# minute} other - {# minutes}}" + minutesActive: "Activité physique\_: {minutes, plural, one {# minute} other {# minutes}}" showDetail: Afficher les détails timeActiveDescription: > Sur ce trajet, vous effectuerez {walkMinutes, plural, one {# @@ -25,8 +31,7 @@ otpUi: plural, one {# minute} other {# minutes}} à vélo. title: Détails du trajet tncFare: "Tarif {companies} : {minTNCFare} - {maxTNCFare}" - transferDiscountExplanation: Cette correspondance vous donne une réduction de - {transferAmount} + transferDiscountExplanation: Cette correspondance vous donne une réduction de {transferAmount} transitFare: Tarif en transports transitFareEntry: "{name} : {value}" transitFareUnknown: Tarif inconnu From a5232ecdaaf5e61a5e65667a97ae59b3ff838d13 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Tue, 20 Jun 2023 15:32:00 -0700 Subject: [PATCH 17/40] fix(trip-details): fix crash --- packages/trip-details/src/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/trip-details/src/index.tsx b/packages/trip-details/src/index.tsx index 0c756cd42..4da7e9097 100644 --- a/packages/trip-details/src/index.tsx +++ b/packages/trip-details/src/index.tsx @@ -89,8 +89,8 @@ export function TripDetails({ } if (leg.fareProducts) { leg.fareProducts.forEach(fp => { - const mediumId = fp.product.medium.id; - const riderCategoryId = fp.product.riderCategory.id; + const mediumId = fp.product.medium?.id; + const riderCategoryId = fp.product.riderCategory?.id; if ( !prev.fareTypes.find( ft => From ff007f31d592fe23cbd4b93f8e9086d43143ea74 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 12:32:58 -0700 Subject: [PATCH 18/40] fix(core-utils): hide undefined fare legs instead of returning 0 --- .../core-utils/src/__tests__/itinerary.js | 68 +++++++++---------- packages/core-utils/src/itinerary.ts | 22 +++--- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/packages/core-utils/src/__tests__/itinerary.js b/packages/core-utils/src/__tests__/itinerary.js index 90181adfb..346901527 100644 --- a/packages/core-utils/src/__tests__/itinerary.js +++ b/packages/core-utils/src/__tests__/itinerary.js @@ -91,52 +91,44 @@ describe("util > itinerary", () => { }); describe("getLegCost", () => { - it("should return the total cost for a leg", () => { - const leg = { - fareProducts: [ - { - product: { - medium: { id: "cash" }, - riderCategory: { id: "regular" }, - name: "rideCost", - price: { amount: 200, currency: "USD" } - } + const leg = { + fareProducts: [ + { + product: { + medium: { id: "cash" }, + riderCategory: { id: "regular" }, + name: "rideCost", + price: { amount: 200, currency: "USD" } } - ] - }; + }, + { + product: { + name: "transfer", + price: { amount: 50, currency: "USD" }, + medium: { id: "cash" }, + riderCategory: { id: "regular" } + } + } + ] + }; + it("should return the total cost for a leg", () => { const result = getLegCost(leg, "cash", "regular"); expect(result.price).toEqual({ amount: 200, currency: "USD" }); }); it("should return the transfer discount amount if a transfer was used", () => { - const leg = { - fareProducts: [ - { - product: { - medium: { id: "cash" }, - riderCategory: { id: "regular" }, - name: "rideCost", - price: { amount: 200, currency: "USD" } - } - }, - { - product: { - name: "transfer", - price: { amount: 50, currency: "USD" }, - medium: { id: "cash" }, - riderCategory: { id: "regular" } - } - } - ] - }; const result = getLegCost(leg, "cash", "regular"); expect(result.price).toEqual({ amount: 200, currency: "USD" }); expect(result.transferAmount).toEqual({ amount: 50, currency: "USD" }); }); it("should return undefined if no fare products exist on the leg", () => { - const leg = {}; - const result = getLegCost(leg, "cash", "regular"); + const emptyleg = {}; + const result = getLegCost(emptyleg, "cash", "regular"); + expect(result.price).toBeUndefined(); + }); + it("should return undefined if the keys are invalid", () => { + const result = getLegCost(leg, "invalidkey", "invalidkey"); expect(result.price).toBeUndefined(); }); }); @@ -151,5 +143,13 @@ describe("util > itinerary", () => { expect(result.amount).toEqual(5.75); expect(result.currency).toMatchSnapshot(); }); + it("should return undefined when the keys are invalid", () => { + const result = getItineraryCost( + fareProductItinerary.legs, + "invalidkey", + "invalidkey" + ); + expect(result).toBeUndefined(); + }); }); }); diff --git a/packages/core-utils/src/itinerary.ts b/packages/core-utils/src/itinerary.ts index 937413f25..1b0fcb374 100644 --- a/packages/core-utils/src/itinerary.ts +++ b/packages/core-utils/src/itinerary.ts @@ -552,7 +552,7 @@ export function getLegCost( leg: Leg, mediumId: string, riderCategoryId: string -): { price: Money; transferAmount?: Money | undefined } { +): { price?: Money; transferAmount?: Money | undefined } { if (!leg.fareProducts) return { price: undefined }; const relevantFareProducts = leg.fareProducts.filter(({ product }) => { return ( @@ -584,17 +584,19 @@ export function getItineraryCost( legs: Leg[], mediumId: string, riderCategoryId: string -): Money { - return legs +): Money | undefined { + const legCosts = legs .filter(leg => leg.fareProducts?.length > 0) .map(leg => getLegCost(leg, mediumId, riderCategoryId).price) - .reduce( - (prev, cur) => ({ - amount: prev.amount + cur?.amount || 0, - currency: prev.currency ?? cur?.currency - }), - { amount: 0, currency: null } - ); + .filter(cost => cost !== undefined); + if (legCosts.length === 0) return undefined; + return legCosts.reduce( + (prev, cur) => ({ + amount: prev.amount + cur?.amount || 0, + currency: prev.currency ?? cur?.currency + }), + { amount: 0, currency: null } + ); } const pickupDropoffTypeToOtp1 = otp2Type => { From 0122ca5fa0b2f0f67c69c5edf392fc96885e731a Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 12:34:18 -0700 Subject: [PATCH 19/40] refactor(trip-details): add story with invalidkey --- packages/trip-details/src/TripDetails.story.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/trip-details/src/TripDetails.story.tsx b/packages/trip-details/src/TripDetails.story.tsx index 44ee67fc3..4d878a6dc 100644 --- a/packages/trip-details/src/TripDetails.story.tsx +++ b/packages/trip-details/src/TripDetails.story.tsx @@ -90,6 +90,11 @@ const otp2FareByLegLayout: FareTableLayout[] = [ columnHeaderKey: "electronic", riderCategoryId: "orca:youth", mediumId: "orca:electronic" + }, + { + columnHeaderKey: "test", + riderCategoryId: "invalidkey", + mediumId: "invalidkey" } ] }, From d5f13402b427afdd3809dd194fc9a4f1aeeeaaae Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 13:37:02 -0700 Subject: [PATCH 20/40] deps(trip-details): use latest core-utils --- packages/trip-details/package.json | 2 +- yarn.lock | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/packages/trip-details/package.json b/packages/trip-details/package.json index 098b241fc..65c4496e8 100644 --- a/packages/trip-details/package.json +++ b/packages/trip-details/package.json @@ -11,7 +11,7 @@ "license": "MIT", "private": false, "dependencies": { - "@opentripplanner/core-utils": "^8.2.1", + "@opentripplanner/core-utils": "^9.0.0-alpha.36", "@styled-icons/fa-solid": "^10.34.0", "flat": "^5.0.2", "react-animate-height": "^3.0.4" diff --git a/yarn.lock b/yarn.lock index 292fe6180..047f4ecba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3241,6 +3241,25 @@ resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca" integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q== +"@opentripplanner/core-utils@^9.0.0-alpha.36": + version "9.0.0-alpha.36" + resolved "https://registry.yarnpkg.com/@opentripplanner/core-utils/-/core-utils-9.0.0-alpha.36.tgz#d28a8f602eea198e23c017cea2dce87fbb41ff1b" + integrity sha512-/Jo4x810D41Htr1eJXekU2MBgqxw2tO7ZTejt2jBuwMwRgL68qPCt45MKcLfXGrJLXv8J/0lVwmkqbcqK95D+A== + dependencies: + "@conveyal/lonlat" "^1.4.1" + "@mapbox/polyline" "^1.1.0" + "@opentripplanner/geocoder" "^1.4.0" + "@styled-icons/foundation" "^10.34.0" + "@turf/along" "^6.0.1" + bowser "^2.7.0" + 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/geocoder@1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@opentripplanner/geocoder/-/geocoder-1.4.0.tgz#728afec6585cf3748a1931493b3a3566421f445d" From fa21a13f68efe21aa62ba460f5d198aff3007b90 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 13:51:04 -0700 Subject: [PATCH 21/40] fix spelling --- packages/trip-details/src/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/trip-details/src/types.ts b/packages/trip-details/src/types.ts index dd00eff80..99a928979 100644 --- a/packages/trip-details/src/types.ts +++ b/packages/trip-details/src/types.ts @@ -26,7 +26,7 @@ export interface FareType { /** * This is the interface used to define the layout for a particular fare table. - * The table with be rendered with the columsn defined here, + * The table with be rendered with the columns defined here, * with each row being an individual transit leg from the itinerary. */ export interface FareTableLayout { From 099920c47f7b99314c748fa8303a8cd25673cf1b Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 13:56:35 -0700 Subject: [PATCH 22/40] fix types issue --- packages/trip-details/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/trip-details/src/index.tsx b/packages/trip-details/src/index.tsx index 7603ea5d0..a997701aa 100644 --- a/packages/trip-details/src/index.tsx +++ b/packages/trip-details/src/index.tsx @@ -302,7 +302,7 @@ export function TripDetails({ ) } From 077dbdbb9168c8ed9bccbb11af001ab14a25d3e9 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 14:44:09 -0700 Subject: [PATCH 23/40] i18n: clean up files --- .../__mocks__/custom-english-messages.yml | 8 +++--- .../__mocks__/custom-french-messages.yml | 15 +++++------ packages/trip-details/i18n-exceptions.json | 11 ++++++++ packages/trip-details/i18n/en-US.yml | 7 ----- packages/trip-details/i18n/es.yml | 26 ++++++++++--------- packages/trip-details/i18n/fr.yml | 7 ----- packages/trip-details/i18n/ko.yml | 14 +++++----- packages/trip-details/i18n/nb_NO.yml | 2 +- packages/trip-details/i18n/vi.yml | 14 +++++----- packages/trip-details/i18n/zh_Hans.yml | 12 ++++----- 10 files changed, 57 insertions(+), 59 deletions(-) create mode 100644 packages/trip-details/i18n-exceptions.json diff --git a/packages/trip-details/__mocks__/custom-english-messages.yml b/packages/trip-details/__mocks__/custom-english-messages.yml index 8cbbf1040..afa5fe070 100644 --- a/packages/trip-details/__mocks__/custom-english-messages.yml +++ b/packages/trip-details/__mocks__/custom-english-messages.yml @@ -1,14 +1,14 @@ otpUi: TripDetails: - departure: >- - Leave at {departureDate, time, short} on - {departureDate, date, long} - fareDetailsHeaders: + FareTable: cash: Cash electronic: ORCA regular: Regular senior: Senior special: LIFT youth: Youth + departure: >- + Leave at {departureDate, time, short} on + {departureDate, date, long} title: Custom Trip Details Title tncFare: Pay {minTNCFare}-{maxTNCFare} to {companies} diff --git a/packages/trip-details/__mocks__/custom-french-messages.yml b/packages/trip-details/__mocks__/custom-french-messages.yml index fae693f24..ab37ecc0d 100644 --- a/packages/trip-details/__mocks__/custom-french-messages.yml +++ b/packages/trip-details/__mocks__/custom-french-messages.yml @@ -1,10 +1,9 @@ -# Example used to overwrite a subset of the messages from /i18n/en-US.yml. otpUi: TripDetails: - fareDetailsHeaders: - regular: "Ordinaire" - youth: "Jeune" - senior: "Senior" - cash: "Espèces" - electronic: "ORCA" - special: "LIFT" + FareTable: + cash: Espèces + electronic: ORCA + regular: Ordinaire + senior: Senior + special: LIFT + youth: Jeune diff --git a/packages/trip-details/i18n-exceptions.json b/packages/trip-details/i18n-exceptions.json new file mode 100644 index 000000000..c52a83135 --- /dev/null +++ b/packages/trip-details/i18n-exceptions.json @@ -0,0 +1,11 @@ +{ + "groups": { + "otpUi.TripDetails.FareTable.*": [ + "cash", + "electronic", + "regular", + "special", + "youth" + ] + } +} diff --git a/packages/trip-details/i18n/en-US.yml b/packages/trip-details/i18n/en-US.yml index dfeea2732..bdcd24cf1 100644 --- a/packages/trip-details/i18n/en-US.yml +++ b/packages/trip-details/i18n/en-US.yml @@ -15,13 +15,6 @@ otpUi: departure: >- Depart {departureDate, date, long} at {departureDate, time, short} - fareDetailsHeaders: - cash: Cash - electronic: Electronic - regular: Adult - senior: Senior - special: Special - youth: Youth hideDetail: Hide details minutesActive: >- Time Spent Active: {minutes, plural, one {# minute} other {# diff --git a/packages/trip-details/i18n/es.yml b/packages/trip-details/i18n/es.yml index d2cf21155..cea653daf 100644 --- a/packages/trip-details/i18n/es.yml +++ b/packages/trip-details/i18n/es.yml @@ -1,5 +1,12 @@ otpUi: TripDetails: + FareTable: + cash: Efectivo + electronic: Electrónico + regular: Adulto + senior: Major edad + special: Especial + youth: Juventud co2: "CO₂ emitido: {co2}" co2description: >- La intensidad de CO₂ se calcula multiplicando la distancia de cada tramo @@ -8,15 +15,15 @@ otpUi: departure: >- Salida {departureDate, date, long} a las {departureDate, time, short} - fareDetailsHeaders: - cash: Efectivo - electronic: Electrónico - regular: Adulto - senior: Major edad - special: Especial - youth: Juventud hideDetail: Ocultar detalles + minutesActive: >- + Tiempo de actividad: {minutes, plural, one {# minuto} other {# + minutos}} showDetail: Mostrar detalles + timeActiveDescription: > + Al hacer este viaje, gastarás {walkMinutes, plural, one {# minuto} + other {# minutos}} caminando y {bikeMinutes, plural, one + {# minuto} other {# minutos}} en bicicleta. title: Detalles del viaje tncFare: "{companies} Tarifa: {minTNCFare} - {maxTNCFare}" transferDiscountExplanation: Se aplica un descuento de transferencia de {transferAmount} @@ -24,8 +31,3 @@ otpUi: transitFareEntry: "{name} : {value}" transitFareUnknown: No hay información sobre las tarifas tripIncludesFlex: Este viaje incluye rutas flexibles. {extraMessage} - minutesActive: 'Tiempo de actividad: {minutes, plural, one {# minuto} - other {# minutos}}' - timeActiveDescription: "Al hacer este viaje, gastarás {walkMinutes, plural, - one {# minuto} other {# minutos}} caminando y {bikeMinutes, - plural, one {# minuto} other {# minutos}} en bicicleta.\n" diff --git a/packages/trip-details/i18n/fr.yml b/packages/trip-details/i18n/fr.yml index 93798c0c2..976a9d3d0 100644 --- a/packages/trip-details/i18n/fr.yml +++ b/packages/trip-details/i18n/fr.yml @@ -15,13 +15,6 @@ otpUi: departure: >- Départ le {departureDate, date, long} à {departureDate, time, short} - fareDetailsHeaders: - cash: Espèces - electronic: Électronique - regular: Normal - senior: Séniors - special: Spécial - youth: Jeunes hideDetail: Masquer les détails minutesActive: "Activité physique\_: {minutes, plural, one {# minute} other {# minutes}}" showDetail: Afficher les détails diff --git a/packages/trip-details/i18n/ko.yml b/packages/trip-details/i18n/ko.yml index 25ca80bcc..53bcc3f9f 100644 --- a/packages/trip-details/i18n/ko.yml +++ b/packages/trip-details/i18n/ko.yml @@ -1,5 +1,12 @@ otpUi: TripDetails: + FareTable: + cash: 현금 + electronic: 전자 + regular: 성인 + senior: 경로 + special: 특별 + youth: 청소년 co2: "CO₂ 배출: {co2}" co2description: >- CO₂ 강도는 각 모드의 CO₂ 강도를 트립에서 각 다리가 걸은 거리를 곱하여 계산됩니다. 각 모드의 CO₂ 강도는 이 @@ -7,13 +14,6 @@ otpUi: departure: >- {departureDate, time, short}{departureDate, date, long} 출발 - fareDetailsHeaders: - cash: 현금 - electronic: 전자 - regular: 성인 - senior: 경로 - special: 특별 - youth: 청소년 hideDetail: 세부정보 숨기기 showDetail: 세부정보 표시 title: 트립 상세정보 diff --git a/packages/trip-details/i18n/nb_NO.yml b/packages/trip-details/i18n/nb_NO.yml index 10f433bb6..e4b9c3594 100644 --- a/packages/trip-details/i18n/nb_NO.yml +++ b/packages/trip-details/i18n/nb_NO.yml @@ -1,4 +1,4 @@ otpUi: TripDetails: - fareDetailsHeaders: + FareTable: cash: Kontanter diff --git a/packages/trip-details/i18n/vi.yml b/packages/trip-details/i18n/vi.yml index 5a532dce6..dbf6dbe04 100644 --- a/packages/trip-details/i18n/vi.yml +++ b/packages/trip-details/i18n/vi.yml @@ -1,5 +1,12 @@ otpUi: TripDetails: + FareTable: + cash: Tiền mặt + electronic: Điện tử + regular: Người lớn + senior: Người lớn tuổi + special: Đặc biệt + youth: Thiếu niên co2: "CO₂ thải ra: {co2}" co2description: >- Nồng độ CO₂ được tính bằng cách nhân khoảng cách của mỗi chặng của một @@ -8,13 +15,6 @@ otpUi: departure: >- Khởi hành {departureDate, date, long} lúc {departureDate, time, short} - fareDetailsHeaders: - cash: Tiền mặt - electronic: Điện tử - regular: Người lớn - senior: Người lớn tuổi - special: Đặc biệt - youth: Thiếu niên hideDetail: Ẩn chi tiết showDetail: Hiển thị chi tiết title: Chi tiết chuyến đi diff --git a/packages/trip-details/i18n/zh_Hans.yml b/packages/trip-details/i18n/zh_Hans.yml index 304d4124d..31ec08ac4 100644 --- a/packages/trip-details/i18n/zh_Hans.yml +++ b/packages/trip-details/i18n/zh_Hans.yml @@ -1,17 +1,17 @@ otpUi: TripDetails: - co2: "排放的二氧化碳: {co2}" - co2description: CO₂ 强度的计算方法是将行程的每条腿的距离乘以每种模式的 CO₂ 强度。 每种模式的二氧化碳强度来自此电子表格。 - departure: >- - {departureDate, date, long} {departureDate, time, - short} 出发 - fareDetailsHeaders: + FareTable: cash: 现金 electronic: 电子的 regular: 成人 senior: 长者 special: 特别的 youth: 青年 + co2: "排放的二氧化碳: {co2}" + co2description: CO₂ 强度的计算方法是将行程的每条腿的距离乘以每种模式的 CO₂ 强度。 每种模式的二氧化碳强度来自此电子表格。 + departure: >- + {departureDate, date, long} {departureDate, time, + short} 出发 hideDetail: 隐藏细节 showDetail: 显示详细资料 title: 行程详情 From c4753fa6a8eca4f03d8c8d7f95246757aad174fd Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 14:49:21 -0700 Subject: [PATCH 24/40] fix crash --- packages/trip-details/src/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/trip-details/src/index.tsx b/packages/trip-details/src/index.tsx index a997701aa..00bf4a3e8 100644 --- a/packages/trip-details/src/index.tsx +++ b/packages/trip-details/src/index.tsx @@ -127,7 +127,7 @@ export function TripDetails({ /> ); - fare = defaultFareTotal.amount && ( + fare = defaultFareTotal?.amount && ( 1 ? "list-item" : "" }}> From 8596ad94430b17a1c2c62ad00522eae2a2d7fadf Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 14:50:25 -0700 Subject: [PATCH 25/40] i18n: remove unused key --- packages/trip-details/i18n/en-US.yml | 1 - packages/trip-details/i18n/es.yml | 1 - packages/trip-details/i18n/fr.yml | 1 - packages/trip-details/i18n/ko.yml | 1 - packages/trip-details/i18n/vi.yml | 1 - packages/trip-details/i18n/zh_Hans.yml | 1 - 6 files changed, 6 deletions(-) diff --git a/packages/trip-details/i18n/en-US.yml b/packages/trip-details/i18n/en-US.yml index bdcd24cf1..aaf2a54f9 100644 --- a/packages/trip-details/i18n/en-US.yml +++ b/packages/trip-details/i18n/en-US.yml @@ -29,5 +29,4 @@ otpUi: transferDiscountExplanation: Transfer discount of {transferAmount} is applied transitFare: Transit Fare transitFareEntry: "{name}: {value}" - transitFareUnknown: No fare info tripIncludesFlex: This trip includes flexible routes. {extraMessage} diff --git a/packages/trip-details/i18n/es.yml b/packages/trip-details/i18n/es.yml index cea653daf..b7247783e 100644 --- a/packages/trip-details/i18n/es.yml +++ b/packages/trip-details/i18n/es.yml @@ -29,5 +29,4 @@ otpUi: transferDiscountExplanation: Se aplica un descuento de transferencia de {transferAmount} transitFare: Tarifa de tránsito transitFareEntry: "{name} : {value}" - transitFareUnknown: No hay información sobre las tarifas tripIncludesFlex: Este viaje incluye rutas flexibles. {extraMessage} diff --git a/packages/trip-details/i18n/fr.yml b/packages/trip-details/i18n/fr.yml index 976a9d3d0..ae9c8f97e 100644 --- a/packages/trip-details/i18n/fr.yml +++ b/packages/trip-details/i18n/fr.yml @@ -27,5 +27,4 @@ otpUi: transferDiscountExplanation: Cette correspondance vous donne une réduction de {transferAmount} transitFare: Tarif en transports transitFareEntry: "{name} : {value}" - transitFareUnknown: Tarif inconnu tripIncludesFlex: Ce trajet comprend un service à la demande (Flex). {extraMessage} diff --git a/packages/trip-details/i18n/ko.yml b/packages/trip-details/i18n/ko.yml index 53bcc3f9f..407a29a24 100644 --- a/packages/trip-details/i18n/ko.yml +++ b/packages/trip-details/i18n/ko.yml @@ -21,5 +21,4 @@ otpUi: transferDiscountExplanation: 환승 할인 {transferAmount} 적용 transitFare: 대중 교통 운임 transitFareEntry: "{name} : {value}" - transitFareUnknown: 운임 정보 없음 tripIncludesFlex: 이 트립에는 가변 경로가 포함되어 있습니다. {extraMessage} diff --git a/packages/trip-details/i18n/vi.yml b/packages/trip-details/i18n/vi.yml index dbf6dbe04..dc5e82735 100644 --- a/packages/trip-details/i18n/vi.yml +++ b/packages/trip-details/i18n/vi.yml @@ -22,5 +22,4 @@ otpUi: transferDiscountExplanation: Giảm giá chuyển khoản {transferAmount} được áp dụng transitFare: Giá vé xe công cộng transitFareEntry: "{name}: {value}" - transitFareUnknown: Không có thông tin giá vé tripIncludesFlex: Chuyến đi này bao gồm các tuyến đường linh hoạt. {extraMessage} diff --git a/packages/trip-details/i18n/zh_Hans.yml b/packages/trip-details/i18n/zh_Hans.yml index 31ec08ac4..cbe393a91 100644 --- a/packages/trip-details/i18n/zh_Hans.yml +++ b/packages/trip-details/i18n/zh_Hans.yml @@ -19,5 +19,4 @@ otpUi: transferDiscountExplanation: 应用了 {transferAmount} 的转让折扣 transitFare: 公共交通费 transitFareEntry: "{name}: {value}" - transitFareUnknown: 没有票价信息 tripIncludesFlex: 这个行程包括灵活的路线. {extraMessage} From 0e7efb28315ed8969cdd31d284641498be49846d Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 15:18:35 -0700 Subject: [PATCH 26/40] refactor: fix i18n issues by restoring itinerary body code --- .../src/TransitLegBody/index.tsx | 69 ++++++++++++------- .../{ => i18n}/i18n-exceptions.json | 1 + 2 files changed, 44 insertions(+), 26 deletions(-) rename packages/trip-details/{ => i18n}/i18n-exceptions.json (90%) diff --git a/packages/itinerary-body/src/TransitLegBody/index.tsx b/packages/itinerary-body/src/TransitLegBody/index.tsx index dce7412fd..4d439b928 100644 --- a/packages/itinerary-body/src/TransitLegBody/index.tsx +++ b/packages/itinerary-body/src/TransitLegBody/index.tsx @@ -1,5 +1,6 @@ import coreUtils from "@opentripplanner/core-utils"; import { + FareProductSelector, FlexBookingInfo, Leg, LegIconComponent, @@ -7,7 +8,13 @@ import { } from "@opentripplanner/types"; import React, { Component, FunctionComponent, ReactElement } from "react"; import AnimateHeight from "react-animate-height"; -import { FormattedMessage, injectIntl, IntlShape } from "react-intl"; +import { + FormattedMessage, + FormattedNumber, + injectIntl, + IntlShape +} from "react-intl"; +import { getLegCost } from "@opentripplanner/core-utils/lib/itinerary"; import { Duration } from "../defaults"; import * as S from "../styled"; @@ -42,6 +49,7 @@ interface Props { TransitLegSubheader?: FunctionComponent; TransitLegSummary: FunctionComponent; transitOperator?: TransitOperator; + defaultFareSelector?: FareProductSelector; } interface State { @@ -132,7 +140,8 @@ class TransitLegBody extends Component { timeZone, TransitLegSubheader, TransitLegSummary, - transitOperator + transitOperator, + defaultFareSelector } = this.props; const { agencyBrandingUrl, agencyName, agencyUrl, alerts } = leg; const { alertsExpanded, stopsExpanded } = this.state; @@ -160,6 +169,14 @@ class TransitLegBody extends Component { !(shouldCollapseDueToAlertCount || alwaysCollapseAlerts) || !leg.alerts; const expandAlerts = alertsExpanded || shouldOnlyShowAlertsExpanded; + const legCost = + defaultFareSelector && + getLegCost( + leg, + defaultFareSelector.mediumId, + defaultFareSelector.riderCategoryId + ); + return ( <> {TransitLegSubheader && } @@ -324,32 +341,32 @@ class TransitLegBody extends Component { > - {/* {leg.fareProducts && ( - - - ) - }} - /> - - )} */} - + testest + {legCost && ( + + + ) + }} + /> + + )} {/* Average wait details, if present */} {leg.averageWait && ( diff --git a/packages/trip-details/i18n-exceptions.json b/packages/trip-details/i18n/i18n-exceptions.json similarity index 90% rename from packages/trip-details/i18n-exceptions.json rename to packages/trip-details/i18n/i18n-exceptions.json index c52a83135..755ff7466 100644 --- a/packages/trip-details/i18n-exceptions.json +++ b/packages/trip-details/i18n/i18n-exceptions.json @@ -5,6 +5,7 @@ "electronic", "regular", "special", + "senior", "youth" ] } From 596fcf85517d925669c2bc4d56cad530647095a4 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 15:19:03 -0700 Subject: [PATCH 27/40] fix(types): add type for specifying fare product ids --- packages/types/src/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index e6626d526..94057d60b 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -764,6 +764,11 @@ export type FareProduct = { }; }; +export type FareProductSelector = { + riderCategoryId: string; + mediumId: string; +}; + /** * Options for units of mass (used in CO₂ calculation config) */ From 1b0757a66051e2a31f3a6e08b0f3ea8a873b4bdc Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 15:42:54 -0700 Subject: [PATCH 28/40] chore: update snapshots --- __snapshots__/storybook.test.ts.snap | 22228 ++++++---------- .../src/TransitLegBody/index.tsx | 1 - 2 files changed, 8651 insertions(+), 13578 deletions(-) diff --git a/__snapshots__/storybook.test.ts.snap b/__snapshots__/storybook.test.ts.snap index b8b863b56..6ee268d42 100644 --- a/__snapshots__/storybook.test.ts.snap +++ b/__snapshots__/storybook.test.ts.snap @@ -24243,2174 +24243,1289 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components - 3826 191st Pl SW, Lynnwood, WA, USA + 47.7792, -122.29032
- 11:57 AM + 3:23 PM
- Walk 0.7 miles to + Walk 0.5 miles to - Alderwood Mall Blvd & 40th Ave W + 48th Ave W & 244th St SW @@ -27324,13 +26409,13 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components aria-hidden={true} className="c15 c16" > - Alderwood Mall Blvd & 40th Ave W + 48th Ave W & 244th St SW
- 12:11 PM + 3:33 PM
- Stop ID 1635 + Stop ID -
@@ -27678,11 +27227,11 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components - - Walk 245 feet to + Walk 200 feet to - Lynnwood Transit Center Bay D3 + Northgate Station
@@ -27846,13 +27395,13 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components aria-hidden={true} className="c15 c16" > - Lynnwood Transit Center Bay D3 + Northgate Station
- 12:27 PM + 4:13 PM
- Stop ID 2422 + Stop ID -
@@ -28200,11 +27886,11 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components - - Walk 0.4 miles to + Walk 1.3 miles to - 11th Ave NE & NE 45th St + New Light Christian Church, Seattle, WA, USA
@@ -28331,7 +28017,7 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components - Unnamed Path + service road - 5th Avenue Northeast + parking aisle - 48 feet + 260 feet
@@ -28397,12 +28083,144 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components - Northeast 45th Street + sidewalk - 0.3 miles + 0.1 miles + + + + +
  • +
    + + + +
    +
    + + RIGHT + on + + sidewalk + + + 0.1 miles + + +
    +
  • +
  • +
    + + + +
    +
    + + HARD_RIGHT + on + + Unnamed Path + + + 0.1 miles + + +
    +
  • +
  • +
    + + + +
    +
    + + RIGHT + on + + South Webster Street + + + 0.2 miles + + +
    +
  • +
  • +
    + + + +
    +
    + + RIGHT + on + + Unnamed Path + + + 181 feet
    @@ -28430,12 +28248,78 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components - 11th Avenue Northeast + South Webster Street + + + 0.2 miles + + + +
  • +
  • +
    + + + +
    +
    + + SLIGHTLY_LEFT + on + + 29th Avenue South + + + 190 feet + + +
    +
  • +
  • +
    + + + +
    +
    + + CONTINUE + on + + Military Road South - 178 feet + 0.4 miles
    @@ -28468,7 +28352,7 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components - 24 feet + 433 feet @@ -28494,26 +28378,16 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components className="c41 c42" > ↑ - 21' + 0' ↓ - 45' + 0' - - - + No elevation data available. mocked-react-resize-detector @@ -28527,21 +28401,18 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components
    -
    - 12:57 PM + 5:18 PM
    - otpUi.TransitLegBody.fromLocation + Arrive at + New Light Christian Church, Seattle, WA, USA
    -
    - Stop ID 9650 -
    -
    -
    - - - - - - Ride - - - - - - - - - - - - - - - 67 - - - - - Northgate Roosevelt - - - - - - - Disembark at - 12th Ave NE & NE 61st St - - - - -
    -
    -
    - Service operated by - - Metro Transit - -
    -
    - To take this route, you must - call 877-680-1287 - at least 1 day in advance - . -
    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
      -
    1. -
      - • -
      -
      - 11th Ave NE & NE 47th St -
      -
    2. -
    3. -
      - • -
      -
      - 11th Ave NE & NE 50th St -
      -
    4. -
    5. -
      - • -
      -
      - 11th Ave NE & NE 52nd St -
      -
    6. -
    7. -
      - • -
      -
      - 11th Ave NE & NE 55th St -
      -
    8. -
    9. -
      - • -
      -
      - 11th Ave NE & NE Ravenna Blvd -
      -
    10. -
    -
    - Fare: - $0.00 -
    -
    -
    -
    -
    -
    -
    -
    -
  • -
  • -
    -
    - - - - -
    -
    - - 12th Ave NE & NE 61st St - -
    -
    - 1:03 PM -
    - - otpUi.TransitLegBody.fromLocation - -
    -
    - Stop ID 23540 - -
    -
    -
    - - - - - - Ride - - - - - - - - - - - - - - - 45 - - - - - Loyal Heights Greenwood - - - - - - - Disembark at - NW 85th St & 8th Ave NW - - - - -
    -
    -
    - Service operated by - - Metro Transit - -
    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
      -
    1. -
      - • -
      -
      - NE 65th St & Roosevelt Way NE -
      -
    2. -
    3. -
      - • -
      -
      - NE 65th St & Oswego Pl NE -
      -
    4. -
    5. -
      - • -
      -
      - NE Ravenna Blvd & NE 68th St -
      -
    6. -
    7. -
      - • -
      -
      - NE Ravenna Blvd & Woodlawn Ave NE -
      -
    8. -
    9. -
      - • -
      -
      - East Green Lake Dr N & 4th Ave NE -
      -
    10. -
    11. -
      - • -
      -
      - East Green Lake Dr N & Sunnyside Ave N -
      -
    12. -
    13. -
      - • -
      -
      - East Green Lake Dr N & Orin Ct N -
      -
    14. -
    15. -
      - • -
      -
      - East Green Lake Dr N & Wallingford Ave N -
      -
    16. -
    17. -
      - • -
      -
      - Wallingford Ave N & N 80th St -
      -
    18. -
    19. -
      - • -
      -
      - Wallingford Ave N & N 82nd St -
      -
    20. -
    21. -
      - • -
      -
      - N 85th St & Wallingford Ave N -
      -
    22. -
    23. -
      - • -
      -
      - N 85th St & Stone Ave N -
      -
    24. -
    25. -
      - • -
      -
      - N 85th St & Aurora Ave N -
      -
    26. -
    27. -
      - • -
      -
      - N 85th St & Fremont Ave N -
      -
    28. -
    29. -
      - • -
      -
      - N 85th St & Greenwood Ave N -
      -
    30. -
    31. -
      - • -
      -
      - NW 85th St & 3rd Ave NW -
      -
    32. -
    -
    - Fare: - $0.00 -
    -
    -
    -
    -
    -
    -
    -
    -
  • -
  • -
    -
    - - - - -
    -
    - - NW 85th St & 8th Ave NW - -
    -
    - 1:24 PM -
    - - otpUi.TransitLegBody.fromLocation - -
    -
    - Stop ID 37060 - -
    -
    -
    - - - - - - - - - - - - - - - Walk 0.1 miles to - - 8212 8th Ave NW, Seattle, WA, USA - - - - -
    - - - - -
    -
    -
      -
    1. -
      - - - -
      -
      - - Head - EAST - on - - Northwest 85th Street - - - 158 feet - - -
      -
    2. -
    3. -
      - - - -
      -
      - - RIGHT - on - - 8th Avenue Northwest - - - 0.1 miles - - -
      -
    4. -
    5. -
      - - - -
      -
      - - LEFT - on - - Northwest 83rd Street - - - 62 feet - - -
      -
    6. -
    -
    -
    -
    -
    -
    -
  • -
  • -
    - - - - -
    -
    - - 8212 8th Ave NW, Seattle, WA, USA - -
    -
    - 1:27 PM -
    - - Arrive at - 8212 8th Ave NW, Seattle, WA, USA - -
    -
  • - -`; - -exports[`Storyshots ItineraryBody/otp-react-redux OTP 2 Flex Itinerary 1`] = ` - - + + +`; + +exports[`Storyshots ItineraryBody/otp-react-redux OTP 2 Flex Itinerary 1`] = ` + + - 3826 191st Pl SW, Lynnwood, WA, USA + 47.7792, -122.29032
    - 11:57 AM + 3:23 PM
    - Walk 0.7 miles to + Walk 0.5 miles to - Alderwood Mall Blvd & 40th Ave W + 48th Ave W & 244th St SW @@ -112367,12 +110179,12 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` aria-hidden={true} className="styled__SRHidden-sc-1q8npbl-56" > - 11 + [o - Silver Firs - Edmonds + @@ -112385,18 +110197,13 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` aria-hidden={true} className="c8" > - Alderwood Mall Blvd & 40th Ave W - - ID 1635 - + 48th Ave W & 244th St SW
    - 12:11 PM + 3:33 PM
    -
    - - 116 - -
    - - Edmonds - + - Disembark at - Lynnwood Transit Center Bay C2 - - ID 2110 - + Northgate Station - Bay 4
    @@ -113505,27 +112103,27 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = `
    -
    - - 67 - - + +
    @@ -113537,1163 +112135,99 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` aria-hidden={true} className="c8" > - 11th Ave NE & NE 45th St - - ID 9650 - + New Light Christian Church, Seattle, WA, USA
    - 12:57 PM + 5:18 PM
    - otpUi.TransitLegBody.fromLocation + Arrive at + New Light Christian Church, Seattle, WA, USA
    +
    -
    -
    - - - - - - Ride - - -
    - - 67 - -
    - - - Northgate Roosevelt - - -
    - - - - Disembark at - 12th Ave NE & NE 61st St - - ID 23540 - - -
    - -
    -
    -
    -
    - To take this route, you must - call 877-680-1287 - at least 1 day in advance - . -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
      -
    1. -
      - • -
      -
      - 11th Ave NE & NE 47th St -
      -
    2. -
    3. -
      - • -
      -
      - 11th Ave NE & NE 50th St -
      -
    4. -
    5. -
      - • -
      -
      - 11th Ave NE & NE 52nd St -
      -
    6. -
    7. -
      - • -
      -
      - 11th Ave NE & NE 55th St -
      -
    8. -
    9. -
      - • -
      -
      - 11th Ave NE & NE Ravenna Blvd -
      -
    10. -
    -
    - Fare: - $0.00 -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    - -
  • -
    -
    -
    -
    -
    - - 45 - - - - -
    -
    -
    -
    -
    - - 12th Ave NE & NE 61st St - - ID 23540 - - -
    -
    - 1:03 PM -
    - - otpUi.TransitLegBody.fromLocation - -
    -
    -
    - - - - - - Ride - - -
    - - 45 - -
    - - - Loyal Heights Greenwood - - -
    - - - - Disembark at - NW 85th St & 8th Ave NW - - ID 37060 - - -
    - -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
      -
    1. -
      - • -
      -
      - NE 65th St & Roosevelt Way NE -
      -
    2. -
    3. -
      - • -
      -
      - NE 65th St & Oswego Pl NE -
      -
    4. -
    5. -
      - • -
      -
      - NE Ravenna Blvd & NE 68th St -
      -
    6. -
    7. -
      - • -
      -
      - NE Ravenna Blvd & Woodlawn Ave NE -
      -
    8. -
    9. -
      - • -
      -
      - East Green Lake Dr N & 4th Ave NE -
      -
    10. -
    11. -
      - • -
      -
      - East Green Lake Dr N & Sunnyside Ave N -
      -
    12. -
    13. -
      - • -
      -
      - East Green Lake Dr N & Orin Ct N -
      -
    14. -
    15. -
      - • -
      -
      - East Green Lake Dr N & Wallingford Ave N -
      -
    16. -
    17. -
      - • -
      -
      - Wallingford Ave N & N 80th St -
      -
    18. -
    19. -
      - • -
      -
      - Wallingford Ave N & N 82nd St -
      -
    20. -
    21. -
      - • -
      -
      - N 85th St & Wallingford Ave N -
      -
    22. -
    23. -
      - • -
      -
      - N 85th St & Stone Ave N -
      -
    24. -
    25. -
      - • -
      -
      - N 85th St & Aurora Ave N -
      -
    26. -
    27. -
      - • -
      -
      - N 85th St & Fremont Ave N -
      -
    28. -
    29. -
      - • -
      -
      - N 85th St & Greenwood Ave N -
      -
    30. -
    31. -
      - • -
      -
      - NW 85th St & 3rd Ave NW -
      -
    32. -
    -
    - Fare: - $0.00 -
    -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
  • -
  • -
    -
    -
    -
    -
    - - - Travel by walking - - - -
    -
    -
    -
    -
    - - NW 85th St & 8th Ave NW - - ID 37060 - - -
    -
    - 1:24 PM -
    - - otpUi.TransitLegBody.fromLocation - -
    -
    -
    - - - - - - - - Walk 0.1 miles to - - 8212 8th Ave NW, Seattle, WA, USA - - - - -
    - - - - -
    -
    -
      -
    1. -
      - - - -
      -
      - - Head - EAST - on - - Northwest 85th Street - - - 158 feet - - -
      -
    2. -
    3. -
      - - - -
      -
      - - RIGHT - on - - 8th Avenue Northwest - - - 0.1 miles - - -
      -
    4. -
    5. -
      - - - -
      -
      - - LEFT - on - - Northwest 83rd Street - - - 62 feet - - -
      -
    6. -
    -
    -
    -
    -
    -
    -
    - -
    -
  • -
  • -
    -
    -
    -
    - -
    -
    -
    -
    -
    - - 8212 8th Ave NW, Seattle, WA, USA - -
    -
    - 1:27 PM -
    - - Arrive at - 8212 8th Ave NW, Seattle, WA, USA - -
    -
    - -
    -
  • - -`; - -exports[`Storyshots ItineraryBody/otp-ui OTP 2 Flex Itinerary 1`] = ` - - + View on map + + + + +
    + + +`; + +exports[`Storyshots ItineraryBody/otp-ui OTP 2 Flex Itinerary 1`] = ` + +
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - No fare info - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    @@ -253246,11 +249619,11 @@ exports[`Storyshots TripDetails Fare Components Itinerary 2`] = ` > Depart - August 20, 2020 + May 26, 2023 at - 11:57 AM + 3:23 PM
    @@ -253297,100 +249670,6 @@ exports[`Storyshots TripDetails Fare Components Itinerary 2`] = ` -
    -
    - -
    -
    - - - - - Transit Fare - : - - $5.75 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    Time Spent Active: - 25 minutes + 41 minutes
    -
    -
    - -
    -
    - - This trip includes flexible routes. - -
    -
    -
    -
    - -
    -
    -
    -
    `; -exports[`Storyshots TripDetails Fare Leg Table Story 1`] = ` +exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 1`] = ` - `; -exports[`Storyshots TripDetails Fare Leg Table Story 2`] = ` +exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 2`] = ` .c2 { display: inline-block; vertical-align: middle; @@ -255722,32 +251392,32 @@ exports[`Storyshots TripDetails Fare Leg Table Story 2`] = ` scope="col" > - Adult + otpUi.TripDetails.FareTable.regular
    - Cash + otpUi.TripDetails.FareTable.cash
    - $5.50 + $5.75
    - Electronic + otpUi.TripDetails.FareTable.electronic
    - $3.25 + $3.00
    - Special + otpUi.TripDetails.FareTable.special
    $1.50 @@ -255757,51 +251427,21 @@ exports[`Storyshots TripDetails Fare Leg Table Story 2`] = `
    - 512 + 347 - $3.25 + $2.75 - - - $3.25 + $2.75 - - $1.50
    - 40 + 1-Line - - - $2.25 + $3.00 - $0.00 + $0.25
    + + + + + + + + + + @@ -255951,135 +251577,58 @@ exports[`Storyshots TripDetails Fare Leg Table Story 2`] = ` scope="col" > - Youth + otpUi.TripDetails.FareTable.senior - - - - -
    + + otpUi.TripDetails.FareTable.youth + + + + otpUi.TripDetails.FareTable.cash + +
    + $0.00 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $0.00 +
    - E Line + 347 - - $0.00 - - + $0.00 +
    + 1-Line + $0.00 - - $0.00
    - Cash + otpUi.TripDetails.FareTable.cash
    - $3.00 + $2.00
    - Electronic + otpUi.TripDetails.FareTable.electronic
    - $1.50 + $1.00
    - 512 - - $1.50 - - - - $1.50 -
    - 40 + 347 - - - $1.50 + $1.00 - - - $0.00 + $1.00
    - E Line + 1-Line - - - $0.00 + $1.00
    - +

    -

    +
    +
    -
    - - - - - - - - - - - - - - - - -
    - - Adult - - - - Cash - -
    - $2.50 -
    - - Electronic - -
    - $2.50 -
    - - Special - -
    - $1.50 -
    - Mariner P&R - Aurora Village - - $2.50 - - $2.50 - - $1.25 -
    - E Line - - $0.00 - - $0.00 - - - $0.25 -
    - - - - - - - - - - - - - - - - -
    +
    - - Youth - -
    + Depart + + May 26, 2023 + + at + + 3:23 PM + + + +
    - - Cash - -
    - $0.00 -
    +
    + +
    + + + +
    +
    - - Electronic - -
    - $0.00 -
    - $0.00 - - $0.00 -
    +
    + + Transit Fare + : + + $5.75 + + +
    + + + + + + + + + + + + + + + + + +
    + + otpUi.TripDetails.FareTable.regular + + + + otpUi.TripDetails.FareTable.cash + +
    + $5.75 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $3.00 +
    + + otpUi.TripDetails.FareTable.special + +
    + $1.50 +
    + + $2.75 + + $2.75 + + $1.50 +
    + + $3.00 + + + + $0.25 + + + + $0.00 +
    + + + + + + + + + + + + + + +
    + + otpUi.TripDetails.FareTable.youth + + + + otpUi.TripDetails.FareTable.cash + +
    + $0.00 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $0.00 +
    + + $0.00 + + $0.00 +
    + + $0.00 + + $0.00 +
    + + + + + + + + + + + + + + +
    + + otpUi.TripDetails.FareTable.senior + + + + otpUi.TripDetails.FareTable.cash + +
    + $2.00 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $1.00 +
    + + $1.00 + + $1.00 +
    + + $1.00 + + + + $0.00 +
    +
    +
    + + +
    - E Line -
    - $0.00 - - $0.00 -
    - - +
    + +
    + + + +
    -
    - - - - - - - - - - - - - -
    - - Senior - - - - Cash - -
    - $2.25 -
    - Mariner P&R - Aurora Village - - $1.25 - - $1.25 -
    + + + +
    - E Line -
    - $1.00 - +
    + + By taking this trip, you'll spend + + 41 minutes + + walking and + + 0 minutes + + biking. + +
    + + + +
    +
    - - $0.00 -
    +
    +
    + + CO₂ Emitted: + + 2,699g + + + +
    +
    +
    +
    + + CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from + + this spreadsheet + + . +
    +
    +
    + + `; @@ -262102,100 +258345,6 @@ exports[`Storyshots TripDetails Park And Ride Itinerary 2`] = ` -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Tarif en transports: - - $9.50 - - - - - - -
    -
    -
    -
    - - Custom details about fares (transitFares: - {"regular":{"currency":{"symbol":"$","currency":"USD","defaultFractionDigits":2,"currencyCode":"USD"},"cents":950}} - ) - - (cents), can be constructed dynamically using any markup. -
    -
    -
    -
    uber @@ -264108,7 +260040,7 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` aria-controls="mocked-random-id" aria-expanded={false} aria-label="otpUi.TripDetails.showDetail" - className="c7 c9" + className="c7 c10" id="expand-button" onClick={[Function]} tabIndex={0} @@ -264170,7 +260102,6 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` Custom details about fares (transitFares: - {"regular":{"currency":{"symbol":"$","currency":"USD","defaultFractionDigits":2,"currencyCode":"USD"},"cents":950}} ) (cents), can be constructed dynamically using any markup. @@ -264213,7 +260144,7 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` aria-controls="mocked-random-id" aria-expanded={false} aria-label="otpUi.TripDetails.showDetail" - className="c7 c9" + className="c7 c10" id="expand-button" onClick={[Function]} tabIndex={0} @@ -264327,7 +260258,7 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` aria-controls="mocked-random-id" aria-expanded={false} aria-label="otpUi.TripDetails.showDetail" - className="c7 c9" + className="c7 c10" id="expand-button" onClick={[Function]} tabIndex={0} @@ -264414,13 +260345,13 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary With Custom Messages 1`] = locale="en-US" messages={ Object { + "otpUi.TripDetails.FareTable.cash": "Cash", + "otpUi.TripDetails.FareTable.electronic": "ORCA", + "otpUi.TripDetails.FareTable.regular": "Regular", + "otpUi.TripDetails.FareTable.senior": "Senior", + "otpUi.TripDetails.FareTable.special": "LIFT", + "otpUi.TripDetails.FareTable.youth": "Youth", "otpUi.TripDetails.departure": "Leave at {departureDate, time, short} on {departureDate, date, long}", - "otpUi.TripDetails.fareDetailsHeaders.cash": "Cash", - "otpUi.TripDetails.fareDetailsHeaders.electronic": "ORCA", - "otpUi.TripDetails.fareDetailsHeaders.regular": "Regular", - "otpUi.TripDetails.fareDetailsHeaders.senior": "Senior", - "otpUi.TripDetails.fareDetailsHeaders.special": "LIFT", - "otpUi.TripDetails.fareDetailsHeaders.youth": "Youth", "otpUi.TripDetails.title": "Custom Trip Details Title", "otpUi.TripDetails.tncFare": "Pay {minTNCFare}-{maxTNCFare} to {companies}", } @@ -264436,6 +260367,13 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary With Custom Messages 1`] = "enabled": true, } } + defaultFareType={ + Object { + "headerKey": "electronicRegular", + "mediumId": "orca:electronic", + "riderCategoryId": "orca:regular", + } + } fareKeyNameMap={ Object { "electronicRegular": "Tarif Orca", @@ -265062,99 +261000,6 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary With Custom Messages 2`] =
    -
    -
    - -
    -
    - - - - - Tarif en transports: - - $9.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    Leave at {departureDate, time, short} on {departureDate, date, long}", - "otpUi.TripDetails.fareDetailsHeaders.cash": "Cash", - "otpUi.TripDetails.fareDetailsHeaders.electronic": "ORCA", - "otpUi.TripDetails.fareDetailsHeaders.regular": "Regular", - "otpUi.TripDetails.fareDetailsHeaders.senior": "Senior", - "otpUi.TripDetails.fareDetailsHeaders.special": "LIFT", - "otpUi.TripDetails.fareDetailsHeaders.youth": "Youth", "otpUi.TripDetails.title": "Custom Trip Details Title", "otpUi.TripDetails.tncFare": "Pay {minTNCFare}-{maxTNCFare} to {companies}", } @@ -265494,53 +261339,6 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 1`] = ` "enabled": true, } } - fareDetailsLayout={ - Array [ - Object { - "cols": Array [ - Object { - "header": "cash", - "key": "regular", - }, - Object { - "header": "electronic", - "key": "electronicRegular", - }, - Object { - "header": "special", - "key": "electronicSpecial", - }, - ], - "header": "regular", - }, - Object { - "cols": Array [ - Object { - "header": "cash", - "key": "youth", - }, - Object { - "header": "electronic", - "key": "electronicYouth", - }, - ], - "header": "youth", - }, - Object { - "cols": Array [ - Object { - "header": "cash", - "key": "cash", - }, - Object { - "header": "electronic", - "key": "electronic", - }, - ], - "header": "senior", - }, - ] - } fareKeyNameMap={ Object { "electronicRegular": "Tarif Orca", @@ -267490,7 +263288,7 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` white-space: nowrap; } -.c13 { +.c9 { color: #00f; font-size: 16px; margin-left: 6px; @@ -267501,15 +263299,6 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` float: right; } -.c9 { - display: inline-block; -} - -.c9 > span { - display: block; - padding-left: 1.75ch; -} - .c2 { margin-top: 6px; } @@ -267555,49 +263344,6 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` white-space: pre; } -.c11 th { - font-weight: normal; - min-width: 5ch; - padding: 0.75em 1.5em; - text-align: center; -} - -.c11 th:nth-of-type(2n + 1) { - background: #cccccc22; -} - -.c11 th.main { - background: #333333; - color: #ffffffcc; -} - -.c10 { - border-collapse: collapse; - display: block; - margin-bottom: 16px; - padding: 0; -} - -.c10 td { - text-align: right; -} - -.c10 td:nth-of-type(2n + 1) { - background: #cccccc22; -} - -.c10 td.no-zebra { - background: none; -} - -.c10 th:first-of-type { - height: 40px; -} - -.c12 { - padding-left: 4px; -} -
    @@ -267696,490 +263442,6 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = `
    -
    -
    - -
    -
    - -
    - - - Tarif en transports: - - $5.50 - - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - Regular - - - - Cash - -
    - $5.50 -
    - - ORCA - -
    - $3.25 -
    - - LIFT - -
    - $1.50 -
    - 512 - - $3.25 - - - - $3.25 - - - - $1.50 -
    - 40 - - - - $2.25 - - - - $0.00 - - - - $0.00 -
    - E Line - - - - $0.00 - - - - $0.00 - - - - $0.00 -
    - - - - - - - - - - - - - - - - - - - - - -
    - - Youth - - - - Cash - -
    - $3.00 -
    - - ORCA - -
    - $1.50 -
    - 512 - - $1.50 - - - - $1.50 -
    - 40 - - - - $1.50 - - - - $0.00 -
    - E Line - - - - $0.00 - - - - $0.00 -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - €2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    { - testest {legCost && ( Date: Mon, 3 Jul 2023 15:53:56 -0700 Subject: [PATCH 29/40] deps: update types versions --- packages/core-utils/package.json | 2 +- packages/trip-details/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core-utils/package.json b/packages/core-utils/package.json index 51fe037e7..feab82d0e 100644 --- a/packages/core-utils/package.json +++ b/packages/core-utils/package.json @@ -31,7 +31,7 @@ "tsc": "tsc" }, "devDependencies": { - "@opentripplanner/types": "^5.0.0", + "@opentripplanner/types": "^6.0.0-alpha.9", "@types/chroma-js": "^2.1.4" } } diff --git a/packages/trip-details/package.json b/packages/trip-details/package.json index cf61c90cc..dbf680e4f 100644 --- a/packages/trip-details/package.json +++ b/packages/trip-details/package.json @@ -17,7 +17,7 @@ "react-animate-height": "^3.0.4" }, "devDependencies": { - "@opentripplanner/types": "^5.0.0", + "@opentripplanner/types": "^6.0.0-alpha.9", "@types/flat": "^5.0.2" }, "peerDependencies": { From b8e2ae98a07ea547a937b2a364a20a01b2e33a80 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 3 Jul 2023 13:28:13 -0700 Subject: [PATCH 30/40] refactor(types): generate commit BREAKING CHANGE: Removes support for older OTP1/REST legs --- packages/types/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 94057d60b..b5d9fa496 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -750,6 +750,9 @@ export type ModeButtonDefinition = { modeSettings?: ModeSetting[]; // From OTP definitions + config }; +/** + * Definition for a fare product used to pay the fare for a leg in a transit journey + */ export type FareProduct = { price: Money; id: string; From 33cad91ad8d07f4b8a361779180861ab53ddee66 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 10 Jul 2023 16:22:45 -0700 Subject: [PATCH 31/40] refactor(types): pr comments --- packages/types/src/index.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index b5d9fa496..d9f2e97ea 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -293,6 +293,7 @@ export type Leg = { dropOffBookingInfo?: FlexDropOffBookingInfo; duration: number; endTime: number; + fareProducts?: { id: string; product: FareProduct }[]; from: Place; headsign?: string; interlineWithPreviousLeg: boolean; @@ -337,7 +338,6 @@ export type Leg = { tripBlockId?: string; tripId?: string; walkingBike?: boolean; - fareProducts?: Array<{ id: string; product: FareProduct }>; }; type TripStopTime = { @@ -754,22 +754,22 @@ export type ModeButtonDefinition = { * Definition for a fare product used to pay the fare for a leg in a transit journey */ export type FareProduct = { - price: Money; id: string; - name: string; - riderCategory?: { + medium?: { id: string; name: string; }; - medium?: { + name: string; + price: Money; + riderCategory?: { id: string; name: string; }; }; export type FareProductSelector = { - riderCategoryId: string; mediumId: string; + riderCategoryId: string; }; /** From 94a3bb6bd37e73014169541ccd02335b4cd2e8ca Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 10 Jul 2023 16:32:01 -0700 Subject: [PATCH 32/40] i18n: improve french text --- packages/trip-details/__mocks__/custom-french-messages.yml | 2 +- packages/trip-details/i18n/fr.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/trip-details/__mocks__/custom-french-messages.yml b/packages/trip-details/__mocks__/custom-french-messages.yml index ab37ecc0d..6be58a368 100644 --- a/packages/trip-details/__mocks__/custom-french-messages.yml +++ b/packages/trip-details/__mocks__/custom-french-messages.yml @@ -3,7 +3,7 @@ otpUi: FareTable: cash: Espèces electronic: ORCA - regular: Ordinaire + regular: Plein tarif senior: Senior special: LIFT youth: Jeune diff --git a/packages/trip-details/i18n/fr.yml b/packages/trip-details/i18n/fr.yml index ae9c8f97e..d26732fef 100644 --- a/packages/trip-details/i18n/fr.yml +++ b/packages/trip-details/i18n/fr.yml @@ -3,7 +3,7 @@ otpUi: FareTable: cash: Espèces electronic: Électronique - regular: Normal + regular: Plein tarif senior: Séniors special: Spécial youth: Jeunes From c76537135aa7ccfcc008fa28ed86d4c59f3cc4e8 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 10 Jul 2023 16:43:12 -0700 Subject: [PATCH 33/40] address pr comments --- .../core-utils/src/__tests__/itinerary.js | 8 +-- .../src/TransitLegBody/index.tsx | 16 +++--- .../trip-details/src/TripDetails.story.tsx | 52 +++++++++---------- packages/trip-details/src/index.tsx | 15 +++--- packages/trip-details/src/types.ts | 15 ++---- packages/trip-details/src/utils.tsx | 4 +- yarn.lock | 5 ++ 7 files changed, 58 insertions(+), 57 deletions(-) diff --git a/packages/core-utils/src/__tests__/itinerary.js b/packages/core-utils/src/__tests__/itinerary.js index e0f31d758..6a10fb8e1 100644 --- a/packages/core-utils/src/__tests__/itinerary.js +++ b/packages/core-utils/src/__tests__/itinerary.js @@ -94,18 +94,20 @@ describe("util > itinerary", () => { const leg = { fareProducts: [ { + id: "testId", product: { medium: { id: "cash" }, - riderCategory: { id: "regular" }, name: "rideCost", - price: { amount: 200, currency: "USD" } + price: { amount: 200, currency: "USD" }, + riderCategory: { id: "regular" } } }, { + id: "testId", product: { + medium: { id: "cash" }, name: "transfer", price: { amount: 50, currency: "USD" }, - medium: { id: "cash" }, riderCategory: { id: "regular" } } } diff --git a/packages/itinerary-body/src/TransitLegBody/index.tsx b/packages/itinerary-body/src/TransitLegBody/index.tsx index d20aef811..53b13b39a 100644 --- a/packages/itinerary-body/src/TransitLegBody/index.tsx +++ b/packages/itinerary-body/src/TransitLegBody/index.tsx @@ -14,7 +14,7 @@ import { injectIntl, IntlShape } from "react-intl"; -import { getLegCost } from "@opentripplanner/core-utils/lib/itinerary"; + import { Duration } from "../defaults"; import * as S from "../styled"; @@ -35,11 +35,12 @@ interface Props { AlertBodyIcon?: FunctionComponent; AlertToggleIcon?: FunctionComponent; alwaysCollapseAlerts: boolean; + defaultFareSelector?: FareProductSelector; intl: IntlShape; leg: Leg; + legDestination: string; LegIcon: LegIconComponent; legIndex: number; - legDestination: string; RouteDescription: FunctionComponent; setActiveLeg: SetActiveLegFunction; setViewedTrip: SetViewedTripFunction; @@ -49,7 +50,6 @@ interface Props { TransitLegSubheader?: FunctionComponent; TransitLegSummary: FunctionComponent; transitOperator?: TransitOperator; - defaultFareSelector?: FareProductSelector; } interface State { @@ -126,13 +126,14 @@ class TransitLegBody extends Component { render(): ReactElement { const { - AlertToggleIcon = S.DefaultAlertToggleIcon, AlertBodyIcon, + AlertToggleIcon = S.DefaultAlertToggleIcon, alwaysCollapseAlerts, + defaultFareSelector, intl, leg, - LegIcon, legDestination, + LegIcon, RouteDescription, setViewedTrip, showAgencyInfo, @@ -140,8 +141,7 @@ class TransitLegBody extends Component { timeZone, TransitLegSubheader, TransitLegSummary, - transitOperator, - defaultFareSelector + transitOperator } = this.props; const { agencyBrandingUrl, agencyName, agencyUrl, alerts } = leg; const { alertsExpanded, stopsExpanded } = this.state; @@ -171,7 +171,7 @@ class TransitLegBody extends Component { const legCost = defaultFareSelector && - getLegCost( + coreUtils.itinerary.getLegCost( leg, defaultFareSelector.mediumId, defaultFareSelector.riderCategoryId diff --git a/packages/trip-details/src/TripDetails.story.tsx b/packages/trip-details/src/TripDetails.story.tsx index 4d878a6dc..bc7eba734 100644 --- a/packages/trip-details/src/TripDetails.story.tsx +++ b/packages/trip-details/src/TripDetails.story.tsx @@ -59,57 +59,57 @@ const StyledTripDetails = styled(TripDetails)` const otp2FareByLegLayout: FareTableLayout[] = [ { - headerKey: "regular", cols: [ { columnHeaderKey: "cash", - riderCategoryId: "orca:regular", - mediumId: "orca:cash" + mediumId: "orca:cash", + riderCategoryId: "orca:regular" }, { columnHeaderKey: "electronic", - riderCategoryId: "orca:regular", - mediumId: "orca:electronic" + mediumId: "orca:electronic", + riderCategoryId: "orca:regular" }, { columnHeaderKey: "special", - riderCategoryId: "orca:special", - mediumId: "orca:electronic" + mediumId: "orca:electronic", + riderCategoryId: "orca:special" } - ] + ], + headerKey: "regular" }, { - headerKey: "youth", cols: [ { columnHeaderKey: "cash", - riderCategoryId: "orca:youth", - mediumId: "orca:cash" + mediumId: "orca:cash", + riderCategoryId: "orca:youth" }, { columnHeaderKey: "electronic", - riderCategoryId: "orca:youth", - mediumId: "orca:electronic" + mediumId: "orca:electronic", + riderCategoryId: "orca:youth" }, { columnHeaderKey: "test", - riderCategoryId: "invalidkey", - mediumId: "invalidkey" + mediumId: "invalidkey", + riderCategoryId: "invalidkey" } - ] + ], + headerKey: "youth" }, { headerKey: "senior", cols: [ { columnHeaderKey: "cash", - riderCategoryId: "orca:senior", - mediumId: "orca:cash" + mediumId: "orca:cash", + riderCategoryId: "orca:senior" }, { columnHeaderKey: "electronic", - riderCategoryId: "orca:senior", - mediumId: "orca:electronic" + mediumId: "orca:electronic", + riderCategoryId: "orca:senior" } ] } @@ -193,11 +193,11 @@ function createTripDetailsTemplate( ): ComponentStory { const TripDetailsTemplate = ( { - TimeActiveDetails, + defaultFareType, DepartureDetails, FareDetails, fareDetailsLayout, - defaultFareType, + TimeActiveDetails, itinerary }: TripDetailsProps, { globals, parameters }: StoryContext @@ -280,9 +280,9 @@ export const BikeTransitBikeItinerary = makeStory({ }); export const LegFareProductsItinerary = makeStory({ - itinerary: otp2FareProducts, + defaultFareType: otp2defaultFareType, fareDetailsLayout: otp2FareByLegLayout, - defaultFareType: otp2defaultFareType + itinerary: otp2FareProducts }); export const WalkInterlinedTransitItinerary = makeStory( @@ -346,14 +346,14 @@ export const TncTransitItinerary = makeStory( export const TncTransitItineraryWithCustomMessages = makeStory( { - TimeActiveDetails: CustomTimeActiveDetails, defaultFareType: { headerKey: "electronicRegular", mediumId: "orca:electronic", riderCategoryId: "orca:regular" }, DepartureDetails: CustomDepartureDetails, - itinerary: tncTransitTncItinerary + itinerary: tncTransitTncItinerary, + TimeActiveDetails: CustomTimeActiveDetails }, { // For illustration purposes, diff --git a/packages/trip-details/src/index.tsx b/packages/trip-details/src/index.tsx index 00bf4a3e8..aa8f1eabb 100644 --- a/packages/trip-details/src/index.tsx +++ b/packages/trip-details/src/index.tsx @@ -1,4 +1,5 @@ import coreUtils from "@opentripplanner/core-utils"; +import { FareProductSelector } from "@opentripplanner/types"; import React, { ReactElement } from "react"; import { FormattedMessage, FormattedNumber } from "react-intl"; import { CalendarAlt } from "@styled-icons/fa-solid/CalendarAlt"; @@ -6,15 +7,13 @@ import { Heartbeat } from "@styled-icons/fa-solid/Heartbeat"; import { MoneyBillAlt } from "@styled-icons/fa-solid/MoneyBillAlt"; import { Leaf } from "@styled-icons/fa-solid/Leaf"; import { Route } from "@styled-icons/fa-solid/Route"; - -import { getItineraryCost } from "@opentripplanner/core-utils/lib/itinerary"; import { flatten } from "flat"; import * as S from "./styled"; import TripDetail from "./trip-detail"; import FareLegTable from "./fare-table"; import { boldText, renderFare } from "./utils"; -import { FareType, TimeActiveDetailsProps, TripDetailsProps } from "./types"; +import { TimeActiveDetailsProps, TripDetailsProps } from "./types"; // Load the default messages. import defaultEnglishMessages from "../i18n/en-US.yml"; @@ -81,7 +80,7 @@ export function TripDetails({ const { companies, fareTypes } = itinerary.legs.reduce<{ companies: string; - fareTypes: FareType[]; + fareTypes: FareProductSelector[]; }>( (prev, leg) => { if (leg.rideHailingEstimate) { @@ -110,7 +109,7 @@ export function TripDetails({ let fare; if (fareTypes.length > 0 && defaultFareType) { - const defaultFareTotal = getItineraryCost( + const defaultFareTotal = coreUtils.itinerary.getItineraryCost( itinerary.legs, defaultFareType.mediumId, defaultFareType.riderCategoryId @@ -160,12 +159,12 @@ export function TripDetails({ } return ( ) } @@ -300,9 +299,9 @@ export function TripDetails({ description={ FareDetails && ( ) } diff --git a/packages/trip-details/src/types.ts b/packages/trip-details/src/types.ts index 99a928979..9a27dc5ef 100644 --- a/packages/trip-details/src/types.ts +++ b/packages/trip-details/src/types.ts @@ -1,6 +1,6 @@ // Prettier does not recognize the import type syntax. // eslint-disable-next-line prettier/prettier -import type { MassUnitOption, Itinerary, Money, Leg } from "@opentripplanner/types"; +import type { FareProductSelector, Itinerary, Leg, Money, MassUnitOption, } from "@opentripplanner/types"; import type { ReactElement } from "react"; export interface TimeActiveDetailsProps { @@ -19,18 +19,13 @@ export interface DepartureDetailsProps { departureDate: Date; } -export interface FareType { - riderCategoryId: string; - mediumId: string; -} - /** * This is the interface used to define the layout for a particular fare table. * The table with be rendered with the columns defined here, * with each row being an individual transit leg from the itinerary. */ export interface FareTableLayout { - cols: (FareType & { + cols: (FareProductSelector & { columnHeaderKey: string; })[] headerKey: string; @@ -41,7 +36,7 @@ export interface FareLegTableProps { } // Total fare amount corresponding to a fare key -export type FareTotals = (FareType & { price: Money })[] +export type FareTotals = (FareProductSelector & { price: Money })[] export interface TransitFareProps { headerKey: string; @@ -55,9 +50,9 @@ export interface TransitFareProps { } export interface FareDetailsProps { + legs: Leg[]; maxTNCFare: number; minTNCFare: number; - legs: Leg[]; } @@ -73,7 +68,7 @@ export interface TripDetailsProps { /** * Determines which transit fare should be displayed by default, should there be multiple transit fare types. */ - defaultFareType?: { headerKey: string } & FareType; + defaultFareType?: { headerKey: string } & FareProductSelector; /** * Slot for a custom component to render the expandable section for departure. */ diff --git a/packages/trip-details/src/utils.tsx b/packages/trip-details/src/utils.tsx index 48f88c23c..36cfd05f6 100644 --- a/packages/trip-details/src/utils.tsx +++ b/packages/trip-details/src/utils.tsx @@ -1,10 +1,10 @@ -import React, { ReactElement } from "react"; +import React, { ReactElement, ReactNode } from "react"; import { FormattedNumber } from "react-intl"; /** * Format text bold (used with FormattedMessage). */ -export function boldText(contents: ReactElement | string): ReactElement { +export function boldText(contents: ReactNode): ReactElement { return {contents}; } diff --git a/yarn.lock b/yarn.lock index 047f4ecba..89314e45f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3275,6 +3275,11 @@ resolved "https://registry.yarnpkg.com/@opentripplanner/types/-/types-6.0.0-alpha.4.tgz#dee3c06675e30c596159d182ed707e7710cd937c" integrity sha512-FlYsHm/tk+x0ldrEG1X9Ph1R1k3way1oEdKX7XSnhu9lNTzL4lO0hfT1PLzNXMfBRar7TzK94PHNDibJsod8Kw== +"@opentripplanner/types@^6.0.0-alpha.9": + version "6.0.0-alpha.10" + resolved "https://registry.yarnpkg.com/@opentripplanner/types/-/types-6.0.0-alpha.10.tgz#1489c55f7741ef46df6882c682580ea96ca23d62" + integrity sha512-s0xBgA3WLqvda5itUYzv7PGyMV/dqITfnA2zpdwsbyzuNQeOYTk1tSQLWr+QH7mbUYJXAs5i8qzC/VNvDSZQqg== + "@peculiar/asn1-schema@^2.1.6", "@peculiar/asn1-schema@^2.3.0": version "2.3.3" resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.3.3.tgz#21418e1f3819e0b353ceff0c2dad8ccb61acd777" From 0b2f9db52503a458349d349d4382ab7a626894bb Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 10 Jul 2023 17:24:26 -0700 Subject: [PATCH 34/40] remove old story --- packages/trip-details/src/TripDetails.story.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/trip-details/src/TripDetails.story.tsx b/packages/trip-details/src/TripDetails.story.tsx index bc7eba734..9ecd344d0 100644 --- a/packages/trip-details/src/TripDetails.story.tsx +++ b/packages/trip-details/src/TripDetails.story.tsx @@ -37,7 +37,6 @@ const walkInterlinedTransitItinerary = require("@opentripplanner/itinerary-body/ const walkOnlyItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-only.json"); const walkTransitWalkItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-transit-walk.json"); const walkTransitWalkTransitWalkItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-transit-walk-transit-walk.json"); -const fareProductsItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json"); const flexItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/flex-itinerary.json"); const otp2ScooterItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/otp2-scooter.json"); const otp2FareProducts = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/leg-fare-products.json"); @@ -369,10 +368,6 @@ export const TncTransitItineraryWithCustomMessages = makeStory( StyledTripDetails ); -export const FareComponentsItinerary = makeStory({ - itinerary: fareProductsItinerary -}); - export const OTP2FlexItinerary = makeStory({ itinerary: flexItinerary }); export const FareLegTableStoryLegProducts = (): ReactElement => { From 48bdcc41c1d6286c4b569c070e9758a225d70f1e Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Mon, 10 Jul 2023 18:13:36 -0700 Subject: [PATCH 35/40] fix(itinerary-body): remove unused prop and add new defaultFareSelector prop BREAKING CHANGE: Removes unused showRouteFares --- .../src/ItineraryBody/index.tsx | 2 + .../src/ItineraryBody/place-row.tsx | 2 + .../src/TransitLegBody/index.tsx | 46 +++++++++---------- .../src/stories/OtpRrItineraryBody.story.tsx | 24 ++++++---- .../src/stories/OtpUiItineraryBody.story.tsx | 5 +- .../itinerary-body-defaults-wrapper.tsx | 4 +- packages/itinerary-body/src/types.ts | 9 +++- 7 files changed, 52 insertions(+), 40 deletions(-) diff --git a/packages/itinerary-body/src/ItineraryBody/index.tsx b/packages/itinerary-body/src/ItineraryBody/index.tsx index 8052c3878..f6362f431 100755 --- a/packages/itinerary-body/src/ItineraryBody/index.tsx +++ b/packages/itinerary-body/src/ItineraryBody/index.tsx @@ -18,6 +18,7 @@ const ItineraryBody = ({ alwaysCollapseAlerts = false, className, config, + defaultFareSelector, diagramVisible, frameLeg = noop, itinerary, @@ -61,6 +62,7 @@ const ItineraryBody = ({ // eslint-disable-next-line react/no-array-index-key key={i + (isDestination ? 1 : 0)} config={config} + defaultFareSelector={defaultFareSelector} diagramVisible={diagramVisible} followsTransit={followsTransit} frameLeg={frameLeg} diff --git a/packages/itinerary-body/src/ItineraryBody/place-row.tsx b/packages/itinerary-body/src/ItineraryBody/place-row.tsx index da751c274..56e582329 100755 --- a/packages/itinerary-body/src/ItineraryBody/place-row.tsx +++ b/packages/itinerary-body/src/ItineraryBody/place-row.tsx @@ -45,6 +45,7 @@ export default function PlaceRow({ TimeColumnContent = DefaultTimeColumnContent, toRouteAbbreviation, TransitLegSubheader, + defaultFareSelector, TransitLegSummary }: PlaceRowProps): ReactElement { // NOTE: Previously there was a check for itineraries that changed vehicles @@ -146,6 +147,7 @@ export default function PlaceRow({ timeZone={config.homeTimezone} TransitLegSubheader={TransitLegSubheader} TransitLegSummary={TransitLegSummary} + defaultFareSelector={defaultFareSelector} transitOperator={coreUtils.route.getTransitOperatorFromLeg( leg, config.transitOperators diff --git a/packages/itinerary-body/src/TransitLegBody/index.tsx b/packages/itinerary-body/src/TransitLegBody/index.tsx index 53b13b39a..c408afce4 100644 --- a/packages/itinerary-body/src/TransitLegBody/index.tsx +++ b/packages/itinerary-body/src/TransitLegBody/index.tsx @@ -341,31 +341,31 @@ class TransitLegBody extends Component { > + {legCost?.price && ( + + + ) + }} + /> + + )} - {legCost && ( - - - ) - }} - /> - - )} {/* Average wait details, if present */} {leg.averageWait && ( diff --git a/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx b/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx index 0954aaaa9..394578f26 100644 --- a/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx +++ b/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx @@ -1,4 +1,4 @@ -import { Itinerary } from "@opentripplanner/types"; +import { FareProductSelector, Itinerary } from "@opentripplanner/types"; import React, { ReactElement } from "react"; import ItineraryBody from ".."; @@ -47,20 +47,21 @@ if (!isRunningJest()) { interface StoryWrapperProps { itinerary: Itinerary; - showRouteFares: boolean; - TimeColumnContent: FunctionComponent; - alwaysCollapseAlerts: boolean; + TimeColumnContent?: FunctionComponent; + defaultFareSelector?: FareProductSelector; + alwaysCollapseAlerts?: boolean; } function OtpRRItineraryBodyWrapper({ + alwaysCollapseAlerts, + defaultFareSelector, itinerary, - showRouteFares, - TimeColumnContent, - alwaysCollapseAlerts + TimeColumnContent }: StoryWrapperProps): ReactElement { return ( ( ); export const IndividualLegFareComponents = (): ReactElement => ( - + ); export const CustomTimeColumn = (): ReactElement => ( diff --git a/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx b/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx index 0f9882d44..a4eaba97c 100644 --- a/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx +++ b/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx @@ -147,10 +147,7 @@ export const OTP2FlexItinerary = (): ReactElement => ( ); export const IndividualLegFareComponents = (): ReactElement => ( - + ); export const CustomAlertIconsItinerary = (): ReactElement => ( diff --git a/packages/itinerary-body/src/stories/itinerary-body-defaults-wrapper.tsx b/packages/itinerary-body/src/stories/itinerary-body-defaults-wrapper.tsx index dbc559ed4..92aabdbac 100644 --- a/packages/itinerary-body/src/stories/itinerary-body-defaults-wrapper.tsx +++ b/packages/itinerary-body/src/stories/itinerary-body-defaults-wrapper.tsx @@ -42,6 +42,7 @@ export default class ItineraryBodyDefaultsWrapper extends Component< render(): ReactElement { const { alwaysCollapseAlerts, + defaultFareSelector, itinerary, LegIcon = TriMetLegIcon, LineColumnContent, @@ -50,7 +51,6 @@ export default class ItineraryBodyDefaultsWrapper extends Component< showAgencyInfo, showLegIcon, showMapButtonColumn = true, - showRouteFares, showViewTripButton, styledItinerary, TimeColumnContent, @@ -78,6 +78,7 @@ export default class ItineraryBodyDefaultsWrapper extends Component< AlertToggleIcon={AlertToggleIcon} alwaysCollapseAlerts={alwaysCollapseAlerts} config={config} + defaultFareSelector={defaultFareSelector} diagramVisible={diagramVisible} frameLeg={action("frameLeg")} itinerary={itinerary} @@ -94,7 +95,6 @@ export default class ItineraryBodyDefaultsWrapper extends Component< showElevationProfile showLegIcon={showLegIcon} showMapButtonColumn={showMapButtonColumn} - showRouteFares={showRouteFares} showViewTripButton={showViewTripButton} TimeColumnContent={TimeColumnContent} toRouteAbbreviation={toRouteAbbreviation} diff --git a/packages/itinerary-body/src/types.ts b/packages/itinerary-body/src/types.ts index b57fff757..208ef1496 100644 --- a/packages/itinerary-body/src/types.ts +++ b/packages/itinerary-body/src/types.ts @@ -2,6 +2,7 @@ import { FunctionComponent } from "react"; import { Config, + FareProductSelector, GradationMap, Itinerary, Leg, @@ -108,6 +109,12 @@ interface ItineraryBodySharedProps { className?: string; /** Contains OTP configuration details. */ config: Config; + /** + * Allows selection of a fare product type for display in the itinerary body. + * When fare leg information is available, it will be shown per-leg. + * Example: regular, cash or regular, electronic. + */ + defaultFareSelector?: FareProductSelector; /** * Should be either null or a legType. Indicates that a particular leg diagram * has been selected and is active. @@ -183,8 +190,6 @@ interface ItineraryBodySharedProps { showLegIcon?: boolean; /** If true, will show the right column with the map button */ showMapButtonColumn?: boolean; - /** If true, will show fare information in transit leg bodies */ - showRouteFares?: boolean; /** If true, shows the view trip button in transit leg bodies */ showViewTripButton?: boolean; /** From 63eb19384954f72e6a2cda47fe20632343c99472 Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Tue, 11 Jul 2023 10:54:48 -0700 Subject: [PATCH 36/40] test: fix itinerary test --- __snapshots__/storybook.test.ts.snap | 3047 ++++------------- .../__tests__/__snapshots__/itinerary.js.snap | 8 - .../core-utils/src/__tests__/itinerary.js | 5 +- 3 files changed, 678 insertions(+), 2382 deletions(-) delete mode 100644 packages/core-utils/src/__tests__/__snapshots__/itinerary.js.snap diff --git a/__snapshots__/storybook.test.ts.snap b/__snapshots__/storybook.test.ts.snap index 3f56b9815..d49fa8f7a 100644 --- a/__snapshots__/storybook.test.ts.snap +++ b/__snapshots__/storybook.test.ts.snap @@ -24241,6 +24241,12 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components textComponent={Symbol(react.fragment)} > `; @@ -27111,665 +27116,677 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components
    - - - - - - - - -
  • -
    -
    - - - - -
    -
    - - Northgate Station - Bay 4 - -
    -
    - 4:09 PM -
    - - otpUi.TransitLegBody.fromLocation - -
    -
    -
    - - - - - - - - - - - - - - - Walk 200 feet to - - Northgate Station - - - - -
    - - - - -
    -
    -
      -
    1. - - - -
      -
      - - Head - NORTH - on - - Unnamed Path - - - 200 feet - - + Fare: + $2.75 +
      +
    +
    +
    +
    +
    + + +
  • +
  • +
    +
    + + + + +
    +
    + + Northgate Station - Bay 4 + +
    +
    + 4:09 PM +
    + + otpUi.TransitLegBody.fromLocation + +
    +
    +
    + + + + + + + + + + + - + + + Walk 200 feet to + + Northgate Station + + + + +
    + + + + +
    +
    +
      +
    1. +
      + + + +
      +
      + + Head + NORTH + on + + Unnamed Path + + + 200 feet + + +
      +
    2. +
    +
    +
    +
    +
    +
    +
  • +
  • +
    +
    + + + + +
    +
    + + Northgate Station + +
    +
    + 4:13 PM +
    + + otpUi.TransitLegBody.fromLocation + +
    +
    + Stop ID + + Stop Viewer + +
    +
    +
    + + + + - + Ride + + + + + + + + + + + + + + + + + - + Disembark at + Othello Station + + + + +
    +
    +
    + Service operated by + +
    +
    +
    +
    +
    + +
    +
    +
    +
      +
    1. +
      + • +
      +
      + Roosevelt Station +
      +
    2. +
    3. +
      + • +
      +
      + U District Station +
      +
    4. +
    5. +
      + • +
      +
      + Univ of Washington Station +
      +
    6. +
    7. +
      + • +
      +
      + Capitol Hill Station +
      +
    8. +
    9. +
      + • +
      +
      + Westlake Station +
      +
    10. +
    11. +
      + • +
      +
      + University St Station +
      +
    12. +
    13. +
      + • +
      +
      + Pioneer Square Station +
      +
    14. +
    15. +
      + • +
      +
      + Int'l Dist/Chinatown Station +
      +
    16. +
    17. +
      + • +
      +
      + Stadium Station +
      +
    18. +
    19. +
      + • +
      +
      + SODO Station +
      +
    20. +
    21. +
      + • +
      +
      + Beacon Hill Station +
      +
    22. +
    23. +
      + • +
      +
      + Mount Baker Station +
      +
    24. +
    25. +
      + • +
      +
      + Columbia City Station +
      +
    26. +
    +
    + Fare: + $3.00
    -
  • - - - - - - - -
  • -
    -
    - - - - -
    -
    - - Northgate Station - -
    -
    - 4:13 PM -
    - - otpUi.TransitLegBody.fromLocation - -
    -
    - Stop ID - - Stop Viewer - -
    -
    -
    - - - - - - Ride - - - - - - - - - - - - - - - - - - - Disembark at - Othello Station - - - - -
    -
    -
    - Service operated by - -
    -
    -
    -
    -
    - -
    -
    -
    -
      -
    1. -
      - • -
      -
      - Roosevelt Station -
      -
    2. -
    3. -
      - • -
      -
      - U District Station -
      -
    4. -
    5. -
      - • -
      -
      - Univ of Washington Station -
      -
    6. -
    7. -
      - • -
      -
      - Capitol Hill Station -
      -
    8. -
    9. -
      - • -
      -
      - Westlake Station -
      -
    10. -
    11. -
      - • -
      -
      - University St Station -
      -
    12. -
    13. -
      - • -
      -
      - Pioneer Square Station -
      -
    14. -
    15. -
      - • -
      -
      - Int'l Dist/Chinatown Station -
      -
    16. -
    17. -
      - • -
      -
      - Stadium Station -
      -
    18. -
    19. -
      - • -
      -
      - SODO Station -
      -
    20. -
    21. -
      - • -
      -
      - Beacon Hill Station -
      -
    22. -
    23. -
      - • -
      -
      - Mount Baker Station -
      -
    24. -
    25. -
      - • -
      -
      - Columbia City Station -
      -
    26. -
    @@ -109343,7 +109360,6 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 1`] = ` "walkTime": 2436, } } - showRouteFares={true} /> `; @@ -248182,1721 +248198,6 @@ exports[`Storyshots TripDetails E Scooter Rental Transit Itinerary 2`] = `
    `; -exports[`Storyshots TripDetails Fare Components Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Fare Components Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - May 26, 2023 - - at - - 3:23 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 41 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 41 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 2,699g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 1`] = ` itinerary getItineraryCost should calculate the total cost of an itinerary 1`] = ` -Object { - "code": "USD", - "digits": 2, -} -`; diff --git a/packages/core-utils/src/__tests__/itinerary.js b/packages/core-utils/src/__tests__/itinerary.js index 6a10fb8e1..5663e4d77 100644 --- a/packages/core-utils/src/__tests__/itinerary.js +++ b/packages/core-utils/src/__tests__/itinerary.js @@ -143,7 +143,10 @@ describe("util > itinerary", () => { "orca:regular" ); expect(result.amount).toEqual(5.75); - expect(result.currency).toMatchSnapshot(); + expect(result.currency).toEqual({ + code: "USD", + digits: 2 + }); }); it("should return undefined when the keys are invalid", () => { const result = getItineraryCost( From eccaf398761b0ce01a39d2d8f87ee07baa1cbcff Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Tue, 11 Jul 2023 11:06:37 -0700 Subject: [PATCH 37/40] fix(trip-details): remove unused types BREAKING CHANGE: Removes types associated with old REST API --- packages/trip-details/src/types.ts | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/packages/trip-details/src/types.ts b/packages/trip-details/src/types.ts index 9a27dc5ef..1feba9d6c 100644 --- a/packages/trip-details/src/types.ts +++ b/packages/trip-details/src/types.ts @@ -1,7 +1,12 @@ // Prettier does not recognize the import type syntax. // eslint-disable-next-line prettier/prettier -import type { FareProductSelector, Itinerary, Leg, Money, MassUnitOption, } from "@opentripplanner/types"; -import type { ReactElement } from "react"; +import type { + FareProductSelector, + Itinerary, + Leg, + MassUnitOption, + Money + } from "@opentripplanner/types"; export interface TimeActiveDetailsProps { bikeMinutes: number; @@ -30,6 +35,9 @@ export interface FareTableLayout { })[] headerKey: string; } +/** + * Interface containing the lgs and the layout of the fare table. + */ export interface FareLegTableProps { layout?: FareTableLayout[]; legs: Leg[]; @@ -38,17 +46,6 @@ export interface FareLegTableProps { // Total fare amount corresponding to a fare key export type FareTotals = (FareProductSelector & { price: Money })[] -export interface TransitFareProps { - headerKey: string; - fareMediumId: string - riderCategoryId: string - fareNameFallback?: ReactElement; - fareKeyNameMap: { - [key: string]: string; - }; - fareTotals: FareTotals; -} - export interface FareDetailsProps { legs: Leg[]; maxTNCFare: number; From 73c71fa5f20ee05ba171428455f916300752004b Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Tue, 11 Jul 2023 13:45:36 -0700 Subject: [PATCH 38/40] refactor: remove unused stories --- .../trip-details/src/TripDetails.story.tsx | 66 ++----------------- 1 file changed, 6 insertions(+), 60 deletions(-) diff --git a/packages/trip-details/src/TripDetails.story.tsx b/packages/trip-details/src/TripDetails.story.tsx index 9ecd344d0..09b23af53 100644 --- a/packages/trip-details/src/TripDetails.story.tsx +++ b/packages/trip-details/src/TripDetails.story.tsx @@ -26,14 +26,7 @@ import customFrenchMessages from "../__mocks__/custom-french-messages.yml"; // import mock itinaries. These are all trip plan outputs from OTP. const bikeOnlyItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/bike-only.json"); -const bikeRentalItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/bike-rental.json"); -const bikeRentalTransitBikeRentalItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/bike-rental-transit-bike-rental.json"); -const bikeTransitBikeItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/bike-transit-bike.json"); -const eScooterRentalItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/e-scooter-rental.json"); -const eScooterRentalTransiteScooterRentalItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/e-scooter-transit-e-scooter.json"); -const parkAndRideItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/park-and-ride.json"); const tncTransitTncItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/tnc-transit-tnc.json"); -const walkInterlinedTransitItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-interlined-transit-walk.json"); const walkOnlyItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-only.json"); const walkTransitWalkItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-transit-walk.json"); const walkTransitWalkTransitWalkItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/walk-transit-walk-transit-walk.json"); @@ -56,7 +49,7 @@ const StyledTripDetails = styled(TripDetails)` } `; -const otp2FareByLegLayout: FareTableLayout[] = [ +const orcaFareByLegLayout: FareTableLayout[] = [ { cols: [ { @@ -114,7 +107,7 @@ const otp2FareByLegLayout: FareTableLayout[] = [ } ]; -const otp2defaultFareType = { +const orcaDefaultFareType = { headerKey: "cash-regular", mediumId: "orca:cash", riderCategoryId: "orca:regular" @@ -266,7 +259,7 @@ export const WalkTransitWalkItinerary = makeStory({ itinerary: walkTransitWalkItinerary }); -export const StyledWalkTransitWalkItinerary = makeStory( +export const StyledItinerary = makeStory( { itinerary: walkTransitWalkItinerary }, @@ -274,59 +267,12 @@ export const StyledWalkTransitWalkItinerary = makeStory( StyledTripDetails ); -export const BikeTransitBikeItinerary = makeStory({ - itinerary: bikeTransitBikeItinerary -}); - export const LegFareProductsItinerary = makeStory({ - defaultFareType: otp2defaultFareType, - fareDetailsLayout: otp2FareByLegLayout, + defaultFareType: orcaDefaultFareType, + fareDetailsLayout: orcaFareByLegLayout, itinerary: otp2FareProducts }); -export const WalkInterlinedTransitItinerary = makeStory( - { - // defaultFareKey: "electronicRegular", - // fareDetailsLayout: fareByLegLayout, - itinerary: walkInterlinedTransitItinerary - }, - { - useCustomFareKeyMap: true, - // For illustration purposes, - // override a subset of localized strings with custom messages. - reactIntl: { - messages: { - "en-US": flattenedEnglishMessages, - fr: flattenedFrenchMessages - } - } - } -); - -export const WalkTransitTransferItinerary = makeStory({ - itinerary: walkTransitWalkTransitWalkItinerary -}); - -export const BikeRentalItinerary = makeStory({ - itinerary: bikeRentalItinerary -}); - -export const EScooterRentalItinerary = makeStory({ - itinerary: eScooterRentalItinerary -}); - -export const ParkAndRideItinerary = makeStory({ - itinerary: parkAndRideItinerary -}); - -export const BikeRentalTransitItinerary = makeStory({ - itinerary: bikeRentalTransitBikeRentalItinerary -}); - -export const EScooterRentalTransitItinerary = makeStory({ - itinerary: eScooterRentalTransiteScooterRentalItinerary -}); - // The render of this itinerary is uninteresting, but the test // is if we can parse an OTP2 itinerary without crashing export const OTP2EScooterRentalTransitItinerary = makeStory({ @@ -372,5 +318,5 @@ export const OTP2FlexItinerary = makeStory({ itinerary: flexItinerary }); export const FareLegTableStoryLegProducts = (): ReactElement => { const otp1legs = otp2FareProducts.legs.map(convertGraphQLResponseToLegacy); - return ; + return ; }; From aa85e518d4264615cc7e4fe51b33dd56686af28f Mon Sep 17 00:00:00 2001 From: Daniel Heppner Date: Tue, 11 Jul 2023 13:47:15 -0700 Subject: [PATCH 39/40] chore: update snapshots --- __snapshots__/storybook.test.ts.snap | 30462 ++++++------------------- 1 file changed, 7537 insertions(+), 22925 deletions(-) diff --git a/__snapshots__/storybook.test.ts.snap b/__snapshots__/storybook.test.ts.snap index d49fa8f7a..a9a04ba9f 100644 --- a/__snapshots__/storybook.test.ts.snap +++ b/__snapshots__/storybook.test.ts.snap @@ -239153,7 +239153,7 @@ exports[`Storyshots TripDetails Bike Only Itinerary 2`] = `
    `; -exports[`Storyshots TripDetails Bike Rental Itinerary 1`] = ` +exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 1`] = ` - - -`; - -exports[`Storyshots TripDetails Bike Rental Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - November 13, 2019 - - at - - 3:45 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 13 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 6 minutes - - walking and - - 7 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 25g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Bike Rental Transit Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Bike Rental Transit Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - November 13, 2019 - - at - - 3:50 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 24 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 10 minutes - - walking and - - 14 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 356g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Bike Transit Bike Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Bike Transit Bike Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - November 13, 2019 - - at - - 3:44 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 3 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 1 minute - - walking and - - 2 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 61g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails E Scooter Rental Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails E Scooter Rental Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - November 13, 2019 - - at - - 3:45 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 2 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 2 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 42g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails E Scooter Rental Transit Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails E Scooter Rental Transit Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - November 13, 2019 - - at - - 3:45 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 19 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 19 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 599g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 2`] = ` -.c2 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c1 th { - font-weight: normal; - min-width: 5ch; - padding: 0.75em 1.5em; - text-align: center; -} - -.c1 th:nth-of-type(2n + 1) { - background: #cccccc22; -} - -.c1 th.main { - background: #333333; - color: #ffffffcc; -} - -.c0 { - border-collapse: collapse; - display: block; - margin-bottom: 16px; - padding: 0; -} - -.c0 td { - text-align: right; -} - -.c0 td:nth-of-type(2n + 1) { - background: #cccccc22; -} - -.c0 td.no-zebra { - background: none; -} - -.c0 th:first-of-type { - height: 40px; -} - -.c3 { - padding-left: 4px; -} - -
    - - - - - - - - - - - - - - - - - - - -
    - - otpUi.TripDetails.FareTable.regular - - - - otpUi.TripDetails.FareTable.cash - -
    - $5.75 -
    - - otpUi.TripDetails.FareTable.electronic - -
    - $3.00 -
    - - otpUi.TripDetails.FareTable.special - -
    - $1.50 -
    - 347 - - $2.75 - - $2.75 - - $1.50 -
    - 1-Line - - $3.00 - - - - $0.25 - - - - $0.00 -
    - - - - - - - - - - - - - - - - -
    - - otpUi.TripDetails.FareTable.youth - - - - otpUi.TripDetails.FareTable.cash - -
    - $0.00 -
    - - otpUi.TripDetails.FareTable.electronic - -
    - $0.00 -
    - 347 - - $0.00 - - $0.00 -
    - 1-Line - - $0.00 - - $0.00 -
    - - - - - - - - - - - - - - - - -
    - - otpUi.TripDetails.FareTable.senior - - - - otpUi.TripDetails.FareTable.cash - -
    - $2.00 -
    - - otpUi.TripDetails.FareTable.electronic - -
    - $1.00 -
    - 347 - - $1.00 - - $1.00 -
    - 1-Line - - $1.00 - - - - $0.00 -
    -
    -`; - -exports[`Storyshots TripDetails Leg Fare Products Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Leg Fare Products Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c13 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c9 { - display: inline-block; -} - -.c9 > span { - display: block; - padding-left: 1.75ch; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -.c11 th { - font-weight: normal; - min-width: 5ch; - padding: 0.75em 1.5em; - text-align: center; -} - -.c11 th:nth-of-type(2n + 1) { - background: #cccccc22; -} - -.c11 th.main { - background: #333333; - color: #ffffffcc; -} - -.c10 { - border-collapse: collapse; - display: block; - margin-bottom: 16px; - padding: 0; -} - -.c10 td { - text-align: right; -} - -.c10 td:nth-of-type(2n + 1) { - background: #cccccc22; -} - -.c10 td.no-zebra { - background: none; -} - -.c10 th:first-of-type { - height: 40px; -} - -.c12 { - padding-left: 4px; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - May 26, 2023 - - at - - 3:23 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - -
    - - Transit Fare - : - - $5.75 - - -
    - - - - - - - - - - - - - - - - - -
    - - otpUi.TripDetails.FareTable.regular - - - - otpUi.TripDetails.FareTable.cash - -
    - $5.75 -
    - - otpUi.TripDetails.FareTable.electronic - -
    - $3.00 -
    - - otpUi.TripDetails.FareTable.special - -
    - $1.50 -
    - - $2.75 - - $2.75 - - $1.50 -
    - - $3.00 - - - - $0.25 - - - - $0.00 -
    - - - - - - - - - - - - - - -
    - - otpUi.TripDetails.FareTable.youth - - - - otpUi.TripDetails.FareTable.cash - -
    - $0.00 -
    - - otpUi.TripDetails.FareTable.electronic - -
    - $0.00 -
    - - $0.00 - - $0.00 -
    - - $0.00 - - $0.00 -
    - - - - - - - - - - - - - - -
    - - otpUi.TripDetails.FareTable.senior - - - - otpUi.TripDetails.FareTable.cash - -
    - $2.00 -
    - - otpUi.TripDetails.FareTable.electronic - -
    - $1.00 -
    - - $1.00 - - $1.00 -
    - - $1.00 - - - - $0.00 -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 41 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 41 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 2,699g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails OTP 2 E Scooter Rental Transit Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails OTP 2 E Scooter Rental Transit Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - June 15, 2022 - - at - - 9:15 AM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 5 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 5 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 7g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails OTP 2 Flex Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails OTP 2 Flex Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - June 22, 2022 - - at - - 4:59 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 12 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 12 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 4,682g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    - -
    -
    - - This trip includes flexible routes. This is the first pickup booking info message. This is the first dropoff booking info message. - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Park And Ride Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Park And Ride Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - November 13, 2019 - - at - - 3:50 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 6 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 6 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 1,246g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Styled Walk Transit Walk Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Styled Walk Transit Walk Itinerary 2`] = ` -.c6 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c9 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c11 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c10 { - float: right; -} - -.c4 { - margin-top: 6px; -} - -.c8 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c5 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c3 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c7 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -.c1 .c2 { - background-color: pink; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - November 13, 2019 - - at - - 3:44 PM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 2 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 2 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 61g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Tnc Transit Itinerary 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` -.c4 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c7 { - background: transparent; - border: 0; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -.c10 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; -} - -.c8 { - float: right; -} - -.c9 { - text-transform: capitalize; -} - -.c2 { - margin-top: 6px; -} - -.c6 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; -} - -.c3 { - float: left; - font-size: 17px; -} - -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; -} - -.c1 { - font-size: 18px; - font-weight: 600; - margin: 0; -} - -.c5 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; -} - -
    -

    - Trip Details -

    -
    -
    -
    - -
    -
    - - Depart - - May 23, 2023 - - at - - 10:58 AM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - uber - - Fare: - - $34.00 - - - $37.00 - - - - -
    -
    -
    -
    - - Custom details about fares (transitFares: - ) - - (cents), can be constructed dynamically using any markup. -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 2 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 2 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 319g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Tnc Transit Itinerary With Custom Messages 1`] = ` -Leave at {departureDate, time, short} on {departureDate, date, long}", - "otpUi.TripDetails.title": "Custom Trip Details Title", - "otpUi.TripDetails.tncFare": "Pay {minTNCFare}-{maxTNCFare} to {companies}", - } - } - onError={[Function]} - textComponent={Symbol(react.fragment)} -> - `; -exports[`Storyshots TripDetails Tnc Transit Itinerary With Custom Messages 2`] = ` -.c6 { - display: inline-block; - vertical-align: middle; - overflow: hidden; -} - -.c8 { - background: transparent; - border: 0; - cursor: pointer; +exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 2`] = ` +.c2 { display: inline-block; - font-size: 14px; - font-weight: 400; - line-height: 1.42857143; - margin: 0; - padding: 0; - -webkit-text-decoration: none; - text-decoration: none; - touch-action: manipulation; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; vertical-align: middle; - white-space: nowrap; -} - -.c9 { - color: #00f; - font-size: 16px; - margin-left: 6px; - margin-top: -2px; + overflow: hidden; } -.c11 { - float: right; +.c1 th { + font-weight: normal; + min-width: 5ch; + padding: 0.75em 1.5em; + text-align: center; } -.c12 { - text-transform: capitalize; +.c1 th:nth-of-type(2n + 1) { + background: #cccccc22; } -.c4 { - margin-top: 6px; +.c1 th.main { + background: #333333; + color: #ffffffcc; } -.c10 { - background-color: #fff; - border: 1px solid #888; - font-size: 12px; - margin-top: 2px; - padding: 8px; +.c0 { + border-collapse: collapse; + display: block; + margin-bottom: 16px; + padding: 0; } -.c5 { - float: left; - font-size: 17px; +.c0 td { + text-align: right; } -.c0 { - background-color: #eee; - border-radius: 6px; - margin-bottom: 15px; - margin-top: 16px; - padding: 10px 16px; +.c0 td:nth-of-type(2n + 1) { + background: #cccccc22; } -.c3 { - font-size: 18px; - font-weight: 600; - margin: 0; +.c0 td.no-zebra { + background: none; } -.c7 { - margin-left: 28px; - padding-top: 2px; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: baseline; - -webkit-box-align: baseline; - -ms-flex-align: baseline; - align-items: baseline; - white-space: pre; +.c0 th:first-of-type { + height: 40px; } -.c1 .c2 { - background-color: pink; +.c3 { + padding-left: 4px; } -
    -

    - Custom Trip Details Title -

    -
    + -
    -
    - -
    -
    + otpUi.TripDetails.FareTable.regular + + +
    + + + + + + + + + + + + + + +
    - - - Leave - - at - - 10:58 AM - - on - - May 23, 2023 - - - - -
    + otpUi.TripDetails.FareTable.cash + +
    + $5.75 +
    -
    -
    - - Custom messages about - - May 23, 2023 - - can be constructed dynamically using any markup. -
    -
    - - -
    -
    + otpUi.TripDetails.FareTable.electronic + +
    + $3.00 +
    + + otpUi.TripDetails.FareTable.special + +
    + $1.50 +
    + 347 + + $2.75 + + $2.75 + + $1.50 +
    + 1-Line + + $3.00 + - -
    +
    - - -
    + + + $0.00 +
    + + + + + + + + + + + + + + + + +
    -
    -
    - -
    -
    - - -
    + otpUi.TripDetails.FareTable.youth + +
    + + otpUi.TripDetails.FareTable.cash + +
    + $0.00 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $0.00 +
    + 347 + + $0.00 + + $0.00 +
    + 1-Line + + $0.00 + + $0.00 +
    + + -
    + + otpUi.TripDetails.FareTable.senior + + +
    + + + + + + + + + + + +
    + + otpUi.TripDetails.FareTable.cash + +
    + $2.00 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $1.00 +
    + 347 + + $1.00 + + $1.00 +
    + 1-Line + + $1.00 + - -
    - Time Spent Active: - - 2 minutes - - -
    -
    +
    +
    +`; + +exports[`Storyshots TripDetails Leg Fare Products Itinerary 1`] = ` + + -
    -
    - - Custom message about - active minutes. -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 319g - - - -
    -
    -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 1`] = ` -Leave at {departureDate, time, short} on {departureDate, date, long}", - "otpUi.TripDetails.title": "Custom Trip Details Title", - "otpUi.TripDetails.tncFare": "Pay {minTNCFare}-{maxTNCFare} to {companies}", - } - } - onError={[Function]} - textComponent={Symbol(react.fragment)} -> - + +`; + +exports[`Storyshots TripDetails Leg Fare Products Itinerary 2`] = ` +.c4 { + display: inline-block; + vertical-align: middle; + overflow: hidden; +} + +.c7 { + background: transparent; + border: 0; + cursor: pointer; + display: inline-block; + font-size: 14px; + font-weight: 400; + line-height: 1.42857143; + margin: 0; + padding: 0; + -webkit-text-decoration: none; + text-decoration: none; + touch-action: manipulation; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + vertical-align: middle; + white-space: nowrap; +} + +.c13 { + color: #00f; + font-size: 16px; + margin-left: 6px; + margin-top: -2px; +} + +.c8 { + float: right; +} + +.c9 { + display: inline-block; +} + +.c9 > span { + display: block; + padding-left: 1.75ch; +} + +.c2 { + margin-top: 6px; +} + +.c6 { + background-color: #fff; + border: 1px solid #888; + font-size: 12px; + margin-top: 2px; + padding: 8px; +} + +.c3 { + float: left; + font-size: 17px; +} + +.c0 { + background-color: #eee; + border-radius: 6px; + margin-bottom: 15px; + margin-top: 16px; + padding: 10px 16px; +} + +.c1 { + font-size: 18px; + font-weight: 600; + margin: 0; +} + +.c5 { + margin-left: 28px; + padding-top: 2px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: baseline; + -webkit-box-align: baseline; + -ms-flex-align: baseline; + align-items: baseline; + white-space: pre; +} + +.c11 th { + font-weight: normal; + min-width: 5ch; + padding: 0.75em 1.5em; + text-align: center; +} + +.c11 th:nth-of-type(2n + 1) { + background: #cccccc22; +} + +.c11 th.main { + background: #333333; + color: #ffffffcc; +} + +.c10 { + border-collapse: collapse; + display: block; + margin-bottom: 16px; + padding: 0; +} + +.c10 td { + text-align: right; +} + +.c10 td:nth-of-type(2n + 1) { + background: #cccccc22; +} + +.c10 td.no-zebra { + background: none; +} + +.c10 th:first-of-type { + height: 40px; +} + +.c12 { + padding-left: 4px; +} + +
    +

    + Trip Details +

    +
    +
    +
    + +
    +
    + + Depart + + May 26, 2023 + + at + + 3:23 PM + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + +
    + + Transit Fare + : + + $5.75 + + +
    + + + + + + + + + + + + + + + + + +
    + + otpUi.TripDetails.FareTable.regular + + + + otpUi.TripDetails.FareTable.cash + +
    + $5.75 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $3.00 +
    + + otpUi.TripDetails.FareTable.special + +
    + $1.50 +
    + + $2.75 + + $2.75 + + $1.50 +
    + + $3.00 + + + + $0.25 + + + + $0.00 +
    + + + + + + + + + + + + + + +
    + + otpUi.TripDetails.FareTable.youth + + + + otpUi.TripDetails.FareTable.cash + +
    + $0.00 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $0.00 +
    + + $0.00 + + $0.00 +
    + + $0.00 + + $0.00 +
    + + + + + + + + + + + + + + +
    + + otpUi.TripDetails.FareTable.senior + + + + otpUi.TripDetails.FareTable.cash + +
    + $2.00 +
    + + otpUi.TripDetails.FareTable.electronic + +
    + $1.00 +
    + + $1.00 + + $1.00 +
    + + $1.00 + + + + $0.00 +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + Time Spent Active: + + 41 minutes + + +
    +
    +
    +
    + + By taking this trip, you'll spend + + 41 minutes + + walking and + + 0 minutes + + biking. + +
    +
    +
    +
    +
    +
    + +
    +
    + + CO₂ Emitted: + + 2,699g + + + +
    +
    +
    +
    + + CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from + + this spreadsheet + + . +
    +
    +
    +
    +
    +
    +`; + +exports[`Storyshots TripDetails OTP 2 E Scooter Rental Transit Itinerary 1`] = ` + + + +`; + +exports[`Storyshots TripDetails OTP 2 E Scooter Rental Transit Itinerary 2`] = ` +.c4 { + display: inline-block; + vertical-align: middle; + overflow: hidden; +} + +.c7 { + background: transparent; + border: 0; + cursor: pointer; + display: inline-block; + font-size: 14px; + font-weight: 400; + line-height: 1.42857143; + margin: 0; + padding: 0; + -webkit-text-decoration: none; + text-decoration: none; + touch-action: manipulation; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + vertical-align: middle; + white-space: nowrap; +} + +.c9 { + color: #00f; + font-size: 16px; + margin-left: 6px; + margin-top: -2px; +} + +.c8 { + float: right; +} + +.c2 { + margin-top: 6px; +} + +.c6 { + background-color: #fff; + border: 1px solid #888; + font-size: 12px; + margin-top: 2px; + padding: 8px; +} + +.c3 { + float: left; + font-size: 17px; +} + +.c0 { + background-color: #eee; + border-radius: 6px; + margin-bottom: 15px; + margin-top: 16px; + padding: 10px 16px; +} + +.c1 { + font-size: 18px; + font-weight: 600; + margin: 0; +} + +.c5 { + margin-left: 28px; + padding-top: 2px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: baseline; + -webkit-box-align: baseline; + -ms-flex-align: baseline; + align-items: baseline; + white-space: pre; +} + +
    +

    + Trip Details +

    +
    +
    +
    + +
    +
    + + Depart + + June 15, 2022 + + at + + 9:15 AM + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + Time Spent Active: + + 5 minutes + + +
    +
    +
    +
    + + By taking this trip, you'll spend + + 5 minutes + + walking and + + 0 minutes + + biking. + +
    +
    +
    +
    +
    +
    + +
    +
    + + CO₂ Emitted: + + 7g + + + +
    +
    +
    +
    + + CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from + + this spreadsheet + + . +
    +
    +
    +
    +
    +
    +`; + +exports[`Storyshots TripDetails OTP 2 Flex Itinerary 1`] = ` + + + +`; + +exports[`Storyshots TripDetails OTP 2 Flex Itinerary 2`] = ` +.c4 { + display: inline-block; + vertical-align: middle; + overflow: hidden; +} + +.c7 { + background: transparent; + border: 0; + cursor: pointer; + display: inline-block; + font-size: 14px; + font-weight: 400; + line-height: 1.42857143; + margin: 0; + padding: 0; + -webkit-text-decoration: none; + text-decoration: none; + touch-action: manipulation; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + vertical-align: middle; + white-space: nowrap; +} + +.c9 { + color: #00f; + font-size: 16px; + margin-left: 6px; + margin-top: -2px; +} + +.c8 { + float: right; +} + +.c2 { + margin-top: 6px; +} + +.c6 { + background-color: #fff; + border: 1px solid #888; + font-size: 12px; + margin-top: 2px; + padding: 8px; +} + +.c3 { + float: left; + font-size: 17px; +} + +.c0 { + background-color: #eee; + border-radius: 6px; + margin-bottom: 15px; + margin-top: 16px; + padding: 10px 16px; +} + +.c1 { + font-size: 18px; + font-weight: 600; + margin: 0; +} + +.c5 { + margin-left: 28px; + padding-top: 2px; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-align-items: baseline; + -webkit-box-align: baseline; + -ms-flex-align: baseline; + align-items: baseline; + white-space: pre; +} + +
    +

    + Trip Details +

    +
    +
    +
    + +
    +
    + + Depart + + June 22, 2022 + + at + + 4:59 PM + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + Time Spent Active: + + 12 minutes + + +
    +
    +
    +
    + + By taking this trip, you'll spend + + 12 minutes + + walking and + + 0 minutes + + biking. + +
    +
    +
    +
    +
    +
    + +
    +
    + + CO₂ Emitted: + + 4,682g + + + +
    +
    +
    +
    + + CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from + + this spreadsheet + + . +
    +
    +
    +
    +
    +
    + +
    +
    + + This trip includes flexible routes. This is the first pickup booking info message. This is the first dropoff booking info message. + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +`; + +exports[`Storyshots TripDetails Styled Itinerary 1`] = ` + + `; -exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` -.c4 { +exports[`Storyshots TripDetails Styled Itinerary 2`] = ` +.c6 { display: inline-block; vertical-align: middle; overflow: hidden; } -.c7 { +.c9 { background: transparent; border: 0; cursor: pointer; @@ -261589,22 +245410,22 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` white-space: nowrap; } -.c9 { +.c11 { color: #00f; font-size: 16px; margin-left: 6px; margin-top: -2px; } -.c8 { +.c10 { float: right; } -.c2 { +.c4 { margin-top: 6px; } -.c6 { +.c8 { background-color: #fff; border: 1px solid #888; font-size: 12px; @@ -261612,7 +245433,7 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` padding: 8px; } -.c3 { +.c5 { float: left; font-size: 17px; } @@ -261625,13 +245446,13 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` padding: 10px 16px; } -.c1 { +.c3 { font-size: 18px; font-weight: 600; margin: 0; } -.c5 { +.c7 { margin-left: 28px; padding-top: 2px; display: -webkit-box; @@ -261645,60 +245466,161 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` white-space: pre; } +.c1 .c2 { + background-color: pink; +} +

    - Custom Trip Details Title + Trip Details

    +
    + +
    +
    + + Depart + + November 13, 2019 + + at + + 3:44 PM + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    - + 2 minutes + +
    + By taking this trip, you'll spend + + 2 minutes + + walking and + + 0 minutes + + biking. +
    - Time Spent Active: - - 9 minutes - + + CO₂ Emitted: + + 61g + + - By taking this trip, you'll spend - - 9 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 4,823g - - - -
    -
    +
    +
    + + CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from + + this spreadsheet + + . +
    +
    +
    +
    + + +`; + +exports[`Storyshots TripDetails Tnc Transit Itinerary 1`] = ` + + -
    -
    - - CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from - - this spreadsheet - - . -
    -
    - - - - -`; - -exports[`Storyshots TripDetails Walk Only Itinerary 1`] = ` - - `; -exports[`Storyshots TripDetails Walk Only Itinerary 2`] = ` +exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` .c4 { display: inline-block; vertical-align: middle; @@ -262146,7 +246244,7 @@ exports[`Storyshots TripDetails Walk Only Itinerary 2`] = ` white-space: nowrap; } -.c9 { +.c10 { color: #00f; font-size: 16px; margin-left: 6px; @@ -262157,6 +246255,10 @@ exports[`Storyshots TripDetails Walk Only Itinerary 2`] = ` float: right; } +.c9 { + text-transform: capitalize; +} + .c2 { margin-top: 6px; } @@ -262246,11 +246348,11 @@ exports[`Storyshots TripDetails Walk Only Itinerary 2`] = ` > Depart - December 13, 2019 + May 23, 2023 at - 11:29 AM + 10:58 AM @@ -262297,6 +246399,125 @@ exports[`Storyshots TripDetails Walk Only Itinerary 2`] = ` +
    +
    + +
    +
    + + + + uber + + Fare: + + $34.00 + - + $37.00 + + + + +
    +
    +
    +
    + + Custom details about fares (transitFares: + ) + + (cents), can be constructed dynamically using any markup. +
    +
    +
    +
    Time Spent Active: - 1 minute + 2 minutes +
    +
    +
    +
    + + Custom messages about + + May 23, 2023 + + can be constructed dynamically using any markup. +
    +
    +
    + +
    +
    + +
    +
    + + + Pay + + $34.00 + - + $37.00 + + to + + uber + + + +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    + Time Spent Active: + + 2 minutes + + +
    +
    +
    +
    + + Custom message about + active minutes. +
    +
    +
    +
    +
    +
    + +
    +
    + + CO₂ Emitted: + + 319g + + + +
    +
    +
    +
    + + CO₂ intensity is calculated by multiplying the distance of each leg of a trip by the CO₂ intensity of each mode. CO₂ intensity of each mode is derived from + + this spreadsheet + + . +
    +
    +
    +
    + + +`; + +exports[`Storyshots TripDetails Walk Only Itinerary 1`] = ` + + `; -exports[`Storyshots TripDetails Walk Transit Transfer Itinerary 2`] = ` +exports[`Storyshots TripDetails Walk Only Itinerary 2`] = ` .c4 { display: inline-block; vertical-align: middle; @@ -263383,11 +247995,11 @@ exports[`Storyshots TripDetails Walk Transit Transfer Itinerary 2`] = ` > Depart - November 13, 2019 + December 13, 2019 at - 3:46 PM + 11:29 AM @@ -263463,7 +248075,7 @@ exports[`Storyshots TripDetails Walk Transit Transfer Itinerary 2`] = ` > Time Spent Active: - 5 minutes + 1 minute