Merged in feat/book-530-selectrate-tracking (pull request #3128)

feat(BOOK-530): fixed noAvailableRooms tracking on select rate page

* feat(BOOK-530): fixed noAvailableRooms tracking on select rate page


Approved-by: Bianca Widstam
This commit is contained in:
Linus Flood
2025-11-11 14:17:02 +00:00
parent 9175331e4d
commit 78ac93d836
8 changed files with 73 additions and 63 deletions

View File

@@ -6,7 +6,6 @@ import { useIntl } from "react-intl"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { selectRate } from "@scandic-hotels/common/constants/routes/hotelReservation" import { selectRate } from "@scandic-hotels/common/constants/routes/hotelReservation"
import { useSessionId } from "@scandic-hotels/common/hooks/useSessionId"
import useStickyPosition from "@scandic-hotels/common/hooks/useStickyPosition" import useStickyPosition from "@scandic-hotels/common/hooks/useStickyPosition"
import { Alert } from "@scandic-hotels/design-system/Alert" import { Alert } from "@scandic-hotels/design-system/Alert"
import { trackNoAvailability } from "@scandic-hotels/tracking/NoAvailabilityTracking" import { trackNoAvailability } from "@scandic-hotels/tracking/NoAvailabilityTracking"
@@ -173,7 +172,6 @@ function useNoAvailabilityTracking() {
useEnterDetailsStore((state) => state.booking) useEnterDetailsStore((state) => state.booking)
const hotelName = useEnterDetailsStore((state) => state.hotelName) const hotelName = useEnterDetailsStore((state) => state.hotelName)
const lang = useLang() const lang = useLang()
const sessionId = useSessionId()
const specialRoomType = rooms const specialRoomType = rooms
?.map((room) => { ?.map((room) => {
@@ -201,7 +199,6 @@ function useNoAvailabilityTracking() {
pageName: "hotelreservation|details", pageName: "hotelreservation|details",
pageType: "bookingenterdetailspage", pageType: "bookingenterdetailspage",
siteSections: "hotelreservation|details", siteSections: "hotelreservation|details",
sessionId,
domain: typeof window !== "undefined" ? window.location.host : "", domain: typeof window !== "undefined" ? window.location.host : "",
}), }),
[ [
@@ -214,7 +211,6 @@ function useNoAvailabilityTracking() {
rooms.length, rooms.length,
searchType, searchType,
bookingCode, bookingCode,
sessionId,
] ]
) )
return track return track

View File

@@ -34,7 +34,7 @@ interface SelectHotelProps {
lang: Lang lang: Lang
} }
export async function SelectHotel({ export function SelectHotel({
bookingCode, bookingCode,
city, city,
hotels, hotels,

View File

@@ -4,7 +4,6 @@ import { usePathname, useSearchParams } from "next/navigation"
import { useCallback, useEffect } from "react" import { useCallback, useEffect } from "react"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { useSessionId } from "@scandic-hotels/common/hooks/useSessionId"
import { toast } from "@scandic-hotels/design-system/Toast" import { toast } from "@scandic-hotels/design-system/Toast"
import { trackNoAvailability } from "@scandic-hotels/tracking/NoAvailabilityTracking" import { trackNoAvailability } from "@scandic-hotels/tracking/NoAvailabilityTracking"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking" import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
@@ -27,7 +26,6 @@ export default function AvailabilityError({
const intl = useIntl() const intl = useIntl()
const pathname = usePathname() const pathname = usePathname()
const searchParams = useSearchParams() const searchParams = useSearchParams()
const sessionId = useSessionId()
const lang = useLang() const lang = useLang()
@@ -71,7 +69,6 @@ export default function AvailabilityError({
pageName: "hotelreservation|select-rate", pageName: "hotelreservation|select-rate",
pageType: "bookingroomsandratespage", pageType: "bookingroomsandratespage",
siteSections: "hotelreservation|select-rate", siteSections: "hotelreservation|select-rate",
sessionId,
domain: typeof window !== "undefined" ? window.location.host : "", domain: typeof window !== "undefined" ? window.location.host : "",
}) })
}, [ }, [
@@ -83,7 +80,6 @@ export default function AvailabilityError({
searchType, searchType,
hotelId, hotelId,
bookingCode, bookingCode,
sessionId,
]) ])
useEffect(() => { useEffect(() => {

View File

@@ -6,8 +6,13 @@ import { useIntl } from "react-intl"
import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert" import { AlertTypeEnum } from "@scandic-hotels/common/constants/alert"
import { Alert } from "@scandic-hotels/design-system/Alert" import { Alert } from "@scandic-hotels/design-system/Alert"
import { trackNoAvailability } from "@scandic-hotels/tracking/NoAvailabilityTracking"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"
import { useSelectRateContext } from "../../../contexts/SelectRate/SelectRateContext" import { useSelectRateContext } from "../../../contexts/SelectRate/SelectRateContext"
import useLang from "../../../hooks/useLang"
import { mapPackageToLabel } from "../../../utils/getRoomFeatureDescription"
import { trackLowestRoomPrice, trackRoomsLoaded } from "../Tracking/tracking" import { trackLowestRoomPrice, trackRoomsLoaded } from "../Tracking/tracking"
import { RateSummary } from "./RateSummary" import { RateSummary } from "./RateSummary"
import Rooms from "./Rooms" import Rooms from "./Rooms"
@@ -23,8 +28,10 @@ interface RoomsContainerProps
export function RoomsContainer({}: RoomsContainerProps) { export function RoomsContainer({}: RoomsContainerProps) {
const intl = useIntl() const intl = useIntl()
const lang = useLang()
const { const {
hotel,
availability: { error, isFetching, isError, data: availabilityData }, availability: { error, isFetching, isError, data: availabilityData },
input: { hasError: hasInputError, errorCode, data: inputData }, input: { hasError: hasInputError, errorCode, data: inputData },
getLowestRoomPrice, getLowestRoomPrice,
@@ -33,7 +40,20 @@ export function RoomsContainer({}: RoomsContainerProps) {
const { price: lowestRoomPrice, currency: lowestRoomPriceCurrency } = const { price: lowestRoomPrice, currency: lowestRoomPriceCurrency } =
getLowestRoomPrice() ?? {} getLowestRoomPrice() ?? {}
const dataAvailable = availabilityData?.length const dataAvailable = availabilityData?.length
const { hotelId, fromDate, toDate } = inputData?.booking ?? {} const { hotelId, fromDate, toDate, bookingCode, searchType, rooms } =
inputData?.booking ?? {}
const specialRoomType = rooms
?.map((room) => {
const packages = room.packages
?.map((pkg) => {
mapPackageToLabel(pkg)
})
.join(",")
return packages ?? ""
})
.join("|")
useEffect(() => { useEffect(() => {
if (!dataAvailable) return if (!dataAvailable) return
@@ -61,6 +81,48 @@ export function RoomsContainer({}: RoomsContainerProps) {
trackRoomsLoaded() trackRoomsLoaded()
}, [isFetching]) }, [isFetching])
useEffect(() => {
if (isFetching || !availabilityData || !toDate || !fromDate) return
const shouldTrackNoAvailability = availabilityData.some((room) => {
if (!room || "error" in room) return false
return room.roomConfigurations.every(
(roomConfig) => roomConfig.status === AvailabilityEnum.NotAvailable
)
})
if (shouldTrackNoAvailability) {
trackNoAvailability({
specialRoomType,
searchTerm: hotel.data?.additionalData?.name || "",
lang,
fromDate,
toDate,
noOfRooms: rooms?.length,
searchType: "hotel",
hotelId,
rewardNight: searchType === SEARCH_TYPE_REDEMPTION ? "yes" : "no",
bookingCode,
pageId: "select-rate",
pageName: "hotelreservation|select-rate",
pageType: "bookingroomsandratespage",
siteSections: "hotelreservation|select-rate",
domain: typeof window !== "undefined" ? window.location.host : "",
})
}
}, [
isFetching,
availabilityData,
bookingCode,
hotelId,
fromDate,
toDate,
specialRoomType,
hotel.data?.additionalData?.name,
rooms?.length,
searchType,
lang,
])
if (isFetching) { if (isFetching) {
return <RoomsContainerSkeleton /> return <RoomsContainerSkeleton />
} }

View File

@@ -1,9 +1,7 @@
"use client" "use client"
import { NoAvailabilityTracking } from "@scandic-hotels/tracking/NoAvailabilityTracking"
import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK" import { TrackingSDK } from "@scandic-hotels/tracking/TrackingSDK"
import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking" import { SEARCH_TYPE_REDEMPTION } from "@scandic-hotels/trpc/constants/booking"
import { AvailabilityEnum } from "@scandic-hotels/trpc/enums/selectHotel"
import { useSelectRateContext } from "../../../contexts/SelectRate/SelectRateContext" import { useSelectRateContext } from "../../../contexts/SelectRate/SelectRateContext"
import useLang from "../../../hooks/useLang" import useLang from "../../../hooks/useLang"
@@ -22,7 +20,7 @@ interface TrackingProps {
export function SelectRateTracking({ hotelData, booking }: TrackingProps) { export function SelectRateTracking({ hotelData, booking }: TrackingProps) {
const lang = useLang() const lang = useLang()
const { availability, input } = useSelectRateContext() const { input } = useSelectRateContext()
const { fromDate, toDate } = getValidDates(booking.fromDate, booking.toDate) const { fromDate, toDate } = getValidDates(booking.fromDate, booking.toDate)
@@ -39,6 +37,7 @@ export function SelectRateTracking({ hotelData, booking }: TrackingProps) {
return packages ?? "" return packages ?? ""
}) })
.join("|") .join("|")
const { hotelsTrackingData, pageTrackingData } = getSelectRateTracking({ const { hotelsTrackingData, pageTrackingData } = getSelectRateTracking({
lang, lang,
arrivalDate, arrivalDate,
@@ -53,47 +52,7 @@ export function SelectRateTracking({ hotelData, booking }: TrackingProps) {
rooms, rooms,
}) })
let shouldTrackNoAvailability = false
if (availability && !availability.isFetching && availability.data) {
shouldTrackNoAvailability = availability.data.some((room) => {
if (!room || "error" in room) return false
const allRoomsNotAvailable = room.roomConfigurations.every(
(roomConfig) => roomConfig.status === AvailabilityEnum.NotAvailable
)
const isPublicPromotionWithCode = room.roomConfigurations.some((r) => {
const filteredCampaigns = r.campaign.filter(Boolean)
return filteredCampaigns.length
? filteredCampaigns.every(
(product) => !!product.rateDefinition?.isCampaignRate
)
: false
})
const noAvailableBookingCodeRooms =
!isPublicPromotionWithCode &&
room.roomConfigurations.every(
(r) => r.status === AvailabilityEnum.NotAvailable || !r.code.length
)
return (
allRoomsNotAvailable ||
(input.bookingCode && noAvailableBookingCodeRooms)
)
})
}
return ( return (
<> <TrackingSDK hotelInfo={hotelsTrackingData} pageData={pageTrackingData} />
<NoAvailabilityTracking
lang={lang}
shouldTrackNoAvailability={shouldTrackNoAvailability}
hotelsTrackingData={hotelsTrackingData}
pageTrackingData={pageTrackingData}
/>
<TrackingSDK hotelInfo={hotelsTrackingData} pageData={pageTrackingData} />
</>
) )
} }

View File

@@ -128,13 +128,13 @@ export async function AlternativeHotelsPage({
} }
lang={lang} lang={lang}
/> />
<TrackingSDK hotelInfo={hotelsTrackingData} pageData={pageTrackingData} />
<NoAvailabilityTracking <NoAvailabilityTracking
lang={lang} lang={lang}
hotelsTrackingData={hotelsTrackingData} hotelsTrackingData={hotelsTrackingData}
pageTrackingData={pageTrackingData} pageTrackingData={pageTrackingData}
shouldTrackNoAvailability={shouldTrackNoAvailability} shouldTrackNoAvailability={shouldTrackNoAvailability}
/> />
<TrackingSDK hotelInfo={hotelsTrackingData} pageData={pageTrackingData} />
</BookingFlowConfig> </BookingFlowConfig>
) )
} }

View File

@@ -112,13 +112,14 @@ export async function SelectHotelPage({
title={city.name} title={city.name}
lang={lang} lang={lang}
/> />
<TrackingSDK hotelInfo={hotelsTrackingData} pageData={pageTrackingData} />
<NoAvailabilityTracking <NoAvailabilityTracking
lang={lang} lang={lang}
hotelsTrackingData={hotelsTrackingData} hotelsTrackingData={hotelsTrackingData}
pageTrackingData={pageTrackingData} pageTrackingData={pageTrackingData}
shouldTrackNoAvailability={shouldTrackNoAvailability} shouldTrackNoAvailability={shouldTrackNoAvailability}
/> />
<TrackingSDK hotelInfo={hotelsTrackingData} pageData={pageTrackingData} />
</BookingFlowConfig> </BookingFlowConfig>
) )
} }

View File

@@ -79,11 +79,11 @@ export function NoAvailabilityTracking({
} }
type TrackNoAvailabilityParams = { type TrackNoAvailabilityParams = {
specialRoomType: string specialRoomType?: string
fromDate: string fromDate: string
toDate: string toDate: string
hotelId: string hotelId?: string
noOfRooms: number noOfRooms?: number
searchType?: string searchType?: string
bookingCode?: string bookingCode?: string
searchTerm: string searchTerm: string
@@ -93,7 +93,6 @@ type TrackNoAvailabilityParams = {
pageType: string pageType: string
siteSections: string siteSections: string
lang: Lang lang: Lang
sessionId: string | null
domain?: string domain?: string
} }
@@ -112,7 +111,6 @@ export function trackNoAvailability({
pageName, pageName,
pageType, pageType,
siteSections, siteSections,
sessionId,
domain, domain,
}: TrackNoAvailabilityParams) { }: TrackNoAvailabilityParams) {
const arrivalDate = new Date(fromDate) const arrivalDate = new Date(fromDate)
@@ -142,8 +140,6 @@ export function trackNoAvailability({
pageName, pageName,
pageType, pageType,
siteSections, siteSections,
sessionId,
siteVersion: "new-web",
}, },
}) })
} }