@opentripplanner/core-utils 14.0.0-alpha.2 → 14.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/esm/itinerary.js +70 -32
- package/esm/itinerary.js.map +1 -1
- package/esm/otpSchema.json +7321 -5821
- package/esm/planQuery.graphql +12 -0
- package/esm/profile.js +1 -1
- package/esm/profile.js.map +1 -1
- package/esm/query-gen.js +2 -2
- package/esm/query-gen.js.map +1 -1
- package/esm/query-params.js +2 -2
- package/esm/query-params.js.map +1 -1
- package/esm/query.js +2 -5
- package/esm/query.js.map +1 -1
- package/esm/storage.js +2 -6
- package/esm/storage.js.map +1 -1
- package/esm/time.js +1 -2
- package/esm/time.js.map +1 -1
- package/lib/index.js +50 -35
- package/lib/index.js.map +1 -1
- package/lib/itinerary.d.ts +25 -8
- package/lib/itinerary.d.ts.map +1 -1
- package/lib/itinerary.js +524 -495
- package/lib/itinerary.js.map +1 -1
- package/lib/map.js +40 -39
- package/lib/map.js.map +1 -1
- package/lib/otpSchema.json +7321 -5821
- package/lib/planQuery.graphql +12 -0
- package/lib/profile.js +1 -1
- package/lib/profile.js.map +1 -1
- package/lib/query-gen.js +134 -138
- package/lib/query-gen.js.map +1 -1
- package/lib/query-params.js +2 -2
- package/lib/query-params.js.map +1 -1
- package/lib/query.js +3 -6
- package/lib/query.js.map +1 -1
- package/lib/route.js +230 -248
- package/lib/route.js.map +1 -1
- package/lib/storage.d.ts.map +1 -1
- package/lib/storage.js +22 -28
- package/lib/storage.js.map +1 -1
- package/lib/suspense.js +28 -16
- package/lib/suspense.js.map +1 -1
- package/lib/time.js +36 -49
- package/lib/time.js.map +1 -1
- package/lib/ui.js +33 -36
- package/lib/ui.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/__snapshots__/query-params.ts.snap +203 -203
- package/src/__tests__/__snapshots__/query.js.snap +28 -28
- package/src/__tests__/__snapshots__/route.js.snap +76 -76
- package/src/__tests__/__snapshots__/time.js.snap +2 -2
- package/src/__tests__/itinerary.ts +108 -23
- package/src/__tests__/query.js +1 -1
- package/src/__tests__/route.js +1 -1
- package/src/core-utils.story.tsx +34 -23
- package/src/itinerary.ts +85 -37
- package/src/otpSchema.json +7321 -5821
- package/src/planQuery.graphql +12 -0
- package/src/profile.js +1 -1
- package/src/query-gen.ts +1 -1
- package/src/query-params.jsx +2 -2
- package/src/query.js +2 -5
- package/src/storage.ts +5 -9
- package/tsconfig.tsbuildinfo +1 -1
package/src/__tests__/query.js
CHANGED
package/src/__tests__/route.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
makeRouteComparator
|
|
6
6
|
} from "../route";
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
import { otp1Routes, otp2Routes } from "./__mocks__/routes.json";
|
|
9
9
|
|
|
10
10
|
function sortRoutes(...routes) {
|
|
11
11
|
routes.sort(makeRouteComparator());
|
package/src/core-utils.story.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable react/display-name */
|
|
1
2
|
import React, { useState } from "react";
|
|
2
3
|
import styled from "styled-components";
|
|
3
4
|
import {
|
|
@@ -42,29 +43,39 @@ const ColorPair = ({ fg, bg }: { fg: string; bg: string }) => {
|
|
|
42
43
|
);
|
|
43
44
|
};
|
|
44
45
|
|
|
45
|
-
export const RouteColorTester =
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
46
|
+
export const RouteColorTester = {
|
|
47
|
+
render: (): JSX.Element => {
|
|
48
|
+
const [fg, setFg] = useState("#333333");
|
|
49
|
+
const [bg, setBg] = useState("#cbeb55");
|
|
50
|
+
return (
|
|
51
|
+
<>
|
|
52
|
+
<ColorPair bg={bg} fg={fg}></ColorPair>
|
|
53
|
+
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
|
54
|
+
<label>
|
|
55
|
+
Foreground Color
|
|
56
|
+
<input
|
|
57
|
+
onChange={e => setFg(e.target.value)}
|
|
58
|
+
type="color"
|
|
59
|
+
value={fg}
|
|
60
|
+
/>
|
|
61
|
+
</label>
|
|
62
|
+
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
|
|
63
|
+
<label>
|
|
64
|
+
Background Color
|
|
65
|
+
<input
|
|
66
|
+
onChange={e => setBg(e.target.value)}
|
|
67
|
+
type="color"
|
|
68
|
+
value={bg}
|
|
69
|
+
/>
|
|
70
|
+
</label>
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
},
|
|
74
|
+
// Disable color contrast checking for the uncorrected color pairs
|
|
75
|
+
parameters: {
|
|
76
|
+
a11y: { config: { rules: [{ id: "color-contrast", reviewOnFail: true }] } },
|
|
77
|
+
storyshots: { disable: true }
|
|
78
|
+
}
|
|
68
79
|
};
|
|
69
80
|
|
|
70
81
|
// Route sort logic story:
|
package/src/itinerary.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import polyline from "@mapbox/polyline";
|
|
2
2
|
import {
|
|
3
|
+
AppliedFareProduct,
|
|
3
4
|
Company,
|
|
4
5
|
Config,
|
|
6
|
+
Currency,
|
|
5
7
|
ElevationProfile,
|
|
6
8
|
ElevationProfileComponent,
|
|
7
9
|
FlexBookingInfo,
|
|
@@ -104,8 +106,6 @@ export function isFlex(leg: Leg): boolean {
|
|
|
104
106
|
legContainsGeometry(leg)
|
|
105
107
|
);
|
|
106
108
|
}
|
|
107
|
-
|
|
108
|
-
// alpha-only comment
|
|
109
109
|
export function isRideshareLeg(leg: Leg): boolean {
|
|
110
110
|
return !!leg.rideHailingEstimate?.provider?.id;
|
|
111
111
|
}
|
|
@@ -609,45 +609,91 @@ export function getDisplayedStopId(placeOrStop: Place | Stop): string {
|
|
|
609
609
|
return stopCode || stopId?.split(":")[1] || stopId;
|
|
610
610
|
}
|
|
611
611
|
|
|
612
|
+
/**
|
|
613
|
+
* Removes the first part of the OTP standard scope (":"), if it is present
|
|
614
|
+
* @param item String that is potentially scoped with `:` character
|
|
615
|
+
* @returns descoped string
|
|
616
|
+
*/
|
|
617
|
+
export const descope = (item: string): string => item?.split(":")?.[1];
|
|
618
|
+
|
|
619
|
+
export type ExtendedMoney = Money & { originalAmount?: number };
|
|
620
|
+
|
|
621
|
+
export const zeroDollars = (currency: Currency): Money => ({
|
|
622
|
+
amount: 0,
|
|
623
|
+
currency
|
|
624
|
+
});
|
|
625
|
+
|
|
612
626
|
/**
|
|
613
627
|
* Extracts useful data from the fare products on a leg, such as the leg cost and transfer info.
|
|
614
|
-
* @param leg
|
|
615
|
-
* @param
|
|
616
|
-
* @param
|
|
617
|
-
* @
|
|
628
|
+
* @param leg Leg with Fares v2 information
|
|
629
|
+
* @param mediumId Desired medium ID to calculate fare for
|
|
630
|
+
* @param riderCategoryId Desire rider category to calculate fare for
|
|
631
|
+
* @param seenFareIds Fare IDs used on previous legs. Used to detect transfer discounts.
|
|
632
|
+
* @returns Object containing price as well as transfer/dependent
|
|
633
|
+
* fare information. `AppliedFareProduct` should contain
|
|
634
|
+
* all the information needed, but the other fields are kept to
|
|
635
|
+
* make the transition to Fares V2 less jarring.
|
|
618
636
|
*/
|
|
619
637
|
export function getLegCost(
|
|
620
638
|
leg: Leg,
|
|
621
639
|
mediumId: string | null,
|
|
622
|
-
riderCategoryId: string | null
|
|
640
|
+
riderCategoryId: string | null,
|
|
641
|
+
seenFareIds?: string[]
|
|
623
642
|
): {
|
|
643
|
+
alternateFareProducts?: AppliedFareProduct[];
|
|
644
|
+
appliedFareProduct?: AppliedFareProduct;
|
|
645
|
+
isDependent?: boolean;
|
|
624
646
|
price?: Money;
|
|
625
|
-
transferAmount?: Money | undefined;
|
|
626
647
|
productUseId?: string;
|
|
627
648
|
} {
|
|
628
649
|
if (!leg.fareProducts) return { price: undefined };
|
|
629
|
-
const relevantFareProducts = leg.fareProducts
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
650
|
+
const relevantFareProducts = leg.fareProducts
|
|
651
|
+
.filter(({ product }) => {
|
|
652
|
+
// riderCategory and medium can be specifically defined as null to handle
|
|
653
|
+
// generic GTFS based fares from OTP when there is no fare model
|
|
654
|
+
|
|
655
|
+
// Remove (optional) agency scoping
|
|
656
|
+
const productRiderCategoryId =
|
|
657
|
+
descope(product?.riderCategory?.id) ||
|
|
658
|
+
product?.riderCategory?.id ||
|
|
659
|
+
null;
|
|
660
|
+
|
|
661
|
+
const productMediaId =
|
|
662
|
+
descope(product?.medium?.id) || product?.medium?.id || null;
|
|
663
|
+
return (
|
|
664
|
+
productRiderCategoryId === riderCategoryId &&
|
|
665
|
+
productMediaId === mediumId &&
|
|
666
|
+
// Make sure there's a price
|
|
667
|
+
// Some fare products don't have a price at all.
|
|
668
|
+
product?.price
|
|
669
|
+
);
|
|
670
|
+
})
|
|
671
|
+
.map(fare => {
|
|
672
|
+
const alreadySeen = seenFareIds?.indexOf(fare.id) > -1;
|
|
673
|
+
const { currency } = fare.product.price;
|
|
674
|
+
return {
|
|
675
|
+
id: fare.id,
|
|
676
|
+
product: {
|
|
677
|
+
...fare.product,
|
|
678
|
+
legPrice: alreadySeen ? zeroDollars(currency) : fare.product.price
|
|
679
|
+
} as AppliedFareProduct
|
|
680
|
+
};
|
|
681
|
+
})
|
|
682
|
+
.sort((a, b) => a.product?.legPrice?.amount - b.product?.legPrice?.amount);
|
|
683
|
+
|
|
684
|
+
// Return the cheapest, but include other matches as well
|
|
685
|
+
const cheapestRelevantFareProduct = relevantFareProducts[0];
|
|
686
|
+
|
|
687
|
+
// TODO: return one object here instead of dumbing it down?
|
|
647
688
|
return {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
689
|
+
alternateFareProducts: relevantFareProducts.splice(1).map(fp => fp.product),
|
|
690
|
+
appliedFareProduct: cheapestRelevantFareProduct?.product,
|
|
691
|
+
isDependent:
|
|
692
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
693
|
+
cheapestRelevantFareProduct?.product.__typename ===
|
|
694
|
+
"DependentFareProduct",
|
|
695
|
+
price: cheapestRelevantFareProduct?.product.legPrice,
|
|
696
|
+
productUseId: cheapestRelevantFareProduct?.id
|
|
651
697
|
};
|
|
652
698
|
}
|
|
653
699
|
|
|
@@ -656,6 +702,7 @@ export function getLegCost(
|
|
|
656
702
|
* @param legs Itinerary legs with fare products (must have used getLegsWithFares)
|
|
657
703
|
* @param category Rider category (youth, regular, senior)
|
|
658
704
|
* @param container Fare container (cash, electronic)
|
|
705
|
+
* @param seenFareIds List of fare product IDs that have already been seen on prev legs.
|
|
659
706
|
* @returns Money object for the total itinerary cost.
|
|
660
707
|
*/
|
|
661
708
|
export function getItineraryCost(
|
|
@@ -663,22 +710,23 @@ export function getItineraryCost(
|
|
|
663
710
|
mediumId: string | null,
|
|
664
711
|
riderCategoryId: string | null
|
|
665
712
|
): Money | undefined {
|
|
666
|
-
const
|
|
713
|
+
const legCostsObj = legs
|
|
667
714
|
// Only legs with fares (no walking legs)
|
|
668
715
|
.filter(leg => leg.fareProducts?.length > 0)
|
|
669
716
|
// Get the leg cost object of each leg
|
|
670
717
|
.map(leg => getLegCost(leg, mediumId, riderCategoryId))
|
|
671
|
-
.filter(cost => cost.
|
|
718
|
+
.filter(cost => cost.appliedFareProduct?.legPrice !== undefined)
|
|
672
719
|
// Filter out duplicate use IDs
|
|
673
720
|
// One fare product can be used on multiple legs,
|
|
674
721
|
// and we don't want to count it more than once.
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
722
|
+
// Use an object keyed by productUseId to deduplicate, then extract prices
|
|
723
|
+
.reduce<{ [productUseId: string]: Money }>((acc, cur) => {
|
|
724
|
+
if (cur.productUseId && acc[cur.productUseId] === undefined) {
|
|
725
|
+
acc[cur.productUseId] = cur.appliedFareProduct?.legPrice;
|
|
678
726
|
}
|
|
679
|
-
return
|
|
680
|
-
},
|
|
681
|
-
|
|
727
|
+
return acc;
|
|
728
|
+
}, {});
|
|
729
|
+
const legCosts = Object.values(legCostsObj);
|
|
682
730
|
|
|
683
731
|
if (legCosts.length === 0) return undefined;
|
|
684
732
|
// Calculate the total
|