import { differenceInCalendarDays, format, isWeekend } from "date-fns" import { CancellationRuleEnum } from "@/constants/booking" import { getSpecialRoomType } from "@/utils/specialRoomType" import { invertedBedTypeMap } from "../../utils" import { TrackingChannelEnum, type TrackingSDKHotelInfo, type TrackingSDKPageData, type TrackingSDKPaymentInfo, } from "@/types/components/tracking" import { BreakfastPackageEnum } from "@/types/enums/breakfast" import { RateEnum } from "@/types/enums/rate" import type { Room } from "@/types/stores/booking-confirmation" import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" import type { RateDefinition } from "@/types/trpc/routers/hotel/roomAvailability" import type { Lang } from "@/constants/languages" function getRate(cancellationRule: RateDefinition["cancellationRule"] | null) { switch (cancellationRule) { case "CancellableBefore6PM": return RateEnum.flex case "Changeable": return RateEnum.change case "NotCancellable": return RateEnum.save default: return "-" } } function findBreakfastPackage( packages: BookingConfirmation["booking"]["packages"] ) { return packages.find( (pkg) => pkg.code === BreakfastPackageEnum.REGULAR_BREAKFAST ) } function mapBreakfastPackage( breakfastPackage: BookingConfirmation["booking"]["packages"][number], adults: number, operaId: string ) { return { hotelid: operaId, productCategory: "", // TODO: Add category productId: breakfastPackage.code!, // Is not found unless code exists productName: "BreakfastAdult", productPoints: 0, productPrice: +breakfastPackage.unitPrice, productType: "food", productUnits: adults, } } export function getTracking( lang: Lang, booking: BookingConfirmation["booking"], hotel: BookingConfirmation["hotel"], rooms: Room[] ) { const arrivalDate = new Date(booking.checkInDate) const departureDate = new Date(booking.checkOutDate) const pageTrackingData: TrackingSDKPageData = { channel: TrackingChannelEnum.hotelreservation, domainLanguage: lang, pageId: "booking-confirmation", pageName: `hotelreservation|confirmation`, pageType: "confirmation", siteSections: `hotelreservation|confirmation`, siteVersion: "new-web", } const noOfAdults = rooms.map((r) => r.adults).join(",") const noOfChildren = rooms.map((r) => r.childrenAges?.length ?? 0).join(",") const noOfRooms = rooms.length const isFlexBooking = booking.rateDefinition.cancellationRule === CancellationRuleEnum.CancellableBefore6PM const hotelsTrackingData: TrackingSDKHotelInfo = { ageOfChildren: rooms.map((r) => r.childrenAges?.join(",") ?? "-").join("|"), analyticsRateCode: rooms .map((r) => getRate(r.rateDefinition.cancellationRule)) .join("|"), ancillaries: rooms .filter((r) => findBreakfastPackage(r.packages)) .map((r) => { return mapBreakfastPackage( findBreakfastPackage(r.packages)!, r.adults, hotel.operaId ) }), arrivalDate: format(arrivalDate, "yyyy-MM-dd"), bedType: rooms .map((r) => r.bedDescription) .join(",") .toLowerCase(), bnr: rooms.map((r) => r.confirmationNumber).join(","), bookingCode: rooms.map((room) => room.bookingCode ?? "n/a").join(", "), bookingCodeAvailability: booking.bookingCode ? rooms.map((room) => (room.bookingCode ? "true" : "false")).join(", ") : undefined, bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday", breakfastOption: rooms .map((r) => { if (r.breakfastIncluded || r.breakfast) { return "breakfast buffet" } return "no breakfast" }) .join(","), childBedPreference: rooms .map( (r) => r.childBedPreferences .map((cbp) => Array(cbp.quantity).fill(invertedBedTypeMap[cbp.bedType]) ) .join(",") ?? "-" ) .join("|"), country: hotel?.address.country, departureDate: format(departureDate, "yyyy-MM-dd"), duration: differenceInCalendarDays(departureDate, arrivalDate), hotelID: hotel.operaId, leadTime: differenceInCalendarDays(arrivalDate, new Date()), noOfAdults, noOfChildren, noOfRooms, rateCode: rooms.map((r) => r.rateDefinition.rateCode).join(","), rateCodeCancellationRule: rooms .map((r) => r.rateDefinition.cancellationText) .join(",") .toLowerCase(), rateCodeName: rooms .map((r) => r.rateDefinition.title) .join(",") .toLowerCase(), //rateCodeType: , //TODO: Add when available in API. "regular, promotion, corporate etx", region: hotel?.address.city, revenueCurrencyCode: rooms.map((r) => r.currencyCode).join(","), roomPrice: rooms.map((r) => r.roomPrice).join(","), roomTypeCode: rooms.map((r) => r.roomTypeCode ?? "-").join(","), searchType: "hotel", specialRoomType: rooms .map((room) => getSpecialRoomType(room.packages)) .join(","), totalPrice: rooms.map((r) => r.totalPrice).join(","), lateArrivalGuarantee: booking.rateDefinition.mustBeGuaranteed ? "mandatory" : isFlexBooking ? booking.guaranteeInfo ? "yes" : "no" : "na", guaranteedProduct: booking.guaranteeInfo && isFlexBooking ? "room" : "na", } const paymentInfo: TrackingSDKPaymentInfo = { paymentStatus: "confirmed", status: booking.guaranteeInfo && isFlexBooking ? "glacardsaveconfirmed" : undefined, type: booking.guaranteeInfo && isFlexBooking ? booking.guaranteeInfo.cardType : undefined, } return { hotelsTrackingData, pageTrackingData, paymentInfo, } }