|
|
|
|
@@ -32,7 +32,6 @@ import { env } from "../../../../env/client"
|
|
|
|
|
import { useBookingFlowContext } from "../../../hooks/useBookingFlowContext"
|
|
|
|
|
import { clearBookingWidgetState } from "../../../hooks/useBookingWidgetState"
|
|
|
|
|
import { useHandleBookingStatus } from "../../../hooks/useHandleBookingStatus"
|
|
|
|
|
import { useIsLoggedIn } from "../../../hooks/useIsLoggedIn"
|
|
|
|
|
import useLang from "../../../hooks/useLang"
|
|
|
|
|
import { useEnterDetailsStore } from "../../../stores/enter-details"
|
|
|
|
|
import ConfirmBooking from "../Confirm"
|
|
|
|
|
@@ -44,6 +43,7 @@ import {
|
|
|
|
|
hasFlexibleRate,
|
|
|
|
|
hasPrepaidRate,
|
|
|
|
|
isPaymentMethodEnum,
|
|
|
|
|
mustGuaranteeBooking,
|
|
|
|
|
writePaymentInfoToSessionStorage,
|
|
|
|
|
} from "./helpers"
|
|
|
|
|
import { type PaymentFormData, paymentSchema } from "./schema"
|
|
|
|
|
@@ -51,6 +51,7 @@ import { getPaymentHeadingConfig } from "./utils"
|
|
|
|
|
|
|
|
|
|
import styles from "./payment.module.css"
|
|
|
|
|
|
|
|
|
|
import type { Lang } from "@scandic-hotels/common/constants/language"
|
|
|
|
|
import type { CreateBookingInput } from "@scandic-hotels/trpc/routers/booking/mutation/create/schema"
|
|
|
|
|
import type { CreditCard } from "@scandic-hotels/trpc/types/user"
|
|
|
|
|
|
|
|
|
|
@@ -74,10 +75,13 @@ export default function PaymentClient({
|
|
|
|
|
const intl = useIntl()
|
|
|
|
|
const pathname = usePathname()
|
|
|
|
|
const searchParams = useSearchParams()
|
|
|
|
|
const isUserLoggedIn = useIsLoggedIn()
|
|
|
|
|
const { getTopOffset } = useStickyPosition({})
|
|
|
|
|
const { user } = useBookingFlowContext()
|
|
|
|
|
|
|
|
|
|
const { user, isLoggedIn } = useBookingFlowContext()
|
|
|
|
|
const [refId, setRefId] = useState("")
|
|
|
|
|
const [isPollingForBookingStatus, setIsPollingForBookingStatus] =
|
|
|
|
|
useState(false)
|
|
|
|
|
const [priceChangeData, setPriceChangeData] =
|
|
|
|
|
useState<PriceChangeData | null>(null)
|
|
|
|
|
const [showBookingAlert, setShowBookingAlert] = useState(false)
|
|
|
|
|
|
|
|
|
|
const {
|
|
|
|
|
@@ -96,35 +100,16 @@ export default function PaymentClient({
|
|
|
|
|
runPreSubmitCallbacks: state.actions.runPreSubmitCallbacks,
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
const bookingMustBeGuaranteed = rooms.some(({ room }, idx) => {
|
|
|
|
|
if (idx === 0 && isUserLoggedIn && room.memberMustBeGuaranteed) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
(room.guest.join || room.guest.membershipNo) &&
|
|
|
|
|
booking.rooms[idx].counterRateCode
|
|
|
|
|
) {
|
|
|
|
|
return room.memberMustBeGuaranteed
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return room.mustBeGuaranteed
|
|
|
|
|
const bookingMustBeGuaranteed = mustGuaranteeBooking({
|
|
|
|
|
isUserLoggedIn: isLoggedIn,
|
|
|
|
|
booking,
|
|
|
|
|
rooms,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const [refId, setRefId] = useState("")
|
|
|
|
|
const [isPollingForBookingStatus, setIsPollingForBookingStatus] =
|
|
|
|
|
useState(false)
|
|
|
|
|
|
|
|
|
|
const [priceChangeData, setPriceChangeData] =
|
|
|
|
|
useState<PriceChangeData | null>(null)
|
|
|
|
|
|
|
|
|
|
const { toDate, fromDate, hotelId } = booking
|
|
|
|
|
|
|
|
|
|
const hasPrepaidRates = rooms.some(hasPrepaidRate)
|
|
|
|
|
const hasFlexRates = rooms.some(hasFlexibleRate)
|
|
|
|
|
const hasOnlyFlexRates = rooms.every(hasFlexibleRate)
|
|
|
|
|
const hasMixedRates = hasPrepaidRates && hasFlexRates
|
|
|
|
|
const isRedemptionBooking = booking.searchType === SEARCH_TYPE_REDEMPTION
|
|
|
|
|
|
|
|
|
|
const methods = useForm<PaymentFormData>({
|
|
|
|
|
defaultValues: {
|
|
|
|
|
@@ -171,9 +156,9 @@ export default function PaymentClient({
|
|
|
|
|
|
|
|
|
|
const hasPriceChange = booking.rooms.some((r) => r.priceChangedMetadata)
|
|
|
|
|
if (hasPriceChange) {
|
|
|
|
|
const priceChangeData = booking.rooms.map(
|
|
|
|
|
(room) => room.priceChangedMetadata || null
|
|
|
|
|
)
|
|
|
|
|
const priceChangeData = booking.rooms
|
|
|
|
|
.map((room) => room.priceChangedMetadata || null)
|
|
|
|
|
.filter(isNotNull)
|
|
|
|
|
setPriceChangeData(priceChangeData)
|
|
|
|
|
} else {
|
|
|
|
|
setIsPollingForBookingStatus(true)
|
|
|
|
|
@@ -204,19 +189,9 @@ export default function PaymentClient({
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const bookingStatus = useHandleBookingStatus({
|
|
|
|
|
refId,
|
|
|
|
|
expectedStatuses: [BookingStatusEnum.BookingCompleted],
|
|
|
|
|
maxRetries,
|
|
|
|
|
retryInterval,
|
|
|
|
|
enabled: isPollingForBookingStatus,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const handlePaymentError = useCallback(
|
|
|
|
|
const { toDate, fromDate, hotelId } = booking
|
|
|
|
|
const trackPaymentError = useCallback(
|
|
|
|
|
(errorMessage: string) => {
|
|
|
|
|
setShowBookingAlert(true)
|
|
|
|
|
setIsSubmitting(false)
|
|
|
|
|
|
|
|
|
|
const currentPaymentMethod = methods.getValues("paymentMethod")
|
|
|
|
|
const smsEnable = methods.getValues("smsConfirmation")
|
|
|
|
|
const guarantee = methods.getValues("guarantee")
|
|
|
|
|
@@ -255,52 +230,30 @@ export default function PaymentClient({
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[
|
|
|
|
|
methods,
|
|
|
|
|
savedCreditCards,
|
|
|
|
|
hotelId,
|
|
|
|
|
bookingMustBeGuaranteed,
|
|
|
|
|
hasOnlyFlexRates,
|
|
|
|
|
setIsSubmitting,
|
|
|
|
|
hotelId,
|
|
|
|
|
methods,
|
|
|
|
|
savedCreditCards,
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (bookingStatus?.data?.booking.paymentUrl) {
|
|
|
|
|
router.push(bookingStatus.data.booking.paymentUrl)
|
|
|
|
|
} else if (
|
|
|
|
|
bookingStatus?.data?.booking.reservationStatus ===
|
|
|
|
|
BookingStatusEnum.BookingCompleted
|
|
|
|
|
) {
|
|
|
|
|
const mainRoom = bookingStatus.data.booking.rooms[0]
|
|
|
|
|
clearBookingWidgetState()
|
|
|
|
|
// Cookie is used by Booking Confirmation page to validate that the user came from payment callback
|
|
|
|
|
document.cookie = `bcsig=${bookingStatus.data.sig}; Path=/; Max-Age=60; Secure; SameSite=Strict`
|
|
|
|
|
const confirmationUrl = `${bookingConfirmation(lang)}?RefId=${encodeURIComponent(mainRoom.refId)}`
|
|
|
|
|
router.push(confirmationUrl)
|
|
|
|
|
} else if (bookingStatus.isTimeout) {
|
|
|
|
|
handlePaymentError("Timeout")
|
|
|
|
|
}
|
|
|
|
|
}, [
|
|
|
|
|
bookingStatus.data,
|
|
|
|
|
bookingStatus.isTimeout,
|
|
|
|
|
router,
|
|
|
|
|
intl,
|
|
|
|
|
lang,
|
|
|
|
|
handlePaymentError,
|
|
|
|
|
])
|
|
|
|
|
const handlePaymentError = useCallback(
|
|
|
|
|
(errorMessage: string) => {
|
|
|
|
|
setShowBookingAlert(true)
|
|
|
|
|
setIsSubmitting(false)
|
|
|
|
|
|
|
|
|
|
const getPaymentMethod = useCallback(
|
|
|
|
|
(paymentMethod: string | null | undefined): PaymentMethodEnum => {
|
|
|
|
|
if (hasFlexRates) {
|
|
|
|
|
return PaymentMethodEnum.card
|
|
|
|
|
}
|
|
|
|
|
return paymentMethod && isPaymentMethodEnum(paymentMethod)
|
|
|
|
|
? paymentMethod
|
|
|
|
|
: PaymentMethodEnum.card
|
|
|
|
|
trackPaymentError(errorMessage)
|
|
|
|
|
},
|
|
|
|
|
[hasFlexRates]
|
|
|
|
|
[setIsSubmitting, trackPaymentError]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
useBookingStatusRedirect({
|
|
|
|
|
refId,
|
|
|
|
|
enabled: isPollingForBookingStatus,
|
|
|
|
|
onError: handlePaymentError,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const scrollToInvalidField = useCallback(async (): Promise<boolean> => {
|
|
|
|
|
// If any room is not complete/valid, scroll to the first invalid field, this is needed as rooms and other fields are in separate forms
|
|
|
|
|
|
|
|
|
|
@@ -308,20 +261,12 @@ export default function PaymentClient({
|
|
|
|
|
const errorNames = Object.keys(methods.formState.errors)
|
|
|
|
|
const firstIncompleteRoomIndex = rooms.findIndex((room) => !room.isComplete)
|
|
|
|
|
|
|
|
|
|
const scrollToElement = (el: HTMLElement) => {
|
|
|
|
|
const offset = getTopOffset()
|
|
|
|
|
const top = el.getBoundingClientRect().top + window.scrollY - offset - 20
|
|
|
|
|
window.scrollTo({ top, behavior: "smooth" })
|
|
|
|
|
const input = el.querySelector<HTMLElement>("input")
|
|
|
|
|
input?.focus({ preventScroll: true })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (invalidField) {
|
|
|
|
|
scrollToElement(invalidField)
|
|
|
|
|
scrollToElement(invalidField, getTopOffset())
|
|
|
|
|
} else if (errorNames.length > 0) {
|
|
|
|
|
const firstErrorEl = document.querySelector(`[name="${errorNames[0]}"]`)
|
|
|
|
|
if (firstErrorEl) {
|
|
|
|
|
scrollToElement(firstErrorEl as HTMLElement)
|
|
|
|
|
scrollToElement(firstErrorEl as HTMLElement, getTopOffset())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -338,63 +283,32 @@ export default function PaymentClient({
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const paymentMethod = getPaymentMethod(data.paymentMethod)
|
|
|
|
|
const paymentMethod = getPaymentMethod(data.paymentMethod, hasFlexRates)
|
|
|
|
|
|
|
|
|
|
const savedCreditCard = savedCreditCards?.find(
|
|
|
|
|
(card) => card.id === data.paymentMethod
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const paymentRedirectUrl = `${env.NEXT_PUBLIC_NODE_ENV === "development" ? `http://localhost:${env.NEXT_PUBLIC_PORT}` : ""}/${lang}/hotelreservation/payment-callback`
|
|
|
|
|
const guarantee = data.guarantee
|
|
|
|
|
const useSavedCard = savedCreditCard
|
|
|
|
|
? {
|
|
|
|
|
card: {
|
|
|
|
|
alias: savedCreditCard.alias,
|
|
|
|
|
expiryDate: savedCreditCard.expirationDate,
|
|
|
|
|
cardType: savedCreditCard.cardType,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
: {}
|
|
|
|
|
|
|
|
|
|
const shouldUsePayment =
|
|
|
|
|
guarantee || bookingMustBeGuaranteed || !hasOnlyFlexRates
|
|
|
|
|
const payment = shouldUsePayment
|
|
|
|
|
? {
|
|
|
|
|
paymentMethod: paymentMethod,
|
|
|
|
|
...useSavedCard,
|
|
|
|
|
success: `${paymentRedirectUrl}/success`,
|
|
|
|
|
error: `${paymentRedirectUrl}/error`,
|
|
|
|
|
cancel: `${paymentRedirectUrl}/cancel`,
|
|
|
|
|
}
|
|
|
|
|
? getPaymentData({ paymentMethod, savedCreditCard, lang })
|
|
|
|
|
: undefined
|
|
|
|
|
|
|
|
|
|
const paymentMethodType = savedCreditCard
|
|
|
|
|
? savedCreditCard.type
|
|
|
|
|
: paymentMethod
|
|
|
|
|
if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
|
|
|
|
|
const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
|
|
|
|
|
writeGlaToSessionStorage(
|
|
|
|
|
lateArrivalGuarantee,
|
|
|
|
|
hotelId,
|
|
|
|
|
paymentMethodType,
|
|
|
|
|
!!savedCreditCard
|
|
|
|
|
)
|
|
|
|
|
trackGlaSaveCardAttempt({
|
|
|
|
|
hotelId,
|
|
|
|
|
hasSavedCreditCard: !!savedCreditCard,
|
|
|
|
|
creditCardType: savedCreditCard?.cardType,
|
|
|
|
|
lateArrivalGuarantee,
|
|
|
|
|
})
|
|
|
|
|
} else if (!hasOnlyFlexRates) {
|
|
|
|
|
trackPaymentEvent({
|
|
|
|
|
event: "paymentAttemptStart",
|
|
|
|
|
hotelId,
|
|
|
|
|
method: paymentMethodType,
|
|
|
|
|
isSavedCreditCard: !!savedCreditCard,
|
|
|
|
|
smsEnable: data.smsConfirmation,
|
|
|
|
|
status: "attempt",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
writePaymentInfoToSessionStorage(paymentMethodType, !!savedCreditCard)
|
|
|
|
|
trackPaymentEvents({
|
|
|
|
|
isSavedCreditCard: !!savedCreditCard,
|
|
|
|
|
paymentMethodType,
|
|
|
|
|
guarantee,
|
|
|
|
|
smsEnable: data.smsConfirmation,
|
|
|
|
|
bookingMustBeGuaranteed,
|
|
|
|
|
hasOnlyFlexRates,
|
|
|
|
|
hotelId,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const payload: CreateBookingInput = {
|
|
|
|
|
checkInDate: fromDate,
|
|
|
|
|
@@ -406,7 +320,7 @@ export default function PaymentClient({
|
|
|
|
|
({ room }, idx): CreateBookingInput["rooms"][number] => {
|
|
|
|
|
const isMainRoom = idx === 0
|
|
|
|
|
let rateCode = ""
|
|
|
|
|
if (isMainRoom && isUserLoggedIn) {
|
|
|
|
|
if (isMainRoom && isLoggedIn) {
|
|
|
|
|
rateCode = booking.rooms[idx].rateCode
|
|
|
|
|
} else if (
|
|
|
|
|
(room.guest.join || room.guest.membershipNo) &&
|
|
|
|
|
@@ -500,17 +414,17 @@ export default function PaymentClient({
|
|
|
|
|
[
|
|
|
|
|
setIsSubmitting,
|
|
|
|
|
scrollToInvalidField,
|
|
|
|
|
getPaymentMethod,
|
|
|
|
|
hasFlexRates,
|
|
|
|
|
savedCreditCards,
|
|
|
|
|
lang,
|
|
|
|
|
bookingMustBeGuaranteed,
|
|
|
|
|
hasOnlyFlexRates,
|
|
|
|
|
lang,
|
|
|
|
|
fromDate,
|
|
|
|
|
toDate,
|
|
|
|
|
hotelId,
|
|
|
|
|
rooms,
|
|
|
|
|
initiateBooking,
|
|
|
|
|
isUserLoggedIn,
|
|
|
|
|
isLoggedIn,
|
|
|
|
|
booking.rooms,
|
|
|
|
|
user?.data?.partnerLoyaltyNumber,
|
|
|
|
|
]
|
|
|
|
|
@@ -526,6 +440,7 @@ export default function PaymentClient({
|
|
|
|
|
const { preHeading, heading, subHeading, showLearnMore } =
|
|
|
|
|
getPaymentHeadingConfig(intl, bookingMustBeGuaranteed, hasOnlyFlexRates)
|
|
|
|
|
|
|
|
|
|
const isRedemptionBooking = booking.searchType === SEARCH_TYPE_REDEMPTION
|
|
|
|
|
return (
|
|
|
|
|
<section
|
|
|
|
|
className={cx(styles.paymentSection, {
|
|
|
|
|
@@ -599,3 +514,148 @@ export default function PaymentClient({
|
|
|
|
|
</section>
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const scrollToElement = (el: HTMLElement, offset: number) => {
|
|
|
|
|
const top = el.getBoundingClientRect().top + window.scrollY - offset - 20
|
|
|
|
|
window.scrollTo({ top, behavior: "smooth" })
|
|
|
|
|
const input = el.querySelector<HTMLElement>("input")
|
|
|
|
|
input?.focus({ preventScroll: true })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getPaymentMethod = (
|
|
|
|
|
paymentMethod: string | null | undefined,
|
|
|
|
|
hasFlexRates: boolean
|
|
|
|
|
): PaymentMethodEnum => {
|
|
|
|
|
if (hasFlexRates) {
|
|
|
|
|
return PaymentMethodEnum.card
|
|
|
|
|
}
|
|
|
|
|
return paymentMethod && isPaymentMethodEnum(paymentMethod)
|
|
|
|
|
? paymentMethod
|
|
|
|
|
: PaymentMethodEnum.card
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createPaymentCallbackUrl(lang: Lang) {
|
|
|
|
|
return `${env.NEXT_PUBLIC_NODE_ENV === "development" ? `http://localhost:${env.NEXT_PUBLIC_PORT}` : ""}/${lang}/hotelreservation/payment-callback`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function useBookingStatusRedirect({
|
|
|
|
|
refId,
|
|
|
|
|
enabled,
|
|
|
|
|
onError,
|
|
|
|
|
}: {
|
|
|
|
|
refId: string
|
|
|
|
|
enabled: boolean
|
|
|
|
|
onError: (errorMessage: string) => void
|
|
|
|
|
}) {
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
const lang = useLang()
|
|
|
|
|
const intl = useIntl()
|
|
|
|
|
|
|
|
|
|
const bookingStatus = useHandleBookingStatus({
|
|
|
|
|
refId,
|
|
|
|
|
expectedStatuses: [BookingStatusEnum.BookingCompleted],
|
|
|
|
|
maxRetries,
|
|
|
|
|
retryInterval,
|
|
|
|
|
enabled,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (bookingStatus?.data?.booking.paymentUrl) {
|
|
|
|
|
router.push(bookingStatus.data.booking.paymentUrl)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
bookingStatus?.data?.booking.reservationStatus ===
|
|
|
|
|
BookingStatusEnum.BookingCompleted
|
|
|
|
|
) {
|
|
|
|
|
const mainRoom = bookingStatus.data.booking.rooms[0]
|
|
|
|
|
clearBookingWidgetState()
|
|
|
|
|
// Cookie is used by Booking Confirmation page to validate that the user came from payment callback
|
|
|
|
|
document.cookie = `bcsig=${bookingStatus.data.sig}; Path=/; Max-Age=60; Secure; SameSite=Strict`
|
|
|
|
|
const confirmationUrl = `${bookingConfirmation(lang)}?RefId=${encodeURIComponent(mainRoom.refId)}`
|
|
|
|
|
router.push(confirmationUrl)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bookingStatus.isTimeout) {
|
|
|
|
|
onError("Timeout")
|
|
|
|
|
}
|
|
|
|
|
}, [bookingStatus.data, bookingStatus.isTimeout, router, intl, lang, onError])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getPaymentData({
|
|
|
|
|
paymentMethod,
|
|
|
|
|
savedCreditCard,
|
|
|
|
|
lang,
|
|
|
|
|
}: {
|
|
|
|
|
paymentMethod: PaymentMethodEnum
|
|
|
|
|
savedCreditCard?: CreditCard
|
|
|
|
|
lang: Lang
|
|
|
|
|
}) {
|
|
|
|
|
const paymentRedirectUrl = createPaymentCallbackUrl(lang)
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
paymentMethod: paymentMethod,
|
|
|
|
|
success: `${paymentRedirectUrl}/success`,
|
|
|
|
|
error: `${paymentRedirectUrl}/error`,
|
|
|
|
|
cancel: `${paymentRedirectUrl}/cancel`,
|
|
|
|
|
card: savedCreditCard
|
|
|
|
|
? {
|
|
|
|
|
alias: savedCreditCard.alias,
|
|
|
|
|
expiryDate: savedCreditCard.expirationDate,
|
|
|
|
|
cardType: savedCreditCard.cardType,
|
|
|
|
|
}
|
|
|
|
|
: undefined,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isNotNull<T>(value: T | null): value is T {
|
|
|
|
|
return value !== null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function trackPaymentEvents(data: {
|
|
|
|
|
isSavedCreditCard: boolean
|
|
|
|
|
paymentMethodType: string
|
|
|
|
|
guarantee: boolean
|
|
|
|
|
smsEnable: boolean
|
|
|
|
|
bookingMustBeGuaranteed: boolean
|
|
|
|
|
hasOnlyFlexRates: boolean
|
|
|
|
|
hotelId: string
|
|
|
|
|
}) {
|
|
|
|
|
const {
|
|
|
|
|
isSavedCreditCard,
|
|
|
|
|
paymentMethodType,
|
|
|
|
|
guarantee,
|
|
|
|
|
smsEnable,
|
|
|
|
|
bookingMustBeGuaranteed,
|
|
|
|
|
hasOnlyFlexRates,
|
|
|
|
|
hotelId,
|
|
|
|
|
} = data
|
|
|
|
|
|
|
|
|
|
if (guarantee || (bookingMustBeGuaranteed && hasOnlyFlexRates)) {
|
|
|
|
|
const lateArrivalGuarantee = guarantee ? "yes" : "mandatory"
|
|
|
|
|
writeGlaToSessionStorage(
|
|
|
|
|
lateArrivalGuarantee,
|
|
|
|
|
hotelId,
|
|
|
|
|
paymentMethodType,
|
|
|
|
|
isSavedCreditCard
|
|
|
|
|
)
|
|
|
|
|
trackGlaSaveCardAttempt({
|
|
|
|
|
hotelId,
|
|
|
|
|
hasSavedCreditCard: isSavedCreditCard,
|
|
|
|
|
creditCardType: isSavedCreditCard ? paymentMethodType : undefined,
|
|
|
|
|
lateArrivalGuarantee,
|
|
|
|
|
})
|
|
|
|
|
} else if (!hasOnlyFlexRates) {
|
|
|
|
|
trackPaymentEvent({
|
|
|
|
|
event: "paymentAttemptStart",
|
|
|
|
|
hotelId,
|
|
|
|
|
method: paymentMethodType,
|
|
|
|
|
isSavedCreditCard,
|
|
|
|
|
smsEnable,
|
|
|
|
|
status: "attempt",
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
writePaymentInfoToSessionStorage(paymentMethodType, isSavedCreditCard)
|
|
|
|
|
}
|
|
|
|
|
|