diff --git a/__snapshots__/storybook.test.ts.snap b/__snapshots__/storybook.test.ts.snap index 7aedd5db5..a9a04ba9f 100644 --- a/__snapshots__/storybook.test.ts.snap +++ b/__snapshots__/storybook.test.ts.snap @@ -24241,2179 +24241,1299 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components textComponent={Symbol(react.fragment)} > `; @@ -26429,7 +25549,7 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components color: #333; } -.c65 { +.c60 { color: #f44256; } @@ -26464,17 +25584,12 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components margin-right: 5px; } -.c63 { - color: #b22727; - margin-top: 5px; -} - .c31::before { content: ""; margin: 0 0.125em; } -.c57 { +.c55 { display: block; font-size: 13px; list-style: none; @@ -26530,16 +25645,11 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components font-weight: inherit; } -.c51 { +.c49 { font-size: 13px; font-weight: 500; } -.c50 { - font-weight: 800; - margin-right: 6px; -} - .c48 { color: #807373; margin-top: 5px; @@ -26742,27 +25852,27 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components padding-left: 1ch; } -.c60 { +.c58 { float: left; margin-left: -36px; color: #fff; } -.c61 { +.c59 { color: #676767; margin-top: 3px; } -.c58 { +.c56 { z-index: 30; position: relative; } -.c53 { +.c51 { margin-top: 5px; } -.c54 { +.c52 { color: #676767; display: -webkit-box; display: -webkit-flex; @@ -26770,30 +25880,30 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components display: flex; } -.c56 { +.c54 { font-size: 14px; } -.c55 { +.c53 { padding: 0; } -.c52 { +.c50 { margin-top: 5px; } -.c52 a { +.c50 a { color: #337ab7; -webkit-text-decoration: none; text-decoration: none; } -.c52 a:hover { +.c50 a:hover { -webkit-text-decoration: underline; text-decoration: underline; } -.c52 img { +.c50 img { margin-left: 5px; vertical-align: middle; } @@ -26807,26 +25917,6 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components font-family: Hind,sans-serif; } -.c1 .c49 { - background-color: rgb(15,106,172); - border-color: white; - border-image: initial; - border-radius: 12px; - border-style: solid; - border-width: 1px; - box-shadow: rgb(0,0,0) 0px 0px 0.25em; - color: white; - display: inline-block; - font-size: 14px; - font-weight: 500; - height: 24px; - line-height: 1.5; - margin-right: 8px; - min-width: 24px; - padding: 2px 3px; - text-align: center; -} - .c1 .c4 { display: table-cell; max-width: 20px; @@ -26851,7 +25941,7 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components width: 100%; } -.c1 .c59 { +.c1 .c57 { margin-left: -23px; } @@ -26887,29 +25977,6 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components } .c44 { - background-color: gray; - left: 5px; - right: 5px; - background-color: #0070c0; - bottom: -11px; - position: absolute; - top: 11px; - z-index: 10; -} - -.c62 { - background-color: gray; - left: 5px; - right: 5px; - background-color: #000088; - background: repeating-linear-gradient( -45deg, #00008830, #00008830 5px, #000088 5px, #000088 10px ); - bottom: -11px; - position: absolute; - top: 11px; - z-index: 10; -} - -.c64 { background-color: gray; left: 5px; right: 5px; @@ -26994,13 +26061,13 @@ exports[`Storyshots ItineraryBody/otp-react-redux Individual Leg Fare Components aria-hidden={true} className="c15 c16" > - 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 +26414,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 - - 116 - - - Edmonds - + - Disembark at - Lynnwood Transit Center Bay C2 + Northgate Station - Bay 4 @@ -28527,21 +28418,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 - . -
-
-
-
-
-
- - - Trip Viewer - -
-
-
-
-
    -
  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 - - Stop Viewer - -
    -
    -
    - - - - - - Ride - - - - - - - - - - - - - - - 45 - - - - - Loyal Heights Greenwood - - - - - - - Disembark at - NW 85th St & 8th Ave NW - - - - -
    -
    -
    - Service operated by - - Metro Transit - -
    -
    -
    -
    -
    -
    - - - Trip Viewer - -
    -
    -
    -
    -
      -
    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 - - Stop Viewer - -
    -
    -
    - - - - - - - - - - - - - - - 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`] = ` + + `; @@ -111510,7 +109371,7 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` overflow: hidden; } -.c58 { +.c53 { color: #f44256; } @@ -111566,17 +109427,12 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` padding-left: 1px; } -.c56 { - color: #b22727; - margin-top: 5px; -} - .c21::before { content: ""; margin: 0 0.125em; } -.c57 { +.c52 { text-align: center; } @@ -111592,17 +109448,6 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` } .c39 { - border-left: solid 8px #0070c0; - height: 100%; - width: 0; - position: absolute; - left: 50%; - -webkit-transform: translateX(-50%); - -ms-transform: translateX(-50%); - transform: translateX(-50%); -} - -.c54 { border-left: solid 8px #008ab0; height: 100%; width: 0; @@ -111613,7 +109458,7 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` transform: translateX(-50%); } -.c50 { +.c48 { display: block; font-size: 13px; list-style: none; @@ -111669,17 +109514,12 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` font-weight: inherit; } -.c45 { +.c43 { font-size: 13px; font-weight: 500; } -.c44 { - font-weight: 800; - margin-right: 6px; -} - -.c43 { +.c42 { color: #807373; margin-top: 5px; } @@ -111833,35 +109673,6 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` } .c40 { - text-align: center; - min-width: 30px; - min-height: 30px; - font-size: 1.2em; - background-color: #0070c0; - color: white; - border-radius: 50%; - display: -webkit-box; - display: -webkit-flex; - display: -ms-flexbox; - display: flex; - -webkit-align-items: center; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center; - -webkit-box-pack: center; - -webkit-justify-content: center; - -ms-flex-pack: center; - justify-content: center; - padding-left: 1px; - border: 1px solid; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - cursor: default; -} - -.c55 { text-align: center; min-width: 30px; min-height: 30px; @@ -111975,33 +109786,27 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` padding-left: 1ch; } -.c42 { - font-weight: 200; - font-size: 0.9em; - margin-left: 10px; -} - -.c52 { +.c50 { float: left; margin-left: -36px; color: #fff; } -.c53 { +.c51 { color: #676767; margin-top: 3px; } -.c51 { +.c49 { z-index: 30; position: relative; } -.c46 { +.c44 { margin-top: 5px; } -.c47 { +.c45 { color: #676767; display: -webkit-box; display: -webkit-flex; @@ -112009,11 +109814,11 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` display: flex; } -.c49 { +.c47 { font-size: 14px; } -.c48 { +.c46 { padding: 0; } @@ -112063,13 +109868,13 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` aria-hidden={true} className="c8" > - 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
    @@ -112215,7 +110020,7 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` viewBox="0 0 261 261" > @@ -112223,17 +110028,17 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` className="c26" > - LEFT + RIGHT on - 40th Avenue West + Cedar Way - 0.5 miles + 0.1 miles @@ -112261,12 +110066,45 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` - Alderwood Mall Boulevard + Northeast 205th Street - 244th Street Southwest - 0.1 miles + 0.4 miles + + + + +
  • +
    + + + +
    +
    + + RIGHT + on + + Unnamed Path + + + 91 feet
    @@ -112292,26 +110130,16 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` className="c32 c33" > ↑ - 2' + 0' ↓ - 101' + 0' - - - + No elevation data available. mocked-react-resize-detector @@ -112367,12 +110195,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 +110213,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
  • +
  • +
    + + + +
    +
    + + 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
    @@ -113380,12 +111938,78 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` - 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
    @@ -113418,7 +112042,7 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` - 24 feet + 433 feet @@ -113444,26 +112068,16 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = ` className="c32 c33" > ↑ - 21' + 0' ↓ - 45' + 0' - - - + No elevation data available. mocked-react-resize-detector @@ -113505,27 +112119,27 @@ exports[`Storyshots ItineraryBody/otp-ui Individual Leg Fare Components 2`] = `
    -
    - - 67 - - + +
    @@ -113537,1102 +112151,38 @@ 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. -
    -
    -
    -
    -
    -
    -
    - - - - View on map - - - - -
    -
  • -
  • -
    -
    -
    -
    - -
    -
    -
    -
    -
    - - 8212 8th Ave NW, Seattle, WA, USA - -
    -
    - 1:27 PM -
    - - Arrive at - 8212 8th Ave NW, Seattle, WA, USA - -
    -
    - - View on map @@ -241603,20827 +239153,7 @@ exports[`Storyshots TripDetails Bike Only Itinerary 2`] = ` `; -exports[`Storyshots TripDetails Bike Rental Itinerary 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 - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - 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 - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - No fare info - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - 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 - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - 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 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 - - August 20, 2020 - - at - - 11:57 AM - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $5.75 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - Time Spent Active: - - 25 minutes - - -
    -
    -
    -
    - - By taking this trip, you'll spend - - 25 minutes - - walking and - - 0 minutes - - biking. - -
    -
    -
    -
    -
    -
    - -
    -
    - - CO₂ Emitted: - - 2,402g - - - -
    -
    -
    -
    - - 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. - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -`; - -exports[`Storyshots TripDetails Fare Leg Table Story 1`] = ` - - - -`; - -exports[`Storyshots TripDetails Fare Leg Table Story 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; -} - -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - Adult - - - - Cash - -
    - $5.50 -
    - - Electronic - -
    - $3.25 -
    - - Special - -
    - $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 -
    - - Electronic - -
    - $1.50 -
    - 512 - - $1.50 - - - - $1.50 -
    - 40 - - - - $1.50 - - - - $0.00 -
    - E Line - - - - $0.00 - - - - $0.00 -
    -
    -`; - -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; -} - -
    - - - - - - - - - - - - - - - - - - - -
    - - 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 - - - - Cash - -
    - $0.00 -
    - - Electronic - -
    - $0.00 -
    - Mariner P&R - Aurora Village - - $0.00 - - $0.00 -
    - E Line - - $0.00 - - $0.00 -
    - - - - - - - - - - - - - - - - -
    - - Senior - - - - Cash - -
    - $2.25 -
    - - Electronic - -
    - $1.25 -
    - Mariner P&R - Aurora Village - - $1.25 - - $1.25 -
    - E Line - - $1.00 - - - - $0.00 -
    -
    -`; - -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 - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    -
    -
    - -
    -
    - 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 Fare Leg Table Story Leg Products 1`] = ` - + `; -exports[`Storyshots TripDetails Styled Walk Transit Walk Itinerary 2`] = ` -.c6 { +exports[`Storyshots TripDetails Fare Leg Table Story Leg Products 2`] = ` +.c2 { 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; +.c1 th { + font-weight: normal; + min-width: 5ch; + padding: 0.75em 1.5em; + text-align: center; } -.c10 { - float: right; +.c1 th:nth-of-type(2n + 1) { + background: #cccccc22; } -.c4 { - margin-top: 6px; +.c1 th.main { + background: #333333; + color: #ffffffcc; } -.c8 { - 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; } -
    -

    - Trip Details -

    -
    + -
    -
    - -
    -
    + otpUi.TripDetails.FareTable.regular + + +
    + + + + + + + + + + + + + +
    - - Depart - - November 13, 2019 - - at - - 3:44 PM - - - -
    + 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 + - -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    - -
    -
    +
    - -
    +
    + + + + + + + + + + + + + + + +
    - Time Spent Active: - 2 minutes + otpUi.TripDetails.FareTable.youth - - -
    +
    -
    -
    - - By taking this trip, you'll spend - - 2 minutes - - walking and - - 0 minutes - - biking. - -
    -
    - - -
    + 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 + - -
    - - 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 - - . -
    -
    -
    - - + + $0.00 +
    `; -exports[`Storyshots TripDetails Tnc Transit Itinerary 1`] = ` +exports[`Storyshots TripDetails Leg Fare Products Itinerary 1`] = ` `; -exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` +exports[`Storyshots TripDetails Leg Fare Products Itinerary 2`] = ` .c4 { display: inline-block; vertical-align: middle; @@ -263780,7 +242311,7 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` white-space: nowrap; } -.c9 { +.c13 { color: #00f; font-size: 16px; margin-left: 6px; @@ -263791,8 +242322,13 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` float: right; } -.c10 { - text-transform: capitalize; +.c9 { + display: inline-block; +} + +.c9 > span { + display: block; + padding-left: 1.75ch; } .c2 { @@ -263840,6 +242376,49 @@ exports[`Storyshots TripDetails Tnc 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; +} +
    @@ -263884,11 +242463,11 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` > Depart - May 23, 2023 + May 26, 2023 at - 10:58 AM + 3:23 PM
    @@ -263965,170 +242544,282 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` - - - Tarif en transports: - - $9.50 - - + Transit Fare + : + + $5.75 + - - - -
    -
    -
    -
    -
    + -
    - Custom details about fares (transitFares: - {"regular":{"currency":{"symbol":"$","currency":"USD","defaultFractionDigits":2,"currencyCode":"USD"},"cents":950}} - ) - - (cents), can be constructed dynamically using any markup.
    @@ -264207,13 +242893,13 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` > Time Spent Active: - 2 minutes + 41 minutes + + + + +
    +
    + +
    +
    + Time Spent Active: + + 5 minutes + + +
    +
    +
    +
    + + By taking this trip, you'll spend + + 5 minutes + + walking and + + 0 minutes + + biking. + +
    +
    +
    +
    +
    +
    + +
    +
    + + CO₂ Emitted: - May 23, 2023 + 7g - Custom messages about - - May 23, 2023 - - can be constructed dynamically using any markup. + 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 +

    +
    - - - - Tarif en transports: - - $9.50 - - - - + Depart + + June 22, 2022 + + at + + 4:59 PM +
    - + 12 minutes + +
    + By taking this trip, you'll spend + + 12 minutes + + walking and + + 0 minutes + + biking. +
    - Time Spent Active: - - 2 minutes - + + CO₂ Emitted: + + 4,682g + + - Custom message about - active minutes. + 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 + + .
    - CO₂ Emitted: - - 319g - + This trip includes flexible routes. This is the first pickup booking info message. This is the first dropoff booking info message. -
    - 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 - - .
    @@ -265465,449 +244981,35 @@ exports[`Storyshots TripDetails Tnc Transit Itinerary With Custom Messages 2`] =
    `; -exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 1`] = ` +exports[`Storyshots TripDetails Styled Itinerary 1`] = ` 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}", - } - } + messages={Object {}} onError={[Function]} textComponent={Symbol(react.fragment)} > - + +`; + +exports[`Storyshots TripDetails Styled 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 Walk Interlined Transit Itinerary 2`] = ` +exports[`Storyshots TripDetails Tnc Transit Itinerary 2`] = ` .c4 { display: inline-block; vertical-align: middle; @@ -267490,7 +246244,7 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` white-space: nowrap; } -.c13 { +.c10 { color: #00f; font-size: 16px; margin-left: 6px; @@ -267502,12 +246256,7 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` } .c9 { - display: inline-block; -} - -.c9 > span { - display: block; - padding-left: 1.75ch; + text-transform: capitalize; } .c2 { @@ -267550,52 +246299,9 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` 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; + -ms-flex-align: baseline; + align-items: baseline; + white-space: pre; }
    - Custom Trip Details Title + Trip Details
    + Depart - Leave + May 23, 2023 at - 12:57 PM - - on - - May 4, 2022 + 10:58 AM
    @@ -267726,416 +246429,47 @@ 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 -
    -
    -
    + uber +
    + Fare: + + $34.00 + - + $37.00 + + +
    + Custom details about fares (transitFares: + ) + + (cents), can be constructed dynamically using any markup.
    @@ -268209,13 +246547,13 @@ exports[`Storyshots TripDetails Walk Interlined Transit Itinerary 2`] = ` > Time Spent Active: - 9 minutes + 2 minutes + +
    +
    +
    + + Custom messages about + + May 23, 2023 + + can be constructed dynamically using any markup. +
    +
    +
    + +
    - Depart - - December 13, 2019 - - at - - 11:29 AM - + + Pay + + $34.00 + - + $37.00 + + to + + uber + +
    Time Spent Active: - 1 minute + 2 minutes - By taking this trip, you'll spend - - 1 minute - - walking and - - 0 minutes - - biking. - + Custom message about + active minutes.
    CO₂ Emitted: - 1g + 319g
    @@ -269871,100 +248046,6 @@ exports[`Storyshots TripDetails Walk Transit Transfer Itinerary 2`] = `
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - €2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    Time Spent Active: - 5 minutes + 1 minute
    -
    -
    - -
    -
    - - - - - Transit Fare - : - - $2.50 - - - - - -
    -
    -
    -
    - -
    -
    -
    -
    itinerary getTransitFare should return defaults with missing fare 1`] = `0`; - -exports[`util > itinerary getTransitFare should work with valid fare component 1`] = `575`; diff --git a/packages/core-utils/src/__tests__/itinerary.js b/packages/core-utils/src/__tests__/itinerary.js index d8a5cc302..5663e4d77 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, - getTransitFare, + 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, @@ -35,30 +37,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 +89,72 @@ describe("util > itinerary", () => { expect(getDisplayedStopId(basePlace)).toBeFalsy(); }); }); + + describe("getLegCost", () => { + const leg = { + fareProducts: [ + { + id: "testId", + product: { + medium: { id: "cash" }, + name: "rideCost", + price: { amount: 200, currency: "USD" }, + riderCategory: { id: "regular" } + } + }, + { + id: "testId", + product: { + medium: { id: "cash" }, + name: "transfer", + price: { amount: 50, currency: "USD" }, + 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 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 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(); + }); + }); + + 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).toEqual({ + code: "USD", + digits: 2 + }); + }); + 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 7bd263dcc..8fb47c78f 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, @@ -474,27 +473,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 @@ -577,20 +555,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) @@ -600,23 +564,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 }; } @@ -629,17 +596,64 @@ export function getLegCost( */ export function getItineraryCost( legs: Leg[], - category: string, - container: string -): Money { - return legs - .filter(leg => !!leg.fareProducts) - .map(leg => getLegCost(leg, category, container).price) - .reduce( - (prev, cur) => ({ - cents: prev.cents + cur?.cents || 0, - currency: prev.currency ?? cur?.currency - }), - { cents: 0, currency: null } - ); + mediumId: string, + riderCategoryId: string +): Money | undefined { + const legCosts = legs + .filter(leg => leg.fareProducts?.length > 0) + .map(leg => getLegCost(leg, mediumId, riderCategoryId).price) + .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 => { + 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 +}); diff --git a/packages/core-utils/src/planQuery.graphql b/packages/core-utils/src/planQuery.graphql index b1ee05731..cc4d99f1f 100644 --- a/packages/core-utils/src/planQuery.graphql +++ b/packages/core-utils/src/planQuery.graphql @@ -1,6 +1,6 @@ query Plan( - $fromPlace: String! - $toPlace: String! + $fromPlace: String! + $toPlace: String! $modes: [TransportMode] $time: String $date: String @@ -57,6 +57,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 @@ -211,4 +233,4 @@ query Plan( inputField } } -} +} \ No newline at end of file diff --git a/packages/itinerary-body/src/ItineraryBody/index.tsx b/packages/itinerary-body/src/ItineraryBody/index.tsx index 73f40333e..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, @@ -35,7 +36,6 @@ const ItineraryBody = ({ showElevationProfile, showLegIcon, showMapButtonColumn = true, - showRouteFares, showViewTripButton, TimeColumnContent, toRouteAbbreviation = defaultRouteAbbr, @@ -50,7 +50,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 @@ -63,11 +62,8 @@ const ItineraryBody = ({ // eslint-disable-next-line react/no-array-index-key key={i + (isDestination ? 1 : 0)} config={config} + defaultFareSelector={defaultFareSelector} 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 bb6e84ad9..0d6d38bd4 100755 --- a/packages/itinerary-body/src/ItineraryBody/place-row.tsx +++ b/packages/itinerary-body/src/ItineraryBody/place-row.tsx @@ -21,8 +21,8 @@ export default function PlaceRow({ AlertToggleIcon, alwaysCollapseAlerts, config, + defaultFareSelector, diagramVisible, - fare, followsTransit, frameLeg, isDestination, @@ -135,11 +135,11 @@ export default function PlaceRow({ AlertBodyIcon={AlertBodyIcon} AlertToggleIcon={AlertToggleIcon} alwaysCollapseAlerts={alwaysCollapseAlerts} - fare={fare} + defaultFareSelector={defaultFareSelector} leg={leg} + legDestination={formattedPlace(leg.to)} LegIcon={LegIcon} legIndex={legIndex} - legDestination={formattedPlace(leg.to)} RouteDescription={RouteDescription} setActiveLeg={setActiveLeg} setViewedTrip={setViewedTrip} diff --git a/packages/itinerary-body/src/TransitLegBody/index.tsx b/packages/itinerary-body/src/TransitLegBody/index.tsx index ec6072acb..c408afce4 100644 --- a/packages/itinerary-body/src/TransitLegBody/index.tsx +++ b/packages/itinerary-body/src/TransitLegBody/index.tsx @@ -1,6 +1,6 @@ import coreUtils from "@opentripplanner/core-utils"; import { - Fare, + FareProductSelector, FlexBookingInfo, Leg, LegIconComponent, @@ -14,6 +14,7 @@ import { injectIntl, IntlShape } from "react-intl"; + import { Duration } from "../defaults"; import * as S from "../styled"; @@ -34,12 +35,12 @@ interface Props { AlertBodyIcon?: FunctionComponent; AlertToggleIcon?: FunctionComponent; alwaysCollapseAlerts: boolean; - fare?: Fare; + defaultFareSelector?: FareProductSelector; intl: IntlShape; leg: Leg; + legDestination: string; LegIcon: LegIconComponent; legIndex: number; - legDestination: string; RouteDescription: FunctionComponent; setActiveLeg: SetActiveLegFunction; setViewedTrip: SetViewedTripFunction; @@ -108,16 +109,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 }); @@ -135,14 +126,14 @@ class TransitLegBody extends Component { render(): ReactElement { const { - AlertToggleIcon = S.DefaultAlertToggleIcon, AlertBodyIcon, + AlertToggleIcon = S.DefaultAlertToggleIcon, alwaysCollapseAlerts, - fare, + defaultFareSelector, intl, leg, - LegIcon, legDestination, + LegIcon, RouteDescription, setViewedTrip, showAgencyInfo, @@ -177,7 +168,14 @@ class TransitLegBody extends Component { const shouldOnlyShowAlertsExpanded = !(shouldCollapseDueToAlertCount || alwaysCollapseAlerts) || !leg.alerts; const expandAlerts = alertsExpanded || shouldOnlyShowAlertsExpanded; - const fareForLeg = this.getFareForLeg(leg, fare); + + const legCost = + defaultFareSelector && + coreUtils.itinerary.getLegCost( + leg, + defaultFareSelector.mediumId, + defaultFareSelector.riderCategoryId + ); return ( <> @@ -343,7 +341,7 @@ class TransitLegBody extends Component { > - {fareForLeg && ( + {legCost?.price && ( { values={{ fare: ( ) }} @@ -368,7 +366,6 @@ class TransitLegBody extends Component { )} - {/* Average wait details, if present */} {leg.averageWait && ( 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": [] + } + ] + } + ] +} 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 } diff --git a/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx b/packages/itinerary-body/src/stories/OtpRrItineraryBody.story.tsx index 7f545819f..020e731e1 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 ".."; @@ -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"); @@ -46,21 +46,22 @@ if (!isRunningJest()) { } interface StoryWrapperProps { + alwaysCollapseAlerts?: boolean; + defaultFareSelector?: FareProductSelector; itinerary: Itinerary; - showRouteFares: boolean; - TimeColumnContent: FunctionComponent; - alwaysCollapseAlerts: boolean; + TimeColumnContent?: FunctionComponent; } function OtpRRItineraryBodyWrapper({ + alwaysCollapseAlerts, + defaultFareSelector, itinerary, - showRouteFares, - TimeColumnContent, - alwaysCollapseAlerts + TimeColumnContent }: StoryWrapperProps): ReactElement { return ( ( export const IndividualLegFareComponents = (): ReactElement => ( ); diff --git a/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx b/packages/itinerary-body/src/stories/OtpUiItineraryBody.story.tsx index b7350d5b1..a4eaba97c 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"); @@ -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 681b31a0d..208ef1496 100644 --- a/packages/itinerary-body/src/types.ts +++ b/packages/itinerary-body/src/types.ts @@ -2,7 +2,7 @@ import { FunctionComponent } from "react"; import { Config, - Fare, + FareProductSelector, GradationMap, Itinerary, Leg, @@ -109,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. @@ -184,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; /** @@ -216,8 +220,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; } 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..6be58a368 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: Plein tarif + senior: Senior + special: LIFT + youth: Jeune diff --git a/packages/trip-details/i18n/en-US.yml b/packages/trip-details/i18n/en-US.yml index c4b11ef5c..aaf2a54f9 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 @@ -8,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 {# @@ -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 d2cf21155..b7247783e 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,24 +15,18 @@ 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} transitFare: Tarifa de tránsito 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 82d2520b0..d26732fef 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: Plein tarif + 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 @@ -8,16 +15,8 @@ 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}}" + minutesActive: "Activité physique\_: {minutes, plural, one {# minute} other {# minutes}}" showDetail: Afficher les détails timeActiveDescription: > Sur ce trajet, vous effectuerez {walkMinutes, plural, one {# @@ -25,9 +24,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 tripIncludesFlex: Ce trajet comprend un service à la demande (Flex). {extraMessage} diff --git a/packages/trip-details/i18n/i18n-exceptions.json b/packages/trip-details/i18n/i18n-exceptions.json new file mode 100644 index 000000000..755ff7466 --- /dev/null +++ b/packages/trip-details/i18n/i18n-exceptions.json @@ -0,0 +1,12 @@ +{ + "groups": { + "otpUi.TripDetails.FareTable.*": [ + "cash", + "electronic", + "regular", + "special", + "senior", + "youth" + ] + } +} diff --git a/packages/trip-details/i18n/ko.yml b/packages/trip-details/i18n/ko.yml index 25ca80bcc..407a29a24 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: 트립 상세정보 @@ -21,5 +21,4 @@ otpUi: transferDiscountExplanation: 환승 할인 {transferAmount} 적용 transitFare: 대중 교통 운임 transitFareEntry: "{name} : {value}" - transitFareUnknown: 운임 정보 없음 tripIncludesFlex: 이 트립에는 가변 경로가 포함되어 있습니다. {extraMessage} 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..dc5e82735 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 @@ -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 304d4124d..cbe393a91 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: 行程详情 @@ -19,5 +19,4 @@ otpUi: transferDiscountExplanation: 应用了 {transferAmount} 的转让折扣 transitFare: 公共交通费 transitFareEntry: "{name}: {value}" - transitFareUnknown: 没有票价信息 tripIncludesFlex: 这个行程包括灵活的路线. {extraMessage} diff --git a/packages/trip-details/package.json b/packages/trip-details/package.json index 2f5ce2757..dbf680e4f 100644 --- a/packages/trip-details/package.json +++ b/packages/trip-details/package.json @@ -11,13 +11,13 @@ "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" }, "devDependencies": { - "@opentripplanner/types": "^5.0.0", + "@opentripplanner/types": "^6.0.0-alpha.9", "@types/flat": "^5.0.2" }, "peerDependencies": { diff --git a/packages/trip-details/src/TripDetails.story.tsx b/packages/trip-details/src/TripDetails.story.tsx index b615acf8c..09b23af53 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"; @@ -26,21 +26,13 @@ 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"); -const fareComponentsItinerary = require("@opentripplanner/itinerary-body/src/__mocks__/itineraries/fare-components.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); @@ -57,104 +49,70 @@ const StyledTripDetails = styled(TripDetails)` } `; -const otp2FareByLegLayout: FareTableLayout[] = [ +const orcaFareByLegLayout: FareTableLayout[] = [ { - header: "regular" as FareTableText, cols: [ { - header: "cash" as FareTableText, - riderCategory: "regular", - fareContainer: "cash" + columnHeaderKey: "cash", + mediumId: "orca:cash", + riderCategoryId: "orca:regular" }, { - header: "electronic" as FareTableText, - riderCategory: "regular", - fareContainer: "electronic" + columnHeaderKey: "electronic", + mediumId: "orca:electronic", + riderCategoryId: "orca:regular" }, { - header: "special" as FareTableText, - riderCategory: "special", - fareContainer: "electronic" + columnHeaderKey: "special", + mediumId: "orca:electronic", + riderCategoryId: "orca:special" } - ] - }, - { - header: "youth" as FareTableText, - cols: [ - { - header: "cash" as FareTableText, - riderCategory: "youth", - fareContainer: "cash" - }, - { - header: "electronic" as FareTableText, - riderCategory: "youth", - fareContainer: "electronic" - } - ] + ], + headerKey: "regular" }, { - header: "senior" as FareTableText, - cols: [ - { - header: "cash" as FareTableText, - riderCategory: "senior", - fareContainer: "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" + columnHeaderKey: "cash", + mediumId: "orca:cash", + riderCategoryId: "orca:youth" }, { - header: "special" as FareTableText, - key: "electronicSpecial" - } - ] - }, - { - header: "youth" as FareTableText, - cols: [ - { - header: "cash" as FareTableText, - key: "youth" + columnHeaderKey: "electronic", + mediumId: "orca:electronic", + riderCategoryId: "orca:youth" }, { - header: "electronic" as FareTableText, - key: "electronicYouth" + columnHeaderKey: "test", + mediumId: "invalidkey", + riderCategoryId: "invalidkey" } - ] + ], + headerKey: "youth" }, { - header: "senior" as FareTableText, + headerKey: "senior", cols: [ { - header: "cash" as FareTableText, - key: "cash" + columnHeaderKey: "cash", + mediumId: "orca:cash", + riderCategoryId: "orca:senior" }, { - header: "electronic" as FareTableText, - key: "electronic" + columnHeaderKey: "electronic", + mediumId: "orca:electronic", + riderCategoryId: "orca:senior" } ] } ]; +const orcaDefaultFareType = { + headerKey: "cash-regular", + mediumId: "orca:cash", + riderCategoryId: "orca:regular" +}; + const englishFareKeyMap = { regular: "Transit Fare", student: "Student Fare", @@ -227,10 +185,11 @@ function createTripDetailsTemplate( ): ComponentStory { const TripDetailsTemplate = ( { - TimeActiveDetails, + defaultFareType, DepartureDetails, FareDetails, fareDetailsLayout, + TimeActiveDetails, itinerary }: TripDetailsProps, { globals, parameters }: StoryContext @@ -251,6 +210,7 @@ function createTripDetailsTemplate( fareKeyNameMap={fareKeyNameMap} itinerary={itinerary} co2Config={defaultCo2Config} + defaultFareType={defaultFareType} /> ); }; @@ -299,7 +259,7 @@ export const WalkTransitWalkItinerary = makeStory({ itinerary: walkTransitWalkItinerary }); -export const StyledWalkTransitWalkItinerary = makeStory( +export const StyledItinerary = makeStory( { itinerary: walkTransitWalkItinerary }, @@ -307,51 +267,10 @@ export const StyledWalkTransitWalkItinerary = makeStory( StyledTripDetails ); -export const BikeTransitBikeItinerary = makeStory({ - itinerary: bikeTransitBikeItinerary -}); - -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 +export const LegFareProductsItinerary = makeStory({ + defaultFareType: orcaDefaultFareType, + fareDetailsLayout: orcaFareByLegLayout, + itinerary: otp2FareProducts }); // The render of this itinerary is uninteresting, but the test @@ -372,10 +291,14 @@ 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 + itinerary: tncTransitTncItinerary, + TimeActiveDetails: CustomTimeActiveDetails }, { // For illustration purposes, @@ -391,23 +314,9 @@ export const TncTransitItineraryWithCustomMessages = makeStory( StyledTripDetails ); -export const FareComponentsItinerary = makeStory({ - itinerary: fareComponentsItinerary -}); - 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..d516be8a4 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,70 @@ 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 + .map(col => ({ + ...col, + total: getItineraryCost(legs, col.mediumId, col.riderCategoryId) + })) + .filter(col => col.total); + 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 +174,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 297ae2119..aa8f1eabb 100644 --- a/packages/trip-details/src/index.tsx +++ b/packages/trip-details/src/index.tsx @@ -1,5 +1,5 @@ -import flatten from "flat"; 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"; @@ -7,17 +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 { 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 { TimeActiveDetailsProps, TripDetailsProps } from "./types"; // Load the default messages. import defaultEnglishMessages from "../i18n/en-US.yml"; @@ -63,54 +59,13 @@ 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, DepartureDetails = null, displayTimeActive = true, FareDetails = null, @@ -122,63 +77,105 @@ 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.rideHailingEstimate) { - companies = leg.rideHailingEstimate.provider.id; - } - }); - let fare; - const fareKeys = transitFares && Object.keys(transitFares).sort(); + const { companies, fareTypes } = itinerary.legs.reduce<{ + companies: string; + fareTypes: FareProductSelector[]; + }>( + (prev, leg) => { + if (leg.rideHailingEstimate) { + prev.companies = leg.rideHailingEstimate.provider.id; + } - if (transitFares && fareKeys.length > 0) { - let defaultFare = defaultFareKey; - if (!transitFares[defaultFareKey]) { - defaultFare = "regular"; - } + 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 && defaultFareType) { + const defaultFareTotal = coreUtils.itinerary.getItineraryCost( + itinerary.legs, + defaultFareType.mediumId, + defaultFareType.riderCategoryId + ); // 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 ( - ); }) @@ -280,15 +277,15 @@ export function TripDetails({ } /> - {fare && ( + {!!fare && ( ) } @@ -302,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 7a180ca2c..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 { MassUnitOption, Fare, Itinerary, Money } from "@opentripplanner/types"; -import type { ReactElement } from "react"; +import type { + FareProductSelector, + Itinerary, + Leg, + MassUnitOption, + Money + } from "@opentripplanner/types"; export interface TimeActiveDetailsProps { bikeMinutes: number; @@ -19,47 +24,34 @@ export interface DepartureDetailsProps { departureDate: Date; } -export enum FareTableText { - regular = "regular", - youth = "youth", - senior = "senior", - special = "special", - cash = "cash", - electronic = "electronic" -} - +/** + * 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: { - header: FareTableText; - key?: string; - riderCategory?: string; - fareContainer?: string; - }[]; - header: FareTableText; + cols: (FareProductSelector & { + columnHeaderKey: string; + })[] + headerKey: string; } -export interface TransitFareData { - [key: string]: Money +/** + * Interface containing the lgs and the layout of the fare table. + */ +export interface FareLegTableProps { + layout?: FareTableLayout[]; + legs: Leg[]; } +// Total fare amount corresponding to a fare key +export type FareTotals = (FareProductSelector & { price: Money })[] + export interface FareDetailsProps { + legs: Leg[]; maxTNCFare: number; minTNCFare: number; - transitFares: TransitFareData; -} - -export interface FareLegTableProps { - layout?: FareTableLayout[]; - itinerary: Itinerary; } -export interface TransitFareProps { - fareKey: string; - fareNameFallback?: ReactElement; - fareKeyNameMap: { - [key: string]: string; - }; - transitFares: Fare; -} export interface TripDetailsProps { /** @@ -73,7 +65,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 } & 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 809c596c1..36cfd05f6 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 React, { ReactElement, ReactNode } from "react"; +import { FormattedNumber } from "react-intl"; /** * Format text bold (used with FormattedMessage). */ -export function boldText(contents: ReactElement): ReactElement { +export function boldText(contents: ReactNode): 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 ( - - ); - } -}; diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 3731bb292..d9f2e97ea 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; @@ -298,6 +293,7 @@ export type Leg = { dropOffBookingInfo?: FlexDropOffBookingInfo; duration: number; endTime: number; + fareProducts?: { id: string; product: FareProduct }[]; from: Place; headsign?: string; interlineWithPreviousLeg: boolean; @@ -342,11 +338,6 @@ 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; }; type TripStopTime = { @@ -368,44 +359,13 @@ type TemporaryTNCPriceType = { * 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: @@ -418,7 +378,6 @@ export type Itinerary = { elevationGained: number; elevationLost: number; endTime: number; - fare?: Fare; legs: Leg[]; startTime: number; tooSloped?: boolean; @@ -791,23 +750,26 @@ 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 = { - amount: Money; id: string; - name: string; - category: { + medium?: { id: string; name: string; }; - container: { + name: string; + price: Money; + riderCategory?: { id: string; name: string; }; }; -export type LegProduct = { - legIndices: Array; - products: Array; +export type FareProductSelector = { + mediumId: string; + riderCategoryId: string; }; /** diff --git a/yarn.lock b/yarn.lock index 292fe6180..89314e45f 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" @@ -3256,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"
    - {boldText(getFormattedTextForConfigKey(header))} + {boldText(headerString)} - {boldText(getFormattedTextForConfigKey(col.header))} + {boldText(useGetHeaderString(col.columnHeaderKey))}
    - {renderFare( - fare?.currency?.currencyCode, - (fare?.cents || 0) / 100 - )} + {renderFare(fare?.currency?.code, fare?.amount || 0)}
    - {leg.routeShortName || leg.route || leg.routeLongName} + {leg.routeShortName || leg.routeLongName} 0 && intl.formatMessage( { defaultMessage: @@ -142,9 +142,9 @@ const FareTypeTable = ({ }, { transferAmount: intl.formatNumber( - fare.transferAmount / 100, + fare?.transferAmount?.amount, { - currency: fare?.price?.currency?.currencyCode, + currency: fare?.price?.currency?.code, currencyDisplay: "narrowSymbol", style: "currency" } @@ -153,15 +153,15 @@ 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 )}