Merged in feat/SW-1879-aa-tracking-bed-breakfastpayment (pull request #1789)
feat: SW-1879 Tracking enter-details sections * feat: SW-1879 Tracking enter-details sections * feat: SW-1879 removed onSelect to trigger in onSubmit * feat: SW-1879 Removed onSelect and triggered inside onSubmit * feat: SW-1879 Optimized to remove unnecessary useEffect triggers in every re-render * feat: SW-1879 Updated breakfast package typings * feat: SW-1879 Reverted RadioCardProps * feat: SW-1879 Optimised code Approved-by: Tobias Johansson Approved-by: Christian Andolf
This commit is contained in:
@@ -100,7 +100,7 @@ export default async function DetailsPage({
|
||||
booking,
|
||||
hotel,
|
||||
rooms,
|
||||
!!breakfastPackages?.length,
|
||||
!!breakfastPackages.length,
|
||||
searchParams.city,
|
||||
!!user,
|
||||
lang
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
|
||||
import RadioCard from "@/components/TempDesignSystem/Form/RadioCard"
|
||||
import { useRoomContext } from "@/contexts/Details/Room"
|
||||
import { trackBedSelection } from "@/utils/tracking"
|
||||
|
||||
import { bedTypeFormSchema } from "./schema"
|
||||
|
||||
@@ -47,18 +48,17 @@ export default function BedType() {
|
||||
roomTypeCode: matchingRoom.value,
|
||||
}
|
||||
updateBedType(bedType)
|
||||
trackBedSelection(bedType.roomTypeCode)
|
||||
}
|
||||
},
|
||||
[bedTypes, updateBedType]
|
||||
)
|
||||
|
||||
const selectedBedType = methods.watch("bedType")
|
||||
const handleSubmit = methods.handleSubmit
|
||||
useEffect(() => {
|
||||
if (methods.formState.isSubmitting) {
|
||||
return
|
||||
}
|
||||
|
||||
methods.watch(() => methods.handleSubmit(onSubmit)())
|
||||
}, [methods, onSubmit])
|
||||
handleSubmit(onSubmit)()
|
||||
}, [selectedBedType, handleSubmit, onSubmit])
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
|
||||
@@ -14,6 +14,7 @@ import RadioCard from "@/components/TempDesignSystem/Form/RadioCard"
|
||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||
import { useRoomContext } from "@/contexts/Details/Room"
|
||||
import { formatPrice } from "@/utils/numberFormatting"
|
||||
import { trackBreakfastSelection } from "@/utils/tracking"
|
||||
|
||||
import { breakfastFormSchema } from "./schema"
|
||||
|
||||
@@ -25,6 +26,7 @@ import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
export default function Breakfast() {
|
||||
const intl = useIntl()
|
||||
const packages = useEnterDetailsStore((state) => state.breakfastPackages)
|
||||
const hotelId = useEnterDetailsStore((state) => state.booking.hotelId)
|
||||
const {
|
||||
actions: { updateBreakfast },
|
||||
room,
|
||||
@@ -49,22 +51,26 @@ export default function Breakfast() {
|
||||
|
||||
const onSubmit = useCallback(
|
||||
(values: BreakfastFormSchema) => {
|
||||
const pkg = packages?.find((p) => p.code === values.breakfast)
|
||||
const pkg = packages.find((p) => p.code === values.breakfast)
|
||||
if (pkg) {
|
||||
updateBreakfast(pkg)
|
||||
} else {
|
||||
updateBreakfast(false)
|
||||
}
|
||||
trackBreakfastSelection({
|
||||
breakfastPackage: pkg ?? packages[0],
|
||||
hotelId,
|
||||
units: pkg ? room.adults : 0,
|
||||
})
|
||||
},
|
||||
[packages, updateBreakfast]
|
||||
[packages, hotelId, room.adults, updateBreakfast]
|
||||
)
|
||||
|
||||
const selectedBreakfast = methods.watch("breakfast")
|
||||
const handleSubmit = methods.handleSubmit
|
||||
useEffect(() => {
|
||||
if (methods.formState.isSubmitting) {
|
||||
return
|
||||
}
|
||||
methods.watch(() => methods.handleSubmit(onSubmit)())
|
||||
}, [methods, onSubmit])
|
||||
handleSubmit(onSubmit)()
|
||||
}, [selectedBreakfast, handleSubmit, onSubmit])
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
|
||||
@@ -13,6 +13,7 @@ import { PaymentMethodEnum } from "@/constants/booking"
|
||||
import Modal from "@/components/Modal"
|
||||
import Divider from "@/components/TempDesignSystem/Divider"
|
||||
import Checkbox from "@/components/TempDesignSystem/Form/Checkbox"
|
||||
import { trackPaymentSectionOpen } from "@/utils/tracking/booking"
|
||||
|
||||
import MySavedCards from "../Payment/MySavedCards"
|
||||
import PaymentOption from "../Payment/PaymentOption"
|
||||
@@ -40,7 +41,16 @@ export default function ConfirmBooking({
|
||||
<div className={styles.guaranteeContainer}>
|
||||
<div className={styles.title}>
|
||||
<div className={styles.checkbox}>
|
||||
<Checkbox name="guarantee" />
|
||||
<Checkbox
|
||||
name="guarantee"
|
||||
registerOptions={{
|
||||
onChange: (e) => {
|
||||
if (e.target.value) {
|
||||
trackPaymentSectionOpen()
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Typography variant="Body/Paragraph/mdBold">
|
||||
<p>
|
||||
{intl.formatMessage({
|
||||
|
||||
@@ -13,7 +13,9 @@ import Input from "@/components/TempDesignSystem/Form/Input"
|
||||
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
|
||||
import { useRoomContext } from "@/contexts/Details/Room"
|
||||
import { trackPaymentSectionOpen } from "@/utils/tracking/booking"
|
||||
|
||||
import { hasPrepaidRate } from "../../Payment/helpers"
|
||||
import JoinScandicFriendsCard from "./JoinScandicFriendsCard"
|
||||
import { multiroomDetailsSchema } from "./schema"
|
||||
|
||||
@@ -25,10 +27,13 @@ const formID = "enter-details"
|
||||
export default function Details() {
|
||||
const intl = useIntl()
|
||||
|
||||
const { canProceedToPayment, lastRoom } = useEnterDetailsStore((state) => ({
|
||||
canProceedToPayment: state.canProceedToPayment,
|
||||
lastRoom: state.lastRoom,
|
||||
}))
|
||||
const { canProceedToPayment, lastRoom, rooms } = useEnterDetailsStore(
|
||||
(state) => ({
|
||||
canProceedToPayment: state.canProceedToPayment,
|
||||
lastRoom: state.lastRoom,
|
||||
rooms: state.rooms,
|
||||
})
|
||||
)
|
||||
|
||||
const {
|
||||
actions: { updateDetails },
|
||||
@@ -61,6 +66,8 @@ export default function Details() {
|
||||
const guestIsGoingToJoin = methods.watch("join")
|
||||
const guestIsMember = methods.watch("membershipNo")
|
||||
|
||||
const hasPrepaidRates = rooms.some(hasPrepaidRate)
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
<form
|
||||
@@ -144,6 +151,11 @@ export default function Details() {
|
||||
typography="Body/Paragraph/mdBold"
|
||||
size="Medium"
|
||||
type="submit"
|
||||
onPress={
|
||||
isPaymentNext && canProceedToPayment && hasPrepaidRates
|
||||
? trackPaymentSectionOpen
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{isPaymentNext
|
||||
? intl.formatMessage({
|
||||
|
||||
@@ -14,6 +14,7 @@ import Input from "@/components/TempDesignSystem/Form/Input"
|
||||
import Phone from "@/components/TempDesignSystem/Form/Phone"
|
||||
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
|
||||
import { useRoomContext } from "@/contexts/Details/Room"
|
||||
import { trackPaymentSectionOpen } from "@/utils/tracking/booking"
|
||||
|
||||
import JoinScandicFriendsCard from "./JoinScandicFriendsCard"
|
||||
import MemberPriceModal from "./MemberPriceModal"
|
||||
@@ -162,6 +163,11 @@ export default function Details({ user }: DetailsProps) {
|
||||
typography="Body/Paragraph/mdBold"
|
||||
size="Medium"
|
||||
type="submit"
|
||||
onPress={
|
||||
isPaymentNext && canProceedToPayment && !room.isFlexRate
|
||||
? trackPaymentSectionOpen
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{isPaymentNext
|
||||
? intl.formatMessage({
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function Multiroom() {
|
||||
}))
|
||||
|
||||
const showBreakfastStep =
|
||||
!room.breakfastIncluded && !!breakfastPackages?.length
|
||||
!room.breakfastIncluded && !!breakfastPackages.length
|
||||
|
||||
const arePreviousRoomsValid = rooms.slice(0, idx).every((r) => r.isComplete)
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function RoomOne({ user }: { user: SafeUser }) {
|
||||
)
|
||||
|
||||
const showBreakfastStep =
|
||||
!room.breakfastIncluded && !!breakfastPackages?.length
|
||||
!room.breakfastIncluded && !!breakfastPackages.length
|
||||
|
||||
return (
|
||||
<section>
|
||||
|
||||
@@ -49,7 +49,7 @@ export function createDetailsStore(
|
||||
initialState: InitialState,
|
||||
searchParams: string,
|
||||
user: SafeUser,
|
||||
breakfastPackages: BreakfastPackages | null
|
||||
breakfastPackages: BreakfastPackages
|
||||
) {
|
||||
const isMember = !!user
|
||||
const isRedemption =
|
||||
@@ -134,7 +134,7 @@ export function createDetailsStore(
|
||||
},
|
||||
}
|
||||
|
||||
if (room.breakfastIncluded || !breakfastPackages?.length) {
|
||||
if (room.breakfastIncluded || !breakfastPackages.length) {
|
||||
delete steps[StepEnum.breakfast]
|
||||
}
|
||||
|
||||
@@ -318,7 +318,7 @@ export function createDetailsStore(
|
||||
childrenInRoom: initialState.booking.rooms[idx].childrenInRoom,
|
||||
bedType: room.bedType,
|
||||
breakfast:
|
||||
!breakfastPackages?.length || room.breakfastIncluded
|
||||
!breakfastPackages.length || room.breakfastIncluded
|
||||
? false
|
||||
: undefined,
|
||||
guest:
|
||||
|
||||
@@ -5,7 +5,7 @@ import type { SelectRateSearchParams } from "../components/hotelReservation/sele
|
||||
|
||||
export interface DetailsProviderProps extends React.PropsWithChildren {
|
||||
booking: SelectRateSearchParams
|
||||
breakfastPackages: BreakfastPackages | null
|
||||
breakfastPackages: BreakfastPackages
|
||||
rooms: Room[]
|
||||
searchParamsStr: string
|
||||
user: SafeUser
|
||||
|
||||
@@ -87,7 +87,7 @@ export interface DetailsState {
|
||||
updateSeachParamString: (searchParamString: string) => void
|
||||
}
|
||||
booking: SelectRateSearchParams
|
||||
breakfastPackages: BreakfastPackages | null
|
||||
breakfastPackages: BreakfastPackages
|
||||
canProceedToPayment: boolean
|
||||
isSubmittingDisabled: boolean
|
||||
isSummaryOpen: boolean
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { trackEvent } from "./base"
|
||||
|
||||
import type { BreakfastPackages } from "@/types/components/hotelReservation/breakfast"
|
||||
import type { LowestRoomPriceEvent } from "@/types/components/tracking"
|
||||
|
||||
export function trackLowestRoomPrice(event: LowestRoomPriceEvent) {
|
||||
@@ -16,3 +17,64 @@ export function trackLowestRoomPrice(event: LowestRoomPriceEvent) {
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Tracking for sections of booking flow enter-details page
|
||||
export function trackBedSelection(bedType: string) {
|
||||
trackEvent({
|
||||
event: "bedSelection",
|
||||
selection: {
|
||||
name: "bed options selection click",
|
||||
bedType: bedType,
|
||||
},
|
||||
pageInfo: {
|
||||
pageName: "hotelreservation|bed",
|
||||
pageType: "bookingbedtypepage",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function trackBreakfastSelection({
|
||||
breakfastPackage,
|
||||
hotelId,
|
||||
units,
|
||||
}: {
|
||||
breakfastPackage: BreakfastPackages[number]
|
||||
hotelId: string
|
||||
units: number
|
||||
}) {
|
||||
trackEvent({
|
||||
event: "breakfastSelection",
|
||||
selection: {
|
||||
name: "breakfast options selection click",
|
||||
},
|
||||
ancillaries: [
|
||||
{
|
||||
hotelId: hotelId,
|
||||
productCategory: "",
|
||||
productId: breakfastPackage.code,
|
||||
productUnits: units,
|
||||
productPrice: breakfastPackage.localPrice.price,
|
||||
productPoints: 0,
|
||||
productType: "food",
|
||||
productName: breakfastPackage.packageType,
|
||||
},
|
||||
],
|
||||
pageInfo: {
|
||||
pageName: "hotelreservation|breakfast",
|
||||
pageType: "bookingbreakfastpage",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function trackPaymentSectionOpen() {
|
||||
trackEvent({
|
||||
event: "paymentSectionOpen",
|
||||
selection: {
|
||||
name: "payment section open",
|
||||
},
|
||||
pageInfo: {
|
||||
pageName: "hotelreservation|payment",
|
||||
pageType: "bookingpaymentpage",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
export { trackClick } from "./base"
|
||||
export { trackLowestRoomPrice } from "./booking"
|
||||
export {
|
||||
trackBedSelection,
|
||||
trackBreakfastSelection,
|
||||
trackLowestRoomPrice,
|
||||
} from "./booking"
|
||||
export { trackAccordionClick, trackOpenSidePeekEvent } from "./componentEvents"
|
||||
export { trackHotelMapClick, trackHotelTabClick } from "./hotelPage"
|
||||
export { trackCancelStay, trackMyStayPageLink } from "./myStay"
|
||||
|
||||
Reference in New Issue
Block a user