fix: fix logic for showing ancillaries and add/remove ancillaries * fix: fix logic for showing ancillaries and add/remove ancillaries * fix: move canModifyAncillary check Approved-by: Niclas Edenvin
223 lines
6.5 KiB
TypeScript
223 lines
6.5 KiB
TypeScript
"use client"
|
|
import { useMemo } from "react"
|
|
import { useIntl } from "react-intl"
|
|
|
|
import { Carousel } from "@/components/Carousel"
|
|
import Title from "@/components/TempDesignSystem/Text/Title"
|
|
import { AddAncillaryProvider } from "@/providers/AddAncillaryProvider"
|
|
|
|
import AddAncillaryFlowModal from "./AddAncillaryFlow/AddAncillaryFlowModal"
|
|
import AncillaryFlowModalWrapper from "./AddAncillaryFlow/AncillaryFlowModalWrapper"
|
|
import WrappedAncillaryCard from "./AddAncillaryFlow/WrappedAncillaryCard"
|
|
import { AddedAncillaries } from "./AddedAncillaries"
|
|
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({
|
|
ancillaries,
|
|
booking,
|
|
packages,
|
|
user,
|
|
savedCreditCards,
|
|
refId,
|
|
}: AncillariesProps) {
|
|
const intl = useIntl()
|
|
|
|
/**
|
|
* A constructed ancillary for breakfast
|
|
*
|
|
* This is a "fake" ancillary for breakfast, since breakfast isn't really an
|
|
* 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 breakfastPackage = packages?.find(
|
|
(p) => p.code === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
|
|
)
|
|
|
|
const breakfastAncillary: SelectedAncillary | undefined = breakfastPackage
|
|
? {
|
|
description: intl.formatMessage({ id: "Buffet" }),
|
|
id: breakfastPackage.code,
|
|
title: intl.formatMessage({ id: "Breakfast" }),
|
|
price: {
|
|
currency: breakfastPackage.localPrice.currency,
|
|
total: breakfastPackage.localPrice.totalPrice,
|
|
},
|
|
// TODO: Change this to the correct URL, whatever that is
|
|
imageUrl:
|
|
"https://images-test.scandichotels.com/publishedmedia/hcf9hchiad7zrvlkc2pt/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(() => {
|
|
if (!ancillaries?.length) {
|
|
return []
|
|
}
|
|
|
|
const withBreakfastPopular = addBreakfastPackage(
|
|
ancillaries,
|
|
breakfastAncillary,
|
|
"Popular"
|
|
)
|
|
const withBreakfastFood = addBreakfastPackage(
|
|
withBreakfastPopular,
|
|
breakfastAncillary,
|
|
"Food"
|
|
)
|
|
const filtered = filterPoints(withBreakfastFood, user)
|
|
return filtered
|
|
}, [ancillaries, breakfastAncillary, user])
|
|
|
|
if (!ancillaries?.length) {
|
|
return null
|
|
}
|
|
|
|
const uniqueAncillaries = generateUniqueAncillaries(allAncillaries)
|
|
|
|
return (
|
|
<AddAncillaryProvider booking={booking} ancillaries={allAncillaries}>
|
|
<div className={styles.container}>
|
|
{uniqueAncillaries.length > 0 && booking.canModifyAncillaries && (
|
|
<>
|
|
<div className={styles.title}>
|
|
<Title as="h5">
|
|
{intl.formatMessage({ id: "Upgrade your stay" })}
|
|
</Title>
|
|
<ViewAllAncillaries />
|
|
</div>
|
|
|
|
<div className={styles.ancillaries}>
|
|
{uniqueAncillaries.slice(0, 4).map((ancillary) => (
|
|
<WrappedAncillaryCard
|
|
ancillary={ancillary}
|
|
key={ancillary.id}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
<div className={styles.mobileAncillaries}>
|
|
<Carousel>
|
|
<Carousel.Content>
|
|
{uniqueAncillaries.map((ancillary) => {
|
|
return (
|
|
<Carousel.Item key={ancillary.id}>
|
|
<WrappedAncillaryCard ancillary={ancillary} />
|
|
</Carousel.Item>
|
|
)
|
|
})}
|
|
</Carousel.Content>
|
|
<Carousel.Previous />
|
|
<Carousel.Next />
|
|
<Carousel.Dots />
|
|
</Carousel>
|
|
</div>
|
|
</>
|
|
)}
|
|
|
|
<AddedAncillaries booking={booking} ancillaries={uniqueAncillaries} />
|
|
|
|
<AncillaryFlowModalWrapper>
|
|
<AddAncillaryFlowModal
|
|
user={user}
|
|
booking={booking}
|
|
packages={packages}
|
|
refId={refId}
|
|
savedCreditCards={savedCreditCards}
|
|
/>
|
|
</AncillaryFlowModalWrapper>
|
|
</div>
|
|
</AddAncillaryProvider>
|
|
)
|
|
}
|