@sabstravtech/obtservices 0.2.2605260950 → 0.2.2606091200

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.
Files changed (133) hide show
  1. package/angular/components/basket-panel.d.ts +1 -1
  2. package/angular/fetchers.d.ts +2 -0
  3. package/angular/lib/vendor/classes/helpers.d.ts +2 -2
  4. package/angular/lib/vendor/fetchers/download-eticket.fetcher.d.ts +10 -0
  5. package/angular/lib/vendor/fetchers/get-flight-exchange-details.fetcher.d.ts +1 -1
  6. package/angular/lib/vendor/fetchers/get-flight-search-exchange.fetcher.d.ts +1 -1
  7. package/angular/lib/vendor/fetchers/get-jyrney-url.fetcher.d.ts +10 -0
  8. package/angular/lib/vendor/fetchers/get-latest-versions.fetcher.d.ts +1 -1
  9. package/angular/lib/vendor/fetchers/get-process-terms-price.fetcher.d.ts +10 -0
  10. package/angular/lib/vendor/fetchers/get-rail-search-exchange.fetcher.d.ts +1 -1
  11. package/angular/lib/vendor/interceptors/http-cancel-interceptor.d.ts +3 -3
  12. package/angular/lib/vendor/services/chatbot-eurostar-search.service.d.ts +38 -0
  13. package/angular/lib/vendor/services/chatbot-flight-search.service.d.ts +100 -0
  14. package/angular/lib/vendor/services/chatbot-hotel-search.service.d.ts +32 -0
  15. package/angular/lib/vendor/services/chatbot-rail-search.service.d.ts +53 -0
  16. package/angular/lib/vendor/services/chatbot-search-dispatcher.service.d.ts +36 -0
  17. package/angular/lib/vendor/services/chatbot.service.d.ts +34 -2
  18. package/angular/lib/vendor/services/enterprise-basket.service.d.ts +15 -12
  19. package/angular/lib/vendor/services/hotel-avallibility.service.d.ts +2 -2
  20. package/angular/lib/vendor/services/http-call.service.d.ts +3 -3
  21. package/angular/lib/vendor/services/http-cancel.service.d.ts +1 -1
  22. package/angular/lib/vendor/services/logon.service.d.ts +5 -5
  23. package/angular/lib/vendor/services/messages.service.d.ts +1 -1
  24. package/angular/lib/vendor/services/my-bookings.service.d.ts +2 -2
  25. package/angular/lib/vendor/services/prompt-update.service.d.ts +1 -1
  26. package/angular/lib/vendor/services/result-aware.service.d.ts +30 -1
  27. package/angular/lib/vendor/services/search-document-validation.service.d.ts +1 -1
  28. package/angular/lib/vendor/services/search-payment-validation.service.d.ts +1 -1
  29. package/angular/lib/vendor/services/search.service.d.ts +16 -15
  30. package/angular/lib/vendor/services/user.service.d.ts +7 -7
  31. package/angular/lib/vendor/services/webtoken.service.d.ts +1 -1
  32. package/angular/lib/vendor/testers/postcode-validate.tester.d.ts +1 -1
  33. package/angular/lib/vendor/types/graphql.angular.types.d.ts +132 -0
  34. package/angular/lib/vendor/updaters/accept-new-price.updater.d.ts +1 -1
  35. package/angular/lib/vendor/updaters/accept-process-terms.updater.d.ts +9 -0
  36. package/angular/lib/vendor/updaters/add-basket-item-markup.updater.d.ts +1 -1
  37. package/angular/lib/vendor/updaters/amend-booking.updater.d.ts +1 -1
  38. package/angular/lib/vendor/updaters/edit-user-address.updater.d.ts +1 -1
  39. package/angular/lib/vendor/updaters/save-user-address.updater.d.ts +1 -1
  40. package/angular/lib/vendor/updaters/set-empty-user-mi-default-value.updater.d.ts +1 -1
  41. package/angular/lib/vendor/updaters/set-mi-values.updater.d.ts +1 -1
  42. package/angular/lib/vendor/updaters/set-user-mi-default-value.updater.d.ts +1 -1
  43. package/angular/services.d.ts +5 -0
  44. package/base/lib/constants/ticket-codes.d.ts +1 -1
  45. package/base/lib/vendor/classes/base-enterprise.d.ts +1 -1
  46. package/base/lib/vendor/classes/base-network-call.d.ts +1 -1
  47. package/base/lib/vendor/classes/basket-info-mi-details.impl.d.ts +1 -1
  48. package/base/lib/vendor/classes/cabhire-enterprise-search.d.ts +3 -3
  49. package/base/lib/vendor/classes/carhire-enterprise-search.d.ts +3 -3
  50. package/base/lib/vendor/classes/draft-basket-info-mi-details.impl.d.ts +1 -1
  51. package/base/lib/vendor/classes/draft-management-info-and-valid.d.ts +2 -2
  52. package/base/lib/vendor/classes/eurostar-enterprise-search.d.ts +5 -5
  53. package/base/lib/vendor/classes/ferry-enterprise-search.d.ts +2 -4
  54. package/base/lib/vendor/classes/flight-enterprise-search.d.ts +5 -5
  55. package/base/lib/vendor/classes/hotel-enterprise-search.d.ts +4 -4
  56. package/base/lib/vendor/classes/irl-enterprise-search.d.ts +2 -2
  57. package/base/lib/vendor/classes/lounges-enterprise-search.d.ts +4 -4
  58. package/base/lib/vendor/classes/management-info-and-valid.d.ts +1 -1
  59. package/base/lib/vendor/classes/modal-types.enum.d.ts +1 -0
  60. package/base/lib/vendor/classes/parking-enterprise-search.d.ts +2 -2
  61. package/base/lib/vendor/classes/rail-enterprise-search.d.ts +5 -7
  62. package/base/lib/vendor/classes/season-ticket-enterprise-search.d.ts +2 -2
  63. package/base/lib/vendor/classes/supplementary-booking-info-impl.d.ts +1 -1
  64. package/base/lib/vendor/fetchers/apply-JIT-hotel-rules.fetcher.d.ts +3 -3
  65. package/base/lib/vendor/fetchers/eurostar-quote.fetcher.d.ts +2 -2
  66. package/base/lib/vendor/fetchers/flight-quote.fetcher.d.ts +3 -3
  67. package/base/lib/vendor/fetchers/hotel-avaliability-fetcher.d.ts +2 -2
  68. package/base/lib/vendor/fetchers/object-fetchable-enterprise.d.ts +1 -1
  69. package/base/lib/vendor/interceptors/http-cancel-interceptor.d.ts +2 -2
  70. package/base/lib/vendor/interfaces/Iambulance-enterprise-search.d.ts +1 -1
  71. package/base/lib/vendor/interfaces/Iapartment-enterprise-search.d.ts +1 -1
  72. package/base/lib/vendor/interfaces/Icarhire-enterprise-search.d.ts +2 -2
  73. package/base/lib/vendor/interfaces/Ienterprise-basket.service.d.ts +6 -5
  74. package/base/lib/vendor/interfaces/Ieurostar-enterprise-search.d.ts +2 -2
  75. package/base/lib/vendor/interfaces/Ifast-track-enterprise-search.d.ts +2 -2
  76. package/base/lib/vendor/interfaces/Iferry-enterprise-search.d.ts +1 -1
  77. package/base/lib/vendor/interfaces/Iflight-enterprise-search.d.ts +4 -4
  78. package/base/lib/vendor/interfaces/Ihotel-enterprise-search.d.ts +1 -1
  79. package/base/lib/vendor/interfaces/Iirl-enterprise-search.d.ts +2 -2
  80. package/base/lib/vendor/interfaces/Ilounges-enterprise-search.d.ts +1 -1
  81. package/base/lib/vendor/interfaces/Imeeting-room-enterprise-search.d.ts +1 -1
  82. package/base/lib/vendor/interfaces/Imybookings.service.d.ts +1 -2
  83. package/base/lib/vendor/interfaces/Irail-enterprise-search.d.ts +1 -1
  84. package/base/lib/vendor/interfaces/Irail-station-information.interface.d.ts +1 -1
  85. package/base/lib/vendor/interfaces/Isearch.service.d.ts +4 -5
  86. package/base/lib/vendor/interfaces/Iseason-tickets-enterprise-search.d.ts +1 -1
  87. package/base/lib/vendor/interfaces/Iuser.service.d.ts +4 -4
  88. package/base/lib/vendor/interfaces/booking-baskes-duplicate-check.interface.d.ts +1 -1
  89. package/base/lib/vendor/interfaces/cab-hire-search-arg.interface.d.ts +2 -2
  90. package/base/lib/vendor/interfaces/car-hire-classes.interface.d.ts +1 -1
  91. package/base/lib/vendor/interfaces/car-hire-search-arg.interface.d.ts +1 -1
  92. package/base/lib/vendor/interfaces/chatbot.types.d.ts +325 -3
  93. package/base/lib/vendor/interfaces/cheapest-price-object.d.ts +1 -1
  94. package/base/lib/vendor/interfaces/eurostar-search-arg.interface.d.ts +2 -2
  95. package/base/lib/vendor/interfaces/flight-multi-destination.interface.d.ts +3 -3
  96. package/base/lib/vendor/interfaces/hotel-recent-search-args.interface.d.ts +2 -2
  97. package/base/lib/vendor/interfaces/hotel-results-configuration.interface.d.ts +1 -1
  98. package/base/lib/vendor/interfaces/irl-search-arg.interface.d.ts +1 -1
  99. package/base/lib/vendor/operations/simple-fetchable-list-approval.d.ts +1 -1
  100. package/base/lib/vendor/operations/simple-fetchable-list-basket.d.ts +14 -1
  101. package/base/lib/vendor/operations/simple-fetchable-list-flight.d.ts +1 -1
  102. package/base/lib/vendor/operations/simple-fetchable-list-location.d.ts +1 -1
  103. package/base/lib/vendor/operations/simple-fetchable-list-misc.d.ts +14 -1
  104. package/base/lib/vendor/operations/simple-fetchable-list-quotes.d.ts +1 -1
  105. package/base/lib/vendor/operations/simple-fetchable-list-search.d.ts +1 -1
  106. package/base/lib/vendor/operations/simple-fetchable-list-user.d.ts +1 -1
  107. package/base/lib/vendor/operations/simple-fetchable-object.d.ts +14 -1
  108. package/base/lib/vendor/operations/simple-fetchers.d.ts +1 -0
  109. package/base/lib/vendor/operations/simple-updaters-basket-approval.d.ts +1 -1
  110. package/base/lib/vendor/operations/simple-updaters-basket-item.d.ts +14 -1
  111. package/base/lib/vendor/operations/simple-updaters-basket.d.ts +1 -1
  112. package/base/lib/vendor/operations/simple-updaters-booking.d.ts +1 -1
  113. package/base/lib/vendor/operations/simple-updaters-user-preference.d.ts +1 -1
  114. package/base/lib/vendor/operations/simple-updaters-user.d.ts +1 -1
  115. package/base/lib/vendor/services/chatbot.service.d.ts +43 -1
  116. package/base/lib/vendor/services/enterprise-basket.service.d.ts +17 -18
  117. package/base/lib/vendor/services/http-cancel.service.d.ts +1 -1
  118. package/base/lib/vendor/services/logon.service.d.ts +3 -3
  119. package/base/lib/vendor/services/my-bookings.service.d.ts +3 -6
  120. package/base/lib/vendor/services/requires-override-reason.service.d.ts +4 -4
  121. package/base/lib/vendor/services/requires-reason.service.d.ts +2 -2
  122. package/base/lib/vendor/services/search.service.d.ts +10 -9
  123. package/base/lib/vendor/services/user.service.d.ts +2 -6
  124. package/base/lib/vendor/testers/base.tester.d.ts +1 -1
  125. package/base/lib/vendor/testers/postcode-validate.tester.d.ts +2 -2
  126. package/base/lib/vendor/types/basket-types.d.ts +2 -2
  127. package/base/lib/vendor/types/graphql.types.d.ts +104 -0
  128. package/base/lib/vendor/types/types.d.ts +37 -36
  129. package/fesm2022/sabstravtech-obtservices-angular.mjs +2746 -155
  130. package/fesm2022/sabstravtech-obtservices-angular.mjs.map +1 -1
  131. package/fesm2022/sabstravtech-obtservices-base.mjs +6431 -6048
  132. package/fesm2022/sabstravtech-obtservices-base.mjs.map +1 -1
  133. package/package.json +1 -1
@@ -1,15 +1,15 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { Injectable, Component, Inject, NgModule, Pipe } from '@angular/core';
3
- import { BaseEnvironment, BaseEventMessenager, BaseHelperRoutines, PaymentMethodType, SchemaFormat, ServiceProvider, BaseModalOpenerService, BaseAcceptNewPriceUpdater, BaseAddItemToBasketUpdater, BaseAddUserToBasketItemUpdater, BaseCreateBasketUpdater, BaseGetBasketFetcher, BaseBookBasketUpdater, BaseDeleteBasketUpdater, BaseRemoveItemFromBasketUpdater, BaseRevalidateBasketUpdater, BaseGetUserFetcher, BaseGetUserBasketsFetcher, BaseSetBasketItemLeadPassengerUpdater, BaseMoveBasketItemToBasket, BaseUpdateBasketNoteUpdater, BaseUpdateBasketTitleUpdater, BaseUserUiConfigsFetcher, BaseUserProductsFetcher, BaseUserMessagesFetcher, BaseGetCompaniesFetcher, BaseGetCompanyFetcher, BaseConfirmMessagesUpdater, BaseSetUserLanguageUpdater, BaseEditUserUpdater, BaseCreateGuestUpdater, BaseGetUserGuestsFetcher, BaseGetOfficeFetcher, BaseRedirectApproverFetcher, BaseAddRedirectApproverUpdater, BaseRemoveRedirectApproverUpdater, BaseStorageService, BaseWebTokenService, BaseSearchCompanyApproversFetcher, BaseAddFavouriteUserUpdater, BaseGetUserFavouriteUsersFetcher, BaseRemoveFavouriteUserUpdater, BaseApexxCreateCardUpdater, BaseApexxDeleteCardUpdater, BaseApexxUpdateCardUpdater, BaseGetApexxListCardsFetcher, BaseSetBasketItemApexxTokenUpdater, BaseGetUserMiFetcher, BaseGetUserDocumentLoyaltyFetcher, BaseGetUserEmergencyContactFetcher, BaseDeleteGuestUpdater, BaseSearchUserWithEmailFetcher, BaseGetOfficeUsersFetcher, BaseRemovePreferredTransportHubUpdater, BaseSetPreferredTransportHubUpdater, BaseGetUserPreferredTransportHubsFetcher, BaseGetUserMiDefaultValuesFetcher, BaseGetUserMiStackFetcher, BaseSetUserMIDefaultValueUpdater, BaseGetEmptyUserMiDefaultValuesFetcher, BaseSetEmptyUserMIDefaultValueUpdater, BaseSearchCompanyUsersFetcher, BaseTrainlineTenantIsFrenchFetcher, BaseUserService, BaseSetPaymentOptionUpdater, BaseGetCancellationInfoFetcher, BaseAddGuestToBasketItemUpdater, BaseAddUpdatedItemToBasketUpdater, BaseCreateBasketNoteUpdater, BaseGetBasketNotesFetcher, BaseGetBasketApprovalTimestampsFetcher, BaseAddBasketItemMarkupUpdater, BaseAddBasketItemCustomRemarkUpdater, BaseGetBasketItemCustomRemarksFetcher, BaseChangeBasketOwnershipUpdater, BaseGetBasketQuoteFetcher, BaseResendApproverEmailFetcher, BaseCheckIfBasketRequiresApprovalFetcher, BaseGetOfficeApproversFetcher, BaseSelectBasketApproverUpdater, BaseGetDraftBasketsFetcher, BaseCreateBasketFromDraftUpdater, BaseSelectBasketNotifyApproverUpdater, BaseCanAmendBookingFetcher, BaseGetUserApproversFetcher, BaseGetMIApproversFetcher, BaseGetBasketApprovalInfoFetcher, BaseShareBasketUpdater, BaseGetUserSharedBasketsFetcher, BaseGetTrainSeatMapFetcher, BaseBeforeAmendCabSearchFetcher, BaseBeforeAmendCarHireSearchFetcher, BaseSendBackToQueueUpdater, BaseGetBasketCo2InfoFetcher, BaseSelectBasketMultiLevelApproversUpdater, BaseValidateBasketMiFetcher, BaseValidateBasketItemMiFetcher, BaseSetMIValuesUpdater, BaseSearchMIAutoSuggestValuesFetcher, BaseGetTrainSeatmapEvolviFetcher, BaseReserveRailSeatsUpdater, BaseGetEvolviSeatmapsAreEnabledFetcher, BasegetRequestedBookingUpdateFetcher, BaseUpdateExchangeBasketUpdater, BaseEnterpriseBasketService, BaseHotelAvalibilityQuoteFetcher, BaseHotelAvalibilityService, AbstractHttpCallService, BaseSearchAirportsFetcher, BaseSearchAirlinesFetcher, BaseSearchCityFetcher, BaseSearchPostcodeFetcher, BaseSearchRailStationsFetcher, BaseSaveUserAddressUpdater, BaseEditUserAddressUpdater, BaseUserAddressesFetcher, BaseGetUserCompanyOfficesFetcher, BaseSearchHotelChainsFetcher, BaseGetConfermaRoomImagesFetcher, BaseValidateIsPostcodeValidTester, BaseDeleteUserAddressUpdater, BaseDeleteRecentSearchUpdater, BaseSaveRecentSearchUpdater, BaseGetUserCarbonAllowanceFetcher, BaseSaveFavouriteSearchUpdater, BaseGetHotelChainsFetcher, BaseGetRailProvidersFetcher, BaseGetAllAirlinesFetcher, BaseGetCarHireProvidersFetcher, BaseLoungeQuoteFetcher, BaseParkingQuoteFetcher, BaseFlightQuoteFetcher, BaseHotelQuoteFetcher, BaseCarhireQuoteFetcher, BaseCarHireAvailabilityDetailFetcher, BaseCabhireQuoteFetcher, BaseRailQuoteFetcher, BaseIrlQuoteFetcher, BaseSearchDepotFetcher, BaseGetRailStationInfoFetcher, BaseGetRailStationFetcher, BaseGetIrlSupplierStationFetcher, BaseGetRiskAlertsFetcher, BaseSearchConfermaQuicklistFetcher, BaseGetUserRecentSearchesFetcher, BaseGetRailcardsFetcher, BaseGetCovidMicrositeTokenFetcher, BaseEurostarQuoteFetcher, BaseSearchUsersCanBookForFetcher, BaseSearchIrlStationsFetcher, BaseIrlDiscountCardFetcher, BaseGetFlightFareRulesFetcher, BaseGetFlightSeatMapFetcher, BaseGetRailLiveDeparturesFetcher, BaseHotelRulesFetcher, BaseApplyJitFlightRulesFetcher, BaseGetUserFavouriteSearchesFetcher, BaseDeleteFavouriteSearchUpdater, BaseEmailBasketFetcher, BaseFastTrackQuoteFetcher, BaseSendOfflineNotificationFetcher, BaseGenerateBasketPdfFetcher, BaseEmailFerryBookingFetcher, BaseGetFlightExtrasOptionsFetcher, BaseConvertCurrencyFetcher, BaseGetCurrencyConversionRatesFetcher, BaseGetHotelDetailsFetcher, BaseGetServiceFetcher, BaseGetFlightBrandedFaresFetcher, BaseGetTrainlineSearchConfigFetcher, BaseSearchRailInwardFetcher, BaseRailSearchExchangeFetcher, BaseCreateItineraryExchangeUpdater, BaseGetAirAvailabilityFetcher, BaseGetFlightAtNewClassFetcher, BaseGetFlightUpsellOffersFetcher, BaseGetOfficesFetcher, BaseFlightSearchExchangeFetcher, BaseFlightExchangeDetailsFetcher, BaseEmailApartmentBookingFetcher, BaseEmailSeasonTicketBookingFetcher, BaseSuggestPlacesFetcher, BaseGetLatLonFromHereIdFetcher, BaseGetGmtItineraryOptionsFetcher, BaseGetGutCitySuggestionsFetcher, BaseGetGutLocationSuggestionsFetcher, BaseGetRouteHappyFetcher, BaseGetMultipleHotelRatingFetcher, BaseEmailMeetingRoomBookingFetcher, BaseEmailAmbulanceBookingFetcher, BaseGetEntLocationByPostcode, BaseGetEntLocationByCity, BaseGetUserRecentBoltSearchesFetcher, BaseSaveRecentBoltSearchUpdater, BaseGetFerryPortsFetcher, BaseGetBannerFetcher, BaseUpdateDOBUpdater, BaseUpdateFlightSeatMapUpdater, BaseDeleteAllRecentSearchesUpdater, BaseGetOfficeDivisionsFetcher, BaseSearchGeoLocationFetcher, BaseSearchDiscoverLocationFetcher, BaseGetPriceHiddenSabreExchangeFetcher, BaseEnterpriseSearchService, BaseGetLatestVersionsFetcher, BaseLogonService, BaseCancelBookingUpdater, BaseAmendBookingUpdater, BaseCheckForDuplicateBookingsFetcher, BaseEnterpriseMyBookingsService, BaseRouteHappyService, BaseHttpCancelService, BaseMessagesService, RailFareNameKeywords, RailSplitType, isGroupTicket, RailFareTypes, SingleOrReturn, FlightSearchType, FlightDirectionEnum, BaseChatbotService, UserFavorurite, ModalTypes, BaseGetMiRequiringMandatoryDefaultValueFetcher, BaseHttpCancelInterceptor } from '@sabstravtech/obtservices/base';
3
+ import { BaseEnvironment, BaseEventMessenager, BaseHelperRoutines, PaymentMethodType, SchemaFormat, ServiceProvider, BaseModalOpenerService, BaseAcceptNewPriceUpdater, BaseAddItemToBasketUpdater, BaseAddUserToBasketItemUpdater, BaseCreateBasketUpdater, BaseGetBasketFetcher, BaseBookBasketUpdater, BaseDeleteBasketUpdater, BaseRemoveItemFromBasketUpdater, BaseRevalidateBasketUpdater, BaseGetUserFetcher, BaseGetUserBasketsFetcher, BaseSetBasketItemLeadPassengerUpdater, BaseMoveBasketItemToBasket, BaseUpdateBasketNoteUpdater, BaseUpdateBasketTitleUpdater, BaseUserUiConfigsFetcher, BaseUserProductsFetcher, BaseUserMessagesFetcher, BaseGetCompaniesFetcher, BaseGetCompanyFetcher, BaseConfirmMessagesUpdater, BaseSetUserLanguageUpdater, BaseEditUserUpdater, BaseCreateGuestUpdater, BaseGetUserGuestsFetcher, BaseGetOfficeFetcher, BaseRedirectApproverFetcher, BaseAddRedirectApproverUpdater, BaseRemoveRedirectApproverUpdater, BaseStorageService, BaseWebTokenService, BaseSearchCompanyApproversFetcher, BaseAddFavouriteUserUpdater, BaseGetUserFavouriteUsersFetcher, BaseRemoveFavouriteUserUpdater, BaseApexxCreateCardUpdater, BaseApexxDeleteCardUpdater, BaseApexxUpdateCardUpdater, BaseGetApexxListCardsFetcher, BaseSetBasketItemApexxTokenUpdater, BaseGetUserMiFetcher, BaseGetUserDocumentLoyaltyFetcher, BaseGetUserEmergencyContactFetcher, BaseDeleteGuestUpdater, BaseSearchUserWithEmailFetcher, BaseGetOfficeUsersFetcher, BaseRemovePreferredTransportHubUpdater, BaseSetPreferredTransportHubUpdater, BaseGetUserPreferredTransportHubsFetcher, BaseGetUserMiDefaultValuesFetcher, BaseGetUserMiStackFetcher, BaseSetUserMIDefaultValueUpdater, BaseGetEmptyUserMiDefaultValuesFetcher, BaseSetEmptyUserMIDefaultValueUpdater, BaseSearchCompanyUsersFetcher, BaseTrainlineTenantIsFrenchFetcher, BaseUserService, BaseSetPaymentOptionUpdater, BaseGetCancellationInfoFetcher, BaseAddGuestToBasketItemUpdater, BaseAddUpdatedItemToBasketUpdater, BaseCreateBasketNoteUpdater, BaseGetBasketNotesFetcher, BaseGetBasketApprovalTimestampsFetcher, BaseAddBasketItemMarkupUpdater, BaseAddBasketItemCustomRemarkUpdater, BaseGetBasketItemCustomRemarksFetcher, BaseChangeBasketOwnershipUpdater, BaseGetBasketQuoteFetcher, BaseGetProcessTermsPriceFetcher, BaseAcceptProcessTermsUpdater, BaseResendApproverEmailFetcher, BaseCheckIfBasketRequiresApprovalFetcher, BaseGetOfficeApproversFetcher, BaseSelectBasketApproverUpdater, BaseGetDraftBasketsFetcher, BaseCreateBasketFromDraftUpdater, BaseSelectBasketNotifyApproverUpdater, BaseCanAmendBookingFetcher, BaseGetUserApproversFetcher, BaseGetMIApproversFetcher, BaseGetBasketApprovalInfoFetcher, BaseShareBasketUpdater, BaseGetUserSharedBasketsFetcher, BaseGetTrainSeatMapFetcher, BaseBeforeAmendCabSearchFetcher, BaseBeforeAmendCarHireSearchFetcher, BaseSendBackToQueueUpdater, BaseGetBasketCo2InfoFetcher, BaseSelectBasketMultiLevelApproversUpdater, BaseValidateBasketMiFetcher, BaseValidateBasketItemMiFetcher, BaseSetMIValuesUpdater, BaseSearchMIAutoSuggestValuesFetcher, BaseGetTrainSeatmapEvolviFetcher, BaseReserveRailSeatsUpdater, BaseGetEvolviSeatmapsAreEnabledFetcher, BasegetRequestedBookingUpdateFetcher, BaseUpdateExchangeBasketUpdater, BaseDownloadETicketFetcher, BaseEnterpriseBasketService, BaseHotelAvalibilityQuoteFetcher, BaseHotelAvalibilityService, AbstractHttpCallService, BaseSearchAirportsFetcher, BaseSearchAirlinesFetcher, BaseSearchCityFetcher, BaseSearchPostcodeFetcher, BaseSearchRailStationsFetcher, BaseSaveUserAddressUpdater, BaseEditUserAddressUpdater, BaseUserAddressesFetcher, BaseGetUserCompanyOfficesFetcher, BaseSearchHotelChainsFetcher, BaseGetConfermaRoomImagesFetcher, BaseValidateIsPostcodeValidTester, BaseDeleteUserAddressUpdater, BaseDeleteRecentSearchUpdater, BaseSaveRecentSearchUpdater, BaseGetUserCarbonAllowanceFetcher, BaseSaveFavouriteSearchUpdater, BaseGetHotelChainsFetcher, BaseGetRailProvidersFetcher, BaseGetAllAirlinesFetcher, BaseGetCarHireProvidersFetcher, BaseLoungeQuoteFetcher, BaseParkingQuoteFetcher, BaseFlightQuoteFetcher, BaseHotelQuoteFetcher, BaseCarhireQuoteFetcher, BaseCarHireAvailabilityDetailFetcher, BaseCabhireQuoteFetcher, BaseRailQuoteFetcher, BaseIrlQuoteFetcher, BaseSearchDepotFetcher, BaseGetRailStationInfoFetcher, BaseGetRailStationFetcher, BaseGetIrlSupplierStationFetcher, BaseGetRiskAlertsFetcher, BaseSearchConfermaQuicklistFetcher, BaseGetUserRecentSearchesFetcher, BaseGetRailcardsFetcher, BaseGetCovidMicrositeTokenFetcher, BaseEurostarQuoteFetcher, BaseSearchUsersCanBookForFetcher, BaseSearchIrlStationsFetcher, BaseIrlDiscountCardFetcher, BaseGetFlightFareRulesFetcher, BaseGetFlightSeatMapFetcher, BaseGetRailLiveDeparturesFetcher, BaseHotelRulesFetcher, BaseApplyJitFlightRulesFetcher, BaseGetUserFavouriteSearchesFetcher, BaseDeleteFavouriteSearchUpdater, BaseEmailBasketFetcher, BaseFastTrackQuoteFetcher, BaseSendOfflineNotificationFetcher, BaseGenerateBasketPdfFetcher, BaseEmailFerryBookingFetcher, BaseGetFlightExtrasOptionsFetcher, BaseConvertCurrencyFetcher, BaseGetCurrencyConversionRatesFetcher, BaseGetHotelDetailsFetcher, BaseGetServiceFetcher, BaseGetFlightBrandedFaresFetcher, BaseGetTrainlineSearchConfigFetcher, BaseSearchRailInwardFetcher, BaseRailSearchExchangeFetcher, BaseCreateItineraryExchangeUpdater, BaseGetAirAvailabilityFetcher, BaseGetFlightAtNewClassFetcher, BaseGetFlightUpsellOffersFetcher, BaseGetOfficesFetcher, BaseFlightSearchExchangeFetcher, BaseFlightExchangeDetailsFetcher, BaseEmailApartmentBookingFetcher, BaseEmailSeasonTicketBookingFetcher, BaseSuggestPlacesFetcher, BaseGetLatLonFromHereIdFetcher, BaseGetGmtItineraryOptionsFetcher, BaseGetGutCitySuggestionsFetcher, BaseGetGutLocationSuggestionsFetcher, BaseGetRouteHappyFetcher, BaseGetMultipleHotelRatingFetcher, BaseEmailMeetingRoomBookingFetcher, BaseEmailAmbulanceBookingFetcher, BaseGetEntLocationByPostcode, BaseGetEntLocationByCity, BaseGetUserRecentBoltSearchesFetcher, BaseSaveRecentBoltSearchUpdater, BaseGetFerryPortsFetcher, BaseGetBannerFetcher, BaseUpdateDOBUpdater, BaseUpdateFlightSeatMapUpdater, BaseDeleteAllRecentSearchesUpdater, BaseGetOfficeDivisionsFetcher, BaseSearchGeoLocationFetcher, BaseSearchDiscoverLocationFetcher, BaseGetJyrneyUrlFetcher, BaseGetPriceHiddenSabreExchangeFetcher, BaseEnterpriseSearchService, BaseGetLatestVersionsFetcher, BaseLogonService, BaseCancelBookingUpdater, BaseAmendBookingUpdater, BaseCheckForDuplicateBookingsFetcher, BaseEnterpriseMyBookingsService, BaseRouteHappyService, BaseHttpCancelService, BaseMessagesService, RailFareNameKeywords, RailSplitType, isGroupTicket, RailFareTypes, SingleOrReturn, FlightSearchType, FlightDirectionEnum, BaseChatbotService, UserFavorurite, RailSearchCriteria, TimeWindow, LocationTypes, EurostarSearchType, ModalTypes, BaseGetMiRequiringMandatoryDefaultValueFetcher, BaseHttpCancelInterceptor } from '@sabstravtech/obtservices/base';
4
4
  import { FormGroup, FormControl, Validators } from '@angular/forms';
5
5
  import * as i1 from 'apollo-angular';
6
6
  import { gql } from 'apollo-angular';
7
- import { Subscription, throwError, of, BehaviorSubject, Subject, forkJoin } from 'rxjs';
7
+ import { Subscription, throwError, of, BehaviorSubject, Subject, forkJoin, filter, take, timeout as timeout$1, catchError as catchError$1, EMPTY, firstValueFrom, skip, combineLatest, race, timer } from 'rxjs';
8
8
  import moment$1 from 'moment';
9
9
  import * as i1$1 from '@angular/common/http';
10
10
  import { HttpHeaders } from '@angular/common/http';
11
11
  import * as i2 from '@angular/router';
12
- import { timeout, map, catchError, takeUntil } from 'rxjs/operators';
12
+ import { timeout, map, catchError, distinctUntilChanged, skipWhile, takeUntil } from 'rxjs/operators';
13
13
  import jwt_decode from 'jwt-decode';
14
14
  import * as i1$2 from '@angular/service-worker';
15
15
  import * as _ from 'lodash';
@@ -2892,6 +2892,7 @@ const UserFieldsFragmentDoc = gql `
2892
2892
  canSeeBookingsOfOthers
2893
2893
  becomeUser
2894
2894
  canOverrideApproval
2895
+ aiTravelAssistantEnabled
2895
2896
  }
2896
2897
  ${UserSummaryFieldsFragmentDoc}`;
2897
2898
  const AcceptNewPriceDocument = gql `
@@ -2915,6 +2916,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
2915
2916
  providedIn: 'root'
2916
2917
  }]
2917
2918
  }], ctorParameters: () => [{ type: i1.Apollo }] });
2919
+ const AcceptProcessTermsDocument = gql `
2920
+ mutation acceptProcessTerms($basketItemId: ID!, $newPrice: Float!) {
2921
+ acceptProcessTerms(basketItemId: $basketItemId, newPrice: $newPrice)
2922
+ }
2923
+ `;
2924
+ class AcceptProcessTermsGQL extends i1.Mutation {
2925
+ document = AcceptProcessTermsDocument;
2926
+ constructor(apollo) {
2927
+ super(apollo);
2928
+ }
2929
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AcceptProcessTermsGQL, deps: [{ token: i1.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
2930
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AcceptProcessTermsGQL, providedIn: 'root' });
2931
+ }
2932
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AcceptProcessTermsGQL, decorators: [{
2933
+ type: Injectable,
2934
+ args: [{
2935
+ providedIn: 'root'
2936
+ }]
2937
+ }], ctorParameters: () => [{ type: i1.Apollo }] });
2918
2938
  const AddBasketItemCustomRemarkDocument = gql `
2919
2939
  mutation addBasketItemCustomRemark($basketItem: ID!, $remark_type: String!, $text: String!) {
2920
2940
  addBasketItemCustomRemark(
@@ -4639,6 +4659,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
4639
4659
  providedIn: 'root'
4640
4660
  }]
4641
4661
  }], ctorParameters: () => [{ type: i1.Apollo }] });
4662
+ const DownloadETicketDocument = gql `
4663
+ query downloadETicket($url: String!) {
4664
+ downloadETicket(url: $url) {
4665
+ content
4666
+ contentType
4667
+ }
4668
+ }
4669
+ `;
4670
+ class DownloadETicketGQL extends i1.Query {
4671
+ document = DownloadETicketDocument;
4672
+ constructor(apollo) {
4673
+ super(apollo);
4674
+ }
4675
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadETicketGQL, deps: [{ token: i1.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
4676
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadETicketGQL, providedIn: 'root' });
4677
+ }
4678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadETicketGQL, decorators: [{
4679
+ type: Injectable,
4680
+ args: [{
4681
+ providedIn: 'root'
4682
+ }]
4683
+ }], ctorParameters: () => [{ type: i1.Apollo }] });
4642
4684
  const EditUserDocument = gql `
4643
4685
  mutation editUser($title: String, $forename: String, $surname: String, $email: String, $additionalEmail: [String], $dob: Date, $selectedLanguage: ID, $emergencyContactName: String, $emergencyContactPhone: String, $emergencyContactEmail: String, $phoneNumbers: [PhoneNumberInput!], $addresses: [AddressInput!], $documents: [DocumentInput!], $loyaltyCodes: [UserLoyaltyCodeInput!], $preferences: [UserPreferenceInput!], $userApprovers: [UserApproverInput!], $eticketEmail: String) {
4644
4686
  editUser(
@@ -7992,6 +8034,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
7992
8034
  providedIn: 'root'
7993
8035
  }]
7994
8036
  }], ctorParameters: () => [{ type: i1.Apollo }] });
8037
+ const GetJyrneyUrlDocument = gql `
8038
+ query getJyrneyUrl {
8039
+ getJyrneyUrl
8040
+ }
8041
+ `;
8042
+ class GetJyrneyUrlGQL extends i1.Query {
8043
+ document = GetJyrneyUrlDocument;
8044
+ constructor(apollo) {
8045
+ super(apollo);
8046
+ }
8047
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetJyrneyUrlGQL, deps: [{ token: i1.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
8048
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetJyrneyUrlGQL, providedIn: 'root' });
8049
+ }
8050
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetJyrneyUrlGQL, decorators: [{
8051
+ type: Injectable,
8052
+ args: [{
8053
+ providedIn: 'root'
8054
+ }]
8055
+ }], ctorParameters: () => [{ type: i1.Apollo }] });
7995
8056
  const GetLatLonFromHereIdDocument = gql `
7996
8057
  query getLatLonFromHereID($id: String!) {
7997
8058
  getLatLonFromHereID(id: $id) {
@@ -8271,6 +8332,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
8271
8332
  providedIn: 'root'
8272
8333
  }]
8273
8334
  }], ctorParameters: () => [{ type: i1.Apollo }] });
8335
+ const GetProcessTermsPriceDocument = gql `
8336
+ query getProcessTermsPrice($basketItemId: ID!, $supplementaryInfo: [SupplementaryBookingInfo!]) {
8337
+ getProcessTermsPrice(
8338
+ basketItemId: $basketItemId
8339
+ supplementaryInfo: $supplementaryInfo
8340
+ ) {
8341
+ amount
8342
+ currency
8343
+ taxItemsWithoutCode {
8344
+ name
8345
+ amount
8346
+ currency
8347
+ }
8348
+ }
8349
+ }
8350
+ `;
8351
+ class GetProcessTermsPriceGQL extends i1.Query {
8352
+ document = GetProcessTermsPriceDocument;
8353
+ constructor(apollo) {
8354
+ super(apollo);
8355
+ }
8356
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetProcessTermsPriceGQL, deps: [{ token: i1.Apollo }], target: i0.ɵɵFactoryTarget.Injectable });
8357
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetProcessTermsPriceGQL, providedIn: 'root' });
8358
+ }
8359
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetProcessTermsPriceGQL, decorators: [{
8360
+ type: Injectable,
8361
+ args: [{
8362
+ providedIn: 'root'
8363
+ }]
8364
+ }], ctorParameters: () => [{ type: i1.Apollo }] });
8274
8365
  const GetRailLiveDeparturesDocument = gql `
8275
8366
  query getRailLiveDepartures($stationCode: String!, $departDateTime: String, $destinationCode: String) {
8276
8367
  getRailLiveDepartures(
@@ -12626,7 +12717,7 @@ class HelperRoutines extends BaseHelperRoutines {
12626
12717
  multiPaymentGroup.push(next);
12627
12718
  }
12628
12719
  else {
12629
- const defaultPayment = next.availablePaymentMethods.find(payment => payment.name === PaymentMethodType.OnAccount);
12720
+ const defaultPayment = next.availablePaymentMethods.find((payment) => payment.name === PaymentMethodType.OnAccount);
12630
12721
  if (defaultPayment) {
12631
12722
  current[index].setValue(defaultPayment);
12632
12723
  }
@@ -12636,54 +12727,96 @@ class HelperRoutines extends BaseHelperRoutines {
12636
12727
  return current;
12637
12728
  }, {}))
12638
12729
  };
12639
- return suppInfoArray ? suppInfoArray.reduce((current, next, index) => {
12640
- const newItems = {};
12641
- if (next.perItemAddress) {
12642
- newItems.perItemAddress = this.addAddressGroup();
12643
- }
12644
- if (next.perItemPhoneNumber) {
12645
- newItems.perItemPhoneNumber = this.addPhoneNumberGroup(checkPhoneNumberValidator);
12646
- }
12647
- if (next?.perItemSupplementarySchema && Object.keys(next.perItemSupplementarySchema).length) {
12648
- newItems.perItemSupplementarySchema = this.makeSchema(next.perItemSupplementarySchema);
12649
- }
12650
- next.userInfo.reduce((currentUsers, user, userIndex) => {
12651
- const userControls = {};
12652
- if (next.perPassengerAddress) {
12653
- userControls.perPassengerAddress = this.addAddressGroup();
12654
- }
12655
- // ENT-15831: always create the phone group for flights so the field can render
12656
- // even when the basket response omits perPassengerPhoneNumber (e.g. setBasketItemPaymentMethod)
12657
- if (next.perPassengerPhoneNumber || basketItems[index]?.service?.type === ServiceType.Flight) {
12658
- userControls.perPassengerPhoneNumber =
12659
- this.addPhoneNumberGroup(checkPhoneNumberValidator);
12660
- }
12661
- if (next.perPassengerSupplementaryBookingInfoSchema && Object.keys(next.perPassengerSupplementaryBookingInfoSchema).length) {
12662
- userControls.perPassengerSupplementaryBookingInfoSchema = this.makeSchema(next.perPassengerSupplementaryBookingInfoSchema);
12730
+ return suppInfoArray
12731
+ ? suppInfoArray.reduce((current, next, index) => {
12732
+ const newItems = {};
12733
+ if (next.perItemAddress) {
12734
+ newItems.perItemAddress = this.addAddressGroup();
12663
12735
  }
12664
- currentUsers['user_' + userIndex] = new FormGroup(userControls);
12665
- return currentUsers;
12666
- }, newItems);
12667
- next.guestInfo.reduce((currentUsers, user, userIndex) => {
12668
- const userControls = {};
12669
- if (next.perPassengerAddress) {
12670
- userControls.perPassengerAddress = this.addAddressGroup();
12736
+ if (next.perItemPhoneNumber) {
12737
+ newItems.perItemPhoneNumber = this.addPhoneNumberGroup(checkPhoneNumberValidator);
12671
12738
  }
12672
- // ENT-15831: always create the phone group for flights so the field can render
12673
- // even when the basket response omits perPassengerPhoneNumber (e.g. setBasketItemPaymentMethod)
12674
- if (next.perPassengerPhoneNumber || basketItems[index]?.service?.type === ServiceType.Flight) {
12675
- userControls.perPassengerPhoneNumber =
12676
- this.addPhoneNumberGroup(checkPhoneNumberValidator);
12739
+ if (next?.perItemSupplementarySchema &&
12740
+ Object.keys(next.perItemSupplementarySchema).length) {
12741
+ newItems.perItemSupplementarySchema = this.makeSchema(next.perItemSupplementarySchema);
12677
12742
  }
12678
- if (next.perPassengerSupplementaryBookingInfoSchema && Object.keys(next.perPassengerSupplementaryBookingInfoSchema).length) {
12679
- userControls.perPassengerSupplementaryBookingInfoSchema = this.makeSchema(next.perPassengerSupplementaryBookingInfoSchema);
12680
- }
12681
- currentUsers['guest_' + userIndex] = new FormGroup(userControls);
12682
- return currentUsers;
12683
- }, newItems);
12684
- current['basketItem_' + index] = new FormGroup(newItems);
12685
- return current;
12686
- }, paymentMethods) : {};
12743
+ next.userInfo.reduce((currentUsers, user, userIndex) => {
12744
+ const userControls = {};
12745
+ if (next.perPassengerAddress) {
12746
+ userControls.perPassengerAddress = this.addAddressGroup();
12747
+ }
12748
+ // ENT-15831: always create the phone group for flights so the field can render
12749
+ // even when the basket response omits perPassengerPhoneNumber (e.g. setBasketItemPaymentMethod)
12750
+ if (next.perPassengerPhoneNumber ||
12751
+ basketItems[index]?.service?.type === ServiceType.Flight) {
12752
+ userControls.perPassengerPhoneNumber =
12753
+ this.addPhoneNumberGroup(checkPhoneNumberValidator);
12754
+ }
12755
+ if (next.perItemPhoneNumber) {
12756
+ newItems.perItemPhoneNumber = this.addPhoneNumberGroup(checkPhoneNumberValidator);
12757
+ }
12758
+ if (next?.perItemSupplementarySchema &&
12759
+ Object.keys(next.perItemSupplementarySchema).length) {
12760
+ newItems.perItemSupplementarySchema = this.makeSchema(next.perItemSupplementarySchema);
12761
+ }
12762
+ next.userInfo.reduce((currentUsers, user, userIndex) => {
12763
+ const userControls = {};
12764
+ if (next.perPassengerAddress) {
12765
+ userControls.perPassengerAddress = this.addAddressGroup();
12766
+ }
12767
+ if (next.perPassengerPhoneNumber) {
12768
+ userControls.perPassengerPhoneNumber =
12769
+ this.addPhoneNumberGroup(checkPhoneNumberValidator);
12770
+ }
12771
+ if (next.perPassengerSupplementaryBookingInfoSchema &&
12772
+ Object.keys(next.perPassengerSupplementaryBookingInfoSchema).length) {
12773
+ userControls.perPassengerSupplementaryBookingInfoSchema = this.makeSchema(next.perPassengerSupplementaryBookingInfoSchema);
12774
+ }
12775
+ currentUsers['user_' + userIndex] = new FormGroup(userControls);
12776
+ return currentUsers;
12777
+ }, newItems);
12778
+ next.guestInfo.reduce((currentUsers, user, userIndex) => {
12779
+ const userControls = {};
12780
+ if (next.perPassengerAddress) {
12781
+ userControls.perPassengerAddress = this.addAddressGroup();
12782
+ }
12783
+ if (next.perPassengerPhoneNumber) {
12784
+ userControls.perPassengerPhoneNumber =
12785
+ this.addPhoneNumberGroup(checkPhoneNumberValidator);
12786
+ }
12787
+ if (next.perPassengerSupplementaryBookingInfoSchema &&
12788
+ Object.keys(next.perPassengerSupplementaryBookingInfoSchema).length) {
12789
+ userControls.perPassengerSupplementaryBookingInfoSchema = this.makeSchema(next.perPassengerSupplementaryBookingInfoSchema);
12790
+ }
12791
+ currentUsers['guest_' + userIndex] = new FormGroup(userControls);
12792
+ return currentUsers;
12793
+ }, newItems);
12794
+ current['basketItem_' + index] = new FormGroup(newItems);
12795
+ return current;
12796
+ }, newItems);
12797
+ next.guestInfo.reduce((currentUsers, user, userIndex) => {
12798
+ const userControls = {};
12799
+ if (next.perPassengerAddress) {
12800
+ userControls.perPassengerAddress = this.addAddressGroup();
12801
+ }
12802
+ // ENT-15831: always create the phone group for flights so the field can render
12803
+ // even when the basket response omits perPassengerPhoneNumber (e.g. setBasketItemPaymentMethod)
12804
+ if (next.perPassengerPhoneNumber ||
12805
+ basketItems[index]?.service?.type === ServiceType.Flight) {
12806
+ userControls.perPassengerPhoneNumber =
12807
+ this.addPhoneNumberGroup(checkPhoneNumberValidator);
12808
+ }
12809
+ if (next.perPassengerSupplementaryBookingInfoSchema &&
12810
+ Object.keys(next.perPassengerSupplementaryBookingInfoSchema).length) {
12811
+ userControls.perPassengerSupplementaryBookingInfoSchema = this.makeSchema(next.perPassengerSupplementaryBookingInfoSchema);
12812
+ }
12813
+ currentUsers['guest_' + userIndex] = new FormGroup(userControls);
12814
+ return currentUsers;
12815
+ }, newItems);
12816
+ current['basketItem_' + index] = new FormGroup(newItems);
12817
+ return current;
12818
+ }, paymentMethods)
12819
+ : {};
12687
12820
  }
12688
12821
  addAddressGroup() {
12689
12822
  return new FormGroup({
@@ -12711,10 +12844,10 @@ class HelperRoutines extends BaseHelperRoutines {
12711
12844
  if (value.type === SchemaFormat.object) {
12712
12845
  current[key] = this.makeSchema(value);
12713
12846
  }
12714
- else if ((data?.required?.includes(key) || key === "ticketDeliveryOption") &&
12847
+ else if ((data?.required?.includes(key) || key === 'ticketDeliveryOption') &&
12715
12848
  value.type !== SchemaFormat.boolean &&
12716
12849
  key !== SchemaFormat.passport) {
12717
- let validators = [Validators.required];
12850
+ const validators = [Validators.required];
12718
12851
  if (value.pattern) {
12719
12852
  validators.push(Validators.pattern(value.pattern));
12720
12853
  }
@@ -12724,7 +12857,7 @@ class HelperRoutines extends BaseHelperRoutines {
12724
12857
  value.oneOf.forEach((oneOf) => {
12725
12858
  const newFormControl = this.makeSchema(oneOf);
12726
12859
  const controlKeys = Object.keys(newFormControl.controls);
12727
- controlKeys.forEach(key => {
12860
+ controlKeys.forEach((key) => {
12728
12861
  if (key === 'dateOfIssue' || key === 'dateOfExpiry') {
12729
12862
  // ! Do this otherwise ngbdate registers as invalid by default, even when no required
12730
12863
  newFormControl.controls[key].setValue(null);
@@ -12788,7 +12921,7 @@ class HelperRoutines extends BaseHelperRoutines {
12788
12921
  }
12789
12922
  isOnStaging() {
12790
12923
  return !!['test'].find((url) => {
12791
- return window.location.hostname.includes(url) && !window.location.hostname.includes('mistest');
12924
+ return (window.location.hostname.includes(url) && !window.location.hostname.includes('mistest'));
12792
12925
  });
12793
12926
  }
12794
12927
  isOnDev() {
@@ -12799,7 +12932,7 @@ class HelperRoutines extends BaseHelperRoutines {
12799
12932
  createPaymentGroup(multiPaymentGroup) {
12800
12933
  return multiPaymentGroup.reduce((acc, basketItem) => {
12801
12934
  if (acc.length) {
12802
- const dupe = acc.find(item => item.paymentMethod === basketItem.availablePaymentMethods[0].name);
12935
+ const dupe = acc.find((item) => item.paymentMethod === basketItem.availablePaymentMethods[0].name);
12803
12936
  if (dupe) {
12804
12937
  dupe.types.push(basketItem.service.type);
12805
12938
  }
@@ -12829,8 +12962,8 @@ class HelperRoutines extends BaseHelperRoutines {
12829
12962
  attemptToFillInAddress(userAddresses = [], addresses = [], form) {
12830
12963
  try {
12831
12964
  // first of all, try to find the User primary address
12832
- const userPrimary = userAddresses.find(addr => addr.userPrimary);
12833
- const officePrimary = addresses.find(addr => addr.officePrimary);
12965
+ const userPrimary = userAddresses.find((addr) => addr.userPrimary);
12966
+ const officePrimary = addresses.find((addr) => addr.officePrimary);
12834
12967
  // if found - fill in the address form with that
12835
12968
  // if not - use the first user addresses
12836
12969
  // if not - use Office Primary
@@ -12860,7 +12993,7 @@ class HelperRoutines extends BaseHelperRoutines {
12860
12993
  return form;
12861
12994
  }
12862
12995
  const keys = Object.keys(form.controls);
12863
- keys.forEach(key => {
12996
+ keys.forEach((key) => {
12864
12997
  const control = form.controls[key];
12865
12998
  // console.log(control);
12866
12999
  if (control['controls']?.perItemSupplementarySchema) {
@@ -12902,13 +13035,13 @@ class HelperRoutines extends BaseHelperRoutines {
12902
13035
  attemptToFillInParkingMobileNumber(data, form) {
12903
13036
  try {
12904
13037
  const outerKeys = Object.keys(form.controls);
12905
- outerKeys.forEach(outerKey => {
13038
+ outerKeys.forEach((outerKey) => {
12906
13039
  const formOuterKey = form.controls[outerKey];
12907
13040
  const formPerItemSupplementarySchema = formOuterKey.controls
12908
13041
  .perItemSupplementarySchema;
12909
13042
  if (formOuterKey.controls.perItemSupplementarySchema) {
12910
13043
  const keys = Object.keys(formPerItemSupplementarySchema.controls);
12911
- keys.forEach(key => {
13044
+ keys.forEach((key) => {
12912
13045
  if (key === 'mobileNum') {
12913
13046
  // now grab the mobile number from the data
12914
13047
  for (let i = 0; i < data.length; i++) {
@@ -12927,7 +13060,8 @@ class HelperRoutines extends BaseHelperRoutines {
12927
13060
  break;
12928
13061
  }
12929
13062
  const phone = userPrimaryPhone || data[0].phoneNumbers[0];
12930
- const telephone = formPerItemSupplementarySchema.controls?.car3_telephone;
13063
+ const telephone = formPerItemSupplementarySchema.controls
13064
+ ?.car3_telephone;
12931
13065
  if (phone) {
12932
13066
  telephone.controls?.TelCountryCode.setValue(`${phone.countryCode}`);
12933
13067
  telephone.controls?.TelNumber.setValue(`${phone.number}`);
@@ -12948,7 +13082,7 @@ class HelperRoutines extends BaseHelperRoutines {
12948
13082
  attemptToFillInDOB(data, index, form, isGuestUser = false) {
12949
13083
  const outerKeys = Object.keys(form.controls);
12950
13084
  const userIndex = isGuestUser ? `guest_${index}` : `user_${index}`;
12951
- outerKeys.forEach(outerKey => {
13085
+ outerKeys.forEach((outerKey) => {
12952
13086
  const formOuterKey = form.controls[outerKey];
12953
13087
  const formUserIndex = formOuterKey.controls[userIndex];
12954
13088
  const formPerPassengerSupplementaryBookingInfoSchema = formUserIndex?.controls
@@ -12969,14 +13103,15 @@ class HelperRoutines extends BaseHelperRoutines {
12969
13103
  attemptToFillInMeal(data, index, form, isGuestUser = false) {
12970
13104
  const outerKeys = Object.keys(form.controls);
12971
13105
  const userIndex = isGuestUser ? `guest_${index}` : `user_${index}`;
12972
- outerKeys.forEach(outerKey => {
13106
+ outerKeys.forEach((outerKey) => {
12973
13107
  const formOuterKey = form.controls[outerKey];
12974
13108
  const formUserIndex = formOuterKey.controls[userIndex];
12975
13109
  const formPerPassengerSupplementaryBookingInfoSchema = formUserIndex?.controls
12976
13110
  ?.perPassengerSupplementaryBookingInfoSchema;
12977
- if (formPerPassengerSupplementaryBookingInfoSchema?.controls?.meal && data?.preferences?.length) {
13111
+ if (formPerPassengerSupplementaryBookingInfoSchema?.controls?.meal &&
13112
+ data?.preferences?.length) {
12978
13113
  const meal = formPerPassengerSupplementaryBookingInfoSchema.controls.meal;
12979
- const mealPref = data.preferences.find(pref => pref.preferenceKey === 'MEAL_REQUEST');
13114
+ const mealPref = data.preferences.find((pref) => pref.preferenceKey === 'MEAL_REQUEST');
12980
13115
  if (mealPref) {
12981
13116
  const mealPrefVal = mealPref.preferenceValue?.match(/(?<=\()(.*?)(?=\))/g);
12982
13117
  meal.setValue(mealPrefVal ? mealPrefVal[0] : '');
@@ -13019,7 +13154,8 @@ class HelperRoutines extends BaseHelperRoutines {
13019
13154
  const keys = Object.keys(form.controls);
13020
13155
  for (const key of keys) {
13021
13156
  const controls = form.controls[key];
13022
- if (key.includes(substring)) { // could possibly change this to a regex
13157
+ if (key.includes(substring)) {
13158
+ // could possibly change this to a regex
13023
13159
  found.push({ controls, key }); // needs the key so we can identify the appropriate mi for pnr
13024
13160
  }
13025
13161
  if (controls.controls) {
@@ -13050,7 +13186,8 @@ class HelperRoutines extends BaseHelperRoutines {
13050
13186
  found.push({ controls, key }); // needs the key so we can identify the appropriate mi for pnr
13051
13187
  }
13052
13188
  }
13053
- else if (key === string) { // could possibly change this to a regex
13189
+ else if (key === string) {
13190
+ // could possibly change this to a regex
13054
13191
  found.push({ controls, key }); // needs the key so we can identify the appropriate mi for pnr
13055
13192
  }
13056
13193
  if (controls.controls) {
@@ -13070,7 +13207,7 @@ class HelperRoutines extends BaseHelperRoutines {
13070
13207
  */
13071
13208
  updateFormValueWithCloneValue(clonedControl, matchKey, form) {
13072
13209
  const keys = Object.keys(form.controls);
13073
- for (let key of keys) {
13210
+ for (const key of keys) {
13074
13211
  let controls = form.controls[key];
13075
13212
  const splitString = matchKey.split('-');
13076
13213
  const splitkey = key.split('-');
@@ -13108,7 +13245,7 @@ class HelperRoutines extends BaseHelperRoutines {
13108
13245
  return basketItems.reduce((bookingInfo, item) => {
13109
13246
  const userArray = this.createBlankUserSupp(item.users);
13110
13247
  const guestArray = this.createBlankUserSupp(item.guests);
13111
- let info = {
13248
+ const info = {
13112
13249
  basketItem: item.id,
13113
13250
  guestInfo: guestArray,
13114
13251
  paymentMethodDetails: {},
@@ -13120,7 +13257,7 @@ class HelperRoutines extends BaseHelperRoutines {
13120
13257
  }, []);
13121
13258
  }
13122
13259
  createBlankUserSupp(users) {
13123
- return users.map(user => {
13260
+ return users.map((user) => {
13124
13261
  return {
13125
13262
  id: user.id,
13126
13263
  supplementaryInfo: {}
@@ -13135,8 +13272,8 @@ class HelperRoutines extends BaseHelperRoutines {
13135
13272
  return basketItems.map((item) => {
13136
13273
  const info = {
13137
13274
  basketItem: item.id,
13138
- userInfo: (item.users || []).map(user => this.buildUserInfoFromSaved(user)),
13139
- guestInfo: (item.guests || []).map(guest => this.buildUserInfoFromSaved(guest)),
13275
+ userInfo: (item.users || []).map((user) => this.buildUserInfoFromSaved(user)),
13276
+ guestInfo: (item.guests || []).map((guest) => this.buildUserInfoFromSaved(guest)),
13140
13277
  supplementaryInfo: item.savedSupplementaryInfo || {},
13141
13278
  paymentMethodDetails: {}
13142
13279
  };
@@ -13178,11 +13315,11 @@ class HelperRoutines extends BaseHelperRoutines {
13178
13315
  };
13179
13316
  }
13180
13317
  checkBasketItemHasService(basket) {
13181
- return !basket.basketItems.find(item => !item.service);
13318
+ return !basket.basketItems.find((item) => !item.service);
13182
13319
  }
13183
13320
  getNamedPropertyFromObject(obj, lookupKey) {
13184
13321
  const keys = Object.keys(obj);
13185
- for (let key of keys) {
13322
+ for (const key of keys) {
13186
13323
  if (key === lookupKey) {
13187
13324
  //@ts-ignore
13188
13325
  return obj[key];
@@ -13191,7 +13328,8 @@ class HelperRoutines extends BaseHelperRoutines {
13191
13328
  else if (typeof obj[key] === 'object') {
13192
13329
  //@ts-ignore
13193
13330
  const found = this.getNamedPropertyFromObject(obj[key], lookupKey);
13194
- if (found) { // else continue
13331
+ if (found) {
13332
+ // else continue
13195
13333
  return found;
13196
13334
  }
13197
13335
  }
@@ -13199,9 +13337,9 @@ class HelperRoutines extends BaseHelperRoutines {
13199
13337
  return null;
13200
13338
  }
13201
13339
  getAllKeysFromObject(obj, includeParentObjectKeys = false) {
13202
- let keys = Object.keys(obj);
13340
+ const keys = Object.keys(obj);
13203
13341
  let returnKeys = [];
13204
- for (let key of keys) {
13342
+ for (const key of keys) {
13205
13343
  //@ts-ignore
13206
13344
  if (typeof obj[key] === 'object') {
13207
13345
  if (includeParentObjectKeys) {
@@ -13218,7 +13356,7 @@ class HelperRoutines extends BaseHelperRoutines {
13218
13356
  }
13219
13357
  getAllControlKeysFromForm(form) {
13220
13358
  let keys = Object.keys(form.controls);
13221
- for (let key of keys) {
13359
+ for (const key of keys) {
13222
13360
  const control = form.controls[key];
13223
13361
  if (control.controls) {
13224
13362
  keys = keys.concat(this.getAllControlKeysFromForm(control));
@@ -13811,8 +13949,7 @@ class WebTokenService extends BaseWebTokenService {
13811
13949
  }
13812
13950
  };
13813
13951
  // Warn if the browser doesn't support addEventListener or the Page Visibility API
13814
- if (typeof document.addEventListener === 'undefined' ||
13815
- hidden === undefined) {
13952
+ if (typeof document.addEventListener === 'undefined' || hidden === undefined) {
13816
13953
  console.log('This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.');
13817
13954
  }
13818
13955
  else {
@@ -14362,6 +14499,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
14362
14499
  args: [HelperRoutines]
14363
14500
  }] }, { type: ModalOpenerService }] });
14364
14501
 
14502
+ class GetProcessTermsPriceFetcher extends BaseGetProcessTermsPriceFetcher {
14503
+ constructor(queryGQL, helpers, modalService) {
14504
+ super(queryGQL, helpers, modalService);
14505
+ }
14506
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetProcessTermsPriceFetcher, deps: [{ token: GetProcessTermsPriceGQL }, { token: HelperRoutines }, { token: ModalOpenerService }], target: i0.ɵɵFactoryTarget.Injectable });
14507
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetProcessTermsPriceFetcher, providedIn: 'root' });
14508
+ }
14509
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetProcessTermsPriceFetcher, decorators: [{
14510
+ type: Injectable,
14511
+ args: [{ providedIn: 'root' }]
14512
+ }], ctorParameters: () => [{ type: GetProcessTermsPriceGQL, decorators: [{
14513
+ type: Inject,
14514
+ args: [GetProcessTermsPriceGQL]
14515
+ }] }, { type: HelperRoutines, decorators: [{
14516
+ type: Inject,
14517
+ args: [HelperRoutines]
14518
+ }] }, { type: ModalOpenerService }] });
14519
+
14520
+ class AcceptProcessTermsUpdater extends BaseAcceptProcessTermsUpdater {
14521
+ constructor(updater, modalService) {
14522
+ super(updater, modalService);
14523
+ }
14524
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AcceptProcessTermsUpdater, deps: [{ token: AcceptProcessTermsGQL }, { token: ModalOpenerService }], target: i0.ɵɵFactoryTarget.Injectable });
14525
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AcceptProcessTermsUpdater, providedIn: 'root' });
14526
+ }
14527
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: AcceptProcessTermsUpdater, decorators: [{
14528
+ type: Injectable,
14529
+ args: [{ providedIn: 'root' }]
14530
+ }], ctorParameters: () => [{ type: AcceptProcessTermsGQL }, { type: ModalOpenerService }] });
14531
+
14365
14532
  class ResendApproverEmailFetcher extends BaseResendApproverEmailFetcher {
14366
14533
  constructor(queryGQL, helpers, modalService) {
14367
14534
  super(queryGQL, helpers, modalService);
@@ -14716,19 +14883,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
14716
14883
  args: [UpdateExchangeBasketGQL]
14717
14884
  }] }, { type: ModalOpenerService }] });
14718
14885
 
14886
+ class DownloadETicketFetcher extends BaseDownloadETicketFetcher {
14887
+ constructor(queryGQL, helpers, modalService) {
14888
+ super(queryGQL, helpers, modalService);
14889
+ }
14890
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadETicketFetcher, deps: [{ token: DownloadETicketGQL }, { token: HelperRoutines }, { token: ModalOpenerService }], target: i0.ɵɵFactoryTarget.Injectable });
14891
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadETicketFetcher, providedIn: 'root' });
14892
+ }
14893
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: DownloadETicketFetcher, decorators: [{
14894
+ type: Injectable,
14895
+ args: [{ providedIn: 'root' }]
14896
+ }], ctorParameters: () => [{ type: DownloadETicketGQL, decorators: [{
14897
+ type: Inject,
14898
+ args: [DownloadETicketGQL]
14899
+ }] }, { type: HelperRoutines, decorators: [{
14900
+ type: Inject,
14901
+ args: [HelperRoutines]
14902
+ }] }, { type: ModalOpenerService }] });
14903
+
14719
14904
  const moment = moment$1;
14720
14905
  const TEMPID = 'TEMPID_';
14721
14906
  class EnterpriseBasketService extends BaseEnterpriseBasketService {
14722
- constructor(acceptNewPriceUpdater, addItemToBasketUpdater, addUserToBasketItem, basketCreator, basketFetcher, bookBasketUpdater, deleteBasketUpdater, helpers, removeItemFromBasketUpdater, revalidateBasketUpdater, getUserFetcher, getUserBasketsFetcher, setBasketItemLeadPassengerUpdater, moveItemToADifferentBasket, updateBasketNotes, updateBasketTitle, userService, modalService, setBasketItemPaymentOption, getCancellationFetcher, addGuestToBasketItem, addUpdatedItemToBasketUpdater, createBasketNote, getBasketNotes, getBasketApprovalTimestampsGQL, addBasketItemMarkupUpdater, addBasketItemCustomRemark, getBasketItemCustomRemarks, changeBasketOwnership, getBasketQuote, resendApproverEmail, basketRequiresApproval, getOfficeApproversFetcher, selectBasketApproverUpdater, getDraftBasketsFetcher, createBasketFromDraftUpdater, selectBasketNotifyApproverUpdater, canAmendBookingFetcher, getUserApproversFetcher, getMIApproversFetcher, getBasketApprovalInfoFetcher, shareBasketUpdater, getUserSharedBasketsFetcher, getTrainSeatMapFetcher, beforeAmendCabSearchQuoteFetcher, beforeAmendCarHireSearchfetcher, storageService, sendBackToQueueUpdater, basketCo2Fetcher, selectBasketMultiLevelApproversUpdater, validateBasketMiFetcher, validateBasketItemMiFetcher, setMIValuesUpdater, searchMIAutoSuggestValuesFetcher, getTrainSeatmapEvolviFetcher, reserveRailSeatsUpdater, evolviSeatmapsAreEnabledFetcher, getRequestedBookingUpdateFetcher, updateExchangeBasketUpdater) {
14723
- super(acceptNewPriceUpdater, addItemToBasketUpdater, addUserToBasketItem, basketCreator, basketFetcher, bookBasketUpdater, deleteBasketUpdater, helpers, removeItemFromBasketUpdater, revalidateBasketUpdater, getUserFetcher, getUserBasketsFetcher, setBasketItemLeadPassengerUpdater, moveItemToADifferentBasket, updateBasketNotes, updateBasketTitle, setBasketItemPaymentOption, getCancellationFetcher, userService, modalService, addGuestToBasketItem, addUpdatedItemToBasketUpdater, createBasketNote, getBasketNotes, getBasketApprovalTimestampsGQL, addBasketItemMarkupUpdater, addBasketItemCustomRemark, getBasketItemCustomRemarks, changeBasketOwnership, getBasketQuote, resendApproverEmail, basketRequiresApproval, getOfficeApproversFetcher, selectBasketApproverUpdater, getDraftBasketsFetcher, createBasketFromDraftUpdater, selectBasketNotifyApproverUpdater, canAmendBookingFetcher, getUserApproversFetcher, getMIApproversFetcher, getBasketApprovalInfoFetcher, shareBasketUpdater, getUserSharedBasketsFetcher, getTrainSeatMapFetcher, beforeAmendCabSearchQuoteFetcher, beforeAmendCarHireSearchfetcher, storageService, sendBackToQueueUpdater, basketCo2Fetcher, selectBasketMultiLevelApproversUpdater, validateBasketMiFetcher, validateBasketItemMiFetcher, setMIValuesUpdater, searchMIAutoSuggestValuesFetcher, getTrainSeatmapEvolviFetcher, reserveRailSeatsUpdater, evolviSeatmapsAreEnabledFetcher, getRequestedBookingUpdateFetcher, updateExchangeBasketUpdater);
14907
+ constructor(acceptNewPriceUpdater, addItemToBasketUpdater, addUserToBasketItem, basketCreator, basketFetcher, bookBasketUpdater, deleteBasketUpdater, helpers, removeItemFromBasketUpdater, revalidateBasketUpdater, getUserFetcher, getUserBasketsFetcher, setBasketItemLeadPassengerUpdater, moveItemToADifferentBasket, updateBasketNotes, updateBasketTitle, userService, modalService, setBasketItemPaymentOption, getCancellationFetcher, addGuestToBasketItem, addUpdatedItemToBasketUpdater, createBasketNote, getBasketNotes, getBasketApprovalTimestampsGQL, addBasketItemMarkupUpdater, addBasketItemCustomRemark, getBasketItemCustomRemarks, changeBasketOwnership, getBasketQuote, getProcessTermsPrice, acceptProcessTermsUpdater, resendApproverEmail, basketRequiresApproval, getOfficeApproversFetcher, selectBasketApproverUpdater, getDraftBasketsFetcher, createBasketFromDraftUpdater, selectBasketNotifyApproverUpdater, canAmendBookingFetcher, getUserApproversFetcher, getMIApproversFetcher, getBasketApprovalInfoFetcher, shareBasketUpdater, getUserSharedBasketsFetcher, getTrainSeatMapFetcher, beforeAmendCabSearchQuoteFetcher, beforeAmendCarHireSearchfetcher, storageService, sendBackToQueueUpdater, basketCo2Fetcher, selectBasketMultiLevelApproversUpdater, validateBasketMiFetcher, validateBasketItemMiFetcher, setMIValuesUpdater, searchMIAutoSuggestValuesFetcher, getTrainSeatmapEvolviFetcher, reserveRailSeatsUpdater, evolviSeatmapsAreEnabledFetcher, getRequestedBookingUpdateFetcher, updateExchangeBasketUpdater, downloadETicketFetcher) {
14908
+ super(acceptNewPriceUpdater, addItemToBasketUpdater, addUserToBasketItem, basketCreator, basketFetcher, bookBasketUpdater, deleteBasketUpdater, helpers, removeItemFromBasketUpdater, revalidateBasketUpdater, getUserFetcher, getUserBasketsFetcher, setBasketItemLeadPassengerUpdater, moveItemToADifferentBasket, updateBasketNotes, updateBasketTitle, setBasketItemPaymentOption, getCancellationFetcher, userService, modalService, addGuestToBasketItem, addUpdatedItemToBasketUpdater, createBasketNote, getBasketNotes, getBasketApprovalTimestampsGQL, addBasketItemMarkupUpdater, addBasketItemCustomRemark, getBasketItemCustomRemarks, changeBasketOwnership, getBasketQuote, getProcessTermsPrice, acceptProcessTermsUpdater, resendApproverEmail, basketRequiresApproval, getOfficeApproversFetcher, selectBasketApproverUpdater, getDraftBasketsFetcher, createBasketFromDraftUpdater, selectBasketNotifyApproverUpdater, canAmendBookingFetcher, getUserApproversFetcher, getMIApproversFetcher, getBasketApprovalInfoFetcher, shareBasketUpdater, getUserSharedBasketsFetcher, getTrainSeatMapFetcher, beforeAmendCabSearchQuoteFetcher, beforeAmendCarHireSearchfetcher, storageService, sendBackToQueueUpdater, basketCo2Fetcher, selectBasketMultiLevelApproversUpdater, validateBasketMiFetcher, validateBasketItemMiFetcher, setMIValuesUpdater, searchMIAutoSuggestValuesFetcher, getTrainSeatmapEvolviFetcher, reserveRailSeatsUpdater, evolviSeatmapsAreEnabledFetcher, getRequestedBookingUpdateFetcher, updateExchangeBasketUpdater, downloadETicketFetcher);
14724
14909
  }
14725
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseBasketService, deps: [{ token: AcceptNewPriceUpdater }, { token: AddItemToBasketUpdater }, { token: AddUserToBasketItemUpdater }, { token: CreateBasketUpdater }, { token: GetBasketFetcher }, { token: BookBasketUpdater }, { token: DeleteBasketUpdater }, { token: HelperRoutines }, { token: RemoveItemFromBasketUpdater }, { token: RevalidateBasketUpdater }, { token: GetUserFetcher }, { token: GetUserBasketsFetcher }, { token: SetBasketItemLeadPassengerUpdater }, { token: MoveBasketItemToBasketUpdater }, { token: UpdateBasketNotesUpdater }, { token: UpdateBasketTitleUpdater }, { token: UserService }, { token: ModalOpenerService }, { token: SetPaymentOptionUpdater }, { token: GetCancellationInfoFetcher }, { token: AddGuestToBasketItemUpdater }, { token: AddUpdatedItemToBasketUpdater }, { token: CreateBasketNoteUpdater }, { token: GetBasketNotesFetcher }, { token: GetBasketApprovalTimestampsFetcher }, { token: AddBasketItemMarkupUpdater }, { token: AddBasketItemCustomRemarkUpdater }, { token: GetBasketItemCustomRemarksFetcher }, { token: ChangeBasketOwnershipUpdater }, { token: GetBasketQuoteFetcher }, { token: ResendApproverEmailFetcher }, { token: CheckIfBasketRequiresApprovalFetcher }, { token: GetOfficeApproversFetcher }, { token: SelectBasketApproverUpdater }, { token: GetDraftBasketsFetcher }, { token: CreateBasketFromDraftUpdater }, { token: SelectBasketNotifyApproverUpdater }, { token: CanAmendBookingFetcher }, { token: GetUserApproversFetcher }, { token: GetMIApproversFetcher }, { token: GetBasketApprovalInfoFetcher }, { token: ShareBasketUpdater }, { token: GetUserSharedBasketsFetcher }, { token: GetTrainSeatmapFetcher }, { token: BeforeAmendCabSearchFetcher }, { token: BeforeAmendCarHireSearchFetcher }, { token: StorageService }, { token: SendBackToQueueUpdater }, { token: GetBasketCo2InfoFetcher }, { token: SelectBasketMultiLevelApproversUpdater }, { token: ValidateBasketMiFetcher }, { token: ValidateBasketItemMiFetcher }, { token: SetMIValuesUpdater }, { token: SearchMIAutoSuggestValuesFetcher }, { token: GetTrainSeatmapEvolviFetcher }, { token: ReserveRailSeatsUpdater }, { token: GetEvolviSeatmapsAreEnabledFetcher }, { token: GetRequestedBookingUpdateFetcher }, { token: UpdateExchangeBasketUpdater }], target: i0.ɵɵFactoryTarget.Injectable });
14910
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseBasketService, deps: [{ token: AcceptNewPriceUpdater }, { token: AddItemToBasketUpdater }, { token: AddUserToBasketItemUpdater }, { token: CreateBasketUpdater }, { token: GetBasketFetcher }, { token: BookBasketUpdater }, { token: DeleteBasketUpdater }, { token: HelperRoutines }, { token: RemoveItemFromBasketUpdater }, { token: RevalidateBasketUpdater }, { token: GetUserFetcher }, { token: GetUserBasketsFetcher }, { token: SetBasketItemLeadPassengerUpdater }, { token: MoveBasketItemToBasketUpdater }, { token: UpdateBasketNotesUpdater }, { token: UpdateBasketTitleUpdater }, { token: UserService }, { token: ModalOpenerService }, { token: SetPaymentOptionUpdater }, { token: GetCancellationInfoFetcher }, { token: AddGuestToBasketItemUpdater }, { token: AddUpdatedItemToBasketUpdater }, { token: CreateBasketNoteUpdater }, { token: GetBasketNotesFetcher }, { token: GetBasketApprovalTimestampsFetcher }, { token: AddBasketItemMarkupUpdater }, { token: AddBasketItemCustomRemarkUpdater }, { token: GetBasketItemCustomRemarksFetcher }, { token: ChangeBasketOwnershipUpdater }, { token: GetBasketQuoteFetcher }, { token: GetProcessTermsPriceFetcher }, { token: AcceptProcessTermsUpdater }, { token: ResendApproverEmailFetcher }, { token: CheckIfBasketRequiresApprovalFetcher }, { token: GetOfficeApproversFetcher }, { token: SelectBasketApproverUpdater }, { token: GetDraftBasketsFetcher }, { token: CreateBasketFromDraftUpdater }, { token: SelectBasketNotifyApproverUpdater }, { token: CanAmendBookingFetcher }, { token: GetUserApproversFetcher }, { token: GetMIApproversFetcher }, { token: GetBasketApprovalInfoFetcher }, { token: ShareBasketUpdater }, { token: GetUserSharedBasketsFetcher }, { token: GetTrainSeatmapFetcher }, { token: BeforeAmendCabSearchFetcher }, { token: BeforeAmendCarHireSearchFetcher }, { token: StorageService }, { token: SendBackToQueueUpdater }, { token: GetBasketCo2InfoFetcher }, { token: SelectBasketMultiLevelApproversUpdater }, { token: ValidateBasketMiFetcher }, { token: ValidateBasketItemMiFetcher }, { token: SetMIValuesUpdater }, { token: SearchMIAutoSuggestValuesFetcher }, { token: GetTrainSeatmapEvolviFetcher }, { token: ReserveRailSeatsUpdater }, { token: GetEvolviSeatmapsAreEnabledFetcher }, { token: GetRequestedBookingUpdateFetcher }, { token: UpdateExchangeBasketUpdater }, { token: DownloadETicketFetcher }], target: i0.ɵɵFactoryTarget.Injectable });
14726
14911
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseBasketService, providedIn: 'root' });
14727
14912
  }
14728
14913
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseBasketService, decorators: [{
14729
14914
  type: Injectable,
14730
14915
  args: [{ providedIn: 'root' }]
14731
- }], ctorParameters: () => [{ type: AcceptNewPriceUpdater }, { type: AddItemToBasketUpdater }, { type: AddUserToBasketItemUpdater }, { type: CreateBasketUpdater }, { type: GetBasketFetcher }, { type: BookBasketUpdater }, { type: DeleteBasketUpdater }, { type: HelperRoutines }, { type: RemoveItemFromBasketUpdater }, { type: RevalidateBasketUpdater }, { type: GetUserFetcher }, { type: GetUserBasketsFetcher }, { type: SetBasketItemLeadPassengerUpdater }, { type: MoveBasketItemToBasketUpdater }, { type: UpdateBasketNotesUpdater }, { type: UpdateBasketTitleUpdater }, { type: UserService }, { type: ModalOpenerService }, { type: SetPaymentOptionUpdater }, { type: GetCancellationInfoFetcher }, { type: AddGuestToBasketItemUpdater }, { type: AddUpdatedItemToBasketUpdater }, { type: CreateBasketNoteUpdater }, { type: GetBasketNotesFetcher }, { type: GetBasketApprovalTimestampsFetcher }, { type: AddBasketItemMarkupUpdater }, { type: AddBasketItemCustomRemarkUpdater }, { type: GetBasketItemCustomRemarksFetcher }, { type: ChangeBasketOwnershipUpdater }, { type: GetBasketQuoteFetcher }, { type: ResendApproverEmailFetcher }, { type: CheckIfBasketRequiresApprovalFetcher }, { type: GetOfficeApproversFetcher }, { type: SelectBasketApproverUpdater }, { type: GetDraftBasketsFetcher }, { type: CreateBasketFromDraftUpdater }, { type: SelectBasketNotifyApproverUpdater }, { type: CanAmendBookingFetcher }, { type: GetUserApproversFetcher }, { type: GetMIApproversFetcher }, { type: GetBasketApprovalInfoFetcher }, { type: ShareBasketUpdater }, { type: GetUserSharedBasketsFetcher }, { type: GetTrainSeatmapFetcher }, { type: BeforeAmendCabSearchFetcher }, { type: BeforeAmendCarHireSearchFetcher }, { type: StorageService }, { type: SendBackToQueueUpdater }, { type: GetBasketCo2InfoFetcher }, { type: SelectBasketMultiLevelApproversUpdater }, { type: ValidateBasketMiFetcher }, { type: ValidateBasketItemMiFetcher }, { type: SetMIValuesUpdater }, { type: SearchMIAutoSuggestValuesFetcher }, { type: GetTrainSeatmapEvolviFetcher }, { type: ReserveRailSeatsUpdater }, { type: GetEvolviSeatmapsAreEnabledFetcher }, { type: GetRequestedBookingUpdateFetcher }, { type: UpdateExchangeBasketUpdater }] });
14916
+ }], ctorParameters: () => [{ type: AcceptNewPriceUpdater }, { type: AddItemToBasketUpdater }, { type: AddUserToBasketItemUpdater }, { type: CreateBasketUpdater }, { type: GetBasketFetcher }, { type: BookBasketUpdater }, { type: DeleteBasketUpdater }, { type: HelperRoutines }, { type: RemoveItemFromBasketUpdater }, { type: RevalidateBasketUpdater }, { type: GetUserFetcher }, { type: GetUserBasketsFetcher }, { type: SetBasketItemLeadPassengerUpdater }, { type: MoveBasketItemToBasketUpdater }, { type: UpdateBasketNotesUpdater }, { type: UpdateBasketTitleUpdater }, { type: UserService }, { type: ModalOpenerService }, { type: SetPaymentOptionUpdater }, { type: GetCancellationInfoFetcher }, { type: AddGuestToBasketItemUpdater }, { type: AddUpdatedItemToBasketUpdater }, { type: CreateBasketNoteUpdater }, { type: GetBasketNotesFetcher }, { type: GetBasketApprovalTimestampsFetcher }, { type: AddBasketItemMarkupUpdater }, { type: AddBasketItemCustomRemarkUpdater }, { type: GetBasketItemCustomRemarksFetcher }, { type: ChangeBasketOwnershipUpdater }, { type: GetBasketQuoteFetcher }, { type: GetProcessTermsPriceFetcher }, { type: AcceptProcessTermsUpdater }, { type: ResendApproverEmailFetcher }, { type: CheckIfBasketRequiresApprovalFetcher }, { type: GetOfficeApproversFetcher }, { type: SelectBasketApproverUpdater }, { type: GetDraftBasketsFetcher }, { type: CreateBasketFromDraftUpdater }, { type: SelectBasketNotifyApproverUpdater }, { type: CanAmendBookingFetcher }, { type: GetUserApproversFetcher }, { type: GetMIApproversFetcher }, { type: GetBasketApprovalInfoFetcher }, { type: ShareBasketUpdater }, { type: GetUserSharedBasketsFetcher }, { type: GetTrainSeatmapFetcher }, { type: BeforeAmendCabSearchFetcher }, { type: BeforeAmendCarHireSearchFetcher }, { type: StorageService }, { type: SendBackToQueueUpdater }, { type: GetBasketCo2InfoFetcher }, { type: SelectBasketMultiLevelApproversUpdater }, { type: ValidateBasketMiFetcher }, { type: ValidateBasketItemMiFetcher }, { type: SetMIValuesUpdater }, { type: SearchMIAutoSuggestValuesFetcher }, { type: GetTrainSeatmapEvolviFetcher }, { type: ReserveRailSeatsUpdater }, { type: GetEvolviSeatmapsAreEnabledFetcher }, { type: GetRequestedBookingUpdateFetcher }, { type: UpdateExchangeBasketUpdater }, { type: DownloadETicketFetcher }] });
14732
14917
 
14733
14918
  class HotelAvalibilityQuoteFetcher extends BaseHotelAvalibilityQuoteFetcher {
14734
14919
  constructor(gql, helpers, modalService) {
@@ -16295,6 +16480,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
16295
16480
  args: [{ providedIn: 'root' }]
16296
16481
  }], ctorParameters: () => [{ type: SearchDiscoverLocationGQL }, { type: HelperRoutines }, { type: ModalOpenerService }] });
16297
16482
 
16483
+ class GetJyrneyUrlFetcher extends BaseGetJyrneyUrlFetcher {
16484
+ constructor(queryGQL, helpers, modalService) {
16485
+ super(queryGQL, helpers, modalService);
16486
+ }
16487
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetJyrneyUrlFetcher, deps: [{ token: GetJyrneyUrlGQL }, { token: HelperRoutines }, { token: ModalOpenerService }], target: i0.ɵɵFactoryTarget.Injectable });
16488
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetJyrneyUrlFetcher, providedIn: 'root' });
16489
+ }
16490
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: GetJyrneyUrlFetcher, decorators: [{
16491
+ type: Injectable,
16492
+ args: [{ providedIn: 'root' }]
16493
+ }], ctorParameters: () => [{ type: GetJyrneyUrlGQL, decorators: [{
16494
+ type: Inject,
16495
+ args: [GetJyrneyUrlGQL]
16496
+ }] }, { type: HelperRoutines, decorators: [{
16497
+ type: Inject,
16498
+ args: [HelperRoutines]
16499
+ }] }, { type: ModalOpenerService }] });
16500
+
16298
16501
  class GetPriceHiddenSabreExchangeFetcher extends BaseGetPriceHiddenSabreExchangeFetcher {
16299
16502
  constructor(gql, modalService, helpers) {
16300
16503
  super(gql, modalService, helpers);
@@ -16308,16 +16511,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
16308
16511
  }], ctorParameters: () => [{ type: GetPriceHiddenSabreExchangeGQL }, { type: ModalOpenerService }, { type: HelperRoutines }] });
16309
16512
 
16310
16513
  class EnterpriseSearchService extends BaseEnterpriseSearchService {
16311
- constructor(searchAirportsFetcher, searchAirlinesFetcher, storageService, userService, router, helpers, hotelAvalibilityService, citiesFetcher, postcodeFetcher, railStationFetcher, saveUserAddressUpdater, editUserAddressUpdater, userAddressesFetcher, basketService, getUserCompanyOfficesFetcher, searchHotelChainsFetcher, getConfermaRoomImagesFetcher, isPostcodeValidValueTester, deleteUserAddressUpdater, deleteRecentSearchUpdater, saveRecentSearchUpdater, getUserCarbonAllowanceFetcher, saveFavouriteSearchUpdater, getHotelChainsFetcher, getRailProvidersFetcher, getAllAirlinesFetcher, getCarHireProvidersFetcher, environment, loungeFetcher, parkingFetcher, httpCallService, flightFetcher, hotelFetcher, carhireFetcher, carHireAvailabilityDetailFetcher, cabhireFetcher, railFetcher, irlFetcher, depotFetcher, getRailStationInfoFetcher, getRailStationFetcher, getIrlSupplierStationFetcher, webTokenService, riskAlertsFetcher, quicklistFetcher, getUserRecentSearchesFetcher, getRailCardsFetcher, getCovidMicrositeTokenFetcher, eurostarFetcher, searchUsersCanBookForFetcher, searchIrlStationsFetcher, irlDiscountCardFetcher, flightFareRulesFetcher, getFlightSeatMapFetcher, getRailLiveDeparturesFetcher, hotelRulesFetcher, flightRulesFetcher, getUserFavouriteSearchesFetcher, deleteFavouriteSearchUpdater, modalService, emailBasketFetcher, fasttrackFetcher, sendOfflineNotificationFetcher, generateBasketPdfFetcher, emailFerryFetcher, getFlightExtrasOptions, convertCurrencyFetcher, getCurrencyConversionRatesFetcher, getHotelDetailsFetcher, getServiceFetcher, getFlightBrandedFaresFetcher, getTrainlineSearchConfigFetcher, searchRailInwardFetcher, getRailSearchExchangeFetcher, createRailItineraryExchangeUpdater, getAirAvailbilityFetcher, getFlightAtNewClassFetcher, getFlightUpsellOffersFetcher, getOfficesFetcher, getFlightSearchExchangeFetcher, getFlightExchangeDetailsFetcher, emailApartmentBookingFetcher, emailSeasonTicketBookingFetcher, suggestPlacesFetcher, getLatLonFromHereIdFetcher, getGMTItineraryOptions, getGutCitySuggestionsFetcher, getGutLocationSuggestionsFetcher, GetRouteHappyFetcher, getMultipleHotelRatingFetcher, emailMeetingRoomBookingFetcher, emailAmbulanceBookingFetcher, getEntLocationByPostcode, getEntLocationByCity, getUserRecentBoltSearchesFetcher, saveRecentBoltSearchUpdater, getFerryPortsFetcher, getBannerFetcher, updateDOBUpdater, updateFlightSeatMapUpdater, deleteAllRecentSearchesUpdater, getOfficeDivisionsFetcher, searchGeoLocationFetcher, searchDiscoverLocationFetcher, getPriceHiddenSabreExchangeFetcher) {
16312
- super(searchAirportsFetcher, searchAirlinesFetcher, storageService, userService, modalService, router, helpers, hotelAvalibilityService, citiesFetcher, postcodeFetcher, railStationFetcher, saveUserAddressUpdater, editUserAddressUpdater, userAddressesFetcher, basketService, getUserCompanyOfficesFetcher, searchHotelChainsFetcher, getConfermaRoomImagesFetcher, isPostcodeValidValueTester, depotFetcher, deleteUserAddressUpdater, deleteRecentSearchUpdater, saveRecentSearchUpdater, getUserCarbonAllowanceFetcher, saveFavouriteSearchUpdater, environment, loungeFetcher, parkingFetcher, httpCallService, flightFetcher, hotelFetcher, carhireFetcher, carHireAvailabilityDetailFetcher, cabhireFetcher, railFetcher, irlFetcher, getRailStationInfoFetcher, getRailStationFetcher, getIrlSupplierStationFetcher, webTokenService, riskAlertsFetcher, quicklistFetcher, getUserRecentSearchesFetcher, getRailCardsFetcher, getCovidMicrositeTokenFetcher, eurostarFetcher, searchUsersCanBookForFetcher, searchIrlStationsFetcher, irlDiscountCardFetcher, flightFareRulesFetcher, getFlightSeatMapFetcher, getRailLiveDeparturesFetcher, hotelRulesFetcher, flightRulesFetcher, getUserFavouriteSearchesFetcher, deleteFavouriteSearchUpdater, emailBasketFetcher, fasttrackFetcher, sendOfflineNotificationFetcher, getHotelChainsFetcher, getRailProvidersFetcher, getAllAirlinesFetcher, getCarHireProvidersFetcher, generateBasketPdfFetcher, emailFerryFetcher, getFlightExtrasOptions, convertCurrencyFetcher, getCurrencyConversionRatesFetcher, getHotelDetailsFetcher, getServiceFetcher, getFlightBrandedFaresFetcher, getTrainlineSearchConfigFetcher, searchRailInwardFetcher, getRailSearchExchangeFetcher, createRailItineraryExchangeUpdater, getAirAvailbilityFetcher, getFlightAtNewClassFetcher, getFlightUpsellOffersFetcher, getOfficesFetcher, emailApartmentBookingFetcher, emailSeasonTicketBookingFetcher, suggestPlacesFetcher, getLatLonFromHereIdFetcher, getGMTItineraryOptions, getGutCitySuggestionsFetcher, getGutLocationSuggestionsFetcher, GetRouteHappyFetcher, getMultipleHotelRatingFetcher, emailMeetingRoomBookingFetcher, getFlightSearchExchangeFetcher, getFlightExchangeDetailsFetcher, getEntLocationByPostcode, getEntLocationByCity, getUserRecentBoltSearchesFetcher, saveRecentBoltSearchUpdater, getFerryPortsFetcher, getBannerFetcher, updateDOBUpdater, updateFlightSeatMapUpdater, deleteAllRecentSearchesUpdater, getOfficeDivisionsFetcher, searchGeoLocationFetcher, searchDiscoverLocationFetcher, getPriceHiddenSabreExchangeFetcher, emailAmbulanceBookingFetcher);
16514
+ constructor(searchAirportsFetcher, searchAirlinesFetcher, storageService, userService, router, helpers, hotelAvalibilityService, citiesFetcher, postcodeFetcher, railStationFetcher, saveUserAddressUpdater, editUserAddressUpdater, userAddressesFetcher, basketService, getUserCompanyOfficesFetcher, searchHotelChainsFetcher, getConfermaRoomImagesFetcher, isPostcodeValidValueTester, deleteUserAddressUpdater, deleteRecentSearchUpdater, saveRecentSearchUpdater, getUserCarbonAllowanceFetcher, saveFavouriteSearchUpdater, getHotelChainsFetcher, getRailProvidersFetcher, getAllAirlinesFetcher, getCarHireProvidersFetcher, environment, loungeFetcher, parkingFetcher, httpCallService, flightFetcher, hotelFetcher, carhireFetcher, carHireAvailabilityDetailFetcher, cabhireFetcher, railFetcher, irlFetcher, depotFetcher, getRailStationInfoFetcher, getRailStationFetcher, getIrlSupplierStationFetcher, webTokenService, riskAlertsFetcher, quicklistFetcher, getUserRecentSearchesFetcher, getRailCardsFetcher, getCovidMicrositeTokenFetcher, eurostarFetcher, searchUsersCanBookForFetcher, searchIrlStationsFetcher, irlDiscountCardFetcher, flightFareRulesFetcher, getFlightSeatMapFetcher, getRailLiveDeparturesFetcher, hotelRulesFetcher, flightRulesFetcher, getUserFavouriteSearchesFetcher, deleteFavouriteSearchUpdater, modalService, emailBasketFetcher, fasttrackFetcher, sendOfflineNotificationFetcher, generateBasketPdfFetcher, emailFerryFetcher, getFlightExtrasOptions, convertCurrencyFetcher, getCurrencyConversionRatesFetcher, getHotelDetailsFetcher, getServiceFetcher, getFlightBrandedFaresFetcher, getTrainlineSearchConfigFetcher, searchRailInwardFetcher, getRailSearchExchangeFetcher, createRailItineraryExchangeUpdater, getAirAvailbilityFetcher, getFlightAtNewClassFetcher, getFlightUpsellOffersFetcher, getOfficesFetcher, getFlightSearchExchangeFetcher, getFlightExchangeDetailsFetcher, emailApartmentBookingFetcher, emailSeasonTicketBookingFetcher, suggestPlacesFetcher, getLatLonFromHereIdFetcher, getGMTItineraryOptions, getGutCitySuggestionsFetcher, getGutLocationSuggestionsFetcher, GetRouteHappyFetcher, getMultipleHotelRatingFetcher, emailMeetingRoomBookingFetcher, emailAmbulanceBookingFetcher, getEntLocationByPostcode, getEntLocationByCity, getUserRecentBoltSearchesFetcher, saveRecentBoltSearchUpdater, getFerryPortsFetcher, getBannerFetcher, updateDOBUpdater, updateFlightSeatMapUpdater, deleteAllRecentSearchesUpdater, getOfficeDivisionsFetcher, searchGeoLocationFetcher, searchDiscoverLocationFetcher, getJyrneyUrlFetcher, getPriceHiddenSabreExchangeFetcher) {
16515
+ super(searchAirportsFetcher, searchAirlinesFetcher, storageService, userService, modalService, router, helpers, hotelAvalibilityService, citiesFetcher, postcodeFetcher, railStationFetcher, saveUserAddressUpdater, editUserAddressUpdater, userAddressesFetcher, basketService, getUserCompanyOfficesFetcher, searchHotelChainsFetcher, getConfermaRoomImagesFetcher, isPostcodeValidValueTester, depotFetcher, deleteUserAddressUpdater, deleteRecentSearchUpdater, saveRecentSearchUpdater, getUserCarbonAllowanceFetcher, saveFavouriteSearchUpdater, environment, loungeFetcher, parkingFetcher, httpCallService, flightFetcher, hotelFetcher, carhireFetcher, carHireAvailabilityDetailFetcher, cabhireFetcher, railFetcher, irlFetcher, getRailStationInfoFetcher, getRailStationFetcher, getIrlSupplierStationFetcher, webTokenService, riskAlertsFetcher, quicklistFetcher, getUserRecentSearchesFetcher, getRailCardsFetcher, getCovidMicrositeTokenFetcher, eurostarFetcher, searchUsersCanBookForFetcher, searchIrlStationsFetcher, irlDiscountCardFetcher, flightFareRulesFetcher, getFlightSeatMapFetcher, getRailLiveDeparturesFetcher, hotelRulesFetcher, flightRulesFetcher, getUserFavouriteSearchesFetcher, deleteFavouriteSearchUpdater, emailBasketFetcher, fasttrackFetcher, sendOfflineNotificationFetcher, getHotelChainsFetcher, getRailProvidersFetcher, getAllAirlinesFetcher, getCarHireProvidersFetcher, generateBasketPdfFetcher, emailFerryFetcher, getFlightExtrasOptions, convertCurrencyFetcher, getCurrencyConversionRatesFetcher, getHotelDetailsFetcher, getServiceFetcher, getFlightBrandedFaresFetcher, getTrainlineSearchConfigFetcher, searchRailInwardFetcher, getRailSearchExchangeFetcher, createRailItineraryExchangeUpdater, getAirAvailbilityFetcher, getFlightAtNewClassFetcher, getFlightUpsellOffersFetcher, getOfficesFetcher, emailApartmentBookingFetcher, emailSeasonTicketBookingFetcher, suggestPlacesFetcher, getLatLonFromHereIdFetcher, getGMTItineraryOptions, getGutCitySuggestionsFetcher, getGutLocationSuggestionsFetcher, GetRouteHappyFetcher, getMultipleHotelRatingFetcher, emailMeetingRoomBookingFetcher, getFlightSearchExchangeFetcher, getFlightExchangeDetailsFetcher, getEntLocationByPostcode, getEntLocationByCity, getUserRecentBoltSearchesFetcher, saveRecentBoltSearchUpdater, getFerryPortsFetcher, getBannerFetcher, updateDOBUpdater, updateFlightSeatMapUpdater, deleteAllRecentSearchesUpdater, getOfficeDivisionsFetcher, searchGeoLocationFetcher, searchDiscoverLocationFetcher, getJyrneyUrlFetcher, getPriceHiddenSabreExchangeFetcher, emailAmbulanceBookingFetcher);
16313
16516
  }
16314
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseSearchService, deps: [{ token: SearchAirportsFetcher }, { token: SearchAirlinesFetcher }, { token: StorageService }, { token: UserService }, { token: i2.Router }, { token: HelperRoutines }, { token: HotelAvalibilityService }, { token: SearchCityFetcher }, { token: SearchPostcodeFetcher }, { token: SearchRailStationsFetcher }, { token: SaveUserAddressUpdater }, { token: EditUserAddressUpdater }, { token: UserAddressesFetcher }, { token: EnterpriseBasketService }, { token: GetUserCompanyOfficesFetcher }, { token: SearchHotelChainsFetcher }, { token: GetConfermaRoomImagesFetcher }, { token: IsPostcodeValidValueTester }, { token: DeleteUserAddressUpdater }, { token: DeleteRecentSearchUpdater }, { token: SaveRecentSearchUpdater }, { token: GetUserCarbonAllowanceFetcher }, { token: SaveFavouriteSearchUpdater }, { token: GetHotelChainsFetcher }, { token: GetRailProvidersFetcher }, { token: GetAllAirlinesFetcher }, { token: GetCarHireProvidersFetcher }, { token: Environment }, { token: LoungeQuoteFetcher }, { token: ParkingQuoteFetcher }, { token: HttpCallService }, { token: FlightQuoteFetcher }, { token: HotelQuoteFetcher }, { token: CarhireQuoteFetcher }, { token: CarHireAvailabilityDetailFetcher }, { token: CabhireQuoteFetcher }, { token: RailQuoteFetcher }, { token: IrlQuoteFetcher }, { token: SearchDepotFetcher }, { token: GetRailStationInfoFetcher }, { token: GetRailStationFetcher }, { token: GetIrlSupplierStationFetcher }, { token: WebTokenService }, { token: GetRiskAlertsFetcher }, { token: SearchConfermaQuicklistFetcher }, { token: GetUserRecentSearchesFetcher }, { token: GetRailcardsFetcher }, { token: GetCovidMicrositeTokenFetcher }, { token: EurostarQuoteFetcher }, { token: SearchUsersCanBookForFetcher }, { token: SearchIrlStationsFetcher }, { token: IrlDiscountCardFetcher }, { token: GetFlightFareRulesFetcher }, { token: GetFlightSeatMapFetcher }, { token: GetRailLiveDeparturesFetcher }, { token: ApplyHotelRulesFetcher }, { token: ApplyJitFlightRulesFetcher }, { token: GetUserFavouriteSearchesFetcher }, { token: DeleteFavouriteSearchUpdater }, { token: ModalOpenerService }, { token: EmailBasketFetcher }, { token: FastTrackQuoteFetcher }, { token: SendOfflineNotificationFetcher }, { token: GenerateBasketPdfFetcher }, { token: EmailFerryBookingFetcher }, { token: GetFlightExtrasOptionsFetcher }, { token: ConvertCurrencyFetcher }, { token: GetCurrencyConversionRatesFetcher }, { token: GetHotelDetailsFetcher }, { token: GetServiceFetcher }, { token: GetFlightBrandedFaresFetcher }, { token: GetTrainlineSearchConfigFetcher }, { token: SearchRailInwardFetcher }, { token: GetRailSearchExchangeFetcher }, { token: CreateItineraryExchangeUpdater }, { token: GetAirAvailabilityFetcher }, { token: GetFlightAtNewClassFetcher }, { token: GetFlightUpsellOffersFetcher }, { token: GetOfficesFetcher }, { token: GetFlightSearchExchangeFetcher }, { token: GetFlightExchangeDetailsFetcher }, { token: EmailApartmentBookingFetcher }, { token: EmailSeasonTicketBookingFetcher }, { token: SuggestPlacesFetcher }, { token: GetLatLonFromHereIdFetcher }, { token: GetGmtItineraryOptionsFetcher }, { token: GetGutCitySuggestionsFetcher }, { token: GetGutLocationSuggestionsFetcher }, { token: GetRouteHappyFetcher }, { token: GetMultipleHotelRatingFetcher }, { token: EmailMeetingRoomBookingFetcher }, { token: EmailAmbulanceBookingFetcher }, { token: GetEntLocationByPostcode }, { token: GetEntLocationByCity }, { token: GetUserRecentBoltSearchesFetcher }, { token: SaveRecentBoltSearchUpdater }, { token: GetFerryPortsFetcher }, { token: GetBannerFetcher }, { token: UpdateDOBUpdater }, { token: UpdateFlightSeatMapUpdater }, { token: DeleteAllRecentSearchesUpdater }, { token: GetOfficeDivisionsFetcher }, { token: SearchGeoLocationFetcher }, { token: SearchDiscoverLocationFetcher }, { token: GetPriceHiddenSabreExchangeFetcher }], target: i0.ɵɵFactoryTarget.Injectable });
16517
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseSearchService, deps: [{ token: SearchAirportsFetcher }, { token: SearchAirlinesFetcher }, { token: StorageService }, { token: UserService }, { token: i2.Router }, { token: HelperRoutines }, { token: HotelAvalibilityService }, { token: SearchCityFetcher }, { token: SearchPostcodeFetcher }, { token: SearchRailStationsFetcher }, { token: SaveUserAddressUpdater }, { token: EditUserAddressUpdater }, { token: UserAddressesFetcher }, { token: EnterpriseBasketService }, { token: GetUserCompanyOfficesFetcher }, { token: SearchHotelChainsFetcher }, { token: GetConfermaRoomImagesFetcher }, { token: IsPostcodeValidValueTester }, { token: DeleteUserAddressUpdater }, { token: DeleteRecentSearchUpdater }, { token: SaveRecentSearchUpdater }, { token: GetUserCarbonAllowanceFetcher }, { token: SaveFavouriteSearchUpdater }, { token: GetHotelChainsFetcher }, { token: GetRailProvidersFetcher }, { token: GetAllAirlinesFetcher }, { token: GetCarHireProvidersFetcher }, { token: Environment }, { token: LoungeQuoteFetcher }, { token: ParkingQuoteFetcher }, { token: HttpCallService }, { token: FlightQuoteFetcher }, { token: HotelQuoteFetcher }, { token: CarhireQuoteFetcher }, { token: CarHireAvailabilityDetailFetcher }, { token: CabhireQuoteFetcher }, { token: RailQuoteFetcher }, { token: IrlQuoteFetcher }, { token: SearchDepotFetcher }, { token: GetRailStationInfoFetcher }, { token: GetRailStationFetcher }, { token: GetIrlSupplierStationFetcher }, { token: WebTokenService }, { token: GetRiskAlertsFetcher }, { token: SearchConfermaQuicklistFetcher }, { token: GetUserRecentSearchesFetcher }, { token: GetRailcardsFetcher }, { token: GetCovidMicrositeTokenFetcher }, { token: EurostarQuoteFetcher }, { token: SearchUsersCanBookForFetcher }, { token: SearchIrlStationsFetcher }, { token: IrlDiscountCardFetcher }, { token: GetFlightFareRulesFetcher }, { token: GetFlightSeatMapFetcher }, { token: GetRailLiveDeparturesFetcher }, { token: ApplyHotelRulesFetcher }, { token: ApplyJitFlightRulesFetcher }, { token: GetUserFavouriteSearchesFetcher }, { token: DeleteFavouriteSearchUpdater }, { token: ModalOpenerService }, { token: EmailBasketFetcher }, { token: FastTrackQuoteFetcher }, { token: SendOfflineNotificationFetcher }, { token: GenerateBasketPdfFetcher }, { token: EmailFerryBookingFetcher }, { token: GetFlightExtrasOptionsFetcher }, { token: ConvertCurrencyFetcher }, { token: GetCurrencyConversionRatesFetcher }, { token: GetHotelDetailsFetcher }, { token: GetServiceFetcher }, { token: GetFlightBrandedFaresFetcher }, { token: GetTrainlineSearchConfigFetcher }, { token: SearchRailInwardFetcher }, { token: GetRailSearchExchangeFetcher }, { token: CreateItineraryExchangeUpdater }, { token: GetAirAvailabilityFetcher }, { token: GetFlightAtNewClassFetcher }, { token: GetFlightUpsellOffersFetcher }, { token: GetOfficesFetcher }, { token: GetFlightSearchExchangeFetcher }, { token: GetFlightExchangeDetailsFetcher }, { token: EmailApartmentBookingFetcher }, { token: EmailSeasonTicketBookingFetcher }, { token: SuggestPlacesFetcher }, { token: GetLatLonFromHereIdFetcher }, { token: GetGmtItineraryOptionsFetcher }, { token: GetGutCitySuggestionsFetcher }, { token: GetGutLocationSuggestionsFetcher }, { token: GetRouteHappyFetcher }, { token: GetMultipleHotelRatingFetcher }, { token: EmailMeetingRoomBookingFetcher }, { token: EmailAmbulanceBookingFetcher }, { token: GetEntLocationByPostcode }, { token: GetEntLocationByCity }, { token: GetUserRecentBoltSearchesFetcher }, { token: SaveRecentBoltSearchUpdater }, { token: GetFerryPortsFetcher }, { token: GetBannerFetcher }, { token: UpdateDOBUpdater }, { token: UpdateFlightSeatMapUpdater }, { token: DeleteAllRecentSearchesUpdater }, { token: GetOfficeDivisionsFetcher }, { token: SearchGeoLocationFetcher }, { token: SearchDiscoverLocationFetcher }, { token: GetJyrneyUrlFetcher }, { token: GetPriceHiddenSabreExchangeFetcher }], target: i0.ɵɵFactoryTarget.Injectable });
16315
16518
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseSearchService, providedIn: 'root' });
16316
16519
  }
16317
16520
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: EnterpriseSearchService, decorators: [{
16318
16521
  type: Injectable,
16319
16522
  args: [{ providedIn: 'root' }]
16320
- }], ctorParameters: () => [{ type: SearchAirportsFetcher }, { type: SearchAirlinesFetcher }, { type: StorageService }, { type: UserService }, { type: i2.Router }, { type: HelperRoutines }, { type: HotelAvalibilityService }, { type: SearchCityFetcher }, { type: SearchPostcodeFetcher }, { type: SearchRailStationsFetcher }, { type: SaveUserAddressUpdater }, { type: EditUserAddressUpdater }, { type: UserAddressesFetcher }, { type: EnterpriseBasketService }, { type: GetUserCompanyOfficesFetcher }, { type: SearchHotelChainsFetcher }, { type: GetConfermaRoomImagesFetcher }, { type: IsPostcodeValidValueTester }, { type: DeleteUserAddressUpdater }, { type: DeleteRecentSearchUpdater }, { type: SaveRecentSearchUpdater }, { type: GetUserCarbonAllowanceFetcher }, { type: SaveFavouriteSearchUpdater }, { type: GetHotelChainsFetcher }, { type: GetRailProvidersFetcher }, { type: GetAllAirlinesFetcher }, { type: GetCarHireProvidersFetcher }, { type: Environment }, { type: LoungeQuoteFetcher }, { type: ParkingQuoteFetcher }, { type: HttpCallService }, { type: FlightQuoteFetcher }, { type: HotelQuoteFetcher }, { type: CarhireQuoteFetcher }, { type: CarHireAvailabilityDetailFetcher }, { type: CabhireQuoteFetcher }, { type: RailQuoteFetcher }, { type: IrlQuoteFetcher }, { type: SearchDepotFetcher }, { type: GetRailStationInfoFetcher }, { type: GetRailStationFetcher }, { type: GetIrlSupplierStationFetcher }, { type: WebTokenService }, { type: GetRiskAlertsFetcher }, { type: SearchConfermaQuicklistFetcher }, { type: GetUserRecentSearchesFetcher }, { type: GetRailcardsFetcher }, { type: GetCovidMicrositeTokenFetcher }, { type: EurostarQuoteFetcher }, { type: SearchUsersCanBookForFetcher }, { type: SearchIrlStationsFetcher }, { type: IrlDiscountCardFetcher }, { type: GetFlightFareRulesFetcher }, { type: GetFlightSeatMapFetcher }, { type: GetRailLiveDeparturesFetcher }, { type: ApplyHotelRulesFetcher }, { type: ApplyJitFlightRulesFetcher }, { type: GetUserFavouriteSearchesFetcher }, { type: DeleteFavouriteSearchUpdater }, { type: ModalOpenerService }, { type: EmailBasketFetcher }, { type: FastTrackQuoteFetcher }, { type: SendOfflineNotificationFetcher }, { type: GenerateBasketPdfFetcher }, { type: EmailFerryBookingFetcher }, { type: GetFlightExtrasOptionsFetcher }, { type: ConvertCurrencyFetcher }, { type: GetCurrencyConversionRatesFetcher }, { type: GetHotelDetailsFetcher }, { type: GetServiceFetcher }, { type: GetFlightBrandedFaresFetcher }, { type: GetTrainlineSearchConfigFetcher }, { type: SearchRailInwardFetcher }, { type: GetRailSearchExchangeFetcher }, { type: CreateItineraryExchangeUpdater }, { type: GetAirAvailabilityFetcher }, { type: GetFlightAtNewClassFetcher }, { type: GetFlightUpsellOffersFetcher }, { type: GetOfficesFetcher }, { type: GetFlightSearchExchangeFetcher }, { type: GetFlightExchangeDetailsFetcher }, { type: EmailApartmentBookingFetcher }, { type: EmailSeasonTicketBookingFetcher }, { type: SuggestPlacesFetcher }, { type: GetLatLonFromHereIdFetcher }, { type: GetGmtItineraryOptionsFetcher }, { type: GetGutCitySuggestionsFetcher }, { type: GetGutLocationSuggestionsFetcher }, { type: GetRouteHappyFetcher }, { type: GetMultipleHotelRatingFetcher }, { type: EmailMeetingRoomBookingFetcher }, { type: EmailAmbulanceBookingFetcher }, { type: GetEntLocationByPostcode }, { type: GetEntLocationByCity }, { type: GetUserRecentBoltSearchesFetcher }, { type: SaveRecentBoltSearchUpdater }, { type: GetFerryPortsFetcher }, { type: GetBannerFetcher }, { type: UpdateDOBUpdater }, { type: UpdateFlightSeatMapUpdater }, { type: DeleteAllRecentSearchesUpdater }, { type: GetOfficeDivisionsFetcher }, { type: SearchGeoLocationFetcher }, { type: SearchDiscoverLocationFetcher }, { type: GetPriceHiddenSabreExchangeFetcher }] });
16523
+ }], ctorParameters: () => [{ type: SearchAirportsFetcher }, { type: SearchAirlinesFetcher }, { type: StorageService }, { type: UserService }, { type: i2.Router }, { type: HelperRoutines }, { type: HotelAvalibilityService }, { type: SearchCityFetcher }, { type: SearchPostcodeFetcher }, { type: SearchRailStationsFetcher }, { type: SaveUserAddressUpdater }, { type: EditUserAddressUpdater }, { type: UserAddressesFetcher }, { type: EnterpriseBasketService }, { type: GetUserCompanyOfficesFetcher }, { type: SearchHotelChainsFetcher }, { type: GetConfermaRoomImagesFetcher }, { type: IsPostcodeValidValueTester }, { type: DeleteUserAddressUpdater }, { type: DeleteRecentSearchUpdater }, { type: SaveRecentSearchUpdater }, { type: GetUserCarbonAllowanceFetcher }, { type: SaveFavouriteSearchUpdater }, { type: GetHotelChainsFetcher }, { type: GetRailProvidersFetcher }, { type: GetAllAirlinesFetcher }, { type: GetCarHireProvidersFetcher }, { type: Environment }, { type: LoungeQuoteFetcher }, { type: ParkingQuoteFetcher }, { type: HttpCallService }, { type: FlightQuoteFetcher }, { type: HotelQuoteFetcher }, { type: CarhireQuoteFetcher }, { type: CarHireAvailabilityDetailFetcher }, { type: CabhireQuoteFetcher }, { type: RailQuoteFetcher }, { type: IrlQuoteFetcher }, { type: SearchDepotFetcher }, { type: GetRailStationInfoFetcher }, { type: GetRailStationFetcher }, { type: GetIrlSupplierStationFetcher }, { type: WebTokenService }, { type: GetRiskAlertsFetcher }, { type: SearchConfermaQuicklistFetcher }, { type: GetUserRecentSearchesFetcher }, { type: GetRailcardsFetcher }, { type: GetCovidMicrositeTokenFetcher }, { type: EurostarQuoteFetcher }, { type: SearchUsersCanBookForFetcher }, { type: SearchIrlStationsFetcher }, { type: IrlDiscountCardFetcher }, { type: GetFlightFareRulesFetcher }, { type: GetFlightSeatMapFetcher }, { type: GetRailLiveDeparturesFetcher }, { type: ApplyHotelRulesFetcher }, { type: ApplyJitFlightRulesFetcher }, { type: GetUserFavouriteSearchesFetcher }, { type: DeleteFavouriteSearchUpdater }, { type: ModalOpenerService }, { type: EmailBasketFetcher }, { type: FastTrackQuoteFetcher }, { type: SendOfflineNotificationFetcher }, { type: GenerateBasketPdfFetcher }, { type: EmailFerryBookingFetcher }, { type: GetFlightExtrasOptionsFetcher }, { type: ConvertCurrencyFetcher }, { type: GetCurrencyConversionRatesFetcher }, { type: GetHotelDetailsFetcher }, { type: GetServiceFetcher }, { type: GetFlightBrandedFaresFetcher }, { type: GetTrainlineSearchConfigFetcher }, { type: SearchRailInwardFetcher }, { type: GetRailSearchExchangeFetcher }, { type: CreateItineraryExchangeUpdater }, { type: GetAirAvailabilityFetcher }, { type: GetFlightAtNewClassFetcher }, { type: GetFlightUpsellOffersFetcher }, { type: GetOfficesFetcher }, { type: GetFlightSearchExchangeFetcher }, { type: GetFlightExchangeDetailsFetcher }, { type: EmailApartmentBookingFetcher }, { type: EmailSeasonTicketBookingFetcher }, { type: SuggestPlacesFetcher }, { type: GetLatLonFromHereIdFetcher }, { type: GetGmtItineraryOptionsFetcher }, { type: GetGutCitySuggestionsFetcher }, { type: GetGutLocationSuggestionsFetcher }, { type: GetRouteHappyFetcher }, { type: GetMultipleHotelRatingFetcher }, { type: EmailMeetingRoomBookingFetcher }, { type: EmailAmbulanceBookingFetcher }, { type: GetEntLocationByPostcode }, { type: GetEntLocationByCity }, { type: GetUserRecentBoltSearchesFetcher }, { type: SaveRecentBoltSearchUpdater }, { type: GetFerryPortsFetcher }, { type: GetBannerFetcher }, { type: UpdateDOBUpdater }, { type: UpdateFlightSeatMapUpdater }, { type: DeleteAllRecentSearchesUpdater }, { type: GetOfficeDivisionsFetcher }, { type: SearchGeoLocationFetcher }, { type: SearchDiscoverLocationFetcher }, { type: GetJyrneyUrlFetcher }, { type: GetPriceHiddenSabreExchangeFetcher }] });
16321
16524
 
16322
16525
  class GetLatestVersionsFetcher extends BaseGetLatestVersionsFetcher {
16323
16526
  constructor(queryGQL, helpers, modalService) {
@@ -16598,9 +16801,9 @@ class RailFareProcessingService {
16598
16801
  const hasAdvance = fares.some((fare) => fare?.name?.toLowerCase().includes(RailFareNameKeywords.ADVANCE));
16599
16802
  const hasFlexible = fares.some((fare) => {
16600
16803
  const nameLower = fare?.name?.toLowerCase() || '';
16601
- return nameLower.includes(RailFareNameKeywords.OFF_PEAK) ||
16804
+ return (nameLower.includes(RailFareNameKeywords.OFF_PEAK) ||
16602
16805
  nameLower.includes(RailFareNameKeywords.ANYTIME) ||
16603
- nameLower.includes(RailFareNameKeywords.SUPER_OFF_PEAK);
16806
+ nameLower.includes(RailFareNameKeywords.SUPER_OFF_PEAK));
16604
16807
  });
16605
16808
  const hasPremiumOrStandard = fares.some((fare) => {
16606
16809
  const nameLower = fare?.name?.toLowerCase() || '';
@@ -16633,7 +16836,8 @@ class RailFareProcessingService {
16633
16836
  let cheapestTicket = null;
16634
16837
  let cheapestPrice = Number.MAX_SAFE_INTEGER;
16635
16838
  for (const candidateTicket of allFares) {
16636
- if (!candidateTicket || candidateTicket.identifiers?.isSplit ||
16839
+ if (!candidateTicket ||
16840
+ candidateTicket.identifiers?.isSplit ||
16637
16841
  candidateTicket.class !== splitTicket.class ||
16638
16842
  candidateTicket.singleOrReturn !== splitTicket.singleOrReturn) {
16639
16843
  continue;
@@ -16657,15 +16861,15 @@ class RailFareProcessingService {
16657
16861
  return candidateTypeLower.includes('advance');
16658
16862
  }
16659
16863
  else if (splitType === RailSplitType.FLEXIBLE) {
16660
- return candidateTypeLower.includes('off-peak') ||
16864
+ return (candidateTypeLower.includes('off-peak') ||
16661
16865
  candidateTypeLower.includes('anytime') ||
16662
- candidateTypeLower.includes('super off-peak');
16866
+ candidateTypeLower.includes('super off-peak'));
16663
16867
  }
16664
16868
  else if (splitType === RailSplitType.COMBINED) {
16665
- return candidateTypeLower.includes('advance') ||
16869
+ return (candidateTypeLower.includes('advance') ||
16666
16870
  candidateTypeLower.includes('off-peak') ||
16667
16871
  candidateTypeLower.includes('anytime') ||
16668
- candidateTypeLower.includes('super off-peak');
16872
+ candidateTypeLower.includes('super off-peak'));
16669
16873
  }
16670
16874
  return true;
16671
16875
  }
@@ -16701,7 +16905,7 @@ class RailFareProcessingService {
16701
16905
  * Find the journey that contains a specific ticket
16702
16906
  */
16703
16907
  findJourneyContainingTicket(targetTicket, journeys) {
16704
- return journeys.find(journey => {
16908
+ return (journeys.find((journey) => {
16705
16909
  const allFares = [
16706
16910
  ...Object.values(journey.singleJourneyFares || {}).flat(),
16707
16911
  ...Object.values(journey.returnJourneyFares || {}).flat(),
@@ -16709,8 +16913,8 @@ class RailFareProcessingService {
16709
16913
  ...Object.values(journey.openReturnJourneyFares || {}).flat(),
16710
16914
  ...Object.values(journey.splitFares || {}).flat()
16711
16915
  ];
16712
- return allFares.some(ticket => ticket?.fareHash === targetTicket.fareHash);
16713
- }) || null;
16916
+ return allFares.some((ticket) => ticket?.fareHash === targetTicket.fareHash);
16917
+ }) || null);
16714
16918
  }
16715
16919
  /**
16716
16920
  * Find the cheapest non-split ticket in a journey
@@ -16721,7 +16925,7 @@ class RailFareProcessingService {
16721
16925
  ...Object.values(journey.returnJourneyFares || {}).flat(),
16722
16926
  ...Object.values(journey.dualSingleJourneyFares || {}).flat(),
16723
16927
  ...Object.values(journey.openReturnJourneyFares || {}).flat()
16724
- ].filter(ticket => ticket && !ticket.identifiers?.isSplit && ticket.selectable && !ticket.unavailable);
16928
+ ].filter((ticket) => ticket && !ticket.identifiers?.isSplit && ticket.selectable && !ticket.unavailable);
16725
16929
  if (!nonSplitFares.length) {
16726
16930
  return null;
16727
16931
  }
@@ -16743,10 +16947,10 @@ class RailFareProcessingService {
16743
16947
  journey.openReturnJourneyFares,
16744
16948
  journey.splitFares
16745
16949
  ];
16746
- return fareTypes.some(fareType => {
16950
+ return fareTypes.some((fareType) => {
16747
16951
  if (!fareType)
16748
16952
  return false;
16749
- return Object.values(fareType).some((fareArray) => fareArray?.some(fare => fare?.fareHash === ticket.fareHash));
16953
+ return Object.values(fareType).some((fareArray) => fareArray?.some((fare) => fare?.fareHash === ticket.fareHash));
16750
16954
  });
16751
16955
  }
16752
16956
  /**
@@ -16761,12 +16965,11 @@ class RailFareProcessingService {
16761
16965
  journey.openReturnJourneyFares,
16762
16966
  journey.splitFares
16763
16967
  ];
16764
- fareTypes.forEach(fareType => {
16968
+ fareTypes.forEach((fareType) => {
16765
16969
  if (fareType) {
16766
16970
  Object.values(fareType).forEach((fareArray) => {
16767
- fareArray?.forEach(fare => {
16768
- if (fare?.class === ticketClass &&
16769
- (fare?.singleOrReturn === singleOrReturn)) {
16971
+ fareArray?.forEach((fare) => {
16972
+ if (fare?.class === ticketClass && fare?.singleOrReturn === singleOrReturn) {
16770
16973
  allTickets.push(fare);
16771
16974
  }
16772
16975
  });
@@ -16774,7 +16977,7 @@ class RailFareProcessingService {
16774
16977
  }
16775
16978
  });
16776
16979
  // Remove duplicates based on fareHash
16777
- const uniqueTickets = allTickets.filter((ticket, index, self) => index === self.findIndex(t => t.fareHash === ticket.fareHash));
16980
+ const uniqueTickets = allTickets.filter((ticket, index, self) => index === self.findIndex((t) => t.fareHash === ticket.fareHash));
16778
16981
  // Sort by price ascending
16779
16982
  return uniqueTickets.sort((a, b) => Number(a.price) - Number(b.price));
16780
16983
  }
@@ -16796,7 +16999,11 @@ class RailFareProcessingService {
16796
16999
  else if (splitType === RailSplitType.COMBINED) {
16797
17000
  comparisonType = 'cheapest single fare';
16798
17001
  }
16799
- return baseTooltip + ', saving ' + this.formatCurrency(+savings, ticket.currency) + ' compared to booking the ' + comparisonType;
17002
+ return (baseTooltip +
17003
+ ', saving ' +
17004
+ this.formatCurrency(+savings, ticket.currency) +
17005
+ ' compared to booking the ' +
17006
+ comparisonType);
16800
17007
  }
16801
17008
  return baseTooltip;
16802
17009
  }
@@ -16820,7 +17027,7 @@ class RailFareProcessingService {
16820
17027
  return true;
16821
17028
  }
16822
17029
  }
16823
- else if (ticket?.discountInfo?.some(x => x.type === DiscountType.Groupsave)) {
17030
+ else if (ticket?.discountInfo?.some((x) => x.type === DiscountType.Groupsave)) {
16824
17031
  return true;
16825
17032
  }
16826
17033
  return false;
@@ -16835,8 +17042,8 @@ class RailFareProcessingService {
16835
17042
  * Check if split tooltip should be shown
16836
17043
  */
16837
17044
  shouldShowSplitTooltip(ticket) {
16838
- return ticket?.identifiers?.isSplit &&
16839
- ticket?.identifiers?.composition?.includes(RailSearchComposition.InterchangeSplit);
17045
+ return (ticket?.identifiers?.isSplit &&
17046
+ ticket?.identifiers?.composition?.includes(RailSearchComposition.InterchangeSplit));
16840
17047
  }
16841
17048
  /**
16842
17049
  * Get the fare type for a ticket within a journey
@@ -16866,19 +17073,19 @@ class RailFareProcessingService {
16866
17073
  */
16867
17074
  calculateTicketSavings(journeys) {
16868
17075
  const ticketSavings = {};
16869
- journeys.forEach(journey => {
17076
+ journeys.forEach((journey) => {
16870
17077
  const fareTypes = [
16871
17078
  journey.dualSingleJourneyFares,
16872
17079
  journey.returnJourneyFares,
16873
17080
  journey.splitFares,
16874
17081
  journey.singleJourneyFares
16875
17082
  ];
16876
- fareTypes.forEach(fares => {
17083
+ fareTypes.forEach((fares) => {
16877
17084
  if (fares) {
16878
- Object.keys(fares).forEach(className => {
17085
+ Object.keys(fares).forEach((className) => {
16879
17086
  const tickets = fares[className];
16880
17087
  if (Array.isArray(tickets)) {
16881
- tickets.forEach(ticket => {
17088
+ tickets.forEach((ticket) => {
16882
17089
  if (ticket?.fareHash) {
16883
17090
  ticketSavings[ticket.fareHash] = this.splitSavings(ticket, journeys);
16884
17091
  }
@@ -16945,16 +17152,23 @@ class RailResultsStateService {
16945
17152
  resultsObject.standardReturns[journey.journeyHash] = standardReturns[0];
16946
17153
  resultsObject.firstClassReturns[journey.journeyHash] = firstClassReturns[0];
16947
17154
  // Calculate date difference from first journey
16948
- const diff = moment$1(journey.departDateTime).startOf('day').diff(moment$1(journeys[0].departDateTime).startOf('day'), 'day');
17155
+ const diff = moment$1(journey.departDateTime)
17156
+ .startOf('day')
17157
+ .diff(moment$1(journeys[0].departDateTime).startOf('day'), 'day');
16949
17158
  datesAfterInitial.push(!!diff);
16950
17159
  // Check for busy times
16951
17160
  const departDateTime = moment$1(journey.departDateTime);
16952
- const departTimeToday = moment$1().clone().hour(departDateTime.hour()).minute(departDateTime.minute()).second(departDateTime.second());
17161
+ const departTimeToday = moment$1()
17162
+ .clone()
17163
+ .hour(departDateTime.hour())
17164
+ .minute(departDateTime.minute())
17165
+ .second(departDateTime.second());
16953
17166
  const sixThirty = moment$1('06:30', 'HH:mm');
16954
17167
  const eightThirty = moment$1('08:30', 'HH:mm');
16955
17168
  const sixteenThirty = moment$1('16:30', 'HH:mm');
16956
17169
  const eighteen = moment$1('18:00', 'HH:mm');
16957
- if (departTimeToday.isBetween(sixThirty, eightThirty) || departTimeToday.isBetween(sixteenThirty, eighteen)) {
17170
+ if (departTimeToday.isBetween(sixThirty, eightThirty) ||
17171
+ departTimeToday.isBetween(sixteenThirty, eighteen)) {
16958
17172
  busyTimes[journey.journeyHash] = true;
16959
17173
  }
16960
17174
  });
@@ -16973,7 +17187,7 @@ class RailResultsStateService {
16973
17187
  journey.singleJourneyFares,
16974
17188
  journey.splitFares
16975
17189
  ];
16976
- fareTypes.forEach(fareType => {
17190
+ fareTypes.forEach((fareType) => {
16977
17191
  if (fareType) {
16978
17192
  Object.keys(fareType).forEach((key) => {
16979
17193
  const arrayOfTickets = fareType[key];
@@ -17012,15 +17226,19 @@ class RailResultsStateService {
17012
17226
  journey.singleJourneyFares,
17013
17227
  journey.splitFares
17014
17228
  ];
17015
- fareTypes.forEach(fareType => {
17229
+ fareTypes.forEach((fareType) => {
17016
17230
  if (fareType) {
17017
17231
  Object.keys(fareType).forEach((key) => {
17018
17232
  const arrayOfTickets = fareType[key];
17019
17233
  arrayOfTickets?.forEach((ticket) => {
17020
- if (ticket?.class === RailClass.Standard && ticket?.singleOrReturn === SingleOrReturn.Return && ticket?.selectable) {
17234
+ if (ticket?.class === RailClass.Standard &&
17235
+ ticket?.singleOrReturn === SingleOrReturn.Return &&
17236
+ ticket?.selectable) {
17021
17237
  standardReturns.push(ticket);
17022
17238
  }
17023
- else if (ticket?.class === RailClass.First && ticket?.singleOrReturn === SingleOrReturn.Return && ticket?.selectable) {
17239
+ else if (ticket?.class === RailClass.First &&
17240
+ ticket?.singleOrReturn === SingleOrReturn.Return &&
17241
+ ticket?.selectable) {
17024
17242
  firstClassReturns.push(ticket);
17025
17243
  }
17026
17244
  });
@@ -17099,7 +17317,7 @@ class RailResultsStateService {
17099
17317
  * Sort fares by price ascending
17100
17318
  */
17101
17319
  sortByPrice(fares) {
17102
- return fares.sort((a, b) => (a.price > b.price) ? 1 : ((b.price > a.price) ? -1 : 0));
17320
+ return fares.sort((a, b) => (a.price > b.price ? 1 : b.price > a.price ? -1 : 0));
17103
17321
  }
17104
17322
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: RailResultsStateService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
17105
17323
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: RailResultsStateService, providedIn: 'root' });
@@ -17238,8 +17456,10 @@ class SearchPaymentValidationService {
17238
17456
  */
17239
17457
  validatePaymentMethods(services) {
17240
17458
  return this.userService.getApexxListCards().pipe(map((cards) => {
17241
- const hasNoStoredCard = !cards?.some(card => card.status === 'ENABLED');
17242
- const serviceList = Object.values(services).flat().filter((service) => service.type !== ServiceType.Ferry);
17459
+ const hasNoStoredCard = !cards?.some((card) => card.status === 'ENABLED');
17460
+ const serviceList = Object.values(services)
17461
+ .flat()
17462
+ .filter((service) => service.type !== ServiceType.Ferry);
17243
17463
  const hasOtherPaymentMethods = this.hasOtherPaymentMethods(serviceList);
17244
17464
  const hasApexxCardInServices = this.hasApexxPaymentMethod(serviceList);
17245
17465
  const allServicesAreApexxOnly = this.isOnlyApexxPaymentMethod(serviceList);
@@ -17257,19 +17477,19 @@ class SearchPaymentValidationService {
17257
17477
  * Check if any service has non-Apexx payment methods
17258
17478
  */
17259
17479
  hasOtherPaymentMethods(serviceList) {
17260
- return serviceList.some(service => (service.availablePaymentMethods || []).some((method) => method.name !== PaymentMethodType.Apexx));
17480
+ return serviceList.some((service) => (service.availablePaymentMethods || []).some((method) => method.name !== PaymentMethodType.Apexx));
17261
17481
  }
17262
17482
  /**
17263
17483
  * Check if any service has Apexx payment method
17264
17484
  */
17265
17485
  hasApexxPaymentMethod(serviceList) {
17266
- return serviceList.some(service => (service.availablePaymentMethods || []).some((method) => method.name === PaymentMethodType.Apexx));
17486
+ return serviceList.some((service) => (service.availablePaymentMethods || []).some((method) => method.name === PaymentMethodType.Apexx));
17267
17487
  }
17268
17488
  /**
17269
17489
  * Check if all services only have Apexx as payment method
17270
17490
  */
17271
17491
  isOnlyApexxPaymentMethod(serviceList) {
17272
- return serviceList.every(service => {
17492
+ return serviceList.every((service) => {
17273
17493
  const methods = service.availablePaymentMethods || [];
17274
17494
  if (methods.length === 0)
17275
17495
  return false;
@@ -17285,7 +17505,8 @@ class SearchPaymentValidationService {
17285
17505
  const isValidList = Array.isArray(serviceList);
17286
17506
  const hasOtherPaymentMethods = this.hasOtherPaymentMethods(serviceList);
17287
17507
  const hasApexxCardInServices = this.hasApexxPaymentMethod(serviceList);
17288
- restrictions[key] = isValidList && !hasOtherPaymentMethods && hasApexxCardInServices && hasNoStoredCard;
17508
+ restrictions[key] =
17509
+ isValidList && !hasOtherPaymentMethods && hasApexxCardInServices && hasNoStoredCard;
17289
17510
  });
17290
17511
  return restrictions;
17291
17512
  }
@@ -17343,9 +17564,119 @@ class ResultAwareService {
17343
17564
  console.log('[ResultAwareService] Captured', outbound.length, 'outbound +', this.railReturnJourneys.length, 'return rail results, sourceId:', this.railSourceId);
17344
17565
  this.resultsAvailableSubject.next(this.condensedResults.length > 0);
17345
17566
  }
17567
+ captureHotelResults(results) {
17568
+ this.currentServiceType = ServiceType.Hotel;
17569
+ this.rawResults = results;
17570
+ this.condensedResults = this.condenseHotelResults(results);
17571
+ this.resultsAvailableSubject.next(this.condensedResults.length > 0);
17572
+ }
17573
+ isHotelSearch() {
17574
+ return this.currentServiceType === ServiceType.Hotel;
17575
+ }
17346
17576
  getCondensedResults() {
17347
17577
  return this.condensedResults;
17348
17578
  }
17579
+ /**
17580
+ * Returns the cheapest single and return fare prices for a raw outbound rail journey.
17581
+ * Used by the chatbot fare panel to show per-category prices on card expand.
17582
+ */
17583
+ getRailJourneyFares(journeyIndex) {
17584
+ const journey = this.rawResults[journeyIndex];
17585
+ if (!journey)
17586
+ return {};
17587
+ const singleTickets = this.collectFareTickets(journey, ['singleJourneyFares'], journeyIndex, false);
17588
+ const returnTickets = this.collectFareTickets(journey, ['returnJourneyFares', 'dualSingleJourneyFares', 'openReturnJourneyFares'], journeyIndex, false);
17589
+ return {
17590
+ singlePrice: singleTickets[0]?.price,
17591
+ returnPrice: returnTickets[0]?.price,
17592
+ singleTickets: singleTickets.length ? singleTickets : undefined,
17593
+ returnTickets: returnTickets.length ? returnTickets : undefined
17594
+ };
17595
+ }
17596
+ /**
17597
+ * Returns the cheapest single fare price and full ticket list for a raw inbound/return rail journey.
17598
+ * Falls back to the other return-leg fare sections if no pure singles are available.
17599
+ */
17600
+ getRailReturnJourneyFares(journeyIndex) {
17601
+ const journey = this.railReturnJourneys[journeyIndex];
17602
+ if (!journey)
17603
+ return {};
17604
+ let singleTickets = this.collectFareTickets(journey, ['singleJourneyFares'], journeyIndex, true);
17605
+ if (!singleTickets.length) {
17606
+ singleTickets = this.collectFareTickets(journey, ['returnJourneyFares', 'dualSingleJourneyFares', 'openReturnJourneyFares'], journeyIndex, true);
17607
+ }
17608
+ return {
17609
+ singlePrice: singleTickets[0]?.price,
17610
+ singleTickets: singleTickets.length ? singleTickets : undefined
17611
+ };
17612
+ }
17613
+ /**
17614
+ * Open the existing OBT rail "View Conditions" dialog for a fare displayed in the chat.
17615
+ */
17616
+ async openRailFareDetails(ticket) {
17617
+ if (!ticket?.fareHash || ticket.section == null || ticket.journeyIndex == null)
17618
+ return;
17619
+ const journey = ticket.isReturnLeg
17620
+ ? this.railReturnJourneys[ticket.journeyIndex]
17621
+ : this.rawResults[ticket.journeyIndex];
17622
+ if (!journey)
17623
+ return;
17624
+ const fareGroup = journey[ticket.section];
17625
+ if (!fareGroup)
17626
+ return;
17627
+ let foundFare = null;
17628
+ for (const key of Object.keys(fareGroup)) {
17629
+ const fares = fareGroup[key];
17630
+ if (!Array.isArray(fares))
17631
+ continue;
17632
+ foundFare = fares.find((f) => f?.fareHash === ticket.fareHash);
17633
+ if (foundFare)
17634
+ break;
17635
+ }
17636
+ if (!foundFare)
17637
+ return;
17638
+ const searchParams = this.searchService.searches[ServiceType.Rail];
17639
+ if (typeof searchParams?.openRailTicketDetailsDialog !== 'function')
17640
+ return;
17641
+ await searchParams.openRailTicketDetailsDialog(journey, foundFare, foundFare.terms, foundFare.identifiers, this.railSourceId || '');
17642
+ }
17643
+ collectFareTickets(journey, sections, journeyIndex, isReturnLeg) {
17644
+ const tickets = [];
17645
+ for (const section of sections) {
17646
+ const fareGroup = journey[section];
17647
+ if (!fareGroup || typeof fareGroup !== 'object')
17648
+ continue;
17649
+ for (const fareCode of Object.keys(fareGroup)) {
17650
+ const fares = fareGroup[fareCode];
17651
+ if (!Array.isArray(fares))
17652
+ continue;
17653
+ for (const fare of fares) {
17654
+ if (!fare || fare.unavailable || !fare.selectable || !(fare.price > 0))
17655
+ continue;
17656
+ tickets.push({
17657
+ type: fare.type || fare.fareName || fareCode || 'Ticket',
17658
+ classOfService: fare.class,
17659
+ price: fare.price,
17660
+ currency: fare.currency || 'GBP',
17661
+ fareHash: fare.fareHash,
17662
+ section,
17663
+ isReturnLeg,
17664
+ journeyIndex
17665
+ });
17666
+ }
17667
+ }
17668
+ }
17669
+ // Sort cheapest first, then dedupe identical type+class+price entries
17670
+ tickets.sort((a, b) => a.price - b.price);
17671
+ const seen = new Set();
17672
+ return tickets.filter((t) => {
17673
+ const key = `${t.type}|${t.classOfService}|${t.price}`;
17674
+ if (seen.has(key))
17675
+ return false;
17676
+ seen.add(key);
17677
+ return true;
17678
+ });
17679
+ }
17349
17680
  hasResults() {
17350
17681
  return this.condensedResults.length > 0;
17351
17682
  }
@@ -17356,6 +17687,15 @@ class ResultAwareService {
17356
17687
  this.resultsAvailableSubject.next(false);
17357
17688
  }
17358
17689
  async executeSelection(selectedIndex, returnIndex) {
17690
+ if (this.currentServiceType === ServiceType.Hotel) {
17691
+ // Hotel indices are 1-based (matching natural user language: "option 1, 2, 3")
17692
+ const hotelArrayIndex = selectedIndex - 1;
17693
+ if (hotelArrayIndex < 0 || hotelArrayIndex >= this.rawResults.length) {
17694
+ throw new Error(`Invalid selection index: ${selectedIndex}`);
17695
+ }
17696
+ await this.executeHotelSelection(this.rawResults[hotelArrayIndex]);
17697
+ return;
17698
+ }
17359
17699
  if (selectedIndex < 0 || selectedIndex >= this.rawResults.length) {
17360
17700
  throw new Error(`Invalid selection index: ${selectedIndex}`);
17361
17701
  }
@@ -17436,7 +17776,7 @@ class ResultAwareService {
17436
17776
  flightNumbers: inLegs
17437
17777
  .map((leg) => `${leg.marketingCarrier || ''}${leg.marketingFlightNumber || ''}`.trim())
17438
17778
  .filter(Boolean)
17439
- .join('/'),
17779
+ .join('/')
17440
17780
  };
17441
17781
  }
17442
17782
  return {
@@ -17455,7 +17795,7 @@ class ResultAwareService {
17455
17795
  to: lastLeg?.destinationAirport || '',
17456
17796
  flightNumbers,
17457
17797
  fares: [{ cabin, price, bags }],
17458
- inbound,
17798
+ inbound
17459
17799
  };
17460
17800
  });
17461
17801
  }
@@ -17465,7 +17805,11 @@ class ResultAwareService {
17465
17805
  }
17466
17806
  try {
17467
17807
  const date = new Date(isoString);
17468
- return date.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', hour12: false });
17808
+ return date.toLocaleTimeString('en-GB', {
17809
+ hour: '2-digit',
17810
+ minute: '2-digit',
17811
+ hour12: false
17812
+ });
17469
17813
  }
17470
17814
  catch {
17471
17815
  return isoString;
@@ -17479,6 +17823,19 @@ class ResultAwareService {
17479
17823
  const m = minutes % 60;
17480
17824
  return `${h}h${m > 0 ? ` ${m}m` : ''}`;
17481
17825
  }
17826
+ computeRailDuration(rj) {
17827
+ if (rj?.journeyDuration) {
17828
+ return this.formatDuration(rj.journeyDuration);
17829
+ }
17830
+ if (rj?.departDateTime && rj?.arriveDateTime) {
17831
+ const dep = new Date(rj.departDateTime).getTime();
17832
+ const arr = new Date(rj.arriveDateTime).getTime();
17833
+ if (!isNaN(dep) && !isNaN(arr) && arr > dep) {
17834
+ return this.formatDuration(Math.round((arr - dep) / 60000));
17835
+ }
17836
+ }
17837
+ return '';
17838
+ }
17482
17839
  async executeRailSelection(journey, returnIndex) {
17483
17840
  const searchParams = this.searchService.searches[ServiceType.Rail];
17484
17841
  // Find the cheapest available fare from the journey
@@ -17492,7 +17849,9 @@ class ResultAwareService {
17492
17849
  let inboundJourney = null;
17493
17850
  let inboundFare = null;
17494
17851
  if (this.railReturnJourneys.length > 0) {
17495
- if (returnIndex !== undefined && returnIndex >= 0 && returnIndex < this.railReturnJourneys.length) {
17852
+ if (returnIndex !== undefined &&
17853
+ returnIndex >= 0 &&
17854
+ returnIndex < this.railReturnJourneys.length) {
17496
17855
  inboundJourney = this.railReturnJourneys[returnIndex];
17497
17856
  }
17498
17857
  else {
@@ -17505,7 +17864,8 @@ class ResultAwareService {
17505
17864
  // Use addToBasket with ignoreTicketExtras=true to skip the travelcard add-on dialog
17506
17865
  // and actually add the item to the basket (selectTicketNoAdd only stores selection without basketing)
17507
17866
  await searchParams.addToBasket(sourceId, searchParams.originalUserSearch, journey, fare, inboundFare || undefined, inboundJourney || undefined, false, // ingoreInvoked
17508
- true);
17867
+ true // ignoreTicketExtras — skip travelcard dialog
17868
+ );
17509
17869
  // Navigate to confirmation
17510
17870
  const basket = (await this.basketService.getDefaultBasket())?.subject.value;
17511
17871
  if (basket?.id) {
@@ -17529,7 +17889,7 @@ class ResultAwareService {
17529
17889
  'returnJourneyFares',
17530
17890
  'singleJourneyFares',
17531
17891
  'dualSingleJourneyFares',
17532
- 'openReturnJourneyFares',
17892
+ 'openReturnJourneyFares'
17533
17893
  ];
17534
17894
  let cheapest = null;
17535
17895
  let cheapestSection = '';
@@ -17564,7 +17924,7 @@ class ResultAwareService {
17564
17924
  'returnJourneyFares',
17565
17925
  'singleJourneyFares',
17566
17926
  'dualSingleJourneyFares',
17567
- 'openReturnJourneyFares',
17927
+ 'openReturnJourneyFares'
17568
17928
  ];
17569
17929
  let expensive = null;
17570
17930
  let expensiveSection = '';
@@ -17601,15 +17961,17 @@ class ResultAwareService {
17601
17961
  const rj = returnJourneys[i];
17602
17962
  const cheapestFare = this.getCheapestRailFare(rj);
17603
17963
  const expensiveFare = this.getMostExpensiveRailFare(rj);
17604
- const cheapestValid = cheapestFare && (cheapestFare.price > 0 || cheapestFare.type.toLowerCase().includes('return'));
17605
- const expensiveValid = expensiveFare && (expensiveFare.price > 0 || expensiveFare.type.toLowerCase().includes('return'));
17964
+ const cheapestValid = cheapestFare &&
17965
+ (cheapestFare.price > 0 || cheapestFare.type.toLowerCase().includes('return'));
17966
+ const expensiveValid = expensiveFare &&
17967
+ (expensiveFare.price > 0 || expensiveFare.type.toLowerCase().includes('return'));
17606
17968
  if (cheapestFare) {
17607
17969
  condensedReturns.push({
17608
17970
  index: i,
17609
17971
  depart: this.formatTime(rj.departDateTime),
17610
17972
  arrive: this.formatTime(rj.arriveDateTime),
17611
17973
  stops: parseInt(rj.changes || '0', 10),
17612
- duration: this.formatDuration(rj.journeyDuration),
17974
+ duration: this.computeRailDuration(rj),
17613
17975
  price: cheapestValid ? cheapestFare.price : 0,
17614
17976
  operator: rj.journeyLegs?.[0]?.operatorName || '',
17615
17977
  policyStatus: cheapestValid
@@ -17625,7 +17987,7 @@ class ResultAwareService {
17625
17987
  depart: this.formatTime(rj.departDateTime),
17626
17988
  arrive: this.formatTime(rj.arriveDateTime),
17627
17989
  stops: parseInt(rj.changes || '0', 10),
17628
- duration: this.formatDuration(rj.journeyDuration),
17990
+ duration: this.computeRailDuration(rj),
17629
17991
  price: expensiveValid ? expensiveFare.price : 0,
17630
17992
  operator: rj.journeyLegs?.[0]?.operatorName || '',
17631
17993
  policyStatus: expensiveValid
@@ -17647,7 +18009,7 @@ class ResultAwareService {
17647
18009
  depart: this.formatTime(journey.departDateTime),
17648
18010
  arrive: this.formatTime(journey.arriveDateTime),
17649
18011
  stops: parseInt(journey.changes || '0', 10),
17650
- duration: this.formatDuration(journey.journeyDuration),
18012
+ duration: this.computeRailDuration(journey),
17651
18013
  price: hasValidFare ? cheapestFare.price : 0,
17652
18014
  cabin: cheapestFare?.class || 'Standard',
17653
18015
  co2: journey.co2PerPassenger || 0,
@@ -17661,14 +18023,15 @@ class ResultAwareService {
17661
18023
  }
17662
18024
  parsdJourneys.push(result);
17663
18025
  const expensiveFare = this.getMostExpensiveRailFare(journey);
17664
- const expensiveValid = expensiveFare && (expensiveFare.price > 0 || expensiveFare.type.toLowerCase().includes('return'));
18026
+ const expensiveValid = expensiveFare &&
18027
+ (expensiveFare.price > 0 || expensiveFare.type.toLowerCase().includes('return'));
17665
18028
  const exResult = {
17666
18029
  index: i,
17667
18030
  operator: journey.journeyLegs?.[0]?.operatorName || '',
17668
18031
  depart: this.formatTime(journey.departDateTime),
17669
18032
  arrive: this.formatTime(journey.arriveDateTime),
17670
18033
  stops: parseInt(journey.changes || '0', 10),
17671
- duration: this.formatDuration(journey.journeyDuration),
18034
+ duration: this.computeRailDuration(journey),
17672
18035
  price: expensiveValid ? expensiveFare.price : 0,
17673
18036
  cabin: expensiveFare?.class || 'Standard',
17674
18037
  co2: journey.co2PerPassenger || 0,
@@ -17716,9 +18079,9 @@ class ResultAwareService {
17716
18079
  return '';
17717
18080
  }
17718
18081
  filterDownCompressedReturnRailOptions(result, condensedReturns = []) {
17719
- condensedReturns = condensedReturns.filter(ret => ret.singleOrReturn === result.singleOrReturn);
18082
+ condensedReturns = condensedReturns.filter((ret) => ret.singleOrReturn === result.singleOrReturn);
17720
18083
  if (result.singleOrReturn === 'Return') {
17721
- condensedReturns.forEach(ret => {
18084
+ condensedReturns.forEach((ret) => {
17722
18085
  ret.price = 0;
17723
18086
  });
17724
18087
  }
@@ -17727,7 +18090,7 @@ class ResultAwareService {
17727
18090
  const arrivalDate = moment$1();
17728
18091
  arrivalDate.hour(arrivalTimeSplit[0]);
17729
18092
  arrivalDate.minutes(arrivalTimeSplit[1]);
17730
- condensedReturns = condensedReturns.filter(ret => {
18093
+ condensedReturns = condensedReturns.filter((ret) => {
17731
18094
  try {
17732
18095
  const departTimeSplit = ret.depart.split(':');
17733
18096
  const retDepartTime = moment$1();
@@ -17741,6 +18104,81 @@ class ResultAwareService {
17741
18104
  });
17742
18105
  return condensedReturns;
17743
18106
  }
18107
+ async selectHotelRoom(hotelIndex, roomId) {
18108
+ const hotel = this.rawResults[hotelIndex];
18109
+ if (!hotel) {
18110
+ return;
18111
+ }
18112
+ const searchParams = this.searchService.searches[ServiceType.Hotel];
18113
+ const room = (hotel.availableRates?.rooms ?? []).find((r) => r?.roomId === roomId);
18114
+ if (!room) {
18115
+ return;
18116
+ }
18117
+ // Rooms in rawResults may lack policyToken if JIT rules completed after the snapshot.
18118
+ // Look up the matching room from fullResults (JIT-processed) and carry policyToken across.
18119
+ if (!room.policyToken) {
18120
+ const fullHotel = (searchParams.fullResults ?? []).find((h) => h.id === hotel.id);
18121
+ const fullRoom = (fullHotel?.availableRates?.rooms ?? []).find((r) => r?.roomId === roomId);
18122
+ if (fullRoom?.policyToken) {
18123
+ room.policyToken = fullRoom.policyToken;
18124
+ }
18125
+ }
18126
+ await searchParams.addHotelRoomToBasket(hotel, room, searchParams.getSearchQuery(true));
18127
+ this.basketService.toggleMenu();
18128
+ const basket = (await this.basketService.getDefaultBasket())?.subject.value;
18129
+ if (basket?.id) {
18130
+ this.router.navigate(['/itinerary', basket.id]);
18131
+ }
18132
+ }
18133
+ async executeHotelSelection(hotel) {
18134
+ const searchParams = this.searchService.searches[ServiceType.Hotel];
18135
+ const rooms = hotel.availableRates?.rooms ?? [];
18136
+ const cheapestRoom = rooms
18137
+ .filter((r) => r && !r.unavailable)
18138
+ .sort((a, b) => a.total - b.total)[0];
18139
+ if (!cheapestRoom) {
18140
+ return;
18141
+ }
18142
+ await searchParams.addHotelRoomToBasket(hotel, cheapestRoom, searchParams.getSearchQuery(true));
18143
+ this.basketService.toggleMenu();
18144
+ const basket = (await this.basketService.getDefaultBasket())?.subject.value;
18145
+ if (basket?.id) {
18146
+ this.router.navigate(['/itinerary', basket.id]);
18147
+ }
18148
+ }
18149
+ condenseHotelResults(results) {
18150
+ const hotelSearch = this.searchService.searches[ServiceType.Hotel];
18151
+ const checkin = hotelSearch?.checkin_date
18152
+ ? moment$1(hotelSearch.checkin_date).format('D MMM')
18153
+ : '';
18154
+ const checkout = hotelSearch?.checkout_date
18155
+ ? moment$1(hotelSearch.checkout_date).format('D MMM')
18156
+ : '';
18157
+ const dateRange = checkin && checkout ? `${checkin} - ${checkout}` : '';
18158
+ return results.map((hotel, index) => {
18159
+ const rooms = hotel.availableRates?.rooms ?? [];
18160
+ const cheapestRoom = rooms
18161
+ .filter((r) => r && !r.unavailable)
18162
+ .sort((a, b) => a.total - b.total)[0];
18163
+ return {
18164
+ index: index + 1, // 1-based so user "option 2" maps directly to selectedIndex: 2
18165
+ name: hotel.name || '',
18166
+ address: [hotel.address?.addressLine1, hotel.address?.city].filter(Boolean).join(', '),
18167
+ price: cheapestRoom?.total ?? 0,
18168
+ pricePerNight: cheapestRoom?.prpn ?? 0,
18169
+ rating: hotel.starRating ?? hotel.rating ?? 0,
18170
+ distance: hotel.location?.distance ?? 0,
18171
+ distanceUnit: hotel.location?.distanceType ?? 'M',
18172
+ policyStatus: hotel.policyStatus,
18173
+ policyMessages: hotel.policyMessages,
18174
+ co2: hotel.co2PerItem,
18175
+ depart: checkin,
18176
+ arrive: checkout,
18177
+ stops: 0,
18178
+ duration: dateRange
18179
+ };
18180
+ });
18181
+ }
17744
18182
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ResultAwareService, deps: [{ token: EnterpriseSearchService }, { token: EnterpriseBasketService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
17745
18183
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ResultAwareService, providedIn: 'root' });
17746
18184
  }
@@ -17758,17 +18196,57 @@ class ChatbotService extends BaseChatbotService {
17758
18196
  messages$ = this.messagesSubject.asObservable();
17759
18197
  loadingSubject = new BehaviorSubject(false);
17760
18198
  loading$ = this.loadingSubject.asObservable();
18199
+ searchingSubject = new BehaviorSubject({
18200
+ searching: false
18201
+ });
18202
+ searchingState$ = this.searchingSubject.asObservable();
18203
+ /** Back-compat boolean stream for callers that only care whether a search is in flight. */
18204
+ searching$ = this.searchingSubject.pipe(map((s) => s.searching));
17761
18205
  fillSearchForm$ = new Subject();
17762
18206
  riskFlagSubject = new BehaviorSubject(null);
17763
18207
  riskFlag$ = this.riskFlagSubject.asObservable();
18208
+ faqsSubject = new BehaviorSubject([]);
18209
+ faqs$ = this.faqsSubject.asObservable();
18210
+ // ENT-16247 — streaming + feedback subjects. Use Subject (not Behaviour)
18211
+ // so late subscribers don't accidentally replay the last token chunk
18212
+ // from a previous turn.
18213
+ tokenEventsSubject = new Subject();
18214
+ tokenEvents$ = this.tokenEventsSubject.asObservable();
18215
+ toolEventsSubject = new Subject();
18216
+ toolEvents$ = this.toolEventsSubject.asObservable();
18217
+ feedbackAckSubject = new Subject();
18218
+ feedbackAck$ = this.feedbackAckSubject.asObservable();
18219
+ /** Tracks the user ID that owns the current chat session, to detect user switches. */
18220
+ sessionOwnerId = null;
18221
+ userChangeSubscription;
17764
18222
  constructor(webTokenService, resultAwareService, environment, userService) {
17765
18223
  super();
17766
18224
  this.webTokenService = webTokenService;
17767
18225
  this.resultAwareService = resultAwareService;
17768
18226
  this.environment = environment;
17769
18227
  this.userService = userService;
18228
+ // Tear down the socket on logout (null user) so the next login reconnects cleanly.
18229
+ // Clear the session only when a different user logs in, so the same user's
18230
+ // conversation persists across logout/login cycles.
18231
+ this.userChangeSubscription = this.userService.fullUserDetails.allDetails
18232
+ .pipe(map((user) => user?.id ?? null), distinctUntilChanged())
18233
+ .subscribe((userId) => {
18234
+ if (userId === null) {
18235
+ // User logged out — disconnect socket but keep session data
18236
+ this.tearDownSocket();
18237
+ }
18238
+ else if (this.sessionOwnerId !== null && this.sessionOwnerId !== userId) {
18239
+ // Different user logged in — start fresh
18240
+ this.clearSession();
18241
+ this.tearDownSocket();
18242
+ }
18243
+ if (userId !== null) {
18244
+ this.sessionOwnerId = userId;
18245
+ }
18246
+ });
17770
18247
  }
17771
18248
  ngOnDestroy() {
18249
+ this.userChangeSubscription.unsubscribe();
17772
18250
  this.tearDownSocket();
17773
18251
  this.fillSearchForm$.complete();
17774
18252
  }
@@ -17791,6 +18269,18 @@ class ChatbotService extends BaseChatbotService {
17791
18269
  notifyRiskFlag(flag) {
17792
18270
  this.riskFlagSubject.next(flag);
17793
18271
  }
18272
+ notifyFaqs(faqs) {
18273
+ this.faqsSubject.next(faqs);
18274
+ }
18275
+ notifyToken(event) {
18276
+ this.tokenEventsSubject.next(event);
18277
+ }
18278
+ notifyTool(event) {
18279
+ this.toolEventsSubject.next(event);
18280
+ }
18281
+ notifyFeedbackAck(ack) {
18282
+ this.feedbackAckSubject.next(ack);
18283
+ }
17794
18284
  hasResults() {
17795
18285
  return this.resultAwareService.hasResults();
17796
18286
  }
@@ -17803,20 +18293,53 @@ class ChatbotService extends BaseChatbotService {
17803
18293
  getSource() {
17804
18294
  return 'web';
17805
18295
  }
17806
- // ── Public override ──────────────────────────────────────────────────────
17807
- clearSession() {
17808
- super.clearSession();
17809
- this.resultAwareService.clearResults();
17810
- }
17811
18296
  getUserCapabilities() {
17812
18297
  return {
17813
18298
  isCrown: this.userService.crownIsSet(),
17814
18299
  isAgent: this.userService.userIsAgent(),
17815
18300
  uiConfigs: {
17816
- hideHotelSearchOptions: this.userService.isUserFavoriteSet(new UserFavorurite('hideHotelSearchOptions')),
17817
- },
18301
+ hideHotelSearchOptions: this.userService.isUserFavoriteSet(new UserFavorurite('hideHotelSearchOptions'))
18302
+ }
17818
18303
  };
17819
18304
  }
18305
+ // ── Public override ──────────────────────────────────────────────────────
18306
+ connect() {
18307
+ const user = this.userService.fullUserDetails.allDetails.value;
18308
+ if (!user?.aiTravelAssistantEnabled) {
18309
+ return;
18310
+ }
18311
+ super.connect();
18312
+ }
18313
+ clearSession() {
18314
+ super.clearSession();
18315
+ this.resultAwareService.clearResults();
18316
+ }
18317
+ injectMessage(message) {
18318
+ this.addMessage(message);
18319
+ }
18320
+ handleResponse(env) {
18321
+ super.handleResponse(env);
18322
+ // Auto-trigger a search as soon as the bot signals parameters are complete.
18323
+ // The dispatcher routes to the travel-type handler, which owns the search +
18324
+ // result-capture flow.
18325
+ const tt = env.parameters?.travelType;
18326
+ if (env.state === 'PARAMS_COMPLETE' &&
18327
+ (tt === 'rail' || tt === 'flight' || tt === 'hotel' || tt === 'eurostar')) {
18328
+ this.notifyFillForm(env.parameters, true);
18329
+ }
18330
+ }
18331
+ // ── Public helpers for travel-type handlers ──────────────────────────────
18332
+ /**
18333
+ * Toggle the chatbot's "searching" indicator from a travel-type handler.
18334
+ * @param travelType optional - lets the UI render a travel-aware label
18335
+ * (e.g. "Searching for flights…" vs "Searching for trains…").
18336
+ */
18337
+ setSearching(searching, travelType) {
18338
+ this.searchingSubject.next({ searching, travelType });
18339
+ }
18340
+ patchAssistantMessage(patch) {
18341
+ this.patchLastAssistantMessage(patch);
18342
+ }
17820
18343
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotService, deps: [{ token: WebTokenService }, { token: ResultAwareService }, { token: Environment }, { token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
17821
18344
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotService, providedIn: 'root' });
17822
18345
  }
@@ -17825,6 +18348,2070 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
17825
18348
  args: [{ providedIn: 'root' }]
17826
18349
  }], ctorParameters: () => [{ type: WebTokenService }, { type: ResultAwareService }, { type: Environment }, { type: UserService }] });
17827
18350
 
18351
+ /** How long (ms) to wait for rail results before giving up on patching the message. */
18352
+ const RAIL_RESULTS_WAIT_MS = 90_000;
18353
+ /** Maximum number of journey cards to render per leg. */
18354
+ const MAX_RAIL_CARDS_PER_LEG = 3;
18355
+ /**
18356
+ * Handles chatbot-driven rail searches. Registered with
18357
+ * `ChatbotSearchDispatcherService`; not used directly.
18358
+ *
18359
+ * Populates the rail search state from the chatbot's parameters (same state
18360
+ * the search form binds to via ngModel) and runs `startSearch()` headlessly
18361
+ * so chatbot rail searches work from any page. Once results arrive, builds
18362
+ * `ChatRailResultCard`s and patches them onto the last assistant message
18363
+ * via {@link ChatbotService.patchAssistantMessage}.
18364
+ */
18365
+ class ChatbotRailSearchService {
18366
+ chatbotService;
18367
+ searchService;
18368
+ resultAwareService;
18369
+ userService;
18370
+ travelType = 'rail';
18371
+ resultsSubscription = null;
18372
+ constructor(chatbotService, searchService, resultAwareService, userService) {
18373
+ this.chatbotService = chatbotService;
18374
+ this.searchService = searchService;
18375
+ this.resultAwareService = resultAwareService;
18376
+ this.userService = userService;
18377
+ }
18378
+ async handle(parameters, autoSearch) {
18379
+ this.searchService.resetSearchChosenObjects();
18380
+ this.searchService.resetSearchPriorities();
18381
+ this.searchService.search_objects[ServiceType.Rail].chosen = true;
18382
+ this.searchService.search_objects[ServiceType.Rail].originalChosen = true;
18383
+ this.searchService.determineHighestSearchPriority();
18384
+ if (this.searchService.travellerInformation.value.length === 0) {
18385
+ const selfTraveller = this.userService.createSelfTraveller();
18386
+ if (selfTraveller) {
18387
+ this.searchService.addTraveller(selfTraveller);
18388
+ }
18389
+ }
18390
+ const departDate = moment$1(parameters.departureDate);
18391
+ const departNgbDate = {
18392
+ year: departDate.year(),
18393
+ month: departDate.month() + 1,
18394
+ day: departDate.date()
18395
+ };
18396
+ if (autoSearch) {
18397
+ // Attach the results subscription before kicking off the search so we
18398
+ // can't miss the resultsAvailable$ emission. Synchronous — safe.
18399
+ this.subscribeToRailResults(parameters);
18400
+ }
18401
+ await this.populateRailParams(parameters, departNgbDate);
18402
+ if (!autoSearch) {
18403
+ return;
18404
+ }
18405
+ const railSearch = this.searchService.searches[ServiceType.Rail];
18406
+ // Surface OBT's existing validation (past dates, missing stations,
18407
+ // same origin/destination, return-before-depart, etc.) instead of letting
18408
+ // the user wait for a search that will silently no-op. Every setter on
18409
+ // RailEnterpriseSearch runs `_isValid()` so the array is current by the
18410
+ // time `populateRailParams` returns.
18411
+ const validationMessages = Array.isArray(railSearch.validationMessages)
18412
+ ? railSearch.validationMessages.filter(Boolean)
18413
+ : [];
18414
+ if (validationMessages.length) {
18415
+ this.resultsSubscription?.unsubscribe();
18416
+ this.resultsSubscription = null;
18417
+ this.chatbotService.patchAssistantMessage({
18418
+ text: this.formatValidationMessages(validationMessages),
18419
+ state: 'RESULTS_READY'
18420
+ });
18421
+ this.chatbotService.setSearching(false);
18422
+ return;
18423
+ }
18424
+ const ok = await railSearch.startSearch();
18425
+ if (!ok) {
18426
+ // Safety net — should rarely fire now that we read validationMessages
18427
+ // up-front, but covers any later-rejecting validation path.
18428
+ this.resultsSubscription?.unsubscribe();
18429
+ this.resultsSubscription = null;
18430
+ const messages = Array.isArray(railSearch.validationMessages)
18431
+ ? railSearch.validationMessages.filter(Boolean)
18432
+ : [];
18433
+ this.chatbotService.patchAssistantMessage({
18434
+ text: messages.length
18435
+ ? this.formatValidationMessages(messages)
18436
+ : `I couldn't run that search — please check the dates and stations and try again.`,
18437
+ state: 'RESULTS_READY'
18438
+ });
18439
+ this.chatbotService.setSearching(false);
18440
+ return;
18441
+ }
18442
+ const railResults = railSearch.results.value;
18443
+ if (railResults?.[0]) {
18444
+ this.resultAwareService.captureRailResults(railResults[0]);
18445
+ }
18446
+ else {
18447
+ console.warn('[ChatbotRailSearchService] no rail results to capture (startSearch returned', ok, ')');
18448
+ this.chatbotService.setSearching(false);
18449
+ }
18450
+ }
18451
+ /**
18452
+ * Render OBT's validationMessages array as a chatbot reply. Single message →
18453
+ * inline sentence; multiple → bullet list so each issue reads clearly.
18454
+ */
18455
+ formatValidationMessages(messages) {
18456
+ if (messages.length === 1) {
18457
+ return `I couldn't run that search — ${messages[0]}. Please adjust and try again.`;
18458
+ }
18459
+ const bullets = messages.map((m) => `• ${m}`).join('\n');
18460
+ return `I couldn't run that search — please fix the following and try again:\n${bullets}`;
18461
+ }
18462
+ // ── Result capture + card building ───────────────────────────────────────
18463
+ /**
18464
+ * Subscribe to ResultAwareService for the next rail result emission, build
18465
+ * the top-N cards per leg, then patch the last assistant message so the
18466
+ * chat widget can render them.
18467
+ */
18468
+ subscribeToRailResults(parameters) {
18469
+ this.resultsSubscription?.unsubscribe();
18470
+ // Reset the BehaviorSubject so a second search doesn't fire the take(1)
18471
+ // subscriber immediately with stale data and then never update.
18472
+ this.resultAwareService.clearResults();
18473
+ this.chatbotService.setSearching(true, 'rail');
18474
+ this.resultsSubscription = this.resultAwareService.resultsAvailable$
18475
+ .pipe(filter(Boolean), take(1), timeout$1(RAIL_RESULTS_WAIT_MS), catchError$1((err) => {
18476
+ console.warn('[ChatbotRailSearchService] rail results timed out or errored', err);
18477
+ this.chatbotService.setSearching(false);
18478
+ return EMPTY;
18479
+ }))
18480
+ .subscribe(() => {
18481
+ const condensed = this.resultAwareService.getCondensedResults();
18482
+ const railResults = this.buildRailResults(condensed, parameters);
18483
+ this.chatbotService.patchAssistantMessage({ railResults, state: 'RESULTS_READY' });
18484
+ this.chatbotService.setSearching(false);
18485
+ });
18486
+ }
18487
+ buildRailResults(condensed, parameters) {
18488
+ const isReturn = !!parameters.returnDate;
18489
+ // condenseRailResults emits (cheapest, expensive) pairs per journey index.
18490
+ // Deduplicate outbound entries by index, keeping the first (cheapest) fare.
18491
+ // (Inbound legs live inside condensed[0].returnOptions and are handled
18492
+ // separately by buildInboundCards.)
18493
+ const seenOutbound = new Set();
18494
+ const outboundRaw = [];
18495
+ for (const r of condensed) {
18496
+ const isReturnEntry = isReturn && r.singleOrReturn?.toLowerCase().includes('return');
18497
+ if (isReturnEntry)
18498
+ continue;
18499
+ if (seenOutbound.has(r.index))
18500
+ continue;
18501
+ seenOutbound.add(r.index);
18502
+ outboundRaw.push(r);
18503
+ }
18504
+ const outboundCards = outboundRaw
18505
+ .slice(0, MAX_RAIL_CARDS_PER_LEG)
18506
+ .map((r) => this.toRailCard(r, parameters.departure, parameters.arrival, parameters.departureDate));
18507
+ const inboundCards = isReturn && parameters.returnDate
18508
+ ? this.buildInboundCards(condensed, parameters, parameters.returnDate)
18509
+ : undefined;
18510
+ return { outbound: outboundCards, inbound: inboundCards, isReturn, parameters };
18511
+ }
18512
+ buildInboundCards(condensed, parameters, returnDate) {
18513
+ // Return journey options live inside condensed[0].returnOptions[]
18514
+ const returnOptions = condensed[0]?.returnOptions ?? [];
18515
+ const seen = new Set();
18516
+ const cards = [];
18517
+ for (const ro of returnOptions) {
18518
+ if (seen.has(ro.index))
18519
+ continue;
18520
+ seen.add(ro.index);
18521
+ const { singlePrice, singleTickets } = this.resultAwareService.getRailReturnJourneyFares(ro.index);
18522
+ cards.push({
18523
+ index: ro.index,
18524
+ departDate: this.formatDate(returnDate),
18525
+ departTime: ro.depart,
18526
+ arriveTime: ro.arrive,
18527
+ from: parameters.arrival,
18528
+ to: parameters.departure,
18529
+ route: `${parameters.arrival} → ${parameters.departure}`,
18530
+ duration: ro.duration,
18531
+ changes: ro.stops,
18532
+ fromPrice: ro.price,
18533
+ currency: 'GBP',
18534
+ operator: ro.operator ?? '',
18535
+ policyStatus: ro.policyStatus,
18536
+ fares: { singlePrice, currency: 'GBP', singleTickets }
18537
+ });
18538
+ if (cards.length === MAX_RAIL_CARDS_PER_LEG)
18539
+ break;
18540
+ }
18541
+ return cards;
18542
+ }
18543
+ toRailCard(r, from, to, date) {
18544
+ const { singlePrice, returnPrice, singleTickets, returnTickets } = this.resultAwareService.getRailJourneyFares(r.index);
18545
+ return {
18546
+ index: r.index,
18547
+ departDate: this.formatDate(date),
18548
+ departTime: r.depart,
18549
+ arriveTime: r.arrive,
18550
+ from,
18551
+ to,
18552
+ route: `${from} → ${to}`,
18553
+ duration: r.duration,
18554
+ changes: r.stops,
18555
+ fromPrice: r.price,
18556
+ currency: 'GBP',
18557
+ operator: r.operator ?? '',
18558
+ policyStatus: r.policyStatus,
18559
+ fares: { singlePrice, returnPrice, currency: 'GBP', singleTickets, returnTickets }
18560
+ };
18561
+ }
18562
+ formatDate(dateStr) {
18563
+ try {
18564
+ return new Date(dateStr).toLocaleDateString('en-GB', {
18565
+ weekday: 'short',
18566
+ day: 'numeric',
18567
+ month: 'short',
18568
+ year: 'numeric'
18569
+ });
18570
+ }
18571
+ catch {
18572
+ return dateStr;
18573
+ }
18574
+ }
18575
+ // ── Param population ─────────────────────────────────────────────────────
18576
+ async populateRailParams(parameters, departNgbDate) {
18577
+ const railParams = this.searchService.searches[ServiceType.Rail];
18578
+ railParams.outbound_date = departNgbDate;
18579
+ if (parameters.departureTime) {
18580
+ railParams.outbound_time = this.normalizeTime(parameters.departureTime);
18581
+ }
18582
+ if (parameters.returnDate) {
18583
+ const returnDate = moment$1(parameters.returnDate);
18584
+ railParams.return_date = {
18585
+ year: returnDate.year(),
18586
+ month: returnDate.month() + 1,
18587
+ day: returnDate.date()
18588
+ };
18589
+ railParams.chosenSearchType = RailSearchJourneyType.ReturnJourney;
18590
+ if (parameters.returnTime) {
18591
+ railParams.return_time = this.normalizeTime(parameters.returnTime);
18592
+ }
18593
+ }
18594
+ else {
18595
+ railParams.chosenSearchType = RailSearchJourneyType.SingleJourney;
18596
+ }
18597
+ if (parameters.railClass) {
18598
+ railParams.chosenSearchClass = RailClass[parameters.railClass] ?? RailClass.All;
18599
+ }
18600
+ if (parameters.outboundTimeCriteria) {
18601
+ railParams.outboundCriteria =
18602
+ parameters.outboundTimeCriteria === 'Arrive'
18603
+ ? RailSearchCriteria.Arrive
18604
+ : RailSearchCriteria.Depart;
18605
+ }
18606
+ if (parameters.returnTimeCriteria) {
18607
+ railParams.returnCriteria =
18608
+ parameters.returnTimeCriteria === 'Arrive'
18609
+ ? RailSearchCriteria.Arrive
18610
+ : RailSearchCriteria.Depart;
18611
+ }
18612
+ if (parameters.isAirportExpress) {
18613
+ railParams.isAirportExpress = true;
18614
+ if (parameters.airportExpressRoute) {
18615
+ railParams.airportExpressStation = parameters.airportExpressRoute;
18616
+ }
18617
+ }
18618
+ else {
18619
+ railParams.isAirportExpress = false;
18620
+ railParams.airportExpressStation = null;
18621
+ }
18622
+ if (parameters.children) {
18623
+ railParams.noOfChildren = parameters.children;
18624
+ }
18625
+ // Railcards must be set BEFORE station resolution so that when locationChange
18626
+ // triggers loadRailcards() in the rail-search component, railParams.railCards
18627
+ // is already populated and selectedTravelCards gets synced correctly.
18628
+ if (parameters.railcards?.length) {
18629
+ const availableCards = await firstValueFrom(this.searchService.getRailCards('GB'));
18630
+ const matched = parameters.railcards
18631
+ .map((code) => {
18632
+ const upper = code.toUpperCase();
18633
+ return availableCards.find((c) => c.code.toUpperCase() === upper || c.name.toUpperCase().includes(upper));
18634
+ })
18635
+ .filter((c) => !!c);
18636
+ if (matched.length) {
18637
+ railParams.railCards = matched;
18638
+ // Prevent preselectRailcardsForTravellers from overriding the chatbot selection
18639
+ railParams.applyRailcards = true;
18640
+ }
18641
+ }
18642
+ const resolvePromises = [
18643
+ this.resolveRailStation(parameters.departureCode, parameters.departure),
18644
+ this.resolveRailStation(parameters.arrivalCode, parameters.arrival)
18645
+ ];
18646
+ if (parameters.viaStation || parameters.viaCode) {
18647
+ resolvePromises.push(this.resolveRailStation(parameters.viaCode, parameters.viaStation || ''));
18648
+ }
18649
+ const [from, to, viaResolved] = await Promise.all(resolvePromises);
18650
+ if (from) {
18651
+ railParams.travellingFrom = from;
18652
+ }
18653
+ if (to) {
18654
+ railParams.travellingTo = to;
18655
+ }
18656
+ if (viaResolved) {
18657
+ railParams.via = true;
18658
+ railParams.viaLocation = viaResolved;
18659
+ }
18660
+ // Re-apply journey type after station resolution: setting travellingFrom/To
18661
+ // triggers validateAndPrepare() which can reset chosenSearchType from
18662
+ // session storage.
18663
+ if (parameters.returnDate) {
18664
+ railParams.chosenSearchType = RailSearchJourneyType.ReturnJourney;
18665
+ }
18666
+ }
18667
+ normalizeTime(time) {
18668
+ const parsed = moment$1(time, ['H:mm', 'HH:mm', 'ha', 'h:mma', 'h a', 'h:mm a']);
18669
+ if (parsed.isValid()) {
18670
+ return parsed.format('HHmm');
18671
+ }
18672
+ return time.replace(':', '');
18673
+ }
18674
+ preferRailStation(stations) {
18675
+ const hub = stations.find((s) => s.name && /\bhub\b/i.test(s.name));
18676
+ if (hub) {
18677
+ return hub;
18678
+ }
18679
+ const nonAirport = stations.find((s) => s.name && !s.name.toLowerCase().includes('airport'));
18680
+ return nonAirport || stations[0];
18681
+ }
18682
+ async resolveRailStation(code, name) {
18683
+ if (!name && !code) {
18684
+ return null;
18685
+ }
18686
+ if (code) {
18687
+ const byCode = await this.lookupRailStations(code);
18688
+ if (byCode?.length) {
18689
+ const exact = byCode.find((s) => s?.railstation?.stationCode === code || s?.stationCode === code);
18690
+ if (exact)
18691
+ return exact;
18692
+ const preferred = this.preferRailStation(byCode);
18693
+ if (preferred)
18694
+ return preferred;
18695
+ }
18696
+ }
18697
+ if (!name) {
18698
+ return null;
18699
+ }
18700
+ const candidates = this.buildRailStationNameCandidates(name);
18701
+ for (const candidate of candidates) {
18702
+ const stations = await this.lookupRailStations(candidate);
18703
+ if (stations?.length) {
18704
+ if (code) {
18705
+ const byCode = stations.find((s) => s?.railstation?.stationCode === code || s?.stationCode === code);
18706
+ if (byCode)
18707
+ return byCode;
18708
+ }
18709
+ const preferred = this.preferRailStation(stations);
18710
+ if (preferred)
18711
+ return preferred;
18712
+ }
18713
+ }
18714
+ return null;
18715
+ }
18716
+ async lookupRailStations(query) {
18717
+ try {
18718
+ const stations = await firstValueFrom(this.searchService.getStationLocations(query));
18719
+ return stations ?? null;
18720
+ }
18721
+ catch {
18722
+ return null;
18723
+ }
18724
+ }
18725
+ /**
18726
+ * Generate progressively-cleaner name variants for rail station lookup.
18727
+ * e.g. "Manchester (all stations)" → ["Manchester (all stations)", "Manchester", "Manchester all stations"]
18728
+ */
18729
+ buildRailStationNameCandidates(name) {
18730
+ const variants = new Set();
18731
+ const trimmed = name.trim();
18732
+ if (trimmed)
18733
+ variants.add(trimmed);
18734
+ const withoutParens = trimmed
18735
+ .replace(/\s*\([^)]*\)\s*/g, ' ')
18736
+ .replace(/\s+/g, ' ')
18737
+ .trim();
18738
+ if (withoutParens)
18739
+ variants.add(withoutParens);
18740
+ const firstWord = withoutParens.split(/\s+/)[0];
18741
+ if (firstWord && firstWord.length > 2)
18742
+ variants.add(firstWord);
18743
+ return Array.from(variants);
18744
+ }
18745
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotRailSearchService, deps: [{ token: ChatbotService }, { token: EnterpriseSearchService }, { token: ResultAwareService }, { token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
18746
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotRailSearchService, providedIn: 'root' });
18747
+ }
18748
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotRailSearchService, decorators: [{
18749
+ type: Injectable,
18750
+ args: [{ providedIn: 'root' }]
18751
+ }], ctorParameters: () => [{ type: ChatbotService }, { type: EnterpriseSearchService }, { type: ResultAwareService }, { type: UserService }] });
18752
+
18753
+ /**
18754
+ * Extracts journey itineraries from a `FlightQuoteResultArray`. Returns both
18755
+ * outbound and (when present) inbound legs separately so the chat UI can
18756
+ * render two card stacks for dual-single return searches.
18757
+ *
18758
+ * `journeys` (return-paired) itineraries carry both legs inside each entry,
18759
+ * so they're returned in `outbound` only.
18760
+ * `multi` (dual-singles) splits the legs across two arrays, which we surface
18761
+ * separately.
18762
+ */
18763
+ function extractJourneys(results) {
18764
+ const empty = { outbound: [], inbound: [], multi: [] };
18765
+ if (!results)
18766
+ return empty;
18767
+ const bundles = Array.isArray(results) ? results : [results];
18768
+ const out = { outbound: [], inbound: [], multi: [] };
18769
+ for (const bundle of bundles) {
18770
+ if (!bundle)
18771
+ continue;
18772
+ if (Array.isArray(bundle.journeys) && bundle.journeys.length) {
18773
+ out.outbound.push(...bundle.journeys);
18774
+ }
18775
+ else if (Array.isArray(bundle.multi)) {
18776
+ // Per-leg arrays — for multi-city this can be 3+ entries. We retain the
18777
+ // full N-leg shape so the multi-city path can render every segment,
18778
+ // while keeping the legacy dual-singles fields populated for the
18779
+ // existing return-as-two-singles UI.
18780
+ const perLeg = bundle.multi.map((m) => Array.isArray(m?.results) ? m.results : []);
18781
+ if (perLeg.length >= 2) {
18782
+ out.multi.push(perLeg);
18783
+ }
18784
+ const outboundLeg = perLeg[0];
18785
+ const inboundLeg = perLeg[1];
18786
+ if (Array.isArray(outboundLeg))
18787
+ out.outbound.push(...outboundLeg);
18788
+ if (Array.isArray(inboundLeg) && perLeg.length === 2)
18789
+ out.inbound.push(...inboundLeg);
18790
+ }
18791
+ }
18792
+ return out;
18793
+ }
18794
+ const FLIGHT_RESULTS_WAIT_MS = 90_000;
18795
+ const MAX_FLIGHT_CARDS = 3;
18796
+ /**
18797
+ * Handles chatbot-driven flight searches. Registered with
18798
+ * `ChatbotSearchDispatcherService`; not used directly.
18799
+ *
18800
+ * Populates the flight search state from the chatbot's parameters (same state
18801
+ * the search form binds to via ngModel) and runs `startSearch()` headlessly
18802
+ * so chatbot flight searches work from any page. Once results arrive, builds
18803
+ * `ChatFlightResultCard`s and patches them onto the last assistant message
18804
+ * via {@link ChatbotService.patchAssistantMessage}.
18805
+ */
18806
+ class ChatbotFlightSearchService {
18807
+ chatbotService;
18808
+ searchService;
18809
+ resultAwareService;
18810
+ userService;
18811
+ travelType = 'flight';
18812
+ resultsSubscription = null;
18813
+ constructor(chatbotService, searchService, resultAwareService, userService) {
18814
+ this.chatbotService = chatbotService;
18815
+ this.searchService = searchService;
18816
+ this.resultAwareService = resultAwareService;
18817
+ this.userService = userService;
18818
+ }
18819
+ async handle(parameters, autoSearch) {
18820
+ this.searchService.resetSearchChosenObjects();
18821
+ this.searchService.resetSearchPriorities();
18822
+ this.searchService.search_objects[ServiceType.Flight].chosen = true;
18823
+ this.searchService.search_objects[ServiceType.Flight].originalChosen = true;
18824
+ this.searchService.determineHighestSearchPriority();
18825
+ if (this.searchService.travellerInformation.value.length === 0) {
18826
+ const selfTraveller = this.userService.createSelfTraveller();
18827
+ if (selfTraveller) {
18828
+ this.searchService.addTraveller(selfTraveller);
18829
+ }
18830
+ }
18831
+ const isMultiCity = (parameters.legs?.length ?? 0) >= 2;
18832
+ // For multi-city the reference date for any downstream calendar widgets
18833
+ // is the first leg; for single/return it's the top-level departureDate.
18834
+ const refDateStr = isMultiCity ? parameters.legs[0].date : parameters.departureDate;
18835
+ const refDate = moment$1(refDateStr);
18836
+ const departNgbDate = {
18837
+ year: refDate.year(),
18838
+ month: refDate.month() + 1,
18839
+ day: refDate.date()
18840
+ };
18841
+ if (autoSearch) {
18842
+ this.subscribeToFlightResults(parameters);
18843
+ }
18844
+ if (isMultiCity) {
18845
+ await this.populateMultiCityFlightParams(parameters);
18846
+ }
18847
+ else {
18848
+ await this.populateFlightParams(parameters, departNgbDate);
18849
+ }
18850
+ if (!autoSearch) {
18851
+ return;
18852
+ }
18853
+ const flightSearch = this.searchService.searches[ServiceType.Flight];
18854
+ // Surface OBT's existing validation (past dates, same origin/destination,
18855
+ // missing airports, return-before-depart, etc.) instead of letting the
18856
+ // user wait for a search that will silently no-op. Setters on
18857
+ // FlightEnterpriseSearch run `_isValid()` on every assignment, so the
18858
+ // array is already populated by the time `populateFlightParams` returns.
18859
+ const validationMessages = Array.isArray(flightSearch.validationMessages)
18860
+ ? flightSearch.validationMessages.filter(Boolean)
18861
+ : [];
18862
+ if (validationMessages.length) {
18863
+ this.resultsSubscription?.unsubscribe();
18864
+ this.resultsSubscription = null;
18865
+ this.chatbotService.patchAssistantMessage({
18866
+ text: this.formatValidationMessages(validationMessages),
18867
+ state: 'RESULTS_READY'
18868
+ });
18869
+ this.chatbotService.setSearching(false);
18870
+ return;
18871
+ }
18872
+ const started = await flightSearch.startSearch();
18873
+ if (!started) {
18874
+ // Safety net — should rarely fire now that we read validationMessages
18875
+ // up-front, but kept in case startSearch rejects for another reason.
18876
+ this.resultsSubscription?.unsubscribe();
18877
+ this.resultsSubscription = null;
18878
+ const messages = Array.isArray(flightSearch.validationMessages)
18879
+ ? flightSearch.validationMessages.filter(Boolean)
18880
+ : [];
18881
+ this.chatbotService.patchAssistantMessage({
18882
+ text: messages.length
18883
+ ? this.formatValidationMessages(messages)
18884
+ : `I couldn't run that search — please check the dates and airports and try again.`,
18885
+ state: 'RESULTS_READY'
18886
+ });
18887
+ this.chatbotService.setSearching(false);
18888
+ return;
18889
+ }
18890
+ // Note: result capture happens inside `subscribeToFlightResults`; we don't
18891
+ // read `flightSearch.results` here because it's a BehaviorSubject that may
18892
+ // still be empty at this point.
18893
+ }
18894
+ // ── Result capture + card building ───────────────────────────────────────
18895
+ subscribeToFlightResults(parameters) {
18896
+ this.resultsSubscription?.unsubscribe();
18897
+ // Reset the BehaviorSubject so a second search doesn't fire the take(1)
18898
+ // subscriber immediately with stale data and then never update.
18899
+ this.resultAwareService.clearResults();
18900
+ this.chatbotService.setSearching(true, 'flight');
18901
+ // Subscribe directly to the flight search's results BehaviorSubject. Unlike
18902
+ // rail, flight `startSearch()` can resolve before results stream in, so
18903
+ // reading `results.value` after the await isn't reliable. We wait for the
18904
+ // first emission that contains actual journey itineraries.
18905
+ const flightSearch = this.searchService.searches[ServiceType.Flight];
18906
+ // Don't mutate the shared `results` BehaviorSubject here: other views
18907
+ // (e.g. the flight results page) subscribe to the same singleton and
18908
+ // pushing `[]` would briefly flash them an empty state. The new
18909
+ // `startSearch()` below replaces `results.value` before `isLoading`
18910
+ // flips to false, so the value we read in the completion handler is
18911
+ // always the fresh search's output.
18912
+ // Use `isLoading` (true → false transition) as the search-complete signal
18913
+ // rather than waiting on the results subject. The previous filter required
18914
+ // `r.length > 0 && hasJourneys(...)` — but a genuinely empty response
18915
+ // (e.g. no Premium Economy KLM flights on that date) also produces an
18916
+ // empty array, indistinguishable from "haven't searched yet", so the
18917
+ // subscriber would hang until the 90s timeout instead of rendering the
18918
+ // "No flights found" empty state. `isLoading` reliably flips to false in
18919
+ // `_startSearch`'s complete/error handlers either way.
18920
+ const loadingSubject = flightSearch.isLoading;
18921
+ this.resultsSubscription = loadingSubject
18922
+ .pipe(skip(1), // drop the BehaviorSubject's replay of the current value
18923
+ filter((loading) => loading === false), take(1), timeout$1(FLIGHT_RESULTS_WAIT_MS), catchError$1((err) => {
18924
+ console.warn('[ChatbotFlightSearchService] flight results timed out or errored', err);
18925
+ this.chatbotService.patchAssistantMessage({
18926
+ flightResults: {
18927
+ outbound: [],
18928
+ isReturn: !!parameters.returnDate,
18929
+ isMultiCity: (parameters.legs?.length ?? 0) >= 2,
18930
+ parameters,
18931
+ sort: 'cheapest'
18932
+ },
18933
+ state: 'RESULTS_READY'
18934
+ });
18935
+ this.chatbotService.setSearching(false);
18936
+ return EMPTY;
18937
+ }))
18938
+ .subscribe(() => {
18939
+ const rawResults = flightSearch.results?.value ?? [];
18940
+ const { outbound, inbound, multi } = extractJourneys(rawResults);
18941
+ const isMultiCity = (parameters.legs?.length ?? 0) >= 2;
18942
+ // Feed ResultAwareService with outbound so its condensed-cards API is
18943
+ // populated for downstream card click → filter navigation.
18944
+ this.resultAwareService.captureFlightResults(outbound);
18945
+ const outboundCondensed = this.resultAwareService.getCondensedResults();
18946
+ let inboundCondensed = [];
18947
+ if (inbound.length) {
18948
+ // Build inbound condensed by re-running the condensation. The
18949
+ // ResultAwareService keeps state for outbound, so we condense the
18950
+ // raw inbound array via a temporary capture/restore.
18951
+ this.resultAwareService.captureFlightResults(inbound);
18952
+ inboundCondensed = this.resultAwareService.getCondensedResults();
18953
+ // Restore outbound as the "current" capture for click-through filters.
18954
+ this.resultAwareService.captureFlightResults(outbound);
18955
+ }
18956
+ const flightResults = isMultiCity
18957
+ ? this.buildMultiCityFlightResults(parameters, outbound)
18958
+ : this.buildFlightResults(outboundCondensed, inboundCondensed, parameters, outbound, inbound);
18959
+ this.chatbotService.patchAssistantMessage({
18960
+ flightResults,
18961
+ state: 'RESULTS_READY'
18962
+ });
18963
+ this.chatbotService.setSearching(false);
18964
+ });
18965
+ }
18966
+ buildFlightResults(outbound, inbound, parameters, rawOutbound = [], rawInbound = []) {
18967
+ const isReturn = !!parameters.returnDate;
18968
+ // sortType is widened on ChatSearchParameters to cover hotel + flight values;
18969
+ // narrow back to the flight-only subset accepted by ChatFlightResults.sort.
18970
+ const sort = parameters.sortType === 'fastest' || parameters.sortType === 'shortest'
18971
+ ? parameters.sortType
18972
+ : 'cheapest';
18973
+ // Optional airline filter: if the user asked for a specific carrier
18974
+ // ("Give me BA flights…"), keep only matching itineraries. Honour it
18975
+ // strictly — better to show "no matches" than mislead the user.
18976
+ const airlineFilter = (parameters.airlineCode || parameters.airline || '').trim().toLowerCase();
18977
+ const applyAirline = (list) => {
18978
+ if (!airlineFilter)
18979
+ return list;
18980
+ return list.filter((r) => {
18981
+ const code = (r.flightNumbers?.match(/^[A-Z]{2,3}/i)?.[0] || '').toLowerCase();
18982
+ const name = (r.airline || '').toLowerCase();
18983
+ return code === airlineFilter || name.includes(airlineFilter);
18984
+ });
18985
+ };
18986
+ // Honour "direct only" / maxConnections=0 strictly. The form-level
18987
+ // maxConnections setting goes to the supplier, but some suppliers ignore
18988
+ // it — re-filter client-side so the user gets what they asked for.
18989
+ const applyStops = (list) => {
18990
+ if (parameters.maxConnections == null)
18991
+ return list;
18992
+ const max = parameters.maxConnections;
18993
+ return list.filter((r) => (r.stops ?? 0) <= max);
18994
+ };
18995
+ const outFiltered = applyStops(applyAirline(outbound));
18996
+ const inFiltered = applyStops(applyAirline(inbound));
18997
+ // Dedupe by physical-flight signature, keep the cheapest fare per flight,
18998
+ // then sort. Without dedup we'd often render two or three "cards" that
18999
+ // are the same KL1034 with different fare brands (Restricted/Flex/Plus)
19000
+ // — the user wants one card per flight with the cheapest price shown,
19001
+ // and the existing fare-options expand panel (built via
19002
+ // indexFaresByFlights) surfaces the other bookable fares.
19003
+ //
19004
+ // Key includes outbound flight numbers + inbound flight numbers AND each
19005
+ // leg's depart time, so two operationally-distinct flights that happen
19006
+ // to share marketing flight numbers (codeshares on different equipment
19007
+ // or schedules) don't collapse into one card.
19008
+ const parseDurationToMins = (d) => {
19009
+ if (!d)
19010
+ return Number.POSITIVE_INFINITY;
19011
+ const h = /(\d+)\s*h/i.exec(d);
19012
+ const m = /(\d+)\s*m/i.exec(d);
19013
+ const total = (h ? +h[1] : 0) * 60 + (m ? +m[1] : 0);
19014
+ return total > 0 ? total : Number.POSITIVE_INFINITY;
19015
+ };
19016
+ const totalDurationMins = (r) => parseDurationToMins(r.duration) + (r.inbound ? parseDurationToMins(r.inbound.duration) : 0);
19017
+ const dedupeCheapestByFlight = (list) => {
19018
+ const seen = new Map();
19019
+ for (const r of list) {
19020
+ const out = r.flightNumbers || '';
19021
+ const inb = r.inbound?.flightNumbers || '';
19022
+ if (!out && !inb) {
19023
+ // No flight numbers to key on (shouldn't happen for real results);
19024
+ // fall back to per-index so we don't collapse unrelated cards.
19025
+ seen.set(`__idx${r.index}`, r);
19026
+ continue;
19027
+ }
19028
+ const key = `${out}|${inb}|${r.depart}|${r.inbound?.depart ?? ''}`;
19029
+ const existing = seen.get(key);
19030
+ if (!existing || (r.price ?? Infinity) < (existing.price ?? Infinity)) {
19031
+ seen.set(key, r);
19032
+ }
19033
+ }
19034
+ const arr = Array.from(seen.values());
19035
+ if (sort === 'fastest' || sort === 'shortest') {
19036
+ arr.sort((a, b) => totalDurationMins(a) - totalDurationMins(b));
19037
+ }
19038
+ else {
19039
+ arr.sort((a, b) => (a.price ?? Infinity) - (b.price ?? Infinity));
19040
+ }
19041
+ return arr;
19042
+ };
19043
+ const outDeduped = dedupeCheapestByFlight(outFiltered);
19044
+ const inDeduped = dedupeCheapestByFlight(inFiltered);
19045
+ // Pre-compute fare-options groupings for the expand panel: group the raw
19046
+ // itineraries by their outbound (+ inbound) flight-numbers signature so a
19047
+ // card can show all bookable cabins/brands for the same physical flights.
19048
+ // For one-way searches the lookup key on the card side is just the
19049
+ // outbound flight numbers (no trailing "|"); use the same shape here so
19050
+ // the maps actually match. For returns, include the inbound legs.
19051
+ const outFareIndex = this.indexFaresByFlights(rawOutbound, isReturn);
19052
+ const inFareIndex = this.indexFaresByFlights(rawInbound, false);
19053
+ const outboundCards = outDeduped
19054
+ .slice(0, MAX_FLIGHT_CARDS)
19055
+ .map((r) => this.toFlightCard(r, parameters, 'outbound', outFareIndex));
19056
+ const inboundCards = inDeduped
19057
+ .slice(0, MAX_FLIGHT_CARDS)
19058
+ .map((r) => this.toFlightCard(r, parameters, 'inbound', inFareIndex));
19059
+ return { outbound: outboundCards, inbound: inboundCards, isReturn, parameters, sort };
19060
+ }
19061
+ /**
19062
+ * Builds a map keyed by an itinerary's flight-number signature to all
19063
+ * bookable fare variants (cabin/brand/price) for the same physical flights.
19064
+ * For combined-return journeys the key includes both outbound + inbound
19065
+ * flight numbers; for dual-single legs it's just that leg's numbers.
19066
+ */
19067
+ indexFaresByFlights(raw, includeInbound) {
19068
+ const map = new Map();
19069
+ if (!raw?.length)
19070
+ return map;
19071
+ raw.forEach((it, idx) => {
19072
+ const key = this.flightSignature(it, includeInbound);
19073
+ if (!key)
19074
+ return;
19075
+ const fare = this.toFareTicket(it, idx);
19076
+ if (!fare)
19077
+ return;
19078
+ const arr = map.get(key) ?? [];
19079
+ arr.push(fare);
19080
+ map.set(key, arr);
19081
+ });
19082
+ // Sort each group cheapest first.
19083
+ for (const arr of map.values()) {
19084
+ arr.sort((a, b) => a.price - b.price);
19085
+ }
19086
+ return map;
19087
+ }
19088
+ flightSignature(it, includeInbound) {
19089
+ const out = (it.outboundFlights || it.outlegs || [])
19090
+ .map((l) => `${l.marketingCarrier || ''}${l.marketingFlightNumber || ''}`)
19091
+ .join('/');
19092
+ if (!out)
19093
+ return '';
19094
+ if (!includeInbound)
19095
+ return out;
19096
+ const inn = (it.inboundFlights || it.inlegs || [])
19097
+ .map((l) => `${l.marketingCarrier || ''}${l.marketingFlightNumber || ''}`)
19098
+ .join('/');
19099
+ return `${out}|${inn}`;
19100
+ }
19101
+ toFareTicket(it, idx) {
19102
+ const price = it?.total?.price;
19103
+ if (!(price > 0))
19104
+ return null;
19105
+ const cabin = it?.outboundFlights?.[0]?.cabinClass || it?.outlegs?.[0]?.cabinClass || '';
19106
+ // Fare brand can live in several places depending on supplier/source.
19107
+ // `fareConditions.brandName/fareFamily` is one path; `outboundFlights[0]
19108
+ // .additional.fareBrand.name` is what the full-results upsell dialog
19109
+ // reads. Fall back across both so we surface the friendliest label.
19110
+ const brand = it?.fareConditions?.brandName ||
19111
+ it?.fareConditions?.fareFamily ||
19112
+ it?.outboundFlights?.[0]?.additional?.fareBrand?.name ||
19113
+ '';
19114
+ const type = brand && cabin
19115
+ ? `${this.formatCabinLabel(cabin)} – ${brand}`
19116
+ : brand || this.formatCabinLabel(cabin) || 'Standard fare';
19117
+ return {
19118
+ type,
19119
+ cabin: cabin || undefined,
19120
+ brand: brand || undefined,
19121
+ price,
19122
+ currency: it?.total?.currency || 'GBP',
19123
+ journeyIndex: idx
19124
+ };
19125
+ }
19126
+ /**
19127
+ * Builds chat cards for a multi-city itinerary. OBT returns one bundle per
19128
+ * search with per-leg result arrays; we surface the top N itineraries by
19129
+ * pairing the i-th cheapest option from every leg into a single "stacked"
19130
+ * card. This is naive (it doesn't try every combinatorial combination) but
19131
+ * gives the user a useful headline view; View Full Results owns the proper
19132
+ * fare-combination picker.
19133
+ *
19134
+ * OBT returns multi-city itineraries as a single `bundle.journeys[]` where
19135
+ * each entry has all legs concatenated in `outboundFlights[]`. We split each
19136
+ * itinerary by leg-date to produce N `ChatFlightLeg`s per card.
19137
+ */
19138
+ buildMultiCityFlightResults(parameters, journeys) {
19139
+ const baseResults = {
19140
+ outbound: [],
19141
+ isReturn: false,
19142
+ isMultiCity: true,
19143
+ parameters,
19144
+ sort: 'cheapest'
19145
+ };
19146
+ const legs = parameters.legs ?? [];
19147
+ if (!journeys.length || !legs.length) {
19148
+ return baseResults;
19149
+ }
19150
+ // Dedupe by full-itinerary flight signature and sort cheapest first.
19151
+ const bySig = new Map();
19152
+ for (const j of journeys) {
19153
+ const sig = (j?.outboundFlights ?? [])
19154
+ .map((f) => `${f.marketingCarrier || ''}${f.marketingFlightNumber || ''}`)
19155
+ .join('/');
19156
+ const existing = bySig.get(sig);
19157
+ if (!existing || (j?.total?.price ?? Infinity) < (existing?.total?.price ?? Infinity)) {
19158
+ bySig.set(sig, j);
19159
+ }
19160
+ }
19161
+ const sorted = [...bySig.values()].sort((a, b) => (a?.total?.price ?? Infinity) - (b?.total?.price ?? Infinity));
19162
+ const cards = [];
19163
+ for (let i = 0; i < Math.min(MAX_FLIGHT_CARDS, sorted.length); i++) {
19164
+ const journey = sorted[i];
19165
+ const buckets = this.splitFlightsByLeg(journey?.outboundFlights ?? [], legs);
19166
+ const chatLegs = legs.map((leg, idx) => this.flightsToChatLeg(buckets[idx] ?? [], leg));
19167
+ const airlineCode = (journey?.outboundFlights?.[0]?.marketingCarrier || '').toUpperCase();
19168
+ const airline = journey?.outboundFlights?.[0]?.marketingCarrierName ||
19169
+ journey?.outboundFlights?.[0]?.airline ||
19170
+ '';
19171
+ const cabin = journey?.fareConditions?.outboundFareConditions?.cabinClass || '';
19172
+ cards.push({
19173
+ index: i,
19174
+ airline,
19175
+ airlineCode,
19176
+ outbound: chatLegs[0],
19177
+ legs: chatLegs,
19178
+ fromPrice: journey?.total?.price ?? 0,
19179
+ currency: journey?.total?.currency || 'GBP',
19180
+ cabin: this.formatCabinLabel(cabin),
19181
+ policyStatus: journey?.preferenceLevel === 'IN_POLICY' ? 'IN_POLICY' : undefined
19182
+ });
19183
+ }
19184
+ return { ...baseResults, outbound: cards };
19185
+ }
19186
+ /**
19187
+ * Split a concatenated multi-city flight list into per-leg buckets. Primary
19188
+ * key is the flight's depart date matching a leg date; falls back to the
19189
+ * latest leg whose date is on or before the flight (covers overnight
19190
+ * connections that depart the day before the next leg's planned date).
19191
+ */
19192
+ splitFlightsByLeg(flights, legs) {
19193
+ const buckets = legs.map(() => []);
19194
+ let currentLeg = 0;
19195
+ for (const f of flights) {
19196
+ const fDate = (f?.departureDateTime || '').slice(0, 10);
19197
+ // Advance currentLeg while the leg's date is strictly before this
19198
+ // flight's date — preserves ordering even when a leg connects overnight.
19199
+ while (currentLeg + 1 < legs.length && legs[currentLeg + 1].date <= fDate) {
19200
+ currentLeg++;
19201
+ }
19202
+ buckets[currentLeg].push(f);
19203
+ }
19204
+ return buckets;
19205
+ }
19206
+ /** Build a `ChatFlightLeg` from the flights assigned to a single leg. */
19207
+ flightsToChatLeg(flights, leg) {
19208
+ const first = flights[0] ?? {};
19209
+ const last = flights[flights.length - 1] ?? first;
19210
+ const flightNumbers = flights
19211
+ .map((f) => `${f.marketingCarrier || ''}${f.marketingFlightNumber || ''}`)
19212
+ .filter(Boolean)
19213
+ .join('/');
19214
+ let duration = '';
19215
+ if (first.departureDateTime && last.arrivalDateTime) {
19216
+ const mins = Math.round((new Date(last.arrivalDateTime).getTime() - new Date(first.departureDateTime).getTime()) /
19217
+ 60000);
19218
+ duration = this.formatDuration(mins);
19219
+ }
19220
+ return {
19221
+ fromCode: first.departureAirport || leg.departureCode || leg.departure,
19222
+ fromName: leg.departure,
19223
+ toCode: last.arrivalAirport || leg.arrivalCode || leg.arrival,
19224
+ toName: leg.arrival,
19225
+ departDate: this.formatDate(leg.date),
19226
+ departTime: this.formatHHmm(first.departureDateTime),
19227
+ arriveTime: this.formatHHmm(last.arrivalDateTime),
19228
+ duration,
19229
+ stops: Math.max(0, flights.length - 1),
19230
+ flightNumbers
19231
+ };
19232
+ }
19233
+ formatHHmm(iso) {
19234
+ if (!iso)
19235
+ return '';
19236
+ const d = new Date(iso);
19237
+ if (Number.isNaN(d.getTime()))
19238
+ return '';
19239
+ return d.toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit', hour12: false });
19240
+ }
19241
+ formatDuration(minutes) {
19242
+ if (!minutes || minutes <= 0)
19243
+ return '';
19244
+ const h = Math.floor(minutes / 60);
19245
+ const m = minutes % 60;
19246
+ return h ? `${h}h ${m}m` : `${m}m`;
19247
+ }
19248
+ toFlightCard(r, parameters, direction = 'outbound', fareIndex) {
19249
+ const airlineCode = (r.flightNumbers?.match(/^[A-Z]{2,3}/i)?.[0] || '').toUpperCase();
19250
+ // For dual-singles inbound cards the leg geography is reversed.
19251
+ const fromCode = direction === 'inbound'
19252
+ ? r.from || parameters.arrivalCode || parameters.arrival
19253
+ : r.from || parameters.departureCode || parameters.departure;
19254
+ const toCode = direction === 'inbound'
19255
+ ? r.to || parameters.departureCode || parameters.departure
19256
+ : r.to || parameters.arrivalCode || parameters.arrival;
19257
+ const fromName = direction === 'inbound' ? parameters.arrival : parameters.departure;
19258
+ const toName = direction === 'inbound' ? parameters.departure : parameters.arrival;
19259
+ const departDateRaw = direction === 'inbound'
19260
+ ? (parameters.returnDate ?? parameters.departureDate)
19261
+ : parameters.departureDate;
19262
+ const outboundLeg = {
19263
+ fromCode,
19264
+ fromName,
19265
+ toCode,
19266
+ toName,
19267
+ departDate: this.formatDate(departDateRaw),
19268
+ departTime: r.depart,
19269
+ arriveTime: r.arrive,
19270
+ duration: r.duration,
19271
+ stops: r.stops,
19272
+ flightNumbers: r.flightNumbers ?? ''
19273
+ };
19274
+ // For combined-return itineraries (journeys), each result already has
19275
+ // both legs inside `r.inbound`. We only attach this for outbound cards.
19276
+ const inbound = direction === 'outbound' && r.inbound && parameters.returnDate
19277
+ ? {
19278
+ fromCode: r.to || parameters.arrivalCode || parameters.arrival,
19279
+ fromName: parameters.arrival,
19280
+ toCode: r.from || parameters.departureCode || parameters.departure,
19281
+ toName: parameters.departure,
19282
+ departDate: this.formatDate(parameters.returnDate),
19283
+ departTime: r.inbound.depart,
19284
+ arriveTime: r.inbound.arrive,
19285
+ duration: r.inbound.duration,
19286
+ stops: r.inbound.stops,
19287
+ flightNumbers: r.inbound.flightNumbers ?? ''
19288
+ }
19289
+ : undefined;
19290
+ // Look up the fare-options group (same physical flights, different
19291
+ // cabin/brand variants). For combined-return cards the key is "out|in";
19292
+ // for outbound-only / inbound-only legs it's just that leg's numbers.
19293
+ let fares;
19294
+ if (fareIndex) {
19295
+ const key = inbound
19296
+ ? `${r.flightNumbers ?? ''}|${r.inbound?.flightNumbers ?? ''}`
19297
+ : (r.flightNumbers ?? '');
19298
+ const tickets = fareIndex.get(key);
19299
+ if (tickets && tickets.length) {
19300
+ fares = { tickets, currency: tickets[0].currency };
19301
+ }
19302
+ }
19303
+ return {
19304
+ index: r.index,
19305
+ airline: r.airline ?? '',
19306
+ airlineCode,
19307
+ outbound: outboundLeg,
19308
+ inbound,
19309
+ fromPrice: r.price,
19310
+ currency: 'GBP',
19311
+ cabin: this.formatCabinLabel(r.cabin ?? parameters.cabinClass ?? ''),
19312
+ policyStatus: r.policyStatus,
19313
+ fares
19314
+ };
19315
+ }
19316
+ formatDate(dateStr) {
19317
+ try {
19318
+ return new Date(dateStr).toLocaleDateString('en-GB', {
19319
+ weekday: 'short',
19320
+ day: 'numeric',
19321
+ month: 'short',
19322
+ year: 'numeric'
19323
+ });
19324
+ }
19325
+ catch {
19326
+ return dateStr;
19327
+ }
19328
+ }
19329
+ formatCabinLabel(cabin) {
19330
+ if (!cabin)
19331
+ return '';
19332
+ // Split CamelCase like 'PremiumEconomy' → 'Premium Economy'
19333
+ return cabin.replace(/([a-z])([A-Z])/g, '$1 $2');
19334
+ }
19335
+ /**
19336
+ * Render OBT's validationMessages array as a chatbot reply. Single message →
19337
+ * inline sentence; multiple → bullet list so each issue reads clearly.
19338
+ */
19339
+ formatValidationMessages(messages) {
19340
+ if (messages.length === 1) {
19341
+ return `I couldn't run that search — ${messages[0]}. Please adjust and try again.`;
19342
+ }
19343
+ const bullets = messages.map((m) => `• ${m}`).join('\n');
19344
+ return `I couldn't run that search — please fix the following and try again:\n${bullets}`;
19345
+ }
19346
+ // ── Param population ─────────────────────────────────────────────────────
19347
+ /**
19348
+ * Tracks the last chatbot flight search's resolved airports so we can decide
19349
+ * whether a follow-up turn is a "refinement of the same journey" (e.g. swap
19350
+ * MAN → AMS for LPL → AMS — same metro, user is just nudging a parameter)
19351
+ * or a "fresh search" (e.g. MAN → AMS to BER → ATH — clearly unrelated, so
19352
+ * any sticky options like "direct only" should be cleared).
19353
+ */
19354
+ lastSearch = null;
19355
+ static NEARBY_AIRPORT_KM = 150;
19356
+ static distanceKm(lat1, lng1, lat2, lng2) {
19357
+ const toRad = (d) => (d * Math.PI) / 180;
19358
+ const R = 6371;
19359
+ const dLat = toRad(lat2 - lat1);
19360
+ const dLng = toRad(lng2 - lng1);
19361
+ const a = Math.sin(dLat / 2) ** 2 +
19362
+ Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) * Math.sin(dLng / 2) ** 2;
19363
+ return 2 * R * Math.asin(Math.sqrt(a));
19364
+ }
19365
+ airportCoords(a) {
19366
+ const lat = a?.latitude ?? a?.lat ?? a?.airportDetail?.latitude;
19367
+ const lng = a?.longitude ?? a?.lng ?? a?.airportDetail?.longitude;
19368
+ if (typeof lat !== 'number' || typeof lng !== 'number')
19369
+ return null;
19370
+ return { lat, lng };
19371
+ }
19372
+ /**
19373
+ * Multi-city counterpart to `populateFlightParams`. Resolves each leg's
19374
+ * origin/destination airports, builds the `IMultiDestination[]` shape the
19375
+ * flight search expects, and switches `chosenSearchType` to multiCity.
19376
+ * Same-journey detection is skipped (the user is describing a fundamentally
19377
+ * new itinerary), so we always do a full reset.
19378
+ */
19379
+ async populateMultiCityFlightParams(parameters) {
19380
+ const flightParams = this.searchService.searches[ServiceType.Flight];
19381
+ if (typeof flightParams.resetParams === 'function') {
19382
+ try {
19383
+ flightParams.resetParams();
19384
+ }
19385
+ catch (err) {
19386
+ console.warn('[ChatbotFlight] resetParams() failed (multi-city)', err);
19387
+ }
19388
+ }
19389
+ this.lastSearch = null;
19390
+ const legs = parameters.legs;
19391
+ const resolved = await Promise.all(legs.map(async (leg) => {
19392
+ const [orig, dest] = await Promise.all([
19393
+ this.resolveAirport(leg.departureCode, leg.departure),
19394
+ this.resolveAirport(leg.arrivalCode, leg.arrival)
19395
+ ]);
19396
+ const timeCriteria = leg.timeCriteria === 'Arrive'
19397
+ ? TimeWindow.Arrive
19398
+ : leg.timeCriteria === 'Depart'
19399
+ ? TimeWindow.Depart
19400
+ : TimeWindow.Anytime;
19401
+ const legMoment = moment$1(leg.date);
19402
+ if (leg.time) {
19403
+ const [hh, mm] = this.normalizeTime(leg.time).match(/.{1,2}/g) || ['00', '00'];
19404
+ legMoment.hours(Number(hh)).minutes(Number(mm));
19405
+ }
19406
+ else {
19407
+ // Default to mid-morning so the time-window the backend builds
19408
+ // around the date is sensible when the user said "anytime".
19409
+ legMoment.hours(9).minutes(0);
19410
+ }
19411
+ return {
19412
+ orig,
19413
+ dest,
19414
+ date: legMoment,
19415
+ outTimeCriteria: timeCriteria,
19416
+ // Matches the multi-city form default (line 848 of
19417
+ // flight-enterprise-search.ts). 0 would mean a zero-minute window
19418
+ // and the backend returns no flights.
19419
+ outTimeFlexibility: 2
19420
+ };
19421
+ }));
19422
+ const missing = resolved.findIndex((r) => !r.orig || !r.dest);
19423
+ if (missing >= 0) {
19424
+ console.warn('[ChatbotFlight] Could not resolve airports for multi-city leg', missing + 1, legs[missing]);
19425
+ }
19426
+ // chosenSearchType must be set BEFORE multiDestination — the setter wipes
19427
+ // multiDestination when transitioning away from multiCity.
19428
+ flightParams.chosenSearchType = FlightSearchType.multiCity;
19429
+ flightParams.multiDestination = resolved;
19430
+ // Mirror the first leg to the standard depart/arrive fields so any code
19431
+ // (incl. the search form's ngOnInit fallback) that reads them still works.
19432
+ if (resolved[0]?.orig) {
19433
+ flightParams.departLocation = resolved[0].orig;
19434
+ }
19435
+ if (resolved[0]?.dest) {
19436
+ flightParams.arriveLocation = resolved[0].dest;
19437
+ }
19438
+ flightParams.outBoundDate = resolved[0]?.date;
19439
+ // departLocation/arriveLocation setters flip chosenSearchType implicitly
19440
+ // (via _isValid → form bindings), so re-assert it after mirroring.
19441
+ flightParams.chosenSearchType = FlightSearchType.multiCity;
19442
+ flightParams.multiDestination = resolved;
19443
+ // Shared optional fields (cabin, passengers, sort) still apply across all
19444
+ // legs — re-use the existing single/return handlers by piggy-backing on
19445
+ // them where they don't depend on departLocation/arrivalLocation.
19446
+ this.applySharedFlightParams(parameters, flightParams);
19447
+ }
19448
+ /**
19449
+ * Apply the subset of `populateFlightParams` that is leg-agnostic (cabin
19450
+ * class, passenger breakdown, sort, refundable flag). Shared between
19451
+ * single/return and multi-city paths.
19452
+ */
19453
+ applySharedFlightParams(parameters, flightParams) {
19454
+ if (parameters.cabinClass) {
19455
+ const cc = String(parameters.cabinClass).trim().toLowerCase();
19456
+ if (cc && cc !== 'any' && cc !== 'all') {
19457
+ flightParams.cabinClass = this.mapCabinClass(parameters.cabinClass);
19458
+ }
19459
+ else if ('cabinClass' in flightParams && FlightCabinClass.Any) {
19460
+ flightParams.cabinClass = FlightCabinClass.Any;
19461
+ }
19462
+ }
19463
+ if (parameters.adults != null) {
19464
+ flightParams.adults = parameters.adults;
19465
+ }
19466
+ else if (parameters.passengers) {
19467
+ flightParams.adults = parameters.passengers;
19468
+ }
19469
+ if (parameters.children != null) {
19470
+ flightParams.children = parameters.children;
19471
+ }
19472
+ if (parameters.infants != null && 'infants' in flightParams) {
19473
+ flightParams.infants = parameters.infants;
19474
+ }
19475
+ }
19476
+ async populateFlightParams(parameters, departNgbDate) {
19477
+ const flightParams = this.searchService.searches[ServiceType.Flight];
19478
+ // Resolve the new turn's airports up-front so we can decide whether this
19479
+ // looks like the same journey (refinement) or a fresh search (full reset).
19480
+ const [from, to] = await Promise.all([
19481
+ this.resolveAirport(parameters.departureCode, parameters.departure),
19482
+ this.resolveAirport(parameters.arrivalCode, parameters.arrival)
19483
+ ]);
19484
+ const fromCoords = this.airportCoords(from);
19485
+ const toCoords = this.airportCoords(to);
19486
+ // Decide whether to do a per-turn full reset of parameters.
19487
+ // - First chatbot search in this session → no previous state to inherit,
19488
+ // reset anyway to wipe any stale state from the form.
19489
+ // - Both origin AND destination within NEARBY_AIRPORT_KM of last search →
19490
+ // treat as a refinement of the same journey and DO NOT reset, so
19491
+ // constraints the user has already expressed ("direct", "BA", cabin)
19492
+ // persist even if the AI omits them in the follow-up tool call.
19493
+ // - Either origin OR destination moved further than the threshold →
19494
+ // treat as a new search and FULL reset.
19495
+ let sameJourney = false;
19496
+ if (this.lastSearch && fromCoords && toCoords) {
19497
+ const fromDist = ChatbotFlightSearchService.distanceKm(fromCoords.lat, fromCoords.lng, this.lastSearch.fromLat, this.lastSearch.fromLng);
19498
+ const toDist = ChatbotFlightSearchService.distanceKm(toCoords.lat, toCoords.lng, this.lastSearch.toLat, this.lastSearch.toLng);
19499
+ sameJourney =
19500
+ fromDist <= ChatbotFlightSearchService.NEARBY_AIRPORT_KM &&
19501
+ toDist <= ChatbotFlightSearchService.NEARBY_AIRPORT_KM;
19502
+ }
19503
+ if (!sameJourney) {
19504
+ // Per-turn full reset: wipe all previous parameters and then apply only
19505
+ // what's in `parameters`. Without this, the long-lived flight-search
19506
+ // singleton (shared with the OBT form) carries forward stale fields —
19507
+ // e.g. "AMS → MAN direct" then later "BER → ATH" would inherit "direct".
19508
+ // We call the search class's own resetParams() so any future fields
19509
+ // automatically get reset too.
19510
+ if (typeof flightParams.resetParams === 'function') {
19511
+ try {
19512
+ flightParams.resetParams();
19513
+ }
19514
+ catch (err) {
19515
+ console.warn('[ChatbotFlight] resetParams() failed', err);
19516
+ }
19517
+ }
19518
+ }
19519
+ if (fromCoords && toCoords) {
19520
+ this.lastSearch = {
19521
+ fromLat: fromCoords.lat,
19522
+ fromLng: fromCoords.lng,
19523
+ toLat: toCoords.lat,
19524
+ toLng: toCoords.lng
19525
+ };
19526
+ }
19527
+ // Targeted resets for fields the AI must be able to clear within the
19528
+ // same journey (e.g. "actually any airline" — the AI omits airlineCode
19529
+ // in the next call and we need to drop the previous KL). For a fresh
19530
+ // journey these are already cleared by resetParams above, so we only
19531
+ // re-touch them on same-journey turns.
19532
+ if (sameJourney) {
19533
+ if ('preferredCarriers' in flightParams) {
19534
+ try {
19535
+ flightParams.preferredCarriers = [null, null, null, null];
19536
+ }
19537
+ catch (err) {
19538
+ console.warn('[ChatbotFlight] failed to reset preferredCarriers', err);
19539
+ }
19540
+ }
19541
+ if ('cabinClass' in flightParams && (parameters.cabinClass || '').trim()) {
19542
+ // Only reset cabin if the AI is sending one — otherwise we want to
19543
+ // keep the previously-stated cabin for the same journey.
19544
+ try {
19545
+ flightParams.cabinClass = FlightCabinClass.Economy;
19546
+ }
19547
+ catch (err) {
19548
+ console.warn('[ChatbotFlight] failed to reset cabinClass', err);
19549
+ }
19550
+ }
19551
+ }
19552
+ flightParams.departDate = departNgbDate;
19553
+ if (parameters.departureTime) {
19554
+ flightParams.departTime = this.normalizeTime(parameters.departureTime);
19555
+ }
19556
+ if (parameters.returnDate) {
19557
+ const returnDate = moment$1(parameters.returnDate);
19558
+ flightParams.returnDate = {
19559
+ year: returnDate.year(),
19560
+ month: returnDate.month() + 1,
19561
+ day: returnDate.date()
19562
+ };
19563
+ flightParams.chosenSearchType = FlightSearchType.return;
19564
+ if (parameters.returnTime) {
19565
+ flightParams.arriveTime = this.normalizeTime(parameters.returnTime);
19566
+ }
19567
+ }
19568
+ else {
19569
+ flightParams.chosenSearchType = FlightSearchType.oneWay;
19570
+ }
19571
+ // Treat explicit "any"/empty values as "clear" rather than "lookup". The
19572
+ // AI sometimes sends `cabinClass: "any"` when the user removes a class
19573
+ // preference — without this guard `mapCabinClass` would fall back to
19574
+ // Economy regardless and a search where the user truly wants "any cabin"
19575
+ // would still be filtered to Economy.
19576
+ if (parameters.cabinClass) {
19577
+ const cc = String(parameters.cabinClass).trim().toLowerCase();
19578
+ if (cc && cc !== 'any' && cc !== 'all') {
19579
+ flightParams.cabinClass = this.mapCabinClass(parameters.cabinClass);
19580
+ }
19581
+ else if ('cabinClass' in flightParams && FlightCabinClass.Any) {
19582
+ flightParams.cabinClass = FlightCabinClass.Any;
19583
+ }
19584
+ }
19585
+ // Passenger breakdown — if the AI passed adults/children/infants, prefer
19586
+ // those; otherwise fall back to total `passengers` as adults.
19587
+ if (parameters.adults != null) {
19588
+ flightParams.adults = parameters.adults;
19589
+ }
19590
+ else if (parameters.passengers) {
19591
+ flightParams.adults = parameters.passengers;
19592
+ }
19593
+ if (parameters.children != null) {
19594
+ flightParams.children = parameters.children;
19595
+ }
19596
+ if (parameters.infants != null && 'infants' in flightParams) {
19597
+ flightParams.infants = parameters.infants;
19598
+ }
19599
+ // Stops / connections — 0 means direct-only. Also flip `directDefaultValue`
19600
+ // so that if the user later navigates to the flight search form (whose
19601
+ // ngOnInit re-derives maxConnections from this flag) the "Direct only"
19602
+ // checkbox stays ticked instead of being silently reset.
19603
+ if (parameters.maxConnections != null) {
19604
+ flightParams.maxConnections = parameters.maxConnections;
19605
+ if ('directDefaultValue' in flightParams) {
19606
+ flightParams.directDefaultValue = parameters.maxConnections === 0;
19607
+ }
19608
+ }
19609
+ if (parameters.includeNearbyAirports != null && 'includeNearbyAirports' in flightParams) {
19610
+ flightParams.includeNearbyAirports = parameters.includeNearbyAirports;
19611
+ }
19612
+ // Time criteria (Depart vs Arrive) + flexibility window. The form's
19613
+ // checkbox/radio binds to the TimeWindow enum ("Depart By" / "Arrive By"
19614
+ // / "Anytime"), so we must translate the short codes from the AI tool.
19615
+ const toTimeWindow = (val) => {
19616
+ const v = val.toLowerCase().replace(/[\s_-]+/g, '');
19617
+ if (v.startsWith('depart'))
19618
+ return TimeWindow.Depart;
19619
+ if (v.startsWith('arrive'))
19620
+ return TimeWindow.Arrive;
19621
+ if (v.startsWith('any'))
19622
+ return TimeWindow.Anytime;
19623
+ return null;
19624
+ };
19625
+ if (parameters.outboundTimeCriteria) {
19626
+ const mapped = toTimeWindow(parameters.outboundTimeCriteria);
19627
+ if (mapped)
19628
+ flightParams.outTimeCriteria = mapped;
19629
+ }
19630
+ if (parameters.returnTimeCriteria) {
19631
+ const mapped = toTimeWindow(parameters.returnTimeCriteria);
19632
+ if (mapped)
19633
+ flightParams.inTimeCriteria = mapped;
19634
+ }
19635
+ if (parameters.timeFlexibility != null) {
19636
+ flightParams.outTimeFlexibility = parameters.timeFlexibility;
19637
+ if (parameters.returnDate) {
19638
+ flightParams.inTimeFlexibility = parameters.timeFlexibility;
19639
+ }
19640
+ }
19641
+ // Via / transit airport.
19642
+ if (parameters.viaStation || parameters.viaCode) {
19643
+ const viaAirport = await this.resolveAirport(parameters.viaCode, parameters.viaStation || '');
19644
+ if (viaAirport) {
19645
+ flightParams.via = viaAirport;
19646
+ if ('showVia' in flightParams)
19647
+ flightParams.showVia = true;
19648
+ }
19649
+ }
19650
+ // Preferred airline → operator1 (which is preferredCarriers[0]).
19651
+ // The form's airline field is a typeahead backed by the searchAirlines
19652
+ // GraphQL query, so we MUST write a real {code, name} object resolved
19653
+ // from that source (an ad-hoc object with the wrong code wouldn't match
19654
+ // anything server-side). Use either the IATA code or the name as the
19655
+ // search term, prefer an exact IATA match, then an exact name match,
19656
+ // then a substring match.
19657
+ //
19658
+ // Skip entirely when the AI passes a "no preference" sentinel — null,
19659
+ // empty string, or the literal word "any"/"all". preferredCarriers was
19660
+ // already reset to all-nulls at the top of this method, so no carrier
19661
+ // filter will be applied to the search in that case.
19662
+ const rawAirlineTerm = (parameters.airlineCode || parameters.airline || '').toString().trim();
19663
+ const isAnyAirline = !rawAirlineTerm ||
19664
+ rawAirlineTerm.toLowerCase() === 'any' ||
19665
+ rawAirlineTerm.toLowerCase() === 'all';
19666
+ if (!isAnyAirline) {
19667
+ if (!Array.isArray(flightParams.preferredCarriers)) {
19668
+ try {
19669
+ flightParams.preferredCarriers = [];
19670
+ }
19671
+ catch (err) {
19672
+ console.warn('[ChatbotFlight] failed to seed preferredCarriers array', err);
19673
+ }
19674
+ }
19675
+ if (Array.isArray(flightParams.preferredCarriers)) {
19676
+ const term = (parameters.airlineCode || parameters.airline || '').trim();
19677
+ if (term.length >= 2) {
19678
+ try {
19679
+ const matches = await firstValueFrom(this.searchService.getAirlinesList(term));
19680
+ const list = matches || [];
19681
+ const upper = term.toUpperCase();
19682
+ const lower = term.toLowerCase();
19683
+ // Avoid silently selecting a regional/subsidiary carrier when the
19684
+ // user named the parent airline. E.g. "KLM" → should match
19685
+ // "KLM Royal Dutch Airlines" not "KLM Cityhopper" (which would
19686
+ // also match a naive substring/startsWith check first).
19687
+ const isSubsidiary = (name) => /\b(cityhopper|cityline|cityjet|express|regional|connect|shuttle|airlink|link|commuter)\b/i.test(name);
19688
+ const startsWith = list.filter((a) => (a.name || '').toLowerCase().startsWith(lower));
19689
+ const startsWithNonSub = startsWith.filter((a) => !isSubsidiary(a.name || ''));
19690
+ const containsNonSub = list.filter((a) => !isSubsidiary(a.name || '') && (a.name || '').toLowerCase().includes(lower));
19691
+ const resolved = list.find((a) => (a.code || '').toUpperCase() === upper) ||
19692
+ list.find((a) => (a.name || '').toLowerCase() === lower) ||
19693
+ startsWithNonSub[0] ||
19694
+ startsWith[0] ||
19695
+ containsNonSub[0] ||
19696
+ list.find((a) => (a.name || '').toLowerCase().includes(lower)) ||
19697
+ list[0];
19698
+ if (resolved) {
19699
+ flightParams.preferredCarriers[0] = {
19700
+ code: resolved.code,
19701
+ name: resolved.name
19702
+ };
19703
+ }
19704
+ }
19705
+ catch (err) {
19706
+ console.warn('[ChatbotFlightSearchService] airline lookup failed', err);
19707
+ }
19708
+ }
19709
+ }
19710
+ }
19711
+ // Apply the airports we already resolved at the top of this method.
19712
+ if (from) {
19713
+ flightParams.departLocation = from;
19714
+ }
19715
+ if (to) {
19716
+ flightParams.arriveLocation = to;
19717
+ }
19718
+ // Re-apply journey type after location resolution in case downstream
19719
+ // setters reset it (mirrors the rail handler safeguard).
19720
+ if (parameters.returnDate) {
19721
+ flightParams.chosenSearchType = FlightSearchType.return;
19722
+ }
19723
+ }
19724
+ mapCabinClass(value) {
19725
+ const normalised = value.replace(/\s+/g, '').toLowerCase();
19726
+ const match = Object.values(FlightCabinClass).find((c) => c.toLowerCase() === normalised);
19727
+ return match ?? FlightCabinClass.Economy;
19728
+ }
19729
+ normalizeTime(time) {
19730
+ const parsed = moment$1(time, ['H:mm', 'HH:mm', 'ha', 'h:mma', 'h a', 'h:mm a']);
19731
+ if (parsed.isValid()) {
19732
+ return parsed.format('HHmm');
19733
+ }
19734
+ return time.replace(':', '');
19735
+ }
19736
+ async resolveAirport(code, name) {
19737
+ if (code && code.length >= 3) {
19738
+ try {
19739
+ const byCode = await firstValueFrom(this.searchService.getAirportsList(code, null));
19740
+ if (byCode?.length > 0) {
19741
+ return byCode.find((a) => a.gateway === code) || byCode[0];
19742
+ }
19743
+ }
19744
+ catch {
19745
+ /* fall through to name search */
19746
+ }
19747
+ }
19748
+ if (name && name.length > 2) {
19749
+ try {
19750
+ const byName = await firstValueFrom(this.searchService.getAirportsList(name, null));
19751
+ if (byName?.length > 0) {
19752
+ return byName[0];
19753
+ }
19754
+ }
19755
+ catch {
19756
+ /* no results */
19757
+ }
19758
+ }
19759
+ return null;
19760
+ }
19761
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotFlightSearchService, deps: [{ token: ChatbotService }, { token: EnterpriseSearchService }, { token: ResultAwareService }, { token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
19762
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotFlightSearchService, providedIn: 'root' });
19763
+ }
19764
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotFlightSearchService, decorators: [{
19765
+ type: Injectable,
19766
+ args: [{ providedIn: 'root' }]
19767
+ }], ctorParameters: () => [{ type: ChatbotService }, { type: EnterpriseSearchService }, { type: ResultAwareService }, { type: UserService }] });
19768
+
19769
+ /** Maximum number of hotel cards to show in the chat widget. */
19770
+ const MAX_HOTEL_CARDS = 3;
19771
+ /** How many candidates to fetch availability for before slicing to MAX_HOTEL_CARDS. */
19772
+ const AVAILABILITY_CANDIDATE_COUNT = 6;
19773
+ /** Safety timeout (ms) for availability polling. */
19774
+ const HOTEL_AVAILABILITY_WAIT_MS = 30_000;
19775
+ /** How long to wait for JIT hotel rules (which set policyToken) before proceeding. */
19776
+ const JIT_RULES_WAIT_MS = 30_000;
19777
+ /**
19778
+ * Handles chatbot-driven hotel searches. Registered with
19779
+ * `ChatbotSearchDispatcherService`; not used directly.
19780
+ *
19781
+ * Populates the hotel search state from the chatbot's parameters, runs the
19782
+ * search headlessly, polls availability for the top candidates, then injects
19783
+ * a `ChatHotelResults` message so the chat widget can render hotel cards.
19784
+ * Works from any page — no search form component needs to be mounted.
19785
+ */
19786
+ class ChatbotHotelSearchService {
19787
+ chatbotService;
19788
+ searchService;
19789
+ hotelAvalibilityService;
19790
+ resultAwareService;
19791
+ travelType = 'hotel';
19792
+ availabilitySubscription = null;
19793
+ constructor(chatbotService, searchService, hotelAvalibilityService, resultAwareService) {
19794
+ this.chatbotService = chatbotService;
19795
+ this.searchService = searchService;
19796
+ this.hotelAvalibilityService = hotelAvalibilityService;
19797
+ this.resultAwareService = resultAwareService;
19798
+ }
19799
+ async handle(parameters, autoSearch) {
19800
+ this.searchService.resetSearchChosenObjects();
19801
+ this.searchService.resetSearchPriorities();
19802
+ this.searchService.search_objects[ServiceType.Hotel].chosen = true;
19803
+ this.searchService.search_objects[ServiceType.Hotel].originalChosen = true;
19804
+ this.searchService.determineHighestSearchPriority();
19805
+ const departDate = moment$1(parameters.departureDate);
19806
+ const departNgbDate = {
19807
+ year: departDate.year(),
19808
+ month: departDate.month() + 1,
19809
+ day: departDate.date()
19810
+ };
19811
+ await this.populateHotelParams(parameters, departDate, departNgbDate);
19812
+ if (!autoSearch) {
19813
+ return;
19814
+ }
19815
+ await this.runSearch(parameters);
19816
+ }
19817
+ // ── Search + availability ─────────────────────────────────────────────────
19818
+ async runSearch(parameters) {
19819
+ const hotelSearch = this.searchService.searches[ServiceType.Hotel];
19820
+ this.resultAwareService.clearResults();
19821
+ let hasResults = false;
19822
+ this.chatbotService.setSearching(true, 'hotel');
19823
+ hasResults = await hotelSearch.startSearch();
19824
+ if (!hasResults) {
19825
+ this.injectNoResultsMessage();
19826
+ this.chatbotService.setSearching(false);
19827
+ return;
19828
+ }
19829
+ await firstValueFrom(hotelSearch.jitRulesReceived.pipe(filter((received) => received), take(1), timeout({ first: JIT_RULES_WAIT_MS, with: () => of(false) })));
19830
+ const candidates = hotelSearch.results.value.slice(0, AVAILABILITY_CANDIDATE_COUNT);
19831
+ const availabilitySubjects = candidates.map((hotel) => this.hotelAvalibilityService.getAvailabilityForId(hotelSearch.makeHotelAvalilityObject(hotel), hotel));
19832
+ const allRoomsReady$ = combineLatest(availabilitySubjects).pipe(filter((results) => results.every((r) => r?.rooms !== undefined)), take(1));
19833
+ const fetchingDone$ = this.hotelAvalibilityService.fetching.pipe(skipWhile((fetching) => !fetching), filter((fetching) => !fetching), take(1));
19834
+ this.availabilitySubscription?.unsubscribe();
19835
+ this.availabilitySubscription = race(allRoomsReady$, fetchingDone$, timer(HOTEL_AVAILABILITY_WAIT_MS))
19836
+ .pipe(take(1), catchError$1((err) => {
19837
+ console.warn('[ChatbotHotelSearchService] availability polling error', err);
19838
+ this.chatbotService.setSearching(false);
19839
+ return EMPTY;
19840
+ }))
19841
+ .subscribe(() => {
19842
+ candidates.forEach((hotel, i) => {
19843
+ const availability = availabilitySubjects[i].value;
19844
+ if (availability?.rooms !== undefined) {
19845
+ const existingRooms = hotel.availableRates?.rooms ?? [];
19846
+ const rooms = (availability.rooms ?? []).map((room) => {
19847
+ if (!room || room.policyToken)
19848
+ return room;
19849
+ const match = existingRooms.find((r) => r?.roomId === room.roomId);
19850
+ return match?.policyToken ? { ...room, policyToken: match.policyToken } : room;
19851
+ });
19852
+ hotel.availableRates = { ...availability, rooms };
19853
+ }
19854
+ });
19855
+ this.sortHotels(candidates, parameters.sortType);
19856
+ const hotelsWithPrices = candidates
19857
+ .filter((hotel) => (hotel.availableRates?.rooms ?? []).some((r) => r?.total > 0))
19858
+ .slice(0, MAX_HOTEL_CARDS);
19859
+ this.resultAwareService.captureHotelResults(hotelsWithPrices);
19860
+ const condensed = this.resultAwareService.getCondensedResults();
19861
+ if (!condensed.length) {
19862
+ this.injectNoResultsMessage();
19863
+ this.chatbotService.setSearching(false);
19864
+ return;
19865
+ }
19866
+ const cards = this.buildHotelCards(condensed, hotelsWithPrices);
19867
+ const hotelSearch = this.searchService.searches[ServiceType.Hotel];
19868
+ const checkin = hotelSearch?.checkin_date
19869
+ ? moment$1(hotelSearch.checkin_date).format('D MMM')
19870
+ : '';
19871
+ const checkout = hotelSearch?.checkout_date
19872
+ ? moment$1(hotelSearch.checkout_date).format('D MMM')
19873
+ : '';
19874
+ const dateRange = checkin && checkout ? `${checkin} - ${checkout}` : '';
19875
+ const searchHeader = [parameters.arrival, dateRange].filter(Boolean).join(' · ');
19876
+ const hotelResults = { cards, searchHeader, parameters };
19877
+ this.chatbotService.patchAssistantMessage({ hotelResults, state: 'RESULTS_READY' });
19878
+ this.chatbotService.setSearching(false);
19879
+ });
19880
+ }
19881
+ // ── Card building ─────────────────────────────────────────────────────────
19882
+ buildHotelCards(condensed, rawHotels) {
19883
+ return condensed.slice(0, MAX_HOTEL_CARDS).map((r, i) => {
19884
+ const raw = rawHotels[i];
19885
+ const rooms = (raw?.availableRates?.rooms ?? [])
19886
+ .filter((room) => room && !room.unavailable && room.total > 0)
19887
+ .map((room) => ({
19888
+ roomId: room.roomId,
19889
+ description: room.roomDescription || room.roomType || 'Standard Room',
19890
+ total: room.total,
19891
+ prpn: room.prpn,
19892
+ currencyCode: room.currencyCode ?? 'GBP',
19893
+ unavailable: !!room.unavailable,
19894
+ policyStatus: room.requiresReasonKeys?.length
19895
+ ? 'ALLOW_WITH_REASON'
19896
+ : 'IN_POLICY'
19897
+ }));
19898
+ return {
19899
+ index: r.index,
19900
+ name: r.name ?? '',
19901
+ address: r.address ?? '',
19902
+ rating: r.rating ?? 0,
19903
+ distance: r.distance ?? 0,
19904
+ distanceUnit: r.distanceUnit ?? 'M',
19905
+ price: r.price,
19906
+ pricePerNight: r.pricePerNight ?? 0,
19907
+ dateRange: r.duration ?? '',
19908
+ policyStatus: r.policyStatus,
19909
+ policyMessages: r.policyMessages,
19910
+ co2: r.co2,
19911
+ currencyCode: rooms[0]?.currencyCode ?? 'GBP',
19912
+ rooms
19913
+ };
19914
+ });
19915
+ }
19916
+ injectNoResultsMessage() {
19917
+ this.chatbotService.injectMessage({
19918
+ id: `hotel-no-results-${Date.now()}`,
19919
+ role: 'assistant',
19920
+ text: 'No hotels found for your search. Try changing your dates or location.',
19921
+ timestamp: new Date(),
19922
+ state: 'SELECTING_RESULT'
19923
+ });
19924
+ }
19925
+ // ── Sort ──────────────────────────────────────────────────────────────────
19926
+ sortHotels(hotels, sortType) {
19927
+ switch (sortType) {
19928
+ case 'distance':
19929
+ hotels.sort((a, b) => (a.location?.distance ?? 0) - (b.location?.distance ?? 0));
19930
+ break;
19931
+ case 'name':
19932
+ hotels.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
19933
+ break;
19934
+ case 'preferred':
19935
+ hotels.sort((a, b) => {
19936
+ const aP = a.preferredType ? 1 : 0;
19937
+ const bP = b.preferredType ? 1 : 0;
19938
+ return bP - aP;
19939
+ });
19940
+ break;
19941
+ case 'cheapest':
19942
+ default:
19943
+ break;
19944
+ }
19945
+ }
19946
+ // ── Param population ──────────────────────────────────────────────────────
19947
+ async populateHotelParams(parameters, departDate, departNgbDate) {
19948
+ const hotelParams = this.searchService.searches[ServiceType.Hotel];
19949
+ hotelParams.checkin_date = departDate;
19950
+ hotelParams.checkin_date_ngb = departNgbDate;
19951
+ if (parameters.returnDate) {
19952
+ const checkoutDate = moment$1(parameters.returnDate);
19953
+ hotelParams.checkout_date = checkoutDate;
19954
+ hotelParams.checkout_date_ngb = {
19955
+ year: checkoutDate.year(),
19956
+ month: checkoutDate.month() + 1,
19957
+ day: checkoutDate.date()
19958
+ };
19959
+ }
19960
+ else {
19961
+ const checkoutDate = departDate.clone().add(1, 'day');
19962
+ hotelParams.checkout_date = checkoutDate;
19963
+ hotelParams.checkout_date_ngb = {
19964
+ year: checkoutDate.year(),
19965
+ month: checkoutDate.month() + 1,
19966
+ day: checkoutDate.date()
19967
+ };
19968
+ }
19969
+ hotelParams.no_of_rooms = parameters.rooms || 1;
19970
+ hotelParams.no_of_occupants = parameters.passengers || 1;
19971
+ if (parameters.hotelName) {
19972
+ hotelParams.hotel_name = parameters.hotelName;
19973
+ }
19974
+ if (parameters.hotelChain) {
19975
+ const term = parameters.hotelChain.toLowerCase();
19976
+ const prefix = parameters.hotelChain.slice(0, 3);
19977
+ const chains = await firstValueFrom(this.searchService.getHotelChain(prefix));
19978
+ if (chains?.length > 0) {
19979
+ const exact = chains.find((c) => c.name.toLowerCase() === term);
19980
+ const startsWithMatches = chains
19981
+ .filter((c) => c.name.toLowerCase().startsWith(term))
19982
+ .sort((a, b) => a.name.length - b.name.length);
19983
+ const includes = chains.find((c) => c.name.toLowerCase().includes(term));
19984
+ hotelParams.hotel_chain = exact ?? startsWithMatches[0] ?? includes ?? chains[0];
19985
+ }
19986
+ }
19987
+ if (parameters.distance) {
19988
+ hotelParams.distance = parameters.distance;
19989
+ }
19990
+ if (parameters.preferredOnly) {
19991
+ hotelParams.prefered_hotels_only = parameters.preferredOnly;
19992
+ }
19993
+ if (parameters.crownRatesOnly) {
19994
+ hotelParams.crownRatesOnly = parameters.crownRatesOnly;
19995
+ }
19996
+ if (parameters.propertyNumber) {
19997
+ hotelParams.location_type_select = LocationTypes.PropertyNumber;
19998
+ hotelParams.propertyNumber = parameters.propertyNumber;
19999
+ }
20000
+ else {
20001
+ const locationType = parameters.locationType || 'address';
20002
+ const locationTypeMap = {
20003
+ address: LocationTypes.Address,
20004
+ office: LocationTypes.Office,
20005
+ shortlist: LocationTypes.Shortlist,
20006
+ airport: LocationTypes.Address,
20007
+ trainstation: LocationTypes.Address
20008
+ };
20009
+ const resolvedLocationType = locationTypeMap[locationType] ?? LocationTypes.Address;
20010
+ hotelParams.location_type_select = resolvedLocationType;
20011
+ if (resolvedLocationType === LocationTypes.Office) {
20012
+ const offices = await firstValueFrom(this.searchService.getOfficeLocationsNoUserAddresses(''));
20013
+ if (offices?.length > 0) {
20014
+ const searchTerm = parameters.arrival?.toLowerCase() ?? '';
20015
+ const match = offices.find((o) => o.name.toLowerCase().includes(searchTerm)) ?? offices[0];
20016
+ hotelParams.office = match;
20017
+ }
20018
+ }
20019
+ else if (resolvedLocationType === LocationTypes.Address) {
20020
+ const arrivalRaw = parameters.arrival;
20021
+ const typeaheadQuery = arrivalRaw.replace(/,\s*/g, ' ').trim();
20022
+ const locations = await firstValueFrom(this.searchService.getDiscoverLocations(typeaheadQuery));
20023
+ if (locations?.length > 0) {
20024
+ const preferredType = locationType === 'trainstation'
20025
+ ? LocationTypes.TrainStation
20026
+ : locationType === 'airport'
20027
+ ? LocationTypes.Airport
20028
+ : LocationTypes.City;
20029
+ const normalised = typeaheadQuery
20030
+ .toLowerCase()
20031
+ .replace(/\b(station|airport|hub|central station)\b/g, '')
20032
+ .trim();
20033
+ const ofType = locations.filter((l) => l.type === preferredType);
20034
+ const match = ofType.find((l) => l.name.toLowerCase().includes(normalised.split(' ')[0])) ??
20035
+ ofType[0] ??
20036
+ locations.find((l) => l.type === LocationTypes.City) ??
20037
+ locations[0];
20038
+ hotelParams.location = match;
20039
+ }
20040
+ }
20041
+ else if (resolvedLocationType === LocationTypes.Shortlist && parameters.country) {
20042
+ const countryInput = parameters.country.toLowerCase();
20043
+ const match = this.searchService.countries?.find((c) => c.cCode.toLowerCase() === countryInput || c.cName.toLowerCase() === countryInput);
20044
+ if (match) {
20045
+ hotelParams.country = match;
20046
+ }
20047
+ }
20048
+ }
20049
+ }
20050
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotHotelSearchService, deps: [{ token: ChatbotService }, { token: EnterpriseSearchService }, { token: HotelAvalibilityService }, { token: ResultAwareService }], target: i0.ɵɵFactoryTarget.Injectable });
20051
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotHotelSearchService, providedIn: 'root' });
20052
+ }
20053
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotHotelSearchService, decorators: [{
20054
+ type: Injectable,
20055
+ args: [{ providedIn: 'root' }]
20056
+ }], ctorParameters: () => [{ type: ChatbotService }, { type: EnterpriseSearchService }, { type: HotelAvalibilityService }, { type: ResultAwareService }] });
20057
+
20058
+ /** Safety timeout (ms) waiting for eurostar results. */
20059
+ const EUROSTAR_RESULTS_WAIT_MS = 60_000;
20060
+ /** Maximum number of outbound/inbound cards to surface in the chat widget. */
20061
+ const MAX_EUROSTAR_CARDS = 3;
20062
+ /**
20063
+ * Handles chatbot-driven Eurostar searches. Registered with
20064
+ * `ChatbotSearchDispatcherService`; not used directly.
20065
+ *
20066
+ * Populates the Eurostar search state from the chatbot's parameters and, when
20067
+ * `autoSearch` is true, runs the search headlessly so it works from any page.
20068
+ * Once results arrive, builds `ChatEurostarResults` and patches them onto the
20069
+ * last assistant message via {@link ChatbotService.patchAssistantMessage}.
20070
+ */
20071
+ class ChatbotEurostarSearchService {
20072
+ chatbotService;
20073
+ searchService;
20074
+ userService;
20075
+ travelType = 'eurostar';
20076
+ resultsSubscription = null;
20077
+ constructor(chatbotService, searchService, userService) {
20078
+ this.chatbotService = chatbotService;
20079
+ this.searchService = searchService;
20080
+ this.userService = userService;
20081
+ }
20082
+ async handle(parameters, autoSearch) {
20083
+ this.searchService.resetSearchChosenObjects();
20084
+ this.searchService.resetSearchPriorities();
20085
+ this.searchService.search_objects[ServiceType.Eurostar].chosen = true;
20086
+ this.searchService.search_objects[ServiceType.Eurostar].originalChosen = true;
20087
+ this.searchService.determineHighestSearchPriority();
20088
+ // Auto-add the signed-in user as the traveller when none is selected so
20089
+ // the search isn't blocked by the "add a traveller" validation rule.
20090
+ // Matches the rail handler pattern.
20091
+ if (this.searchService.travellerInformation.value.length === 0) {
20092
+ const selfTraveller = this.userService.createSelfTraveller();
20093
+ if (selfTraveller) {
20094
+ this.searchService.addTraveller(selfTraveller);
20095
+ }
20096
+ }
20097
+ const departDate = moment$1(parameters.departureDate);
20098
+ const departNgbDate = {
20099
+ year: departDate.year(),
20100
+ month: departDate.month() + 1,
20101
+ day: departDate.date()
20102
+ };
20103
+ await this.populateEurostarParams(parameters, departNgbDate);
20104
+ if (!autoSearch) {
20105
+ return;
20106
+ }
20107
+ await this.runSearch(parameters);
20108
+ }
20109
+ // ── Search ────────────────────────────────────────────────────────────────
20110
+ async runSearch(parameters) {
20111
+ const eurostarSearch = this.searchService.searches[ServiceType.Eurostar];
20112
+ // Surface OBT's existing validation (past dates, missing stations,
20113
+ // same origin/destination, return-before-depart, incompatible cabins)
20114
+ // before triggering the search — matches the rail handler pattern.
20115
+ const validationMessages = Array.isArray(eurostarSearch.validationMessages)
20116
+ ? eurostarSearch.validationMessages.filter(Boolean)
20117
+ : [];
20118
+ if (validationMessages.length) {
20119
+ this.chatbotService.patchAssistantMessage({
20120
+ text: this.formatValidationMessages(validationMessages),
20121
+ state: 'RESULTS_READY'
20122
+ });
20123
+ this.chatbotService.setSearching(false);
20124
+ return;
20125
+ }
20126
+ this.subscribeToResults(parameters);
20127
+ let started = false;
20128
+ try {
20129
+ started = await eurostarSearch.startSearch();
20130
+ }
20131
+ catch (err) {
20132
+ console.warn('[ChatbotEurostarSearchService] startSearch threw', err);
20133
+ }
20134
+ if (!started) {
20135
+ this.resultsSubscription?.unsubscribe();
20136
+ this.resultsSubscription = null;
20137
+ // Re-read validation messages in case a late-firing setter pushed new
20138
+ // ones (e.g. station resolution returning nothing).
20139
+ const lateMessages = Array.isArray(eurostarSearch.validationMessages)
20140
+ ? eurostarSearch.validationMessages.filter(Boolean)
20141
+ : [];
20142
+ this.chatbotService.patchAssistantMessage({
20143
+ text: lateMessages.length
20144
+ ? this.formatValidationMessages(lateMessages)
20145
+ : `I couldn't run that Eurostar search — please check the dates and stations and try again.`,
20146
+ state: 'RESULTS_READY'
20147
+ });
20148
+ this.chatbotService.setSearching(false);
20149
+ }
20150
+ }
20151
+ /**
20152
+ * Render OBT's validationMessages array as a chatbot reply. Single message →
20153
+ * inline sentence; multiple → bullet list so each issue reads clearly.
20154
+ */
20155
+ formatValidationMessages(messages) {
20156
+ if (messages.length === 1) {
20157
+ return `I couldn't run that Eurostar search — ${messages[0]}. Please adjust and try again.`;
20158
+ }
20159
+ const bullets = messages.map((m) => `• ${m}`).join('\n');
20160
+ return `I couldn't run that Eurostar search — please fix the following and try again:\n${bullets}`;
20161
+ }
20162
+ subscribeToResults(parameters) {
20163
+ this.resultsSubscription?.unsubscribe();
20164
+ const eurostarSearch = this.searchService.searches[ServiceType.Eurostar];
20165
+ this.chatbotService.setSearching(true, 'eurostar');
20166
+ // Use `isLoading` (true → false) as the search-complete signal, matching
20167
+ // the flight handler pattern. This correctly handles empty result sets
20168
+ // where waiting on results.length > 0 would hang until the timeout.
20169
+ const loadingSubject = eurostarSearch.isLoading;
20170
+ this.resultsSubscription = loadingSubject
20171
+ .pipe(skip(1), filter((loading) => loading === false), take(1), timeout$1(EUROSTAR_RESULTS_WAIT_MS), catchError$1((err) => {
20172
+ console.warn('[ChatbotEurostarSearchService] results timed out or errored', err);
20173
+ this.chatbotService.patchAssistantMessage({
20174
+ text: `The Eurostar search took too long to respond. Please try again in a moment.`,
20175
+ state: 'RESULTS_READY'
20176
+ });
20177
+ this.chatbotService.setSearching(false);
20178
+ return EMPTY;
20179
+ }))
20180
+ .subscribe(() => {
20181
+ const rawResults = eurostarSearch.results?.value ?? [];
20182
+ const isReturn = !!parameters.returnDate;
20183
+ // Results may come as EurostarResults[] (with .outbound/.inbound) or
20184
+ // as a flat array of items depending on the supplier path.
20185
+ const outboundItems = this.extractItems(rawResults, 'outbound');
20186
+ const inboundItems = isReturn ? this.extractItems(rawResults, 'inbound') : [];
20187
+ const outbound = outboundItems
20188
+ .slice(0, MAX_EUROSTAR_CARDS)
20189
+ .map((item, i) => this.buildCard(item, i));
20190
+ const inbound = inboundItems
20191
+ .slice(0, MAX_EUROSTAR_CARDS)
20192
+ .map((item, i) => this.buildCard(item, i));
20193
+ const eurostarResults = {
20194
+ outbound,
20195
+ ...(isReturn && inbound.length ? { inbound } : {}),
20196
+ isReturn,
20197
+ parameters
20198
+ };
20199
+ this.chatbotService.patchAssistantMessage({ eurostarResults, state: 'RESULTS_READY' });
20200
+ this.chatbotService.setSearching(false);
20201
+ });
20202
+ }
20203
+ // ── Result helpers ────────────────────────────────────────────────────────
20204
+ extractItems(results, direction) {
20205
+ if (!results?.length) {
20206
+ return [];
20207
+ }
20208
+ // EurostarResults shape: [{ outbound: EurostarItem[], inbound: EurostarItem[] }].
20209
+ // Detect by scanning any item rather than the first, in case the first
20210
+ // wrapper is empty for one direction.
20211
+ const hasWrappedShape = results.some((r) => r && direction in r);
20212
+ if (hasWrappedShape) {
20213
+ return results.flatMap((r) => r?.[direction] ?? []);
20214
+ }
20215
+ // Flat array of EurostarQuoteResult journeys
20216
+ return results;
20217
+ }
20218
+ buildCard(item, index) {
20219
+ const fares = [];
20220
+ for (const cls of ['standardFare', 'standardPremierFare', 'businessPremierFare']) {
20221
+ const fare = item[cls];
20222
+ if (!fare || fare.isDisabled) {
20223
+ continue;
20224
+ }
20225
+ const isUnavailable = !!fare.unavailable;
20226
+ fares.push({
20227
+ class: fare.class ?? cls,
20228
+ price: fare.price ?? 0,
20229
+ currency: fare.currency ?? 'GBP',
20230
+ policyStatus: isUnavailable
20231
+ ? 'UNAVAILABLE'
20232
+ : fare.requiresReasonKeys?.length
20233
+ ? 'ALLOW_WITH_REASON'
20234
+ : 'IN_POLICY',
20235
+ policyMessages: fare.requiresReasonMessages ?? [],
20236
+ unavailable: isUnavailable
20237
+ });
20238
+ }
20239
+ return {
20240
+ index,
20241
+ timeDeparture: item.timeDeparture ?? '',
20242
+ timeArrival: item.timeArrival ?? '',
20243
+ duration: item.duration ?? '',
20244
+ fares,
20245
+ co2PerPassenger: item.co2PerPassenger ?? 0
20246
+ };
20247
+ }
20248
+ // ── Param population ──────────────────────────────────────────────────────
20249
+ async populateEurostarParams(parameters, departNgbDate) {
20250
+ const eurostarParams = this.searchService.searches[ServiceType.Eurostar];
20251
+ eurostarParams.departDate = departNgbDate;
20252
+ if (parameters.departureTime) {
20253
+ eurostarParams.departTime = this.normalizeTime(parameters.departureTime);
20254
+ eurostarParams.outTimeCriteria =
20255
+ parameters.outboundTimeCriteria === 'Arrive' ? TimeWindow.Arrive : TimeWindow.Depart;
20256
+ }
20257
+ else {
20258
+ eurostarParams.outTimeCriteria = TimeWindow.Anytime;
20259
+ }
20260
+ if (parameters.returnDate) {
20261
+ const returnDate = moment$1(parameters.returnDate);
20262
+ eurostarParams.returnDate = {
20263
+ year: returnDate.year(),
20264
+ month: returnDate.month() + 1,
20265
+ day: returnDate.date()
20266
+ };
20267
+ eurostarParams.chosenSearchType = EurostarSearchType.return;
20268
+ if (parameters.returnTime) {
20269
+ eurostarParams.arriveTime = this.normalizeTime(parameters.returnTime);
20270
+ eurostarParams.inTimeCriteria =
20271
+ parameters.returnTimeCriteria === 'Arrive' ? TimeWindow.Arrive : TimeWindow.Depart;
20272
+ }
20273
+ else {
20274
+ eurostarParams.inTimeCriteria = TimeWindow.Anytime;
20275
+ }
20276
+ }
20277
+ else {
20278
+ eurostarParams.chosenSearchType = EurostarSearchType.oneWay;
20279
+ }
20280
+ // Map the ai-agents cabin class string to the FlightCabinClass enum values
20281
+ // used by the Eurostar search class internals. Always set both outbound
20282
+ // and return cabin classes — `updateSerchQuery` calls
20283
+ // `turnCabinTypeToName(returnCabinClass)` on return trips and crashes if
20284
+ // it's undefined. Keeping them in sync also satisfies the cabin-match
20285
+ // validation rule (`checkCabinMatchisValid`).
20286
+ const mappedCabin = this.mapCabinClass(parameters.cabinClass);
20287
+ eurostarParams.cabinClass = mappedCabin;
20288
+ eurostarParams.returnCabinClass = mappedCabin;
20289
+ // Always set maxConnections so a previous "direct only" search doesn't
20290
+ // persist when the user removes that constraint. `null` = no limit.
20291
+ eurostarParams.maxConnections =
20292
+ parameters.maxConnections !== undefined && parameters.maxConnections !== null
20293
+ ? parameters.maxConnections
20294
+ : null;
20295
+ const [fromStation, toStation] = await Promise.all([
20296
+ this.resolveStation(parameters.departureCode, parameters.departure),
20297
+ this.resolveStation(parameters.arrivalCode, parameters.arrival)
20298
+ ]);
20299
+ if (fromStation) {
20300
+ eurostarParams.departLocation = fromStation;
20301
+ }
20302
+ if (toStation) {
20303
+ eurostarParams.arriveLocation = toStation;
20304
+ }
20305
+ }
20306
+ mapCabinClass(cabinClass) {
20307
+ switch (cabinClass) {
20308
+ case 'Standard':
20309
+ return FlightCabinClass.Economy;
20310
+ case 'StandardPremier':
20311
+ return FlightCabinClass.PremiumEconomy;
20312
+ case 'BusinessPremier':
20313
+ return FlightCabinClass.Business;
20314
+ default:
20315
+ return FlightCabinClass.Any;
20316
+ }
20317
+ }
20318
+ async resolveStation(code, name) {
20319
+ if (code) {
20320
+ try {
20321
+ const byCode = await firstValueFrom(this.searchService.lookupEurostarStations(code));
20322
+ if (byCode?.length > 0) {
20323
+ return byCode.find((s) => s.gateway === code) ?? byCode[0];
20324
+ }
20325
+ }
20326
+ catch (err) {
20327
+ console.warn('[ChatbotEurostarSearchService] station lookup by code failed', { code }, err);
20328
+ }
20329
+ }
20330
+ if (name) {
20331
+ try {
20332
+ const byName = await firstValueFrom(this.searchService.lookupEurostarStations(name));
20333
+ if (byName?.length > 0) {
20334
+ return byName[0];
20335
+ }
20336
+ }
20337
+ catch (err) {
20338
+ console.warn('[ChatbotEurostarSearchService] station lookup by name failed', { name }, err);
20339
+ }
20340
+ }
20341
+ return null;
20342
+ }
20343
+ normalizeTime(time) {
20344
+ const parsed = moment$1(time, ['HH:mm', 'H:mm', 'ha', 'h:mma', 'HHmm']);
20345
+ return parsed.isValid() ? parsed.format('HHmm') : time;
20346
+ }
20347
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotEurostarSearchService, deps: [{ token: ChatbotService }, { token: EnterpriseSearchService }, { token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
20348
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotEurostarSearchService, providedIn: 'root' });
20349
+ }
20350
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotEurostarSearchService, decorators: [{
20351
+ type: Injectable,
20352
+ args: [{ providedIn: 'root' }]
20353
+ }], ctorParameters: () => [{ type: ChatbotService }, { type: EnterpriseSearchService }, { type: UserService }] });
20354
+
20355
+ /**
20356
+ * Routes `ChatbotService.fillSearchForm$` events to per-travel-type handlers.
20357
+ *
20358
+ * **To add a new travel type (hotel / eurostar / taxi / …):**
20359
+ * 1. Create a new service implementing `ChatbotTravelHandler` (use
20360
+ * `ChatbotRailSearchService` or `ChatbotFlightSearchService` as a
20361
+ * reference implementation).
20362
+ * 2. Inject it into this dispatcher and add it to {@link handlers}.
20363
+ * 3. Nothing else needs to change — the consuming app calls {@link init}
20364
+ * once (typically from its root component's `ngOnInit`), and search
20365
+ * forms can ask {@link handles} which travel types to skip.
20366
+ */
20367
+ class ChatbotSearchDispatcherService {
20368
+ chatbotService;
20369
+ initialised = false;
20370
+ handlers;
20371
+ constructor(chatbotService, rail, flight, hotel, eurostar) {
20372
+ this.chatbotService = chatbotService;
20373
+ this.handlers = [rail, flight, hotel, eurostar];
20374
+ }
20375
+ /** Call once at app start. Idempotent. */
20376
+ init() {
20377
+ if (this.initialised) {
20378
+ return;
20379
+ }
20380
+ this.initialised = true;
20381
+ this.chatbotService.fillSearchForm$.subscribe(({ parameters, autoSearch }) => {
20382
+ const handler = this.findHandler(parameters?.travelType);
20383
+ if (!handler) {
20384
+ // No global handler registered for this travel type — falls through
20385
+ // to the consuming app's per-form flow.
20386
+ return;
20387
+ }
20388
+ handler.handle(parameters, autoSearch).catch((err) => {
20389
+ console.error(`[ChatbotSearchDispatcherService] handler '${parameters.travelType}' failed:`, err);
20390
+ });
20391
+ });
20392
+ }
20393
+ /**
20394
+ * Whether a global handler is registered for the given travel type. Used by
20395
+ * search forms to know which travel types they should skip (avoiding
20396
+ * double-handling).
20397
+ */
20398
+ handles(travelType) {
20399
+ return !!this.findHandler(travelType);
20400
+ }
20401
+ findHandler(travelType) {
20402
+ if (!travelType) {
20403
+ return undefined;
20404
+ }
20405
+ return this.handlers.find((h) => h.travelType === travelType);
20406
+ }
20407
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotSearchDispatcherService, deps: [{ token: ChatbotService }, { token: ChatbotRailSearchService }, { token: ChatbotFlightSearchService }, { token: ChatbotHotelSearchService }, { token: ChatbotEurostarSearchService }], target: i0.ɵɵFactoryTarget.Injectable });
20408
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotSearchDispatcherService, providedIn: 'root' });
20409
+ }
20410
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotSearchDispatcherService, decorators: [{
20411
+ type: Injectable,
20412
+ args: [{ providedIn: 'root' }]
20413
+ }], ctorParameters: () => [{ type: ChatbotService }, { type: ChatbotRailSearchService }, { type: ChatbotFlightSearchService }, { type: ChatbotHotelSearchService }, { type: ChatbotEurostarSearchService }] });
20414
+
17828
20415
  class BasketPanelComponent extends WithSubscriptionComponent {
17829
20416
  basketService;
17830
20417
  userService;
@@ -17934,13 +20521,17 @@ class BasketPanelComponent extends WithSubscriptionComponent {
17934
20521
  // /itinerary
17935
20522
  const requiresApproval = this.selectedBasket.subject.value.requiresManualApproval;
17936
20523
  const navigateTo = this.basketService.continueSearchAndBook(basketItems, this.getItineraryUrl(this.selectedBasket.id), this.searchService);
17937
- if (navigateTo && !(navigateTo[0] === '/itinerary' || navigateTo[0] === '/basket/booking-details')) { // ! - itinerary - lightning - booking-details -scion
20524
+ if (navigateTo &&
20525
+ !(navigateTo[0] === '/itinerary' || navigateTo[0] === '/basket/booking-details')) {
20526
+ // ! - itinerary - lightning - booking-details -scion
17938
20527
  this.router.navigate(navigateTo);
17939
20528
  }
17940
20529
  else if (navigateTo) {
17941
20530
  if (requiresApproval) {
17942
20531
  console.warn(`+++ Basket requires approval - display warning modal +++`);
17943
- this.modalService.open(ModalTypes.ApprovalWarningModalComponent, { backdrop: 'static' }).then(result => {
20532
+ this.modalService
20533
+ .open(ModalTypes.ApprovalWarningModalComponent, { backdrop: 'static' })
20534
+ .then((result) => {
17944
20535
  if (result) {
17945
20536
  console.log(`+++ User has selected continue +++`);
17946
20537
  this.router.navigate(navigateTo);
@@ -18085,7 +20676,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
18085
20676
  type: Pipe,
18086
20677
  args: [{
18087
20678
  name: 'memoize',
18088
- pure: true, //can be omitted as default value
20679
+ pure: true //can be omitted as default value
18089
20680
  }]
18090
20681
  }] });
18091
20682
 
@@ -18109,5 +20700,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImpo
18109
20700
  * Generated bundle index. Do not edit.
18110
20701
  */
18111
20702
 
18112
- export { AcceptNewPriceDocument, AcceptNewPriceGQL, AcceptNewPriceUpdater, AccessibilityInfoFragmentDoc, AddBasketItemCustomRemarkDocument, AddBasketItemCustomRemarkGQL, AddBasketItemCustomRemarkUpdater, AddBasketItemMarkupDocument, AddBasketItemMarkupGQL, AddBasketItemMarkupUpdater, AddFavouriteUserDocument, AddFavouriteUserGQL, AddFavouriteUserUpdater, AddGuestToBasketItemUpdater, AddGuestsToBasketItemDocument, AddGuestsToBasketItemGQL, AddItemToBasketDocument, AddItemToBasketGQL, AddItemToBasketUpdater, AddRedirectApproverDocument, AddRedirectApproverGQL, AddRedirectApproverUpdater, AddToBasketFieldsFragmentDoc, AddUpdatedItemToBasketDocument, AddUpdatedItemToBasketGQL, AddUpdatedItemToBasketUpdater, AddUserToBasketItemUpdater, AddUsersToBasketItemDocument, AddUsersToBasketItemGQL, AddressType, AmendBookingDocument, AmendBookingGQL, AmendBookingUpdater, ApexxCardStatus, ApexxCreateCardDocument, ApexxCreateCardGQL, ApexxDeleteCardDocument, ApexxDeleteCardGQL, ApexxDeleteCardUpdater, ApexxListCardsDocument, ApexxListCardsGQL, ApexxUpdateCardDocument, ApexxUpdateCardGQL, ApexxUpdateCardUpdater, ApplyJitFlightRulesDocument, ApplyJitFlightRulesGQL, ApplyJitHotelRulesDocument, ApplyJitHotelRulesGQL, ApprovalEventType, ApproverUserFieldsFragmentDoc, AuthHttpService, BaggageType, BannerDisplayTarget, BasketFieldsFragmentDoc, BasketItemStatus, BasketMinimalFieldsFragmentDoc, BasketPanelComponent, BasketStatus, BeforeAmendCabSearchDocument, BeforeAmendCabSearchFetcher, BeforeAmendCabSearchGQL, BeforeAmendCarHireSearchDocument, BeforeAmendCarHireSearchFetcher, BeforeAmendCarHireSearchGQL, BookBasketDocument, BookBasketFieldsFragmentDoc, BookBasketGQL, BookBasketUpdater, BookerType, CabHireVehicleType, CabhireQuoteFetcher, CanAmendBookingDocument, CanAmendBookingFetcher, CanAmendBookingGQL, CancelBookingDocument, CancelBookingGQL, CancelBookingUpdater, CarHireAvailabilityDetailFetcher, CarHireAvailabilityDetailRequestDocument, CarHireAvailabilityDetailRequestGQL, CarHireClass, CarHireTransmission, CarHireType, CarbonPolicyDuration, CarbonPolicySource, CarhireQuoteFetcher, ChangeBasketOwnershipDocument, ChangeBasketOwnershipGQL, ChangeBasketOwnershipUpdater, ChangeMode, ChatbotService, CheckForDuplicateBookingsDocument, CheckForDuplicateBookingsFetcher, CheckForDuplicateBookingsGQL, CheckIfBasketRequiresApprovalDocument, CheckIfBasketRequiresApprovalFetcher, CheckIfBasketRequiresApprovalGQL, CompanyType, ConfirmMessagesDocument, ConfirmMessagesGQL, ConvertCurrencyDocument, ConvertCurrencyFetcher, ConvertCurrencyGQL, CreateBasketDocument, CreateBasketFieldsFragmentDoc, CreateBasketFromDraftDocument, CreateBasketFromDraftGQL, CreateBasketFromDraftUpdater, CreateBasketGQL, CreateBasketNoteDocument, CreateBasketNoteGQL, CreateBasketNoteUpdater, CreateBasketUpdater, CreateGuestDocument, CreateGuestGQL, CreateGuestUpdater, CreateItineraryExchangeDocument, CreateItineraryExchangeGQL, CurrencyCode, CycleInfoFragmentDoc, DeleteAllRecentSearchesDocument, DeleteAllRecentSearchesGQL, DeleteAllRecentSearchesUpdater, DeleteBasketDocument, DeleteBasketGQL, DeleteBasketUpdater, DeleteFavouriteSearchDocument, DeleteFavouriteSearchGQL, DeleteFavouriteSearchUpdater, DeleteGuestDocument, DeleteGuestGQL, DeleteGuestUpdater, DeleteRecentSearchDocument, DeleteRecentSearchGQL, DeleteUserAddressDocument, DeleteUserAddressGQL, DiscountType, DistanceTypes, DivisionFieldsFragmentDoc, DocGender, DocType, DraftBasketType, EditUserAddressDocument, EditUserAddressGQL, EditUserAddressUpdater, EditUserDocument, EditUserGQL, EmailAmbulanceBookingFetcher, EmailAmbulanceBookingReqDocument, EmailAmbulanceBookingReqGQL, EmailApartmentBookingFetcher, EmailApartmentBookingReqDocument, EmailApartmentBookingReqGQL, EmailBasketDocument, EmailBasketFetcher, EmailBasketGQL, EmailFerryBookingFetcher, EmailFerryBookingReqDocument, EmailFerryBookingReqGQL, EmailMeetingRoomBookingFetcher, EmailMeetingRoomBookingReqDocument, EmailMeetingRoomBookingReqGQL, EmailSeasonTicketBookingFetcher, EmailSeasonTicketBookingReqDocument, EmailSeasonTicketBookingReqGQL, EntLocationsByCityDocument, EntLocationsByCityGQL, EntLocationsByPostcodeDocument, EntLocationsByPostcodeGQL, EnterpriseBasketService, EnterpriseMyBookingsService, EnterpriseSearchService, Environment, ErrorsFragmentDoc, EurostarQuoteFetcher, EventMessenager, EvolviSeatmapsAreEnabledDocument, EvolviSeatmapsAreEnabledGQL, ExchangeType, ExternalHttpService, FailedEmail, FareRuleType, FareType, FerryOrEurotunnel, FlightCabinClass, FlightItineraryFieldsFragmentDoc, FlightPassengerType, FlightQuoteFetcher, GenerateBasketPdfDocument, GenerateBasketPdfFetcher, GenerateBasketPdfGQL, GetAirAvailabilityDocument, GetAirAvailabilityFetcher, GetAirAvailabilityGQL, GetAllAirlinesDocument, GetAllAirlinesFetcher, GetAllAirlinesGQL, GetApexxListCardsFetcher, GetBannerDocument, GetBannerFetcher, GetBannerGQL, GetBasketApprovalInfoDocument, GetBasketApprovalInfoFetcher, GetBasketApprovalInfoGQL, GetBasketApprovalTimestampsDocument, GetBasketApprovalTimestampsGQL, GetBasketCo2InfoFetcher, GetBasketFetcher, GetBasketItemCustomRemarksDocument, GetBasketItemCustomRemarksFetcher, GetBasketItemCustomRemarksGQL, GetBasketNotesDocument, GetBasketNotesFetcher, GetBasketNotesGQL, GetBasketQuoteDocument, GetBasketQuoteFetcher, GetBasketQuoteGQL, GetBrandedFaresDocument, GetBrandedFaresGQL, GetCancellationInfoDocument, GetCancellationInfoFetcher, GetCancellationInfoGQL, GetCarHireDepotsDocument, GetCarHireDepotsGQL, GetCarHireProvidersDocument, GetCarHireProvidersFetcher, GetCarHireProvidersGQL, GetCompaniesDocument, GetCompaniesFetcher, GetCompaniesGQL, GetCompanyDocument, GetCompanyFetcher, GetCompanyGQL, GetConfermaQuicklistDocument, GetConfermaQuicklistGQL, GetConfermaRoomImagesDocument, GetConfermaRoomImagesGQL, GetCovidMicrositeTokenDocument, GetCovidMicrositeTokenFetcher, GetCovidMicrositeTokenGQL, GetCurrencyConversionRatesDocument, GetCurrencyConversionRatesFetcher, GetCurrencyConversionRatesGQL, GetDivisionDocument, GetDivisionGQL, GetDraftBasketsDocument, GetDraftBasketsFetcher, GetDraftBasketsGQL, GetEmptyUserMiDefaultValuesDocument, GetEmptyUserMiDefaultValuesFetcher, GetEmptyUserMiDefaultValuesGQL, GetEntLocationByPostcode, GetEvolviSeatmapsAreEnabledFetcher, GetFerryPortsDocument, GetFerryPortsFetcher, GetFerryPortsGQL, GetFlightAtNewClassDocument, GetFlightAtNewClassFetcher, GetFlightAtNewClassGQL, GetFlightBrandedFaresFetcher, GetFlightExchangeDetailsDocument, GetFlightExchangeDetailsFetcher, GetFlightExchangeDetailsGQL, GetFlightExtrasOptionsDocument, GetFlightExtrasOptionsFetcher, GetFlightExtrasOptionsGQL, GetFlightFareRulesDocument, GetFlightFareRulesFetcher, GetFlightFareRulesGQL, GetFlightSearchExchangeDocument, GetFlightSearchExchangeFetcher, GetFlightSearchExchangeGQL, GetFlightSeatMapDocument, GetFlightSeatMapFetcher, GetFlightSeatMapGQL, GetFlightUpsellOffersDocument, GetFlightUpsellOffersFetcher, GetFlightUpsellOffersGQL, GetGmtItineraryOptionsDocument, GetGmtItineraryOptionsFetcher, GetGmtItineraryOptionsGQL, GetGutCitySuggestionsDocument, GetGutCitySuggestionsFetcher, GetGutCitySuggestionsGQL, GetGutLocationSuggestionsDocument, GetGutLocationSuggestionsFetcher, GetGutLocationSuggestionsGQL, GetHotelChainsDocument, GetHotelChainsFetcher, GetHotelChainsGQL, GetHotelDetailsDocument, GetHotelDetailsFetcher, GetHotelDetailsGQL, GetIrlDiscountCardsDocument, GetIrlDiscountCardsGQL, GetIrlSupplierStationDocument, GetIrlSupplierStationFetcher, GetIrlSupplierStationGQL, GetLatLonFromHereIdDocument, GetLatLonFromHereIdFetcher, GetLatLonFromHereIdGQL, GetLatestVersionsDocument, GetLatestVersionsFetcher, GetLatestVersionsGQL, GetMIApproversFetcher, GetMiApproversDocument, GetMiApproversGQL, GetMiRequiringMandatoryDefaultValueDocument, GetMiRequiringMandatoryDefaultValueFetcher, GetMiRequiringMandatoryDefaultValueGQL, GetMultipleHotelRatingDocument, GetMultipleHotelRatingFetcher, GetMultipleHotelRatingGQL, GetMultipleHotelsAvailabilityDocument, GetMultipleHotelsAvailabilityGQL, GetOfficeApproversDocument, GetOfficeApproversFetcher, GetOfficeApproversGQL, GetOfficeDivisionsDocument, GetOfficeDivisionsFetcher, GetOfficeDivisionsGQL, GetOfficeDocument, GetOfficeFetcher, GetOfficeGQL, GetOfficeUsersDocument, GetOfficeUsersFetcher, GetOfficeUsersGQL, GetOfficesDocument, GetOfficesFetcher, GetOfficesGQL, GetPriceHiddenSabreExchangeDocument, GetPriceHiddenSabreExchangeFetcher, GetPriceHiddenSabreExchangeGQL, GetRailcardsFetcher as GetRailCardsFetcher, GetRailLiveDeparturesDocument, GetRailLiveDeparturesFetcher, GetRailLiveDeparturesGQL, GetRailProvidersDocument, GetRailProvidersFetcher, GetRailProvidersGQL, GetRailSearchExchangeDocument, GetRailSearchExchangeGQL, GetRailStationDocument, GetRailStationFetcher, GetRailStationGQL, GetRailStationInfoDocument, GetRailStationInfoFetcher, GetRailStationInfoGQL, GetRailcardsDocument, GetRailcardsFetcher, GetRailcardsGQL, GetRedirectApproverDocument, RedirectApproverFetcher as GetRedirectApproverFetcher, GetRedirectApproverGQL, GetRequestedBookingUpdateDocument, GetRequestedBookingUpdateFetcher, GetRequestedBookingUpdateGQL, GetRiskAlertsDocument, GetRiskAlertsFetcher, GetRiskAlertsGQL, GetRouteHappyDocument, GetRouteHappyFetcher, GetRouteHappyGQL, SearchCompanyApproversFetcher as GetSearchCompanyApproversFetcher, GetServiceDocument, GetServiceFetcher, GetServiceGQL, GetTrainSeatMapDocument, GetTrainSeatMapEvolviDocument, GetTrainSeatMapEvolviGQL, GetTrainSeatMapGQL, GetTrainSeatmapEvolviFetcher, GetTrainSeatmapFetcher, GetTrainlineSearchConfigDocument, GetTrainlineSearchConfigFetcher, GetTrainlineSearchConfigGQL, GetUserAddressesDocument, GetUserAddressesGQL, GetUserApproversDocument, GetUserApproversFetcher, GetUserApproversGQL, GetUserBasketCo2InfoDocument, GetUserBasketCo2InfoGQL, GetUserBasketDocument, GetUserBasketGQL, GetUserBasketsDocument, GetUserBasketsFetcher, GetUserBasketsGQL, GetUserCarbonAllowanceDocument, GetUserCarbonAllowanceFetcher, GetUserCarbonAllowanceGQL, GetUserCompanyOfficesDocument, GetUserCompanyOfficesFetcher, GetUserCompanyOfficesGQL, GetUserCarbonAllowanceFetcher as GetUserCurrentCarbonAllowanceFetcher, GetUserDocument, GetUserDocumentLoyaltyDocument, GetUserDocumentLoyaltyFetcher, GetUserDocumentLoyaltyGQL, GetUserEmergencyContactDocument, GetUserEmergencyContactFetcher, GetUserEmergencyContactGQL, GetUserFavouriteSearchesDocument, GetUserFavouriteSearchesFetcher, GetUserFavouriteSearchesGQL, GetUserFavouriteUsersDocument, GetUserFavouriteUsersFetcher, GetUserFavouriteUsersGQL, GetUserFetcher, GetUserGQL, GetUserGuestsDocument, GetUserGuestsFetcher, GetUserGuestsGQL, GetUserMessagesDocument, GetUserMessagesGQL, GetUserMiDefaultValuesDocument, GetUserMiDefaultValuesFetcher, GetUserMiDefaultValuesGQL, GetUserMiDocument, GetUserMiFetcher, GetUserMiGQL, GetUserMiStackDocument, GetUserMiStackFetcher, GetUserMiStackGQL, GetUserPhoneDocument, GetUserPhoneGQL, GetUserPhoneNumbersDocument, GetUserPhoneNumbersGQL, GetUserPreferredTransportHubsDocument, GetUserPreferredTransportHubsFetcher, GetUserPreferredTransportHubsGQL, GetUserRecentBoltSearchesDocument, GetUserRecentBoltSearchesGQL, GetUserRecentSearchesDocument, GetUserRecentSearchesFetcher, GetUserRecentSearchesGQL, GetUserServicesDocument, GetUserServicesGQL, GetUserSharedBasketsDocument, GetUserSharedBasketsFetcher, GetUserSharedBasketsGQL, GetUserUiConfigsDocument, GetUserUiConfigsGQL, GmtItineraryAirportOptionFragmentFragmentDoc, GmtItineraryEurostarOptionFragmentFragmentDoc, GmtItineraryRailStationOptioFragmentFragmentDoc, GroupedFieldsFragmentDoc, HelpInfoFragmentDoc, HelperRoutines, HotelAvalibilityQuoteFetcher, HotelAvalibilityService, HotelQuoteFetcher, HotelStaticTagDisplay, HttpCallService, HttpCancelInterceptor, HttpCancelService, InvokedUserFieldsFragmentDoc, IrlClass, IrlJourneyType, IrlSupplier, IrlTravellerStatus, IsPostcodeValidDocument, IsPostcodeValidGQL, ItineraryEmailTo, LeadPassengerType, LocationType, Location_DetailFragmentDoc, LogLevelType, LogonService, LoungeQuoteFetcher, LoungesInfoFragmentDoc, ManagementInfoDefaultValuePrepopulation, ManagementInfoFieldFragmentDoc, ManagementInfoScope, ManagementInfoSpecialValueSource, ManagementInfoUiPresentation, ManagementInfoValueFieldFragmentDoc, ManagementInfoValueHandling, MarkupFareType, MarkupFlightCabinClass, MarkupFlightSpecialFares, MeetingRoomCatering, MeetingRoomDuration, MeetingRoomEquipment, MeetingRoomLayout, MemoizePipe, MessageTarget, MessageType, MessagesService, ModalOpenerService, MoveItemToADifferentBasketDocument, MoveItemToADifferentBasketGQL, OBTServicesModule, OBTproviders, OfficeFieldsFragmentDoc, OwnerFieldsFragmentDoc, OysterCardsInfoFragmentDoc, ParkingQuoteFetcher, ParkingStationFragmentDoc, PassengerInputType, PassengerType, PaymentMethodFieldsFragmentDoc, PaymentMethodWithCardFieldsFragmentDoc, PhoneType, PlaceCategory, PreferenceKey, ProfileConfigOption, PromptUpdateService, RailAccountsListFragmentDoc, RailCallingPointsFragmentDoc, RailClass, RailFareProcessingService, RailJourneyFareFragmentDoc, RailJourneyOptionFragmentDoc, RailQuoteFetcher, RailResultsStateService, RailSearchComposition, RailSearchJourneyType, RailSeatInfoFragmentDoc, RailSeatPreferenceTypeFragmentDoc, RailSegmentFieldsFragmentDoc, RailStationClassification, RailStoppingPattern, RailTicketFieldsFragmentDoc, RailTicketOptionFieldsFragmentDoc, RailTicketQueueListFragmentDoc, RedirectApproverFetcher, RemoveFavouriteUserDocument, RemoveFavouriteUserGQL, RemoveFavouriteUserUpdater, RemoveItemFromBasketDocument, RemoveItemFromBasketGQL, RemoveItemFromBasketUpdater, RemovePreferredTransportHubDocument, RemovePreferredTransportHubGQL, RemovePreferredTransportHubUpdater, RemoveRedirectApproverDocument, RemoveRedirectApproverGQL, RemoveRedirectApproverUpdater, ResendApproverEmailDocument, ResendApproverEmailFetcher, ResendApproverEmailGQL, ReserveRailSeatsDocument, ReserveRailSeatsGQL, ReserveRailSeatsUpdater, ResultAwareService, RevalidateBasketDocument, RevalidateBasketGQL, RevalidateBasketUpdater, RiskLevel, RoomAvaliabilityFragmentDoc, RouteHappyService, SaveFavouriteSearchDocument, SaveFavouriteSearchGQL, SaveFavouriteSearchUpdater, SaveRecentBoltSearchDocument, SaveRecentBoltSearchGQL, SaveRecentBoltSearchUpdater, SaveRecentSearchDocument, SaveRecentSearchGQL, SaveRecentSearchUpdater, SaveUserAddressDocument, SaveUserAddressGQL, SaveUserAddressUpdater, SearchAirlinesDocument, SearchAirlinesFetcher, SearchAirlinesGQL, SearchAirportsDocument, SearchAirportsFetcher, SearchAirportsGQL, SearchCabHireDocument, SearchCabHireGQL, SearchCarHireDocument, SearchCarHireGQL, SearchCitiesDocument, SearchCitiesGQL, SearchCityFetcher, SearchCompanyApproversDocument, SearchCompanyApproversFetcher, SearchCompanyApproversGQL, SearchCompanyUsersDocument, SearchCompanyUsersFetcher, SearchCompanyUsersGQL, SearchDepotFetcher, SearchDiscoverLocationDocument, SearchDiscoverLocationFetcher, SearchDiscoverLocationGQL, SearchDocumentValidationService, SearchEurostarDocument, SearchEurostarGQL, SearchFastTrackDocument, SearchFastTrackGQL, SearchFlightsV2Document, SearchFlightsV2GQL, SearchGeoLocationDocument, SearchGeoLocationFetcher, SearchGeoLocationGQL, SearchHotelChainsDocument, SearchHotelChainsFetcher, SearchHotelChainsGQL, SearchHotelsDocument, SearchHotelsGQL, SearchIrlDocument, SearchIrlGQL, SearchIrlStationsFetcher, SearchIrlSupplierStationsDocument, SearchIrlSupplierStationsGQL, SearchLoungesDocument, SearchLoungesGQL, SearchMIAutoSuggestValuesFetcher, SearchMiAutoSuggestValuesDocument, SearchMiAutoSuggestValuesGQL, SearchParkingDocument, SearchParkingGQL, SearchPaymentValidationService, SearchPostcodeFetcher, SearchPostcodesDocument, SearchPostcodesGQL, SearchRailDocument, SearchRailGQL, SearchRailInwardDocument, SearchRailInwardFetcher, SearchRailInwardGQL, SearchRailStationsDocument, SearchRailStationsFetcher, SearchRailStationsGQL, SearchUserAddressDocument, SearchUserAddressGQL, SearchUserCanBookForDocument, SearchUserCanBookForGQL, SearchUserWithEmailDocument, SearchUserWithEmailFetcher, SearchUserWithEmailGQL, SearchUsersCanBookForFetcher, SeasonTicketCardType, SeasonTicketClassType, SeasonTicketDeliveryType, SeasonTicketLondonUnderground, SeasonTicketType, SelectBasketApproverDocument, SelectBasketApproverGQL, SelectBasketApproverUpdater, SelectBasketMultiLevelApproversDocument, SelectBasketMultiLevelApproversGQL, SelectBasketMultiLevelApproversUpdater, SelectBasketNotifyApproverDocument, SelectBasketNotifyApproverGQL, SelectBasketNotifyApproverUpdater, SendBackToQueueDocument, SendBackToQueueGQL, SendBackToQueueUpdater, SendOfflineNotificationDocument, SendOfflineNotificationFetcher, SendOfflineNotificationGQL, ServiceMinimalFieldsFragmentDoc, ServiceType, SetBasketItemApexxTokenDocument, SetBasketItemApexxTokenGQL, SetBasketItemApexxTokenUpdater, SetBasketItemLeadPassengerDocument, SetBasketItemLeadPassengerGQL, SetBasketItemPaymentMethodDocument, SetBasketItemPaymentMethodGQL, SetEmptyUserMIDefaultValueUpdater, SetEmptyUserMiDefaultValueDocument, SetEmptyUserMiDefaultValueGQL, SetMIValuesUpdater, SetMiValuesDocument, SetMiValuesGQL, SetPaymentOptionUpdater, SetPreferredTransportHubDocument, SetPreferredTransportHubGQL, SetPreferredTransportHubUpdater, SetUserLanguageDocument, SetUserLanguageGQL, SetUserMIDefaultValueUpdater, SetUserMiDefaultValueDocument, SetUserMiDefaultValueGQL, ShareBasketDocument, ShareBasketGQL, ShareBasketUpdater, ShoppingInfoFragmentDoc, SmartCardsInfoFragmentDoc, SplitRailJourneyFareFragmentDoc, StorageService, SuggestPlacesDocument, SuggestPlacesFetcher, SuggestPlacesGQL, TicketOfficeInfoFragmentDoc, TicketQueueService, TicketType, TimeType, ToiletsBabyInfoFragmentDoc, TrainlineTenantIsFrenchDocument, TrainlineTenantIsFrenchFetcher, TrainlineTenantIsFrenchGQL, TransportType, TravellerGuestsFieldsFragmentDoc, TravellerUserFieldsFragmentDoc, UiConfigTarget, UpdateBasketNotesDocument, UpdateBasketNotesGQL, UpdateBasketTitleDocument, UpdateBasketTitleGQL, UpdateDOBUpdater, UpdateDobDocument, UpdateDobGQL, UpdateExchangeBasketDocument, UpdateExchangeBasketGQL, UpdateExchangeBasketUpdater, UpdateFlightSeatMapDocument, UpdateFlightSeatMapGQL, UpdateFlightSeatMapUpdater, UserApproversFieldsFragmentDoc, UserFieldsFragmentDoc, UserMessagesFetcher, UserMiFragmentDoc, UserMinimalFieldsFragmentDoc, UserProductsFetcher, UserService, UserSummaryFieldsFragmentDoc, UserUiConfigsFetcher, UsersFragmentDoc, ValidateBasketItemMiDocument, ValidateBasketItemMiFetcher, ValidateBasketItemMiGQL, ValidateBasketMiDocument, ValidateBasketMiFetcher, ValidateBasketMiGQL, VehicleType, WebTokenService, WifiInfoFragmentDoc, WithSubscriptionComponent };
20703
+ export { AcceptNewPriceDocument, AcceptNewPriceGQL, AcceptNewPriceUpdater, AcceptProcessTermsDocument, AcceptProcessTermsGQL, AccessibilityInfoFragmentDoc, AddBasketItemCustomRemarkDocument, AddBasketItemCustomRemarkGQL, AddBasketItemCustomRemarkUpdater, AddBasketItemMarkupDocument, AddBasketItemMarkupGQL, AddBasketItemMarkupUpdater, AddFavouriteUserDocument, AddFavouriteUserGQL, AddFavouriteUserUpdater, AddGuestToBasketItemUpdater, AddGuestsToBasketItemDocument, AddGuestsToBasketItemGQL, AddItemToBasketDocument, AddItemToBasketGQL, AddItemToBasketUpdater, AddRedirectApproverDocument, AddRedirectApproverGQL, AddRedirectApproverUpdater, AddToBasketFieldsFragmentDoc, AddUpdatedItemToBasketDocument, AddUpdatedItemToBasketGQL, AddUpdatedItemToBasketUpdater, AddUserToBasketItemUpdater, AddUsersToBasketItemDocument, AddUsersToBasketItemGQL, AddressType, AmendBookingDocument, AmendBookingGQL, AmendBookingUpdater, ApexxCardStatus, ApexxCreateCardDocument, ApexxCreateCardGQL, ApexxDeleteCardDocument, ApexxDeleteCardGQL, ApexxDeleteCardUpdater, ApexxListCardsDocument, ApexxListCardsGQL, ApexxUpdateCardDocument, ApexxUpdateCardGQL, ApexxUpdateCardUpdater, ApplyJitFlightRulesDocument, ApplyJitFlightRulesGQL, ApplyJitHotelRulesDocument, ApplyJitHotelRulesGQL, ApprovalEventType, ApproverUserFieldsFragmentDoc, AuthHttpService, BaggageType, BannerDisplayTarget, BasketFieldsFragmentDoc, BasketItemStatus, BasketMinimalFieldsFragmentDoc, BasketPanelComponent, BasketStatus, BeforeAmendCabSearchDocument, BeforeAmendCabSearchFetcher, BeforeAmendCabSearchGQL, BeforeAmendCarHireSearchDocument, BeforeAmendCarHireSearchFetcher, BeforeAmendCarHireSearchGQL, BookBasketDocument, BookBasketFieldsFragmentDoc, BookBasketGQL, BookBasketUpdater, BookerType, CabHireVehicleType, CabhireQuoteFetcher, CanAmendBookingDocument, CanAmendBookingFetcher, CanAmendBookingGQL, CancelBookingDocument, CancelBookingGQL, CancelBookingUpdater, CarHireAvailabilityDetailFetcher, CarHireAvailabilityDetailRequestDocument, CarHireAvailabilityDetailRequestGQL, CarHireClass, CarHireTransmission, CarHireType, CarbonPolicyDuration, CarbonPolicySource, CarhireQuoteFetcher, ChangeBasketOwnershipDocument, ChangeBasketOwnershipGQL, ChangeBasketOwnershipUpdater, ChangeMode, ChatbotEurostarSearchService, ChatbotFlightSearchService, ChatbotHotelSearchService, ChatbotRailSearchService, ChatbotSearchDispatcherService, ChatbotService, CheckForDuplicateBookingsDocument, CheckForDuplicateBookingsFetcher, CheckForDuplicateBookingsGQL, CheckIfBasketRequiresApprovalDocument, CheckIfBasketRequiresApprovalFetcher, CheckIfBasketRequiresApprovalGQL, CompanyType, ConfirmMessagesDocument, ConfirmMessagesGQL, ConvertCurrencyDocument, ConvertCurrencyFetcher, ConvertCurrencyGQL, CreateBasketDocument, CreateBasketFieldsFragmentDoc, CreateBasketFromDraftDocument, CreateBasketFromDraftGQL, CreateBasketFromDraftUpdater, CreateBasketGQL, CreateBasketNoteDocument, CreateBasketNoteGQL, CreateBasketNoteUpdater, CreateBasketUpdater, CreateGuestDocument, CreateGuestGQL, CreateGuestUpdater, CreateItineraryExchangeDocument, CreateItineraryExchangeGQL, CurrencyCode, CycleInfoFragmentDoc, DeleteAllRecentSearchesDocument, DeleteAllRecentSearchesGQL, DeleteAllRecentSearchesUpdater, DeleteBasketDocument, DeleteBasketGQL, DeleteBasketUpdater, DeleteFavouriteSearchDocument, DeleteFavouriteSearchGQL, DeleteFavouriteSearchUpdater, DeleteGuestDocument, DeleteGuestGQL, DeleteGuestUpdater, DeleteRecentSearchDocument, DeleteRecentSearchGQL, DeleteUserAddressDocument, DeleteUserAddressGQL, DiscountType, DistanceTypes, DivisionFieldsFragmentDoc, DocGender, DocType, DownloadETicketDocument, DownloadETicketFetcher, DownloadETicketGQL, DraftBasketType, EditUserAddressDocument, EditUserAddressGQL, EditUserAddressUpdater, EditUserDocument, EditUserGQL, EmailAmbulanceBookingFetcher, EmailAmbulanceBookingReqDocument, EmailAmbulanceBookingReqGQL, EmailApartmentBookingFetcher, EmailApartmentBookingReqDocument, EmailApartmentBookingReqGQL, EmailBasketDocument, EmailBasketFetcher, EmailBasketGQL, EmailFerryBookingFetcher, EmailFerryBookingReqDocument, EmailFerryBookingReqGQL, EmailMeetingRoomBookingFetcher, EmailMeetingRoomBookingReqDocument, EmailMeetingRoomBookingReqGQL, EmailSeasonTicketBookingFetcher, EmailSeasonTicketBookingReqDocument, EmailSeasonTicketBookingReqGQL, EntLocationsByCityDocument, EntLocationsByCityGQL, EntLocationsByPostcodeDocument, EntLocationsByPostcodeGQL, EnterpriseBasketService, EnterpriseMyBookingsService, EnterpriseSearchService, Environment, ErrorsFragmentDoc, EurostarQuoteFetcher, EventMessenager, EvolviSeatmapsAreEnabledDocument, EvolviSeatmapsAreEnabledGQL, ExchangeType, ExternalHttpService, FailedEmail, FareRuleType, FareType, FerryOrEurotunnel, FlightCabinClass, FlightItineraryFieldsFragmentDoc, FlightPassengerType, FlightQuoteFetcher, GenerateBasketPdfDocument, GenerateBasketPdfFetcher, GenerateBasketPdfGQL, GetAirAvailabilityDocument, GetAirAvailabilityFetcher, GetAirAvailabilityGQL, GetAllAirlinesDocument, GetAllAirlinesFetcher, GetAllAirlinesGQL, GetApexxListCardsFetcher, GetBannerDocument, GetBannerFetcher, GetBannerGQL, GetBasketApprovalInfoDocument, GetBasketApprovalInfoFetcher, GetBasketApprovalInfoGQL, GetBasketApprovalTimestampsDocument, GetBasketApprovalTimestampsGQL, GetBasketCo2InfoFetcher, GetBasketFetcher, GetBasketItemCustomRemarksDocument, GetBasketItemCustomRemarksFetcher, GetBasketItemCustomRemarksGQL, GetBasketNotesDocument, GetBasketNotesFetcher, GetBasketNotesGQL, GetBasketQuoteDocument, GetBasketQuoteFetcher, GetBasketQuoteGQL, GetBrandedFaresDocument, GetBrandedFaresGQL, GetCancellationInfoDocument, GetCancellationInfoFetcher, GetCancellationInfoGQL, GetCarHireDepotsDocument, GetCarHireDepotsGQL, GetCarHireProvidersDocument, GetCarHireProvidersFetcher, GetCarHireProvidersGQL, GetCompaniesDocument, GetCompaniesFetcher, GetCompaniesGQL, GetCompanyDocument, GetCompanyFetcher, GetCompanyGQL, GetConfermaQuicklistDocument, GetConfermaQuicklistGQL, GetConfermaRoomImagesDocument, GetConfermaRoomImagesGQL, GetCovidMicrositeTokenDocument, GetCovidMicrositeTokenFetcher, GetCovidMicrositeTokenGQL, GetCurrencyConversionRatesDocument, GetCurrencyConversionRatesFetcher, GetCurrencyConversionRatesGQL, GetDivisionDocument, GetDivisionGQL, GetDraftBasketsDocument, GetDraftBasketsFetcher, GetDraftBasketsGQL, GetEmptyUserMiDefaultValuesDocument, GetEmptyUserMiDefaultValuesFetcher, GetEmptyUserMiDefaultValuesGQL, GetEntLocationByPostcode, GetEvolviSeatmapsAreEnabledFetcher, GetFerryPortsDocument, GetFerryPortsFetcher, GetFerryPortsGQL, GetFlightAtNewClassDocument, GetFlightAtNewClassFetcher, GetFlightAtNewClassGQL, GetFlightBrandedFaresFetcher, GetFlightExchangeDetailsDocument, GetFlightExchangeDetailsFetcher, GetFlightExchangeDetailsGQL, GetFlightExtrasOptionsDocument, GetFlightExtrasOptionsFetcher, GetFlightExtrasOptionsGQL, GetFlightFareRulesDocument, GetFlightFareRulesFetcher, GetFlightFareRulesGQL, GetFlightSearchExchangeDocument, GetFlightSearchExchangeFetcher, GetFlightSearchExchangeGQL, GetFlightSeatMapDocument, GetFlightSeatMapFetcher, GetFlightSeatMapGQL, GetFlightUpsellOffersDocument, GetFlightUpsellOffersFetcher, GetFlightUpsellOffersGQL, GetGmtItineraryOptionsDocument, GetGmtItineraryOptionsFetcher, GetGmtItineraryOptionsGQL, GetGutCitySuggestionsDocument, GetGutCitySuggestionsFetcher, GetGutCitySuggestionsGQL, GetGutLocationSuggestionsDocument, GetGutLocationSuggestionsFetcher, GetGutLocationSuggestionsGQL, GetHotelChainsDocument, GetHotelChainsFetcher, GetHotelChainsGQL, GetHotelDetailsDocument, GetHotelDetailsFetcher, GetHotelDetailsGQL, GetIrlDiscountCardsDocument, GetIrlDiscountCardsGQL, GetIrlSupplierStationDocument, GetIrlSupplierStationFetcher, GetIrlSupplierStationGQL, GetJyrneyUrlDocument, GetJyrneyUrlFetcher, GetJyrneyUrlGQL, GetLatLonFromHereIdDocument, GetLatLonFromHereIdFetcher, GetLatLonFromHereIdGQL, GetLatestVersionsDocument, GetLatestVersionsFetcher, GetLatestVersionsGQL, GetMIApproversFetcher, GetMiApproversDocument, GetMiApproversGQL, GetMiRequiringMandatoryDefaultValueDocument, GetMiRequiringMandatoryDefaultValueFetcher, GetMiRequiringMandatoryDefaultValueGQL, GetMultipleHotelRatingDocument, GetMultipleHotelRatingFetcher, GetMultipleHotelRatingGQL, GetMultipleHotelsAvailabilityDocument, GetMultipleHotelsAvailabilityGQL, GetOfficeApproversDocument, GetOfficeApproversFetcher, GetOfficeApproversGQL, GetOfficeDivisionsDocument, GetOfficeDivisionsFetcher, GetOfficeDivisionsGQL, GetOfficeDocument, GetOfficeFetcher, GetOfficeGQL, GetOfficeUsersDocument, GetOfficeUsersFetcher, GetOfficeUsersGQL, GetOfficesDocument, GetOfficesFetcher, GetOfficesGQL, GetPriceHiddenSabreExchangeDocument, GetPriceHiddenSabreExchangeFetcher, GetPriceHiddenSabreExchangeGQL, GetProcessTermsPriceDocument, GetProcessTermsPriceGQL, GetRailcardsFetcher as GetRailCardsFetcher, GetRailLiveDeparturesDocument, GetRailLiveDeparturesFetcher, GetRailLiveDeparturesGQL, GetRailProvidersDocument, GetRailProvidersFetcher, GetRailProvidersGQL, GetRailSearchExchangeDocument, GetRailSearchExchangeGQL, GetRailStationDocument, GetRailStationFetcher, GetRailStationGQL, GetRailStationInfoDocument, GetRailStationInfoFetcher, GetRailStationInfoGQL, GetRailcardsDocument, GetRailcardsFetcher, GetRailcardsGQL, GetRedirectApproverDocument, RedirectApproverFetcher as GetRedirectApproverFetcher, GetRedirectApproverGQL, GetRequestedBookingUpdateDocument, GetRequestedBookingUpdateFetcher, GetRequestedBookingUpdateGQL, GetRiskAlertsDocument, GetRiskAlertsFetcher, GetRiskAlertsGQL, GetRouteHappyDocument, GetRouteHappyFetcher, GetRouteHappyGQL, SearchCompanyApproversFetcher as GetSearchCompanyApproversFetcher, GetServiceDocument, GetServiceFetcher, GetServiceGQL, GetTrainSeatMapDocument, GetTrainSeatMapEvolviDocument, GetTrainSeatMapEvolviGQL, GetTrainSeatMapGQL, GetTrainSeatmapEvolviFetcher, GetTrainSeatmapFetcher, GetTrainlineSearchConfigDocument, GetTrainlineSearchConfigFetcher, GetTrainlineSearchConfigGQL, GetUserAddressesDocument, GetUserAddressesGQL, GetUserApproversDocument, GetUserApproversFetcher, GetUserApproversGQL, GetUserBasketCo2InfoDocument, GetUserBasketCo2InfoGQL, GetUserBasketDocument, GetUserBasketGQL, GetUserBasketsDocument, GetUserBasketsFetcher, GetUserBasketsGQL, GetUserCarbonAllowanceDocument, GetUserCarbonAllowanceFetcher, GetUserCarbonAllowanceGQL, GetUserCompanyOfficesDocument, GetUserCompanyOfficesFetcher, GetUserCompanyOfficesGQL, GetUserCarbonAllowanceFetcher as GetUserCurrentCarbonAllowanceFetcher, GetUserDocument, GetUserDocumentLoyaltyDocument, GetUserDocumentLoyaltyFetcher, GetUserDocumentLoyaltyGQL, GetUserEmergencyContactDocument, GetUserEmergencyContactFetcher, GetUserEmergencyContactGQL, GetUserFavouriteSearchesDocument, GetUserFavouriteSearchesFetcher, GetUserFavouriteSearchesGQL, GetUserFavouriteUsersDocument, GetUserFavouriteUsersFetcher, GetUserFavouriteUsersGQL, GetUserFetcher, GetUserGQL, GetUserGuestsDocument, GetUserGuestsFetcher, GetUserGuestsGQL, GetUserMessagesDocument, GetUserMessagesGQL, GetUserMiDefaultValuesDocument, GetUserMiDefaultValuesFetcher, GetUserMiDefaultValuesGQL, GetUserMiDocument, GetUserMiFetcher, GetUserMiGQL, GetUserMiStackDocument, GetUserMiStackFetcher, GetUserMiStackGQL, GetUserPhoneDocument, GetUserPhoneGQL, GetUserPhoneNumbersDocument, GetUserPhoneNumbersGQL, GetUserPreferredTransportHubsDocument, GetUserPreferredTransportHubsFetcher, GetUserPreferredTransportHubsGQL, GetUserRecentBoltSearchesDocument, GetUserRecentBoltSearchesGQL, GetUserRecentSearchesDocument, GetUserRecentSearchesFetcher, GetUserRecentSearchesGQL, GetUserServicesDocument, GetUserServicesGQL, GetUserSharedBasketsDocument, GetUserSharedBasketsFetcher, GetUserSharedBasketsGQL, GetUserUiConfigsDocument, GetUserUiConfigsGQL, GmtItineraryAirportOptionFragmentFragmentDoc, GmtItineraryEurostarOptionFragmentFragmentDoc, GmtItineraryRailStationOptioFragmentFragmentDoc, GroupedFieldsFragmentDoc, HelpInfoFragmentDoc, HelperRoutines, HotelAvalibilityQuoteFetcher, HotelAvalibilityService, HotelQuoteFetcher, HotelStaticTagDisplay, HttpCallService, HttpCancelInterceptor, HttpCancelService, InvokedUserFieldsFragmentDoc, IrlClass, IrlJourneyType, IrlSupplier, IrlTravellerStatus, IsPostcodeValidDocument, IsPostcodeValidGQL, ItineraryEmailTo, LeadPassengerType, LocationType, Location_DetailFragmentDoc, LogLevelType, LogonService, LoungeQuoteFetcher, LoungesInfoFragmentDoc, ManagementInfoDefaultValuePrepopulation, ManagementInfoFieldFragmentDoc, ManagementInfoScope, ManagementInfoSpecialValueSource, ManagementInfoUiPresentation, ManagementInfoValueFieldFragmentDoc, ManagementInfoValueHandling, MarkupFareType, MarkupFlightCabinClass, MarkupFlightSpecialFares, MeetingRoomCatering, MeetingRoomDuration, MeetingRoomEquipment, MeetingRoomLayout, MemoizePipe, MessageTarget, MessageType, MessagesService, ModalOpenerService, MoveItemToADifferentBasketDocument, MoveItemToADifferentBasketGQL, OBTServicesModule, OBTproviders, OfficeFieldsFragmentDoc, OwnerFieldsFragmentDoc, OysterCardsInfoFragmentDoc, ParkingQuoteFetcher, ParkingStationFragmentDoc, PassengerInputType, PassengerType, PaymentMethodFieldsFragmentDoc, PaymentMethodWithCardFieldsFragmentDoc, PhoneType, PlaceCategory, PreferenceKey, ProfileConfigOption, PromptUpdateService, RailAccountsListFragmentDoc, RailCallingPointsFragmentDoc, RailClass, RailFareProcessingService, RailJourneyFareFragmentDoc, RailJourneyOptionFragmentDoc, RailQuoteFetcher, RailResultsStateService, RailSearchComposition, RailSearchJourneyType, RailSeatInfoFragmentDoc, RailSeatPreferenceTypeFragmentDoc, RailSegmentFieldsFragmentDoc, RailStationClassification, RailStoppingPattern, RailTicketFieldsFragmentDoc, RailTicketOptionFieldsFragmentDoc, RailTicketQueueListFragmentDoc, RedirectApproverFetcher, RemoveFavouriteUserDocument, RemoveFavouriteUserGQL, RemoveFavouriteUserUpdater, RemoveItemFromBasketDocument, RemoveItemFromBasketGQL, RemoveItemFromBasketUpdater, RemovePreferredTransportHubDocument, RemovePreferredTransportHubGQL, RemovePreferredTransportHubUpdater, RemoveRedirectApproverDocument, RemoveRedirectApproverGQL, RemoveRedirectApproverUpdater, ResendApproverEmailDocument, ResendApproverEmailFetcher, ResendApproverEmailGQL, ReserveRailSeatsDocument, ReserveRailSeatsGQL, ReserveRailSeatsUpdater, ResultAwareService, RevalidateBasketDocument, RevalidateBasketGQL, RevalidateBasketUpdater, RiskLevel, RoomAvaliabilityFragmentDoc, RouteHappyService, SaveFavouriteSearchDocument, SaveFavouriteSearchGQL, SaveFavouriteSearchUpdater, SaveRecentBoltSearchDocument, SaveRecentBoltSearchGQL, SaveRecentBoltSearchUpdater, SaveRecentSearchDocument, SaveRecentSearchGQL, SaveRecentSearchUpdater, SaveUserAddressDocument, SaveUserAddressGQL, SaveUserAddressUpdater, SearchAirlinesDocument, SearchAirlinesFetcher, SearchAirlinesGQL, SearchAirportsDocument, SearchAirportsFetcher, SearchAirportsGQL, SearchCabHireDocument, SearchCabHireGQL, SearchCarHireDocument, SearchCarHireGQL, SearchCitiesDocument, SearchCitiesGQL, SearchCityFetcher, SearchCompanyApproversDocument, SearchCompanyApproversFetcher, SearchCompanyApproversGQL, SearchCompanyUsersDocument, SearchCompanyUsersFetcher, SearchCompanyUsersGQL, SearchDepotFetcher, SearchDiscoverLocationDocument, SearchDiscoverLocationFetcher, SearchDiscoverLocationGQL, SearchDocumentValidationService, SearchEurostarDocument, SearchEurostarGQL, SearchFastTrackDocument, SearchFastTrackGQL, SearchFlightsV2Document, SearchFlightsV2GQL, SearchGeoLocationDocument, SearchGeoLocationFetcher, SearchGeoLocationGQL, SearchHotelChainsDocument, SearchHotelChainsFetcher, SearchHotelChainsGQL, SearchHotelsDocument, SearchHotelsGQL, SearchIrlDocument, SearchIrlGQL, SearchIrlStationsFetcher, SearchIrlSupplierStationsDocument, SearchIrlSupplierStationsGQL, SearchLoungesDocument, SearchLoungesGQL, SearchMIAutoSuggestValuesFetcher, SearchMiAutoSuggestValuesDocument, SearchMiAutoSuggestValuesGQL, SearchParkingDocument, SearchParkingGQL, SearchPaymentValidationService, SearchPostcodeFetcher, SearchPostcodesDocument, SearchPostcodesGQL, SearchRailDocument, SearchRailGQL, SearchRailInwardDocument, SearchRailInwardFetcher, SearchRailInwardGQL, SearchRailStationsDocument, SearchRailStationsFetcher, SearchRailStationsGQL, SearchUserAddressDocument, SearchUserAddressGQL, SearchUserCanBookForDocument, SearchUserCanBookForGQL, SearchUserWithEmailDocument, SearchUserWithEmailFetcher, SearchUserWithEmailGQL, SearchUsersCanBookForFetcher, SeasonTicketCardType, SeasonTicketClassType, SeasonTicketDeliveryType, SeasonTicketLondonUnderground, SeasonTicketType, SelectBasketApproverDocument, SelectBasketApproverGQL, SelectBasketApproverUpdater, SelectBasketMultiLevelApproversDocument, SelectBasketMultiLevelApproversGQL, SelectBasketMultiLevelApproversUpdater, SelectBasketNotifyApproverDocument, SelectBasketNotifyApproverGQL, SelectBasketNotifyApproverUpdater, SendBackToQueueDocument, SendBackToQueueGQL, SendBackToQueueUpdater, SendOfflineNotificationDocument, SendOfflineNotificationFetcher, SendOfflineNotificationGQL, ServiceMinimalFieldsFragmentDoc, ServiceType, SetBasketItemApexxTokenDocument, SetBasketItemApexxTokenGQL, SetBasketItemApexxTokenUpdater, SetBasketItemLeadPassengerDocument, SetBasketItemLeadPassengerGQL, SetBasketItemPaymentMethodDocument, SetBasketItemPaymentMethodGQL, SetEmptyUserMIDefaultValueUpdater, SetEmptyUserMiDefaultValueDocument, SetEmptyUserMiDefaultValueGQL, SetMIValuesUpdater, SetMiValuesDocument, SetMiValuesGQL, SetPaymentOptionUpdater, SetPreferredTransportHubDocument, SetPreferredTransportHubGQL, SetPreferredTransportHubUpdater, SetUserLanguageDocument, SetUserLanguageGQL, SetUserMIDefaultValueUpdater, SetUserMiDefaultValueDocument, SetUserMiDefaultValueGQL, ShareBasketDocument, ShareBasketGQL, ShareBasketUpdater, ShoppingInfoFragmentDoc, SmartCardsInfoFragmentDoc, SplitRailJourneyFareFragmentDoc, StorageService, SuggestPlacesDocument, SuggestPlacesFetcher, SuggestPlacesGQL, TicketOfficeInfoFragmentDoc, TicketQueueService, TicketType, TimeType, ToiletsBabyInfoFragmentDoc, TrainlineTenantIsFrenchDocument, TrainlineTenantIsFrenchFetcher, TrainlineTenantIsFrenchGQL, TransportType, TravellerGuestsFieldsFragmentDoc, TravellerUserFieldsFragmentDoc, UiConfigTarget, UpdateBasketNotesDocument, UpdateBasketNotesGQL, UpdateBasketTitleDocument, UpdateBasketTitleGQL, UpdateDOBUpdater, UpdateDobDocument, UpdateDobGQL, UpdateExchangeBasketDocument, UpdateExchangeBasketGQL, UpdateExchangeBasketUpdater, UpdateFlightSeatMapDocument, UpdateFlightSeatMapGQL, UpdateFlightSeatMapUpdater, UserApproversFieldsFragmentDoc, UserFieldsFragmentDoc, UserMessagesFetcher, UserMiFragmentDoc, UserMinimalFieldsFragmentDoc, UserProductsFetcher, UserService, UserSummaryFieldsFragmentDoc, UserUiConfigsFetcher, UsersFragmentDoc, ValidateBasketItemMiDocument, ValidateBasketItemMiFetcher, ValidateBasketItemMiGQL, ValidateBasketMiDocument, ValidateBasketMiFetcher, ValidateBasketMiGQL, VehicleType, WebTokenService, WifiInfoFragmentDoc, WithSubscriptionComponent };
18113
20704
  //# sourceMappingURL=sabstravtech-obtservices-angular.mjs.map