feat: trackingsdk as client component * feat: trackingsdk as client component * Cleanup * Merge changes from feat/trackingsdk-client * revert yarn.lock * Added lcpTime and wait with tracking until we have the values Approved-by: Joakim Jäderberg
170 lines
6.1 KiB
TypeScript
170 lines
6.1 KiB
TypeScript
import { differenceInCalendarDays, format, isWeekend } from "date-fns"
|
|
import { notFound } from "next/navigation"
|
|
import { Suspense } from "react"
|
|
|
|
import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests"
|
|
import { serverClient } from "@/lib/trpc/server"
|
|
|
|
import HotelDetails from "@/components/HotelReservation/BookingConfirmation/HotelDetails"
|
|
import PaymentDetails from "@/components/HotelReservation/BookingConfirmation/PaymentDetails"
|
|
import Promos from "@/components/HotelReservation/BookingConfirmation/Promos"
|
|
import Receipt from "@/components/HotelReservation/BookingConfirmation/Receipt"
|
|
import Rooms from "@/components/HotelReservation/BookingConfirmation/Rooms"
|
|
import SidePanel from "@/components/HotelReservation/SidePanel"
|
|
import Divider from "@/components/TempDesignSystem/Divider"
|
|
import TrackingSDK from "@/components/TrackingSDK"
|
|
import { getLang } from "@/i18n/serverContext"
|
|
|
|
import { invertedBedTypeMap } from "../utils"
|
|
import Alerts from "./Alerts"
|
|
import Confirmation from "./Confirmation"
|
|
|
|
import styles from "./bookingConfirmation.module.css"
|
|
|
|
import type { BookingConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation"
|
|
import {
|
|
TrackingChannelEnum,
|
|
type TrackingSDKHotelInfo,
|
|
type TrackingSDKPageData,
|
|
type TrackingSDKPaymentInfo,
|
|
} from "@/types/components/tracking"
|
|
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
|
|
|
export default async function BookingConfirmation({
|
|
confirmationNumber,
|
|
}: BookingConfirmationProps) {
|
|
const lang = getLang()
|
|
const bookingConfirmation = await getBookingConfirmation(confirmationNumber)
|
|
|
|
if (!bookingConfirmation) {
|
|
return notFound()
|
|
}
|
|
const { booking, hotel, room } = bookingConfirmation
|
|
if (!room) {
|
|
return notFound()
|
|
}
|
|
|
|
const arrivalDate = new Date(booking.checkInDate)
|
|
const departureDate = new Date(booking.checkOutDate)
|
|
|
|
const breakfastPkgSelected = booking.packages.find(
|
|
(pkg) => pkg.code === BreakfastPackageEnum.REGULAR_BREAKFAST
|
|
)
|
|
|
|
const breakfastAncillary = breakfastPkgSelected && {
|
|
hotelid: hotel.operaId,
|
|
productName: "BreakfastAdult",
|
|
productCategory: "", // TODO: Add category
|
|
productId: breakfastPkgSelected.code ?? "",
|
|
productPrice: +breakfastPkgSelected.unitPrice,
|
|
productUnits: booking.adults,
|
|
productPoints: 0,
|
|
productType: "food",
|
|
}
|
|
|
|
const initialPageTrackingData: TrackingSDKPageData = {
|
|
pageId: "booking-confirmation",
|
|
domainLanguage: lang,
|
|
channel: TrackingChannelEnum["hotelreservation"],
|
|
pageName: `hotelreservation|confirmation`,
|
|
siteSections: `hotelreservation|confirmation`,
|
|
pageType: "confirmation",
|
|
siteVersion: "new-web",
|
|
}
|
|
|
|
const initialHotelsTrackingData: TrackingSDKHotelInfo = {
|
|
arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
|
|
departureDate: format(departureDate, "yyyy-MM-dd"),
|
|
noOfAdults: booking.adults,
|
|
noOfChildren: booking.childrenAges?.length,
|
|
ageOfChildren: booking.childrenAges?.join(","),
|
|
childBedPreference: booking?.childBedPreferences
|
|
?.flatMap((c) => Array(c.quantity).fill(invertedBedTypeMap[c.bedType]))
|
|
.join("|"),
|
|
noOfRooms: 1, // // TODO: Handle multiple rooms
|
|
duration: differenceInCalendarDays(departureDate, arrivalDate),
|
|
leadTime: differenceInCalendarDays(arrivalDate, new Date()),
|
|
searchType: "hotel",
|
|
bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
|
|
country: hotel?.address.country,
|
|
hotelID: hotel.operaId,
|
|
region: hotel?.address.city,
|
|
rateCode: booking.rateDefinition.rateCode ?? undefined,
|
|
//rateCodeType: , //TODO: Add when available in API. "regular, promotion, corporate etx",
|
|
rateCodeName: booking.rateDefinition.title ?? undefined,
|
|
rateCodeCancellationRule:
|
|
booking.rateDefinition?.cancellationText ?? undefined,
|
|
revenueCurrencyCode: booking.currencyCode,
|
|
breakfastOption: booking.rateDefinition.breakfastIncluded
|
|
? "breakfast buffet"
|
|
: "no breakfast",
|
|
totalPrice: booking.totalPrice,
|
|
//specialRoomType: getSpecialRoomType(booking.packages), TODO: Add
|
|
//roomTypeName: booking.roomTypeCode ?? undefined, TODO: Do we get the name?
|
|
bedType: room?.bedType.name,
|
|
roomTypeCode: booking.roomTypeCode ?? undefined,
|
|
roomPrice: booking.roomPrice,
|
|
bnr: booking.confirmationNumber ?? undefined,
|
|
ancillaries: breakfastAncillary ? [breakfastAncillary] : [],
|
|
}
|
|
|
|
const paymentInfo: TrackingSDKPaymentInfo = {
|
|
paymentStatus: "confirmed",
|
|
}
|
|
|
|
const linkedReservations = await Promise.all(
|
|
// TODO: How to handle partial failure (e.g. one booking can't be fetched)? Need UX/UI
|
|
booking.linkedReservations.map(async (res) => {
|
|
const confirmation = await serverClient().booking.confirmation({
|
|
confirmationNumber: res.confirmationNumber,
|
|
})
|
|
return confirmation
|
|
})
|
|
)
|
|
|
|
return (
|
|
<>
|
|
<Confirmation booking={booking} hotel={hotel} room={room}>
|
|
<div className={styles.booking}>
|
|
<Alerts booking={booking} />
|
|
<Rooms
|
|
booking={booking}
|
|
mainRoom={room}
|
|
linkedReservations={booking.linkedReservations}
|
|
/>
|
|
<Suspense fallback={null}>
|
|
<PaymentDetails
|
|
booking={booking}
|
|
linkedReservations={linkedReservations}
|
|
/>
|
|
</Suspense>
|
|
<Divider color="primaryLightSubtle" />
|
|
<HotelDetails hotel={hotel} />
|
|
<Promos
|
|
confirmationNumber={booking.confirmationNumber}
|
|
hotelId={hotel.operaId}
|
|
lastName={booking.guest.lastName}
|
|
/>
|
|
<div className={styles.mobileReceipt}>
|
|
<Suspense fallback={null}>
|
|
<Receipt booking={booking} hotel={hotel} room={room} />
|
|
</Suspense>
|
|
</div>
|
|
</div>
|
|
<aside className={styles.aside}>
|
|
<SidePanel variant="receipt">
|
|
<Suspense fallback={null}>
|
|
<Receipt booking={booking} hotel={hotel} room={room} />
|
|
</Suspense>
|
|
</SidePanel>
|
|
</aside>
|
|
</Confirmation>
|
|
<TrackingSDK
|
|
pageData={initialPageTrackingData}
|
|
hotelInfo={initialHotelsTrackingData}
|
|
paymentInfo={paymentInfo}
|
|
/>
|
|
</>
|
|
)
|
|
}
|