From 13ad822b624d87a938f8cb0e4959f2a2f2ce4a2b Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Fri, 13 Sep 2024 15:09:53 -0400 Subject: [PATCH] fix: `isFlex` truthy more of the time --- .../core-utils/src/__tests__/itinerary.ts | 16 +++++++ packages/core-utils/src/itinerary.ts | 42 ++++++++++++++----- 2 files changed, 47 insertions(+), 11 deletions(-) diff --git a/packages/core-utils/src/__tests__/itinerary.ts b/packages/core-utils/src/__tests__/itinerary.ts index ee4a49c7f..0053b7e1e 100644 --- a/packages/core-utils/src/__tests__/itinerary.ts +++ b/packages/core-utils/src/__tests__/itinerary.ts @@ -9,6 +9,7 @@ import { getLegRouteLongName, getLegRouteName, getLegRouteShortName, + isFlex, isTransit, mapOldElevationComponentToNew } from "../itinerary"; @@ -16,6 +17,7 @@ import { const bikeRentalItinerary = require("./__mocks__/bike-rental-itinerary.json"); const tncItinerary = require("./__mocks__/tnc-itinerary.json"); const fareProductItinerary = require("./__mocks__/fare-products-itinerary.json"); +const flexItinerary = require("../../../itinerary-body/src/__mocks__/itineraries/flex-itinerary.json"); const basePlace = { lat: 0, @@ -40,6 +42,20 @@ describe("util > itinerary", () => { }); }); + describe("isFlex", () => { + it("should detect flex if present", () => { + fareProductItinerary.legs.forEach(leg => expect(isFlex(leg)).toBe(false)); + tncItinerary.legs.forEach(leg => expect(isFlex(leg)).toBe(false)); + expect(isFlex(flexItinerary.legs[0])).toBe(false); + expect(isFlex(flexItinerary.legs[1])).toBe(false); + expect(isFlex(flexItinerary.legs[2])).toBe(false); + expect(isFlex(flexItinerary.legs[3])).toBe(false); + expect(isFlex(flexItinerary.legs[4])).toBe(false); + expect(isFlex(flexItinerary.legs[5])).toBe(true); + expect(isFlex(flexItinerary.legs[6])).toBe(false); // Does not exist + expect(isFlex(flexItinerary.legs[7])).toBe(false); // Does not exist + }); + }); describe("isTransit", () => { it("should work", () => { expect(isTransit("CAR")).toBeFalsy(); diff --git a/packages/core-utils/src/itinerary.ts b/packages/core-utils/src/itinerary.ts index aac986a49..282949eee 100644 --- a/packages/core-utils/src/itinerary.ts +++ b/packages/core-utils/src/itinerary.ts @@ -52,7 +52,7 @@ export function isTransit(mode: string): boolean { * property which encodes this info. */ export function isReservationRequired(leg: Leg): boolean { - return leg.boardRule === "mustPhone" || leg.alightRule === "mustPhone"; + return leg?.boardRule === "mustPhone" || leg?.alightRule === "mustPhone"; } /** * Returns true if a user must ask the driver to let the user off @@ -61,25 +61,45 @@ export function isReservationRequired(leg: Leg): boolean { */ export function isCoordinationRequired(leg: Leg): boolean { return ( - leg.boardRule === "coordinateWithDriver" || - leg.alightRule === "coordinateWithDriver" + leg?.boardRule === "coordinateWithDriver" || + leg?.alightRule === "coordinateWithDriver" ); } -/** - * The two rules checked by the above two functions are the only values - * returned by OTP when a leg is a flex leg. - */ -export function isFlex(leg: Leg): boolean { - return isReservationRequired(leg) || isCoordinationRequired(leg); -} +export function containsGeometry(place: Place): boolean { + return ( + place?.stop?.geometries !== null && place?.stop?.geometries !== undefined + ); +} +export function endsWithGeometry(leg: Leg): boolean { + return containsGeometry(leg?.to); +} +export function startsWithGeometry(leg: Leg): boolean { + return containsGeometry(leg?.from); +} +export function legContainsGeometry(leg: Leg): boolean { + return endsWithGeometry(leg) || startsWithGeometry(leg); +} export function isAdvanceBookingRequired(info: FlexBookingInfo): boolean { return info?.latestBookingTime?.daysPrior > 0; } export function legDropoffRequiresAdvanceBooking(leg: Leg): boolean { - return isAdvanceBookingRequired(leg.dropOffBookingInfo); + return isAdvanceBookingRequired(leg?.dropOffBookingInfo); } +/** + * The two rules checked by the above two functions are the only values + * returned by OTP when a leg is a flex leg. + */ +export function isFlex(leg: Leg): boolean { + return ( + isReservationRequired(leg) || + isCoordinationRequired(leg) || + legDropoffRequiresAdvanceBooking(leg) || + isAdvanceBookingRequired(leg?.pickupBookingInfo) || + legContainsGeometry(leg) + ); +} export function isRideshareLeg(leg: Leg): boolean { return !!leg.rideHailingEstimate?.provider?.id; }