Files
web/apps/scandic-web/components/HotelReservation/BookingConfirmation/Tracking/tracking.ts
Joakim Jäderberg 7dee6d5083 Merged in chore/move-enter-details (pull request #2778)
Chore/move enter details

Approved-by: Anton Gunnarsson
2025-09-11 07:16:24 +00:00

214 lines
7.3 KiB
TypeScript

import { createHash } from "crypto"
import { differenceInCalendarDays, format, isWeekend } from "date-fns"
import { readPaymentInfoFromSessionStorage } from "@scandic-hotels/booking-flow/components/EnterDetails/Payment/helpers"
import { invertedBedTypeMap } from "@scandic-hotels/booking-flow/utils/SelectRate"
import { getSpecialRoomType } from "@scandic-hotels/booking-flow/utils/specialRoomType"
import { CancellationRuleEnum } from "@scandic-hotels/common/constants/booking"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { RateEnum } from "@scandic-hotels/common/constants/rate"
import {
TrackingChannelEnum,
type TrackingSDKAncillaries,
type TrackingSDKHotelInfo,
type TrackingSDKPageData,
type TrackingSDKPaymentInfo,
} from "@scandic-hotels/tracking/types"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import type { Room } from "@scandic-hotels/booking-flow/types/stores/booking-confirmation"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"
import type { RateDefinition } from "@scandic-hotels/trpc/types/roomAvailability"
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 mapAncillaryPackage(
ancillaryPackage: BookingConfirmation["booking"]["packages"][number],
operaId: string
) {
const isPoints = ancillaryPackage.currency === CurrencyEnum.POINTS
return {
hotelid: operaId,
productCategory: "", // TODO: Add category
productId: ancillaryPackage.code,
productName: ancillaryPackage.description,
productPoints: isPoints ? ancillaryPackage.totalPrice : 0,
productPrice: isPoints ? 0 : ancillaryPackage.totalPrice,
productType:
ancillaryPackage.code === BreakfastPackageEnum.REGULAR_BREAKFAST
? "food"
: "room preference",
productUnits: ancillaryPackage.totalUnit,
productDeliveryTime: "",
}
}
export function getTracking(
lang: Lang,
booking: BookingConfirmation["booking"],
hotel: BookingConfirmation["hotel"],
rooms: Room[],
searchTerm?: string
) {
const arrivalDate = new Date(booking.checkInDate)
const departureDate = new Date(booking.checkOutDate)
const paymentInfoSessionData = readPaymentInfoFromSessionStorage()
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 isGuaranteedFlexBooking = booking.guaranteeInfo && isFlexBooking
const ancillaries: TrackingSDKAncillaries = rooms
.flatMap((r) => r.packages)
.filter(
(p) =>
p.code === RoomPackageCodeEnum.PET_ROOM ||
p.code === BreakfastPackageEnum.REGULAR_BREAKFAST
)
.map((pkg) => mapAncillaryPackage(pkg, hotel.operaId))
const hotelsTrackingData: TrackingSDKHotelInfo = {
ageOfChildren: rooms.map((r) => r.childrenAges?.join(",") ?? "").join("|"),
analyticsRateCode: rooms
.map((r) => getRate(r.rateDefinition.cancellationRule))
.join("|"),
arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
bedType: rooms
.map((r) => r.bedType)
.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.cancellationRule)
.join(",")
.toLowerCase(),
rateCodeName: rooms.map(constructRateCodeName).join(","),
rateCodeType: rooms.map((r) => r.rateCodeType?.toLowerCase()).join(","),
region: hotel?.address.city,
revenueCurrencyCode: [...new Set(rooms.map((r) => r.currencyCode))].join(
","
),
rewardNight: booking.roomPoints > 0 ? "yes" : "no",
rewardNightAvailability: booking.roomPoints > 0 ? "true" : "false",
points: booking.roomPoints > 0 ? booking.roomPoints : undefined,
roomPrice: rooms.reduce((total, room) => total + room.roomPrice, 0),
roomTypeCode: rooms.map((r) => r.roomTypeCode ?? "").join(","),
searchTerm,
searchType: "hotel",
specialRoomType: rooms
.map((room) => getSpecialRoomType(room.packages))
.join(","),
totalPrice: rooms.reduce((total, room) => total + room.totalPrice, 0),
lateArrivalGuarantee: booking.rateDefinition.mustBeGuaranteed
? "mandatory"
: isFlexBooking
? booking.guaranteeInfo
? "yes"
: "no"
: "na",
guaranteedProduct: isGuaranteedFlexBooking ? "room" : "na",
emailId: getSHAHash(booking.guest.email),
mobileNumber: getSHAHash(booking.guest.phoneNumber),
}
const paymentInfo: TrackingSDKPaymentInfo = {
paymentStatus: isGuaranteedFlexBooking
? "glacardsaveconfirmed"
: "confirmed",
type:
booking.guaranteeInfo?.cardType ?? paymentInfoSessionData?.paymentMethod,
}
return {
hotelsTrackingData,
pageTrackingData,
paymentInfo,
ancillaries,
}
}
function constructRateCodeName(room: Room) {
if (room.cheques) {
return "corporate cheque"
} else if (room.vouchers) {
return "voucher"
} else if (room.roomPoints) {
return "redemption"
}
const rate = getRate(room.rateDefinition.cancellationRule)
const bookingCodeStr = room.bookingCode ? room.bookingCode.toUpperCase() : ""
const breakfastIncludedStr = room.breakfastIncluded
? "incl. breakfast"
: "excl. breakfast"
return [bookingCodeStr, rate, breakfastIncludedStr]
.filter(Boolean)
.join(" - ")
}
function getSHAHash(key: string) {
return createHash("sha256").update(key).digest("hex")
}