diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx index 782d21eae..0d23ab18a 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/ActionButtons/index.tsx @@ -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() diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx index 6c24f0779..4869324ed 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/AddAncillaryFlowModal/index.tsx @@ -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 diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/WrappedAncillaryCard/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/WrappedAncillaryCard/index.tsx index b72434548..8631c13f8 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/WrappedAncillaryCard/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddAncillaryFlow/WrappedAncillaryCard/index.tsx @@ -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 (
{ selectAncillary(ancillary) - trackViewAncillary(ancillary) + trackViewAncillary(ancillary, booking) }} > diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx index 46b756bbe..fce6930fa 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx @@ -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() diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx index 73b9a55e8..60902ccf1 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx @@ -137,6 +137,7 @@ export function AddedAncillaries({ title={ancillaryTitle} booking={booking} ancillary={ancillary} + addedBreakfastPackages={addedBreakfastPackages} />
) : null} @@ -205,6 +206,7 @@ export function AddedAncillaries({ title={ancillaryTitle} booking={booking} ancillary={ancillary} + addedBreakfastPackages={addedBreakfastPackages} /> ) : null} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx index 6bfecf4fe..2e908cbf7 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback/index.tsx @@ -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`) }, diff --git a/apps/scandic-web/components/HotelReservation/MyStay/TrackGuarantee.tsx b/apps/scandic-web/components/HotelReservation/MyStay/TrackGuarantee.tsx index 18edeb8d1..cef37bda9 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/TrackGuarantee.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/TrackGuarantee.tsx @@ -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 + ), }) } diff --git a/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts b/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts index 6f1d33037..7dabf4a78 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/utils/ancillaries.ts @@ -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) { diff --git a/apps/scandic-web/components/SidePeeks/BookedRoomSidePeek/RoomDetails.tsx b/apps/scandic-web/components/SidePeeks/BookedRoomSidePeek/RoomDetails.tsx index aaa28ba9f..33ceaa478 100644 --- a/apps/scandic-web/components/SidePeeks/BookedRoomSidePeek/RoomDetails.tsx +++ b/apps/scandic-web/components/SidePeeks/BookedRoomSidePeek/RoomDetails.tsx @@ -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 = diff --git a/apps/scandic-web/utils/tracking/myStay.ts b/apps/scandic-web/utils/tracking/myStay.ts index 27d0d6395..9278c749e 100644 --- a/apps/scandic-web/utils/tracking/myStay.ts +++ b/apps/scandic-web/utils/tracking/myStay.ts @@ -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({