diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Confirmation/confirmation.module.css b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.module.css similarity index 61% rename from apps/scandic-web/components/HotelReservation/BookingConfirmation/Confirmation/confirmation.module.css rename to apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.module.css index e3d91663e..528a447cf 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Confirmation/confirmation.module.css +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.module.css @@ -19,3 +19,26 @@ padding-top: var(--Spacing-x9); } } + +.booking { + display: flex; + flex-direction: column; + gap: var(--Spacing-x5); + grid-area: booking; + padding-bottom: var(--Spacing-x9); +} + +.aside { + display: none; +} + +@media screen and (min-width: 1367px) { + .mobileReceipt { + display: none; + } + + .aside { + display: grid; + grid-area: receipt; + } +} diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx index 2e9ab9faa..0cc1b897c 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(confirmation)/booking-confirmation/page.tsx @@ -1,14 +1,84 @@ +import { notFound } from "next/navigation" + import { getBookingConfirmation } from "@/lib/trpc/memoizedRequests" -import BookingConfirmation from "@/components/HotelReservation/BookingConfirmation" +import Alerts from "@/components/HotelReservation/BookingConfirmation/Alerts" +import Header from "@/components/HotelReservation/BookingConfirmation/Header" +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 Tracking from "@/components/HotelReservation/BookingConfirmation/Tracking" +import { mapRoomState } from "@/components/HotelReservation/BookingConfirmation/utils" +import SidePanel from "@/components/HotelReservation/SidePanel" +import Divider from "@/components/TempDesignSystem/Divider" +import { getIntl } from "@/i18n" +import BookingConfirmationProvider from "@/providers/BookingConfirmationProvider" + +import styles from "./page.module.css" import type { LangParams, PageArgs } from "@/types/params" export default async function BookingConfirmationPage({ + params, searchParams, -}: PageArgs) { - void getBookingConfirmation(searchParams.confirmationNumber) +}: PageArgs) { + const refId = searchParams.RefId + + if (!refId) { + notFound() + } + + const bookingConfirmation = await getBookingConfirmation(refId, params.lang) + + if (!bookingConfirmation) { + notFound() + } + + const { booking, hotelData, room } = bookingConfirmation + const { hotel } = hotelData + + const intl = await getIntl() + return ( - + +
+
+
+ + + + + + +
+ +
+
+ +
+ +
) } diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx index 571a44d89..951141819 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/gla-payment-callback/page.tsx @@ -6,10 +6,12 @@ import { } from "@/constants/booking" import { myStay } from "@/constants/routes/myStay" import { serverClient } from "@/lib/trpc/server" +import { createCounter } from "@/server/telemetry" import GuaranteeCallback from "@/components/HotelReservation/MyStay/Ancillaries/GuaranteeCallback" import TrackGuarantee from "@/components/HotelReservation/MyStay/TrackGuarantee" import LoadingSpinner from "@/components/LoadingSpinner" +import { setLang } from "@/i18n/serverContext" import type { LangParams, PageArgs } from "@/types/params" @@ -19,45 +21,56 @@ export default async function GuaranteePaymentCallbackPage({ }: PageArgs< LangParams, { - status: PaymentCallbackStatusEnum - RefId: string + status?: PaymentCallbackStatusEnum + RefId?: string confirmationNumber?: string ancillary?: string } >) { - console.log(`[gla-payment-callback] callback started`) const lang = params.lang const status = searchParams.status - const confirmationNumber = searchParams.confirmationNumber const refId = searchParams.RefId - if (!refId) { - notFound() - } + const confirmationNumber = searchParams.confirmationNumber const isAncillaryFlow = searchParams.ancillary + setLang(params.lang) + + if (!status || !confirmationNumber || !refId) { + notFound() + } + + const glaSuccessCounter = createCounter("gla", "success") + const metricsGlaSuccess = glaSuccessCounter.init({ + confirmationNumber, + }) + + metricsGlaSuccess.start() + const myStayUrl = `${myStay[lang]}?RefId=${encodeURIComponent(refId)}` - const searchObject = new URLSearchParams() if (status === PaymentCallbackStatusEnum.Success && confirmationNumber) { if (isAncillaryFlow) { return ( ) } - console.log(`[gla-payment-callback] redirecting to: ${myStayUrl}`) + return } let errorMessage = undefined if (confirmationNumber) { + const searchObject = new URLSearchParams() + try { const bookingStatus = await serverClient().booking.status({ - confirmationNumber, + refId, }) const error = bookingStatus.errors.find((e) => e.errorCode) diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/cancel/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/cancel/page.tsx new file mode 100644 index 000000000..773da8fc6 --- /dev/null +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/cancel/page.tsx @@ -0,0 +1,29 @@ +import { + BookingErrorCodeEnum, + PaymentCallbackStatusEnum, +} from "@/constants/booking" +import { details } from "@/constants/routes/hotelReservation" + +import HandleErrorCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleErrorCallback" + +import type { LangParams, PageArgs } from "@/types/params" + +export default async function PaymentCallbackCancelPage({ + params, +}: PageArgs) { + console.log(`[payment-callback] cancel callback started`) + const lang = params.lang + + const returnUrl = details(lang) + const searchObject = new URLSearchParams() + + searchObject.set("errorCode", BookingErrorCodeEnum.TransactionCancelled) + + return ( + + ) +} diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/error/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/error/page.tsx new file mode 100644 index 000000000..3dc556d5e --- /dev/null +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/error/page.tsx @@ -0,0 +1,71 @@ +import { + BookingErrorCodeEnum, + PaymentCallbackStatusEnum, +} from "@/constants/booking" +import { details } from "@/constants/routes/hotelReservation" +import { serverClient } from "@/lib/trpc/server" + +import HandleErrorCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleErrorCallback" +import { calculateRefId } from "@/utils/refId" + +import type { LangParams, PageArgs } from "@/types/params" + +export default async function PaymentCallbackErrorPage({ + params, + searchParams, +}: PageArgs< + LangParams, + { + confirmationNumber?: string + } +>) { + console.log(`[payment-callback] error callback started`) + + const lang = params.lang + const confirmationNumber = searchParams.confirmationNumber + + const returnUrl = details(lang) + const searchObject = new URLSearchParams() + + let errorMessage = undefined + + if (confirmationNumber) { + const refId = calculateRefId(confirmationNumber, "") + + try { + const bookingStatus = await serverClient().booking.confirmationError({ + refId, + }) + + // TODO: how to handle errors for multiple rooms? + const error = bookingStatus.errors.find((e) => e.errorCode) + + errorMessage = + error?.description ?? + `No error message found for booking ${confirmationNumber}` + + searchObject.set( + "errorCode", + error + ? error.errorCode.toString() + : BookingErrorCodeEnum.TransactionFailed + ) + } catch { + console.error( + `[payment-callback] failed to get booking status for ${confirmationNumber}` + ) + + searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed) + errorMessage = `Failed to get booking status for ${confirmationNumber}` + } + } + + return ( + + ) +} diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx deleted file mode 100644 index 74984d9e0..000000000 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/page.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { - BOOKING_CONFIRMATION_NUMBER, - BookingErrorCodeEnum, - PaymentCallbackStatusEnum, -} from "@/constants/booking" -import { - bookingConfirmation, - details, -} from "@/constants/routes/hotelReservation" -import { serverClient } from "@/lib/trpc/server" - -import HandleErrorCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleErrorCallback" -import HandleSuccessCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback" - -import type { LangParams, PageArgs } from "@/types/params" - -export default async function PaymentCallbackPage({ - params, - searchParams, -}: PageArgs< - LangParams, - { - status: PaymentCallbackStatusEnum - confirmationNumber?: string - hotel?: string - } ->) { - console.log(`[payment-callback] callback started`) - const lang = params.lang - const status = searchParams.status - const confirmationNumber = searchParams.confirmationNumber - - if (status === PaymentCallbackStatusEnum.Success && confirmationNumber) { - const confirmationUrl = `${bookingConfirmation(lang)}?${BOOKING_CONFIRMATION_NUMBER}=${confirmationNumber}` - console.log( - `[payment-callback] rendering success callback with confirmation number: ${confirmationNumber}` - ) - - return ( - - ) - } - - const returnUrl = details(lang) - const searchObject = new URLSearchParams() - - let errorMessage = undefined - - if (confirmationNumber) { - try { - const bookingStatus = await serverClient().booking.status({ - confirmationNumber, - }) - - // TODO: how to handle errors for multiple rooms? - const error = bookingStatus.errors.find((e) => e.errorCode) - - errorMessage = - error?.description ?? - `No error message found for booking ${confirmationNumber}, status: ${status}` - - searchObject.set( - "errorCode", - error - ? error.errorCode.toString() - : BookingErrorCodeEnum.TransactionFailed - ) - } catch { - console.error( - `[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}` - ) - if (status === PaymentCallbackStatusEnum.Cancel) { - searchObject.set("errorCode", BookingErrorCodeEnum.TransactionCancelled) - } - if (status === PaymentCallbackStatusEnum.Error) { - searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed) - errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}` - } - } - } - - return ( - - ) -} diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/success/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/success/page.tsx new file mode 100644 index 000000000..fa6185a71 --- /dev/null +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/(payment-callback)/payment-callback/success/page.tsx @@ -0,0 +1,44 @@ +import { notFound } from "next/navigation" + +import { bookingConfirmation } from "@/constants/routes/hotelReservation" +import { createCounter } from "@/server/telemetry" + +import HandleSuccessCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback" +import { setLang } from "@/i18n/serverContext" +import { calculateRefId } from "@/utils/refId" + +import type { LangParams, PageArgs } from "@/types/params" + +export default async function PaymentCallbackSuccessPage({ + params, + searchParams, +}: PageArgs< + LangParams, + { + confirmationNumber?: string + } +>) { + const confirmationNumber = searchParams.confirmationNumber + + setLang(params.lang) + + if (!confirmationNumber) { + notFound() + } + + const paymentSuccessCounter = createCounter("payment", "success") + const metricsPaymentSuccess = paymentSuccessCounter.init({ + confirmationNumber, + }) + + metricsPaymentSuccess.start() + + const refId = calculateRefId(confirmationNumber, "") + + return ( + + ) +} diff --git a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx index 3308028c0..b9bc7083a 100644 --- a/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx +++ b/apps/scandic-web/app/[lang]/(live)/(public)/hotelreservation/my-stay/page.tsx @@ -6,6 +6,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography" import { env } from "@/env/server" import { dt } from "@/lib/dt" import { + findBooking, getAncillaryPackages, getBookingConfirmation, getLinkedReservations, @@ -13,8 +14,8 @@ import { getProfileSafely, getSavedPaymentCardsSafely, } from "@/lib/trpc/memoizedRequests" -import { decrypt } from "@/server/routers/utils/encryption" +import { auth } from "@/auth" import AdditionalInfoForm from "@/components/HotelReservation/FindMyBooking/AdditionalInfoForm" import accessBooking, { ACCESS_GRANTED, @@ -32,6 +33,8 @@ import Image from "@/components/Image" import { getIntl } from "@/i18n" import { setLang } from "@/i18n/serverContext" import MyStayProvider from "@/providers/MyStay" +import { parseRefId } from "@/utils/refId" +import { isValidSession } from "@/utils/session" import { getCurrentWebUrl } from "@/utils/url" import styles from "./page.module.css" @@ -44,27 +47,48 @@ export default async function MyStay({ searchParams, }: PageArgs) { setLang(params.lang) + const refId = searchParams.RefId if (!refId) { notFound() } - const value = decrypt(refId) - if (!value) { - return notFound() + const session = await auth() + const isLoggedIn = isValidSession(session) + const { confirmationNumber, lastName } = parseRefId(refId) + const bv = cookies().get("bv")?.value + let bookingConfirmation + if (isLoggedIn) { + bookingConfirmation = await getBookingConfirmation(refId, params.lang) + } else if (bv) { + const params = new URLSearchParams(bv) + const firstName = params.get("firstName") + const email = params.get("email") + + if (firstName && email) { + bookingConfirmation = await findBooking( + confirmationNumber, + lastName, + firstName, + email + ) + } else { + return + } + } else { + return } - const [confirmationNumber, lastName] = value.split(",") - const bookingConfirmation = await getBookingConfirmation(confirmationNumber) if (!bookingConfirmation) { return notFound() } - const { additionalData, booking, hotel, roomCategories } = bookingConfirmation + const { booking, hotelData } = bookingConfirmation + const { hotel } = hotelData const user = await getProfileSafely() - const bv = cookies().get("bv")?.value + const intl = await getIntl() const access = accessBooking(booking.guest, lastName, user, bv) @@ -74,9 +98,7 @@ export default async function MyStay({ const fromDate = dt(booking.checkInDate).format("YYYY-MM-DD") const toDate = dt(booking.checkOutDate).format("YYYY-MM-DD") - const linkedReservationsPromise = getLinkedReservations({ - rooms: booking.linkedReservations, - }) + const linkedReservationsPromise = getLinkedReservations(refId, params.lang) const packagesInput = { adults: booking.adults, @@ -121,7 +143,7 @@ export default async function MyStay({ const imageSrc = hotel.hotelContent.images.imageSizes.large ?? - additionalData.gallery?.heroImages[0]?.imageSizes.large ?? + hotelData.additionalData.gallery?.heroImages[0]?.imageSizes.large ?? hotel.galleryImages[0]?.imageSizes.large const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com" @@ -138,7 +160,7 @@ export default async function MyStay({ lang={params.lang} linkedReservationsPromise={linkedReservationsPromise} refId={refId} - roomCategories={roomCategories} + roomCategories={hotelData.roomCategories} savedCreditCards={savedCreditCards} >
@@ -197,10 +219,7 @@ export default async function MyStay({ return (
- +
) @@ -232,3 +251,19 @@ export default async function MyStay({ return notFound() } + +function RenderAdditionalInfoForm({ + refId, + lastName, +}: { + refId: string + lastName: string +}) { + return ( +
+
+ +
+
+ ) +} diff --git a/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/loading.tsx b/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/loading.tsx new file mode 100644 index 000000000..4b9d47ee6 --- /dev/null +++ b/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/loading.tsx @@ -0,0 +1 @@ +export { MyStaySkeleton } from "@/components/HotelReservation/MyStay/myStaySkeleton" diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Receipt/receipt.module.css b/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.module.css similarity index 100% rename from apps/scandic-web/components/HotelReservation/MyStay/Receipt/receipt.module.css rename to apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.module.css diff --git a/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx b/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx index a5a66c0e0..ba0961c62 100644 --- a/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx +++ b/apps/scandic-web/app/[lang]/(no-layout)/hotelreservation/my-stay/receipt/page.tsx @@ -1,20 +1,215 @@ +import { cookies } from "next/headers" import { notFound } from "next/navigation" -import { Suspense } from "react" -import { MyStaySkeleton } from "@/components/HotelReservation/MyStay/myStaySkeleton" -import { Receipt } from "@/components/HotelReservation/MyStay/Receipt" +import ScandicLogoIcon from "@scandic-hotels/design-system/Icons/ScandicLogoIcon" +import { Typography } from "@scandic-hotels/design-system/Typography" +import { dt } from "@/lib/dt" +import { + findBooking, + getAncillaryPackages, + getBookingConfirmation, + getProfileSafely, +} from "@/lib/trpc/memoizedRequests" + +import { auth } from "@/auth" +import AdditionalInfoForm from "@/components/HotelReservation/FindMyBooking/AdditionalInfoForm" +import accessBooking, { + ACCESS_GRANTED, + ERROR_BAD_REQUEST, + ERROR_UNAUTHORIZED, +} from "@/components/HotelReservation/MyStay/accessBooking" +import Footer from "@/components/HotelReservation/MyStay/Receipt/Footer" +import Specification from "@/components/HotelReservation/MyStay/Receipt/Specification" +import Total from "@/components/HotelReservation/MyStay/Receipt/Total" +import { getIntl } from "@/i18n" +import { parseRefId } from "@/utils/refId" +import { isValidSession } from "@/utils/session" + +import styles from "./page.module.css" + +import { CurrencyEnum } from "@/types/enums/currency" import type { LangParams, PageArgs } from "@/types/params" export default async function ReceiptPage({ + params, searchParams, }: PageArgs) { - if (!searchParams.RefId) { + const refId = searchParams.RefId + + if (!refId) { notFound() } + + const session = await auth() + const isLoggedIn = isValidSession(session) + const { confirmationNumber, lastName } = parseRefId(refId) + + const bv = cookies().get("bv")?.value + let bookingConfirmation + if (isLoggedIn) { + bookingConfirmation = await getBookingConfirmation(refId, params.lang) + } else if (bv) { + const params = new URLSearchParams(bv) + const firstName = params.get("firstName") + const email = params.get("email") + + if (firstName && email) { + bookingConfirmation = await findBooking( + confirmationNumber, + lastName, + firstName, + email + ) + } else { + return + } + } else { + return + } + + if (!bookingConfirmation) { + return notFound() + } + + const { booking, hotelData, room } = bookingConfirmation + const { hotel } = hotelData + + const intl = await getIntl() + const user = await getProfileSafely() + + const access = accessBooking(booking.guest, lastName, user, bv) + + if (access === ACCESS_GRANTED) { + const ancillaryPackages = await getAncillaryPackages({ + fromDate: dt(booking.checkInDate).format("YYYY-MM-DD"), + hotelId: hotel.operaId, + toDate: dt(booking.checkOutDate).format("YYYY-MM-DD"), + }) + + const currency = + booking.currencyCode !== CurrencyEnum.POINTS + ? booking.currencyCode + : (booking.ancillaries.find((a) => a.currency !== CurrencyEnum.POINTS) + ?.currency ?? + booking.packages.find((p) => p.currency !== CurrencyEnum.POINTS) + ?.currency) + + return ( +
+
+ +
+
+ +
{hotel.name}
+
+ +
+ {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} + {`${hotel.address.streetAddress}, ${hotel.address.zipCode} ${hotel.address.city}`} +
+
+ +
+ {hotel.contactInformation.email} +
+
+ +
+ {hotel.contactInformation.phoneNumber} +
+
+
+
+ + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +
{`${booking.guest.firstName} ${booking.guest.lastName}`}
+
+ {booking.guest.membershipNumber && ( + + {/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */} +
{`${intl.formatMessage({ + defaultMessage: "Member", + })} ${booking.guest.membershipNumber}`}
+
+ )} + +
+ {booking.guest.email} +
+
+ +
+ {booking.guest.phoneNumber} +
+
+
+
+
+ + + +
+ +
+
+ ) + } + + if (access === ERROR_BAD_REQUEST) { + return ( +
+
+ +
+
+ ) + } + + if (access === ERROR_UNAUTHORIZED) { + return ( +
+
+ +

+ {intl.formatMessage({ + defaultMessage: "You need to be logged in to view your booking", + })} +

+
+ +

+ {intl.formatMessage({ + defaultMessage: + "And you need to be logged in with the same member account that made the booking.", + })} +

+
+
+
+ ) + } + + return notFound() +} + +function RenderAdditionalInfoForm({ + refId, + lastName, +}: { + refId: string + lastName: string +}) { return ( - }> - - +
+
+ +
+
) } diff --git a/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx b/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx index e083c1cde..69743c69a 100644 --- a/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx +++ b/apps/scandic-web/app/[lang]/webview/hotelreservation/my-stay/page.tsx @@ -6,6 +6,7 @@ import { Typography } from "@scandic-hotels/design-system/Typography" import { env } from "@/env/server" import { dt } from "@/lib/dt" import { + findBooking, getAncillaryPackages, getBookingConfirmation, getLinkedReservations, @@ -13,8 +14,8 @@ import { getProfileSafely, getSavedPaymentCardsSafely, } from "@/lib/trpc/memoizedRequests" -import { decrypt } from "@/server/routers/utils/encryption" +import { auth } from "@/auth" import AdditionalInfoForm from "@/components/HotelReservation/FindMyBooking/AdditionalInfoForm" import accessBooking, { ACCESS_GRANTED, @@ -32,6 +33,8 @@ import Image from "@/components/Image" import { getIntl } from "@/i18n" import { setLang } from "@/i18n/serverContext" import MyStayProvider from "@/providers/MyStay" +import { parseRefId } from "@/utils/refId" +import { isValidSession } from "@/utils/session" import { getCurrentWebUrl } from "@/utils/url" import styles from "./page.module.css" @@ -44,27 +47,47 @@ export default async function MyStay({ searchParams, }: PageArgs) { setLang(params.lang) + const refId = searchParams.RefId if (!refId) { notFound() } - const value = decrypt(refId) - if (!value) { - return notFound() - } + const session = await auth() + const isLoggedIn = isValidSession(session) + const { confirmationNumber, lastName } = parseRefId(refId) - const [confirmationNumber, lastName] = value.split(",") - const bookingConfirmation = await getBookingConfirmation(confirmationNumber) + const bv = cookies().get("bv")?.value + let bookingConfirmation + if (isLoggedIn) { + bookingConfirmation = await getBookingConfirmation(refId, params.lang) + } else if (bv) { + const params = new URLSearchParams(bv) + const firstName = params.get("firstName") + const email = params.get("email") + + if (firstName && email) { + bookingConfirmation = await findBooking( + confirmationNumber, + lastName, + firstName, + email + ) + } else { + return + } + } else { + return + } if (!bookingConfirmation) { return notFound() } - const { additionalData, booking, hotel, roomCategories } = bookingConfirmation + const { booking, hotelData } = bookingConfirmation + const { hotel } = hotelData const user = await getProfileSafely() - const bv = cookies().get("bv")?.value const intl = await getIntl() const access = accessBooking(booking.guest, lastName, user, bv) @@ -74,9 +97,7 @@ export default async function MyStay({ const fromDate = dt(booking.checkInDate).format("YYYY-MM-DD") const toDate = dt(booking.checkOutDate).format("YYYY-MM-DD") - const linkedReservationsPromise = getLinkedReservations({ - rooms: booking.linkedReservations, - }) + const linkedReservationsPromise = getLinkedReservations(refId, params.lang) const packagesInput = { adults: booking.adults, @@ -98,9 +119,9 @@ export default async function MyStay({ (pkg) => pkg.code === BreakfastPackageEnum.REGULAR_BREAKFAST ) const breakfastIncluded = booking.rateDefinition.breakfastIncluded - const alreadyHasABreakfastSelection = + const shouldFetchBreakfastPackages = !hasBreakfastPackage && !breakfastIncluded - if (alreadyHasABreakfastSelection) { + if (shouldFetchBreakfastPackages) { void getPackages(packagesInput) } void getSavedPaymentCardsSafely(savedPaymentCardsInput) @@ -112,7 +133,7 @@ export default async function MyStay({ }) let breakfastPackages = null - if (alreadyHasABreakfastSelection) { + if (shouldFetchBreakfastPackages) { breakfastPackages = await getPackages(packagesInput) } const savedCreditCards = await getSavedPaymentCardsSafely( @@ -121,7 +142,7 @@ export default async function MyStay({ const imageSrc = hotel.hotelContent.images.imageSizes.large ?? - additionalData.gallery?.heroImages[0]?.imageSizes.large ?? + hotelData.additionalData.gallery?.heroImages[0]?.imageSizes.large ?? hotel.galleryImages[0]?.imageSizes.large const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com" @@ -138,7 +159,7 @@ export default async function MyStay({ lang={params.lang} linkedReservationsPromise={linkedReservationsPromise} refId={refId} - roomCategories={roomCategories} + roomCategories={hotelData.roomCategories} savedCreditCards={savedCreditCards} >
@@ -197,10 +218,7 @@ export default async function MyStay({ return (
- +
) @@ -232,3 +250,19 @@ export default async function MyStay({ return notFound() } + +function RenderAdditionalInfoForm({ + refId, + lastName, +}: { + refId: string + lastName: string +}) { + return ( +
+
+ +
+
+ ) +} diff --git a/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx b/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx index 4830d7543..be8849787 100644 --- a/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx +++ b/apps/scandic-web/components/HotelReservation/AddToCalendar/index.tsx @@ -1,4 +1,5 @@ "use client" + import { createEvent } from "ics" import { useIntl } from "react-intl" diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Confirmation/index.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Confirmation/index.tsx deleted file mode 100644 index 88b99038c..000000000 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Confirmation/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -"use client" -import { useRef } from "react" - -import Header from "@/components/HotelReservation/BookingConfirmation/Header" - -import styles from "./confirmation.module.css" - -import type { ConfirmationProps } from "@/types/components/hotelReservation/bookingConfirmation/bookingConfirmation" - -export default function Confirmation({ - booking, - hotel, - children, - refId, -}: React.PropsWithChildren) { - const mainRef = useRef(null) - - return ( -
-
- {children} -
- ) -} diff --git a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Header/Actions/ManageBooking.tsx b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Header/Actions/ManageBooking.tsx index 28a81406d..ef49a8988 100644 --- a/apps/scandic-web/components/HotelReservation/BookingConfirmation/Header/Actions/ManageBooking.tsx +++ b/apps/scandic-web/components/HotelReservation/BookingConfirmation/Header/Actions/ManageBooking.tsx @@ -1,15 +1,22 @@ "use client" + import { useIntl } from "react-intl" import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon" +import { myStay } from "@/constants/routes/myStay" + import Button from "@/components/TempDesignSystem/Button" import Link from "@/components/TempDesignSystem/Link" +import useLang from "@/hooks/useLang" import type { ManageBookingProps } from "@/types/components/hotelReservation/bookingConfirmation/actions/manageBooking" -export default function ManageBooking({ bookingUrl }: ManageBookingProps) { +export default function ManageBooking({ refId }: ManageBookingProps) { const intl = useIntl() + const lang = useLang() + + const bookingUrl = `${myStay[lang]}?RefId=${refId}` return (