Merged in fix/SW-2853-tracking-breakfast-ancillaries (pull request #2188)
fix(SW-2853): tracking for breakfast ancillaries * fix(SW-2853): tracking for breakfast ancillaries * fix(SW-2853): viewAncillary event fix for breakfast * fix(SW-2853): pr comment spread room facilities Approved-by: Tobias Johansson
This commit is contained in:
@@ -32,6 +32,7 @@ export default function ActionButtons({
|
||||
selectDeliveryTime,
|
||||
selectQuantityAndDeliveryTime,
|
||||
selectedAncillary,
|
||||
breakfastData,
|
||||
} = useAddAncillaryStore((state) => ({
|
||||
currentStep: state.currentStep,
|
||||
isBreakfast: state.isBreakfast,
|
||||
@@ -41,6 +42,7 @@ export default function ActionButtons({
|
||||
selectDeliveryTime: state.selectDeliveryTime,
|
||||
selectQuantityAndDeliveryTime: state.selectQuantityAndDeliveryTime,
|
||||
selectedAncillary: state.selectedAncillary,
|
||||
breakfastData: state.breakfastData,
|
||||
}))
|
||||
const isMobile = useMediaQuery("(max-width: 767px)")
|
||||
const { setError } = useFormContext()
|
||||
@@ -69,7 +71,8 @@ export default function ActionButtons({
|
||||
trackAddAncillary(
|
||||
selectedAncillary,
|
||||
quantityWithCard,
|
||||
quantityWithPoints
|
||||
quantityWithPoints,
|
||||
breakfastData
|
||||
)
|
||||
if (isMobile) {
|
||||
selectQuantityAndDeliveryTime()
|
||||
|
||||
@@ -162,6 +162,7 @@ export default function AddAncillaryFlowModal({
|
||||
data.deliveryTime,
|
||||
"ancillary",
|
||||
selectedAncillary,
|
||||
breakfastData,
|
||||
booking.guaranteeInfo?.cardType,
|
||||
booking.roomTypeCode
|
||||
)
|
||||
@@ -180,12 +181,22 @@ export default function AddAncillaryFlowModal({
|
||||
})
|
||||
router.refresh()
|
||||
} else {
|
||||
trackAncillaryFailed(packages, data.deliveryTime, selectedAncillary)
|
||||
trackAncillaryFailed(
|
||||
packages,
|
||||
data.deliveryTime,
|
||||
selectedAncillary,
|
||||
breakfastData
|
||||
)
|
||||
toast.error(ancillaryErrorMessage)
|
||||
}
|
||||
},
|
||||
onError: () => {
|
||||
trackAncillaryFailed(packages, data.deliveryTime, selectedAncillary)
|
||||
trackAncillaryFailed(
|
||||
packages,
|
||||
data.deliveryTime,
|
||||
selectedAncillary,
|
||||
breakfastData
|
||||
)
|
||||
toast.error(ancillaryErrorMessage)
|
||||
},
|
||||
}
|
||||
@@ -200,7 +211,8 @@ export default function AddAncillaryFlowModal({
|
||||
savedCreditCard,
|
||||
packages,
|
||||
selectedAncillary,
|
||||
data.deliveryTime
|
||||
data.deliveryTime,
|
||||
breakfastData
|
||||
)
|
||||
if (booking.refId) {
|
||||
const card = savedCreditCard
|
||||
@@ -270,6 +282,7 @@ export default function AddAncillaryFlowModal({
|
||||
selectedAncillary,
|
||||
packages: packagesToAdd,
|
||||
isBreakfast,
|
||||
breakfastData,
|
||||
})
|
||||
const shouldSkipGuarantee =
|
||||
booking.guaranteeInfo || (data.quantityWithCard ?? 0) <= 0
|
||||
|
||||
@@ -13,14 +13,17 @@ export default function WrappedAncillaryCard({
|
||||
ancillary,
|
||||
}: WrappedAncillaryProps) {
|
||||
const { description, ...ancillaryWithoutDescription } = ancillary
|
||||
const selectAncillary = useAddAncillaryStore((state) => state.selectAncillary)
|
||||
const { selectAncillary, booking } = useAddAncillaryStore((state) => ({
|
||||
selectAncillary: state.selectAncillary,
|
||||
booking: state.booking,
|
||||
}))
|
||||
|
||||
return (
|
||||
<div
|
||||
role="button"
|
||||
onClick={() => {
|
||||
selectAncillary(ancillary)
|
||||
trackViewAncillary(ancillary)
|
||||
trackViewAncillary(ancillary, booking)
|
||||
}}
|
||||
>
|
||||
<AncillaryCard ancillary={ancillaryWithoutDescription} />
|
||||
|
||||
@@ -20,12 +20,14 @@ export default function RemoveButton({
|
||||
title,
|
||||
booking,
|
||||
ancillary,
|
||||
addedBreakfastPackages,
|
||||
}: {
|
||||
refId: string
|
||||
codes: string[]
|
||||
title?: string
|
||||
booking: Room
|
||||
ancillary: PackageSchema
|
||||
addedBreakfastPackages: PackageSchema[] | undefined
|
||||
}) {
|
||||
const lang = useLang()
|
||||
const intl = useIntl()
|
||||
@@ -75,7 +77,8 @@ export default function RemoveButton({
|
||||
trackRemoveAncillary(
|
||||
ancillary,
|
||||
booking.hotelId,
|
||||
booking.ancillary?.deliveryTime
|
||||
booking.ancillary?.deliveryTime,
|
||||
addedBreakfastPackages
|
||||
)
|
||||
router.refresh()
|
||||
|
||||
|
||||
@@ -137,6 +137,7 @@ export function AddedAncillaries({
|
||||
title={ancillaryTitle}
|
||||
booking={booking}
|
||||
ancillary={ancillary}
|
||||
addedBreakfastPackages={addedBreakfastPackages}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
@@ -205,6 +206,7 @@ export function AddedAncillaries({
|
||||
title={ancillaryTitle}
|
||||
booking={booking}
|
||||
ancillary={ancillary}
|
||||
addedBreakfastPackages={addedBreakfastPackages}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -47,7 +47,7 @@ export default function GuaranteeAncillaryHandler({
|
||||
return
|
||||
}
|
||||
|
||||
const { formData, selectedAncillary, packages } = sessionData
|
||||
const { formData, selectedAncillary, packages, breakfastData } = sessionData
|
||||
|
||||
addAncillary.mutate(
|
||||
{
|
||||
@@ -67,7 +67,8 @@ export default function GuaranteeAncillaryHandler({
|
||||
packages,
|
||||
formData.deliveryTime,
|
||||
"room + ancillary",
|
||||
selectedAncillary
|
||||
selectedAncillary,
|
||||
breakfastData
|
||||
)
|
||||
clearAncillarySessionData()
|
||||
router.replace(returnUrl)
|
||||
@@ -75,7 +76,8 @@ export default function GuaranteeAncillaryHandler({
|
||||
trackAncillaryFailed(
|
||||
packages,
|
||||
formData.deliveryTime,
|
||||
selectedAncillary
|
||||
selectedAncillary,
|
||||
breakfastData
|
||||
)
|
||||
router.replace(`${returnUrl}&errorCode=AncillaryFailed`)
|
||||
}
|
||||
@@ -84,7 +86,8 @@ export default function GuaranteeAncillaryHandler({
|
||||
trackAncillaryFailed(
|
||||
packages,
|
||||
formData.deliveryTime,
|
||||
selectedAncillary
|
||||
selectedAncillary,
|
||||
breakfastData
|
||||
)
|
||||
router.replace(`${returnUrl}&errorCode=AncillaryFailed`)
|
||||
},
|
||||
|
||||
@@ -12,7 +12,10 @@ import {
|
||||
import { getAncillarySessionData } from "@/components/HotelReservation/MyStay/utils/ancillaries"
|
||||
import LoadingSpinner from "@/components/LoadingSpinner"
|
||||
import { trackEvent } from "@/utils/tracking/base"
|
||||
import { buildAncillaries } from "@/utils/tracking/myStay"
|
||||
import {
|
||||
buildAncillariesTracking,
|
||||
buildBreakfastTracking,
|
||||
} from "@/utils/tracking/myStay"
|
||||
|
||||
interface TrackGuaranteeProps {
|
||||
status: string
|
||||
@@ -32,7 +35,8 @@ export default function TrackGuarantee({
|
||||
useEffect(() => {
|
||||
const trackAncillaryPaymentEvent = (event: string, status: string) => {
|
||||
const sessionData = getAncillarySessionData()
|
||||
const { formData, selectedAncillary, packages } = sessionData || {}
|
||||
const { formData, selectedAncillary, packages, breakfastData } =
|
||||
sessionData || {}
|
||||
|
||||
trackEvent({
|
||||
event,
|
||||
@@ -42,11 +46,13 @@ export default function TrackGuarantee({
|
||||
lateArrivalGuarantee: "yes",
|
||||
guaranteedProduct: "room + ancillary",
|
||||
},
|
||||
ancillaries: buildAncillaries(
|
||||
packages ?? [],
|
||||
selectedAncillary,
|
||||
formData?.deliveryTime
|
||||
),
|
||||
ancillaries: breakfastData
|
||||
? buildBreakfastTracking(breakfastData)
|
||||
: buildAncillariesTracking(
|
||||
packages ?? [],
|
||||
selectedAncillary,
|
||||
formData?.deliveryTime
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
SelectedAncillary,
|
||||
} from "@/types/components/myPages/myStay/ancillaries"
|
||||
import type { AncillaryFormData } from "@/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/schema"
|
||||
import type { BreakfastData } from "@/stores/my-stay/add-ancillary-flow"
|
||||
|
||||
export const generateDeliveryOptions = () => {
|
||||
const timeSlots = ["16:00-17:00", "17:00-18:00", "18:00-19:00", "19:00-20:00"]
|
||||
@@ -49,6 +50,7 @@ export const getAncillarySessionData = ():
|
||||
comment: string | undefined
|
||||
}[]
|
||||
isBreakfast: boolean
|
||||
breakfastData: BreakfastData | null
|
||||
}
|
||||
| undefined => {
|
||||
if (typeof window === "undefined") return undefined
|
||||
@@ -67,6 +69,7 @@ export function setAncillarySessionData({
|
||||
selectedAncillary,
|
||||
packages,
|
||||
isBreakfast,
|
||||
breakfastData,
|
||||
}: {
|
||||
formData?: AncillaryFormData
|
||||
selectedAncillary?: Ancillary["ancillaryContent"][number] | null
|
||||
@@ -76,6 +79,7 @@ export function setAncillarySessionData({
|
||||
comment: string | undefined
|
||||
}[]
|
||||
isBreakfast: boolean
|
||||
breakfastData: BreakfastData | null
|
||||
}) {
|
||||
if (typeof window === "undefined") return
|
||||
try {
|
||||
@@ -88,6 +92,7 @@ export function setAncillarySessionData({
|
||||
selectedAncillary,
|
||||
packages,
|
||||
isBreakfast,
|
||||
breakfastData,
|
||||
})
|
||||
)
|
||||
} catch (error) {
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function RoomDetails({
|
||||
}: RoomDetailsProps) {
|
||||
const intl = useIntl()
|
||||
|
||||
const filteredSortedFacilities = roomFacilities
|
||||
const filteredSortedFacilities = [...roomFacilities]
|
||||
.sort((a, b) => a.sortOrder - b.sortOrder)
|
||||
.map((facility) => {
|
||||
const Icon = <FacilityIcon name={facility.icon} color="Icon/Default" />
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { trackEvent } from "./base"
|
||||
|
||||
import type { SelectedAncillary } from "@/types/components/myPages/myStay/ancillaries"
|
||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
import { CurrencyEnum } from "@/types/enums/currency"
|
||||
import type { Room } from "@/types/stores/my-stay"
|
||||
import type { PackageSchema } from "@/types/trpc/routers/booking/confirmation"
|
||||
import type { CreditCard } from "@/types/user"
|
||||
import type { BreakfastData } from "@/stores/my-stay/add-ancillary-flow"
|
||||
|
||||
export function trackCancelStay(hotelId: string, bnr: string) {
|
||||
trackEvent({
|
||||
@@ -45,7 +48,7 @@ export function trackGlaSaveCardAttempt(
|
||||
})
|
||||
}
|
||||
|
||||
export function buildAncillaries(
|
||||
export function buildAncillariesTracking(
|
||||
packages: {
|
||||
code: string
|
||||
quantity: number
|
||||
@@ -57,11 +60,14 @@ export function buildAncillaries(
|
||||
return packages.map((pkg) => {
|
||||
const payedWithCard = pkg.code === selectedAncillary?.id
|
||||
const payedWithPoints = pkg.code === selectedAncillary?.loyaltyCode
|
||||
const ancillaryDeliveryTime = selectedAncillary?.requiresDeliveryTime
|
||||
? deliveryTime
|
||||
: undefined
|
||||
|
||||
return {
|
||||
productId: pkg.code,
|
||||
productUnits: pkg.quantity,
|
||||
productDeliveryTime: deliveryTime,
|
||||
productDeliveryTime: ancillaryDeliveryTime,
|
||||
productName: selectedAncillary?.title,
|
||||
productCategory: selectedAncillary?.categoryName,
|
||||
...(payedWithCard && {
|
||||
@@ -83,7 +89,8 @@ export function trackGlaAncillaryAttempt(
|
||||
comment: string | undefined
|
||||
}[],
|
||||
selectedAncillary: SelectedAncillary | null,
|
||||
deliveryTime: string | undefined
|
||||
deliveryTime: string | undefined,
|
||||
breakfastData: BreakfastData | null
|
||||
) {
|
||||
trackEvent({
|
||||
event: "GuaranteeAttemptAncillary",
|
||||
@@ -91,7 +98,9 @@ export function trackGlaAncillaryAttempt(
|
||||
status: "glacardsaveattempt",
|
||||
type: savedCreditCard?.cardType,
|
||||
},
|
||||
ancillaries: buildAncillaries(packages, selectedAncillary, deliveryTime),
|
||||
ancillaries: breakfastData
|
||||
? buildBreakfastTracking(breakfastData, selectedAncillary?.hotelId)
|
||||
: buildAncillariesTracking(packages, selectedAncillary, deliveryTime),
|
||||
hotelInfo: {
|
||||
hotelId: selectedAncillary?.hotelId,
|
||||
lateArrivalGuarantee: "yes",
|
||||
@@ -110,6 +119,7 @@ export function trackAncillarySuccess(
|
||||
deliveryTime: string | null | undefined,
|
||||
guaranteedProduct: string,
|
||||
selectedAncillary: SelectedAncillary | null,
|
||||
breakfastData: BreakfastData | null,
|
||||
cardType?: string,
|
||||
roomTypeCode?: string
|
||||
) {
|
||||
@@ -125,7 +135,9 @@ export function trackAncillarySuccess(
|
||||
status: "glacardsaveconfirmed",
|
||||
type: cardType,
|
||||
},
|
||||
ancillaries: buildAncillaries(packages, selectedAncillary, deliveryTime),
|
||||
ancillaries: breakfastData
|
||||
? buildBreakfastTracking(breakfastData, selectedAncillary?.hotelId)
|
||||
: buildAncillariesTracking(packages, selectedAncillary, deliveryTime),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -136,11 +148,14 @@ export function trackAncillaryFailed(
|
||||
comment?: string
|
||||
}[],
|
||||
deliveryTime: string | null | undefined,
|
||||
selectedAncillary: SelectedAncillary | null
|
||||
selectedAncillary: SelectedAncillary | null,
|
||||
breakfastData: BreakfastData | null
|
||||
) {
|
||||
trackEvent({
|
||||
event: "GuaranteeFailAncillary",
|
||||
ancillaries: buildAncillaries(packages, selectedAncillary, deliveryTime),
|
||||
ancillaries: breakfastData
|
||||
? buildBreakfastTracking(breakfastData, selectedAncillary?.hotelId)
|
||||
: buildAncillariesTracking(packages, selectedAncillary, deliveryTime),
|
||||
hotelInfo: {
|
||||
hotelId: selectedAncillary?.hotelId,
|
||||
lateArrivalGuarantee: "yes",
|
||||
@@ -149,47 +164,129 @@ export function trackAncillaryFailed(
|
||||
})
|
||||
}
|
||||
|
||||
export function trackViewAncillary(ancillary: SelectedAncillary) {
|
||||
export function buildBreakfastTracking(
|
||||
breakfastData: BreakfastData,
|
||||
hotelId?: number
|
||||
) {
|
||||
const items = []
|
||||
|
||||
if (breakfastData.nrOfAdults) {
|
||||
items.push({
|
||||
hotelId,
|
||||
productId: BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST,
|
||||
productName: "Breakfast",
|
||||
productUnits: breakfastData.nrOfAdults * breakfastData.nrOfNights,
|
||||
productPrice:
|
||||
breakfastData.priceAdult *
|
||||
breakfastData.nrOfAdults *
|
||||
breakfastData.nrOfNights,
|
||||
currency: breakfastData.currency,
|
||||
productCategory: "Food",
|
||||
})
|
||||
}
|
||||
|
||||
if (breakfastData.nrOfPayingChildren) {
|
||||
items.push({
|
||||
hotelId,
|
||||
productId: BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST,
|
||||
productName: "Breakfast",
|
||||
productUnits: breakfastData.nrOfPayingChildren * breakfastData.nrOfNights,
|
||||
productPrice:
|
||||
breakfastData.priceChild *
|
||||
breakfastData.nrOfPayingChildren *
|
||||
breakfastData.nrOfNights,
|
||||
currency: breakfastData.currency,
|
||||
productCategory: "Food",
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
export function trackViewAncillary(
|
||||
ancillary: SelectedAncillary,
|
||||
booking: Room
|
||||
) {
|
||||
const { hotelId, id, title, categoryName } = ancillary
|
||||
const isBreakfast = id === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
|
||||
const hasPayingChildren = booking.childrenAges.some((age) => age >= 4)
|
||||
|
||||
const ancillaries = [
|
||||
{
|
||||
hotelId,
|
||||
productId: id,
|
||||
productName: title,
|
||||
productCategory: categoryName,
|
||||
},
|
||||
]
|
||||
|
||||
if (isBreakfast && hasPayingChildren) {
|
||||
ancillaries.push({
|
||||
hotelId,
|
||||
productId: BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST,
|
||||
productName: title,
|
||||
productCategory: categoryName,
|
||||
})
|
||||
}
|
||||
|
||||
trackEvent({
|
||||
event: "viewAncillary",
|
||||
ancillaries: [
|
||||
{
|
||||
hotelId: ancillary.hotelId,
|
||||
productId: ancillary.id,
|
||||
productName: ancillary.title,
|
||||
productCategory: ancillary.categoryName,
|
||||
},
|
||||
],
|
||||
ancillaries,
|
||||
})
|
||||
}
|
||||
|
||||
export function trackRemoveAncillary(
|
||||
ancillary: PackageSchema,
|
||||
hotelId: string,
|
||||
deliveryTime?: string
|
||||
deliveryTime?: string,
|
||||
addedBreakfastPackages?: PackageSchema[]
|
||||
) {
|
||||
const isBreakfastPackage =
|
||||
ancillary.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
|
||||
const isPoints = ancillary.currency === CurrencyEnum.POINTS
|
||||
const packagesWithoutFreeChildBreakfast = addedBreakfastPackages?.filter(
|
||||
(p) => p.code !== BreakfastPackageEnum.FREE_CHILD_BREAKFAST
|
||||
)
|
||||
|
||||
const ancillaries = isBreakfastPackage
|
||||
? (packagesWithoutFreeChildBreakfast?.map((pkg) => ({
|
||||
hotelId,
|
||||
productId: pkg.code,
|
||||
productPrice: pkg.totalPrice,
|
||||
productUnits: pkg.totalUnit,
|
||||
productType: pkg.type,
|
||||
})) ?? [])
|
||||
: [
|
||||
{
|
||||
hotelId,
|
||||
productId: ancillary.code,
|
||||
productPrice: isPoints ? 0 : ancillary.totalPrice,
|
||||
productPoints: isPoints ? ancillary.totalPrice : 0,
|
||||
productUnits: ancillary.totalUnit,
|
||||
productType: ancillary.type,
|
||||
productDeliveryTime: deliveryTime,
|
||||
},
|
||||
]
|
||||
|
||||
trackEvent({
|
||||
event: "removeAncillary",
|
||||
ancillaries: [
|
||||
{
|
||||
hotelId,
|
||||
productId: ancillary.code,
|
||||
productPrice: isPoints ? 0 : ancillary.totalPrice,
|
||||
productPoints: isPoints ? ancillary.totalPrice : 0,
|
||||
productUnits: ancillary.totalUnit,
|
||||
productType: ancillary.type,
|
||||
productDeliveryTime: deliveryTime,
|
||||
},
|
||||
],
|
||||
ancillaries,
|
||||
})
|
||||
}
|
||||
|
||||
export function trackAddAncillary(
|
||||
ancillary: SelectedAncillary | null,
|
||||
quantityWithCard: number | null,
|
||||
quantityWithPoints: number | null
|
||||
quantityWithPoints: number | null,
|
||||
breakfastData: BreakfastData | null
|
||||
) {
|
||||
if (breakfastData) {
|
||||
return trackEvent({
|
||||
event: "addAncillary",
|
||||
ancillaries: buildBreakfastTracking(breakfastData, ancillary?.hotelId),
|
||||
})
|
||||
}
|
||||
|
||||
const ancillaries = []
|
||||
if ((quantityWithCard ?? 0) > 0) {
|
||||
ancillaries.push({
|
||||
|
||||
Reference in New Issue
Block a user