Files
web/apps/scandic-web/components/HotelReservation/BookingConfirmation/index.tsx
Linus Flood 0c498d82ca Merged in feat/trackingsdk-client (pull request #1420)
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
2025-02-27 07:22:58 +00:00

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}
/>
</>
)
}