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 b05fa45bb..cc92c33b2 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 @@ -204,7 +204,6 @@ export default async function MyStay({ {booking.showAncillaries && ancillaryPackagesPromise && ( { const observer = new ResizeObserver( debounce(([entry]) => { - if (entry.contentRect.width > 1366) { - closeMobileSearch() + if (entry.contentRect.width > 768) { + setIsOpen(false) + document.body.style.removeProperty("overflow-y") } }) ) diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx index 4bf3dbf98..46b756bbe 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/RemoveButton.tsx @@ -11,10 +11,8 @@ import { toast } from "@/components/TempDesignSystem/Toasts" import useLang from "@/hooks/useLang" import { trackRemoveAncillary } from "@/utils/tracking/myStay" -import type { - BookingConfirmation, - PackageSchema, -} from "@/types/trpc/routers/booking/confirmation" +import type { Room } from "@/types/stores/my-stay" +import type { PackageSchema } from "@/types/trpc/routers/booking/confirmation" export default function RemoveButton({ refId, @@ -26,7 +24,7 @@ export default function RemoveButton({ refId: string codes: string[] title?: string - booking: BookingConfirmation["booking"] + booking: Room ancillary: PackageSchema }) { const lang = useLang() diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx index 4a83a0680..982fed9ba 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/AddedAncillaries/index.tsx @@ -16,10 +16,8 @@ import styles from "./addedAncillaries.module.css" import type { AddedAncillariesProps } from "@/types/components/myPages/myStay/ancillaries" import { BreakfastPackageEnum } from "@/types/enums/breakfast" -import type { - BookingConfirmation, - PackageSchema, -} from "@/types/trpc/routers/booking/confirmation" +import type { Room } from "@/types/stores/my-stay" +import type { PackageSchema } from "@/types/trpc/routers/booking/confirmation" export function AddedAncillaries({ ancillaries, @@ -28,7 +26,7 @@ export function AddedAncillaries({ const intl = useIntl() const addedBreakfastPackages = getBreakfastPackagesFromAncillaryFlow( - booking.packages + booking.originalPackages ) const addedAncillaries = getAddedAncillaries(booking, addedBreakfastPackages) @@ -226,7 +224,7 @@ export function AddedAncillaries({ * not in the booking flow. */ function getAddedAncillaries( - booking: BookingConfirmation["booking"], + booking: Room, addedBreakfastPackages: PackageSchema[] | undefined ) { if (!addedBreakfastPackages?.length) { diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/index.tsx b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/index.tsx index c83ab786b..1b79411c7 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/index.tsx +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/index.tsx @@ -1,7 +1,9 @@ "use client" -import { use, useMemo } from "react" +import { use } from "react" import { useIntl } from "react-intl" +import { useMyStayStore } from "@/stores/my-stay" + import { Carousel } from "@/components/Carousel" import Title from "@/components/TempDesignSystem/Text/Title" import { AddAncillaryProvider } from "@/providers/AddAncillaryProvider" @@ -10,82 +12,39 @@ import AddAncillaryFlowModal from "./AddAncillaryFlow/AddAncillaryFlowModal" import AncillaryFlowModalWrapper from "./AddAncillaryFlow/AncillaryFlowModalWrapper" import WrappedAncillaryCard from "./AddAncillaryFlow/WrappedAncillaryCard" import { AddedAncillaries } from "./AddedAncillaries" +import { generateUniqueAncillaries, mapAncillaries } from "./utils" import ViewAllAncillaries from "./ViewAllAncillaries" import styles from "./ancillaries.module.css" import type { - Ancillaries, AncillariesProps, - Ancillary, SelectedAncillary, } from "@/types/components/myPages/myStay/ancillaries" import { BreakfastPackageEnum } from "@/types/enums/breakfast" -import type { User } from "@/types/user" - -function filterPoints(ancillaries: Ancillaries, user: User | null) { - return ancillaries.map((ancillary) => { - return { - ...ancillary, - ancillaryContent: ancillary.ancillaryContent.map( - ({ points, ...ancillary }) => ({ - ...ancillary, - points: user ? points : undefined, - }) - ), - } - }) -} - -function generateUniqueAncillaries( - ancillaries: Ancillaries -): Ancillary["ancillaryContent"] { - const uniqueAncillaries = new Map( - ancillaries.flatMap((a) => { - return a.ancillaryContent.map((ancillary) => [ancillary.id, ancillary]) - }) - ) - return [...uniqueAncillaries.values()] -} - -/** - * Adds the breakfast package to the ancillaries - * - * Returns the ancillaries array with the breakfast package added to the - * specified category. If the category doesn't exist it's created. - */ -function addBreakfastPackage( - ancillaries: Ancillaries, - breakfast: SelectedAncillary | undefined, - categoryName: string -): Ancillaries { - if (!breakfast) return ancillaries - - const category = ancillaries.find((a) => a.categoryName === categoryName) - - if (category) { - const newCategory = { - ...category, - ancillaryContent: [breakfast, ...category.ancillaryContent], - } - - return ancillaries.map((ancillary) => - ancillary.categoryName === categoryName ? newCategory : ancillary - ) - } - - return [{ categoryName, ancillaryContent: [breakfast] }, ...ancillaries] -} export function Ancillaries({ ancillariesPromise, - booking, packages, - user, savedCreditCards, + user, }: AncillariesProps) { const intl = useIntl() const ancillaries = use(ancillariesPromise) + const bookedRoom = useMyStayStore((state) => state.bookedRoom) + + if (!bookedRoom || bookedRoom.isCancelled || !bookedRoom.showAncillaries) { + return null + } + + const alreadyHasBreakfast = + bookedRoom.rateDefinition.breakfastIncluded || bookedRoom.breakfast + + const breakfastPackageAdults = alreadyHasBreakfast + ? undefined + : packages?.find( + (p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST + ) /** * A constructed ancillary for breakfast @@ -94,70 +53,31 @@ export function Ancillaries({ * ancillary in the system. This makes it play nicely with the add ancillary * flow. If the user shouldn't be able to add breakfast this will be `undefined`. */ - const breakfastAncillary = useMemo(() => { - // This is the logic deciding if breakfast should be addable or not - if ( - booking.rateDefinition.breakfastIncluded || - booking.packages.some((p) => - Object.values(BreakfastPackageEnum).includes( - p.code as unknown as BreakfastPackageEnum - ) - ) - ) { - return undefined - } + const breakfastAncillary: SelectedAncillary | undefined = + breakfastPackageAdults + ? { + description: intl.formatMessage({ + defaultMessage: "Buffet", + }), + id: breakfastPackageAdults.code, + title: intl.formatMessage({ + defaultMessage: "Breakfast", + }), + price: { + currency: breakfastPackageAdults.localPrice.currency, + total: breakfastPackageAdults.localPrice.totalPrice, + }, + imageUrl: + "https://images.scandichotels.com/publishedmedia/inyre69evkpzgtygjnvp/Breakfast_-_Scandic_Sweden_-_Free_to_use.jpg", + requiresDeliveryTime: false, + loyaltyCode: undefined, + points: undefined, + hotelId: Number(bookedRoom.hotelId), + categoryName: "Food", + } + : undefined - const breakfastPackageAdults = packages?.find( - (p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST - ) - - const breakfastAncillary: SelectedAncillary | undefined = - breakfastPackageAdults - ? { - description: intl.formatMessage({ - defaultMessage: "Buffet", - }), - id: breakfastPackageAdults.code, - title: intl.formatMessage({ - defaultMessage: "Breakfast", - }), - price: { - currency: breakfastPackageAdults.localPrice.currency, - total: breakfastPackageAdults.localPrice.totalPrice, - }, - imageUrl: - "https://images.scandichotels.com/publishedmedia/inyre69evkpzgtygjnvp/Breakfast_-_Scandic_Sweden_-_Free_to_use.jpg", - requiresDeliveryTime: false, - loyaltyCode: undefined, - points: undefined, - hotelId: Number(booking.hotelId), - categoryName: "Food", - } - : undefined - - return breakfastAncillary - }, [ - booking.packages, - booking.rateDefinition.breakfastIncluded, - intl, - packages, - booking.hotelId, - ]) - - const allAncillaries = useMemo(() => { - const withBreakfastPopular = addBreakfastPackage( - ancillaries ?? [], - breakfastAncillary, - "Popular" - ) - const withBreakfastFood = addBreakfastPackage( - withBreakfastPopular, - breakfastAncillary, - "Food" - ) - const filtered = filterPoints(withBreakfastFood, user) - return filtered - }, [ancillaries, breakfastAncillary, user]) + const allAncillaries = mapAncillaries(ancillaries, breakfastAncillary, user) if (!allAncillaries.length) { return null @@ -166,9 +86,9 @@ export function Ancillaries({ const uniqueAncillaries = generateUniqueAncillaries(allAncillaries) return ( - +
- {uniqueAncillaries.length > 0 && booking.canModifyAncillaries && ( + {uniqueAncillaries.length > 0 && bookedRoom.canModifyAncillaries && ( <>
@@ -209,12 +129,15 @@ export function Ancillaries({ </> )} - <AddedAncillaries booking={booking} ancillaries={uniqueAncillaries} /> + <AddedAncillaries + booking={bookedRoom} + ancillaries={uniqueAncillaries} + /> <AncillaryFlowModalWrapper> <AddAncillaryFlowModal user={user} - booking={booking} + booking={bookedRoom} packages={packages} savedCreditCards={savedCreditCards} /> diff --git a/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/utils.ts b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/utils.ts new file mode 100644 index 000000000..265817d1a --- /dev/null +++ b/apps/scandic-web/components/HotelReservation/MyStay/Ancillaries/utils.ts @@ -0,0 +1,79 @@ +import type { + Ancillaries, + Ancillary, + SelectedAncillary, +} from "@/types/components/myPages/myStay/ancillaries" +import type { User } from "@/types/user" + +function filterPoints(ancillaries: Ancillaries, user: User | null) { + return ancillaries.map((ancillary) => { + return { + ...ancillary, + ancillaryContent: ancillary.ancillaryContent.map( + ({ points, ...ancillary }) => ({ + ...ancillary, + points: user ? points : undefined, + }) + ), + } + }) +} + +export function generateUniqueAncillaries( + ancillaries: Ancillaries +): Ancillary["ancillaryContent"] { + const uniqueAncillaries = new Map( + ancillaries.flatMap((a) => { + return a.ancillaryContent.map((ancillary) => [ancillary.id, ancillary]) + }) + ) + return [...uniqueAncillaries.values()] +} + +/** + * Adds the breakfast package to the ancillaries + * + * Returns the ancillaries array with the breakfast package added to the + * specified category. If the category doesn't exist it's created. + */ +function addBreakfastPackage( + ancillaries: Ancillaries, + breakfast: SelectedAncillary | undefined, + categoryName: string +): Ancillaries { + if (!breakfast) return ancillaries + + const category = ancillaries.find((a) => a.categoryName === categoryName) + + if (category) { + const newCategory = { + ...category, + ancillaryContent: [breakfast, ...category.ancillaryContent], + } + + return ancillaries.map((ancillary) => + ancillary.categoryName === categoryName ? newCategory : ancillary + ) + } + + return [{ categoryName, ancillaryContent: [breakfast] }, ...ancillaries] +} + +export function mapAncillaries( + ancillaries: Ancillaries | null, + breakfastAncillary: SelectedAncillary | undefined, + user: User | null +) { + const withBreakfastPopular = addBreakfastPackage( + ancillaries ?? [], + breakfastAncillary, + "Popular" + ) + const withBreakfastFood = addBreakfastPackage( + withBreakfastPopular, + breakfastAncillary, + "Food" + ) + + return filterPoints(withBreakfastFood, user) +} diff --git a/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts b/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts index ba905441f..480ef8a3f 100644 --- a/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts +++ b/apps/scandic-web/components/HotelReservation/MyStay/utils/mapRoomDetails.ts @@ -64,17 +64,17 @@ export function mapRoomDetails({ ) // We don't get `requestedPrice` in packages const breakfastChildren: Omit<BreakfastPackage, "requestedPrice"> | null = - (breakfastPackageChildren && !booking.rateDefinition.breakfastIncluded) + breakfastPackageChildren && !booking.rateDefinition.breakfastIncluded ? { - code: breakfastPackageChildren.code, - description: breakfastPackageChildren.description, - localPrice: { - currency: breakfastPackageChildren.currency, - price: breakfastPackageChildren.unitPrice, - totalPrice: breakfastPackageChildren.totalPrice, - }, - packageType: PackageTypeEnum.BreakfastChildren, - } + code: breakfastPackageChildren.code, + description: breakfastPackageChildren.description, + localPrice: { + currency: breakfastPackageChildren.currency, + price: breakfastPackageChildren.unitPrice, + totalPrice: breakfastPackageChildren.totalPrice, + }, + packageType: PackageTypeEnum.BreakfastChildren, + } : null const isCancelled = booking.reservationStatus === BookingStatusEnum.Cancelled @@ -135,43 +135,23 @@ export function mapRoomDetails({ })) return { - adults: booking.adults, + ...booking, bedType: { description: room?.bedType.mainBed.description ?? "", roomTypeCode: room?.bedType.code ?? "", }, - bookingCode: booking.bookingCode, breakfast, breakfastChildren, - canChangeDate: booking.canChangeDate, - cancellationNumber: booking.cancellationNumber, - checkInDate: booking.checkInDate, - checkOutDate: booking.checkOutDate, - cheques: booking.cheques, - childrenAges: booking.childrenAges, childrenAsString, childrenInRoom, - confirmationNumber: booking.confirmationNumber, - createDateTime: booking.createDateTime, - currencyCode: booking.currencyCode, - guaranteeInfo: booking.guaranteeInfo, - guest: booking.guest, - hotelId: booking.hotelId, - isCancelable: booking.isCancelable, isCancelled, - linkedReservations: booking.linkedReservations, - mainRoom: booking.mainRoom, - multiRoom: booking.multiRoom, + originalPackages: booking.packages, packages, priceType, rate, - rateDefinition: booking.rateDefinition, - refId: booking.refId, - reservationStatus: booking.reservationStatus, room, roomName: room?.name ?? "", roomNumber, - roomPoints: booking.roomPoints, roomPrice: { perNight: { local: { @@ -188,13 +168,6 @@ export function mapRoomDetails({ requested: undefined, }, }, - roomTypeCode: booking.roomTypeCode, terms: booking.rateDefinition.cancellationText, - totalPoints: booking.totalPoints, - totalPrice: booking.totalPrice, - totalPriceExVat: booking.totalPriceExVat, - vatAmount: booking.vatAmount, - vatPercentage: booking.vatPercentage, - vouchers: booking.vouchers, } } diff --git a/apps/scandic-web/providers/AddAncillaryProvider.tsx b/apps/scandic-web/providers/AddAncillaryProvider.tsx index be07981ff..b67f9737d 100644 --- a/apps/scandic-web/providers/AddAncillaryProvider.tsx +++ b/apps/scandic-web/providers/AddAncillaryProvider.tsx @@ -11,7 +11,7 @@ import { AddAncillaryContext } from "@/contexts/AddAncillary" import type { Ancillaries } from "@/types/components/myPages/myStay/ancillaries" import type { AddAncillaryStore } from "@/types/contexts/add-ancillary" -import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" +import type { Room } from "@/types/stores/my-stay" export function AddAncillaryProvider({ ancillaries, @@ -19,7 +19,7 @@ export function AddAncillaryProvider({ children, }: { ancillaries: Ancillaries - booking: BookingConfirmation["booking"] + booking: Room children: React.ReactNode }) { const storeRef = useRef<AddAncillaryStore>() diff --git a/apps/scandic-web/stores/my-stay/add-ancillary-flow.ts b/apps/scandic-web/stores/my-stay/add-ancillary-flow.ts index e079dbc6b..2c92f812e 100644 --- a/apps/scandic-web/stores/my-stay/add-ancillary-flow.ts +++ b/apps/scandic-web/stores/my-stay/add-ancillary-flow.ts @@ -11,7 +11,7 @@ import type { SelectedAncillary, } from "@/types/components/myPages/myStay/ancillaries" import { BreakfastPackageEnum } from "@/types/enums/breakfast" -import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" +import type { Room } from "@/types/stores/my-stay" export enum AncillaryStepEnum { selectAncillary = 0, @@ -43,7 +43,7 @@ export type BreakfastData = { export interface AddAncillaryState { currentStep: number steps: Steps - booking: BookingConfirmation["booking"] + booking: Room ancillaries: Ancillaries categories: Ancillary["categoryName"][] selectedCategory: string @@ -75,7 +75,7 @@ function findAncillaryByCategory( } export const createAddAncillaryStore = ( - booking: BookingConfirmation["booking"], + booking: Room, ancillaries: Ancillaries ) => { const selectedCategory = ancillaries[0].categoryName diff --git a/apps/scandic-web/types/components/myPages/myStay/ancillaries.ts b/apps/scandic-web/types/components/myPages/myStay/ancillaries.ts index 24ec3b354..4bdf267d0 100644 --- a/apps/scandic-web/types/components/myPages/myStay/ancillaries.ts +++ b/apps/scandic-web/types/components/myPages/myStay/ancillaries.ts @@ -1,6 +1,6 @@ import type { z } from "zod" -import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" +import type { Room } from "@/types/stores/my-stay" import type { CreditCard, User } from "@/types/user" import type { ancillaryPackagesSchema, @@ -12,33 +12,29 @@ export type Ancillary = Ancillaries[number] export type SelectedAncillary = Ancillary["ancillaryContent"][number] export type Packages = z.output<typeof packagesSchema> -export interface AncillariesProps extends Pick<BookingConfirmation, "booking"> { +export interface AncillariesProps { ancillariesPromise: Promise<Ancillaries | null> packages: Packages | null - user: User | null savedCreditCards: CreditCard[] | null + user: User | null } export interface AddedAncillariesProps { ancillaries: Ancillary["ancillaryContent"][number][] | null - booking: BookingConfirmation["booking"] + booking: Room } export interface AncillaryProps { ancillary: Ancillary["ancillaryContent"][number] } -export interface MyStayProps extends BookingConfirmation { - ancillaries: Ancillaries | null -} - export interface AncillaryGridModalProps { ancillaries: Ancillaries user: User | null } -export interface AddAncillaryFlowModalProps - extends Pick<BookingConfirmation, "booking"> { +export interface AddAncillaryFlowModalProps { + booking: Room packages: Packages | null user: User | null savedCreditCards: CreditCard[] | null diff --git a/apps/scandic-web/types/stores/my-stay.ts b/apps/scandic-web/types/stores/my-stay.ts index 2398256b5..93cbb1157 100644 --- a/apps/scandic-web/types/stores/my-stay.ts +++ b/apps/scandic-web/types/stores/my-stay.ts @@ -10,36 +10,9 @@ import type { Hotel, Room as HotelRoom, RoomCategories } from "@/types/hotel" import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation" import type { CreditCard } from "@/types/user" -export type Room = Pick< +export type Room = Omit< BookingConfirmation["booking"], - | "adults" - | "bookingCode" - | "canChangeDate" - | "cancellationNumber" - | "checkInDate" - | "checkOutDate" - | "cheques" - | "childrenAges" - | "confirmationNumber" - | "createDateTime" - | "currencyCode" - | "guaranteeInfo" - | "guest" - | "hotelId" - | "isCancelable" - | "linkedReservations" - | "multiRoom" - | "rateDefinition" - | "refId" - | "reservationStatus" - | "roomPoints" - | "roomTypeCode" - | "totalPoints" - | "totalPrice" - | "totalPriceExVat" - | "vatAmount" - | "vatPercentage" - | "vouchers" + "packages" | "roomPrice" > & { bedType: BedTypeSchema breakfast: Omit<BreakfastPackage, "requestedPrice"> | undefined | false @@ -48,6 +21,7 @@ export type Room = Pick< childrenInRoom: Child[] isCancelled: boolean mainRoom: boolean + originalPackages: BookingConfirmation["booking"]["packages"] packages: Packages | null priceType: PriceTypeEnum rate: string