Merged in feat/sw-1688-list-breakfast (pull request #1615)
Feat/sw-1688 list breakfast Approved-by: Pontus Dreij
This commit is contained in:
@@ -80,7 +80,7 @@ export default function Breakfast() {
|
||||
ancillary={{
|
||||
title: intl.formatMessage({ id: "Breakfast buffet" }),
|
||||
price: {
|
||||
total: pkg.localPrice.price,
|
||||
totalPrice: pkg.localPrice.price,
|
||||
currency: pkg.localPrice.currency,
|
||||
included:
|
||||
pkg.code === BreakfastPackageEnum.FREE_MEMBER_BREAKFAST,
|
||||
@@ -100,7 +100,7 @@ export default function Breakfast() {
|
||||
ancillary={{
|
||||
title: intl.formatMessage({ id: "No breakfast" }),
|
||||
price: {
|
||||
total: 0,
|
||||
totalPrice: 0,
|
||||
currency: packages?.[0].localPrice.currency ?? "",
|
||||
},
|
||||
description: intl.formatMessage({
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function PriceSummary({
|
||||
label={intl.formatMessage({ id: "Price including VAT" })}
|
||||
value={formatPrice(
|
||||
intl,
|
||||
selectedAncillary.price.total,
|
||||
selectedAncillary.price.totalPrice,
|
||||
selectedAncillary.price.currency
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function PriceDetails({
|
||||
}
|
||||
const totalPrice =
|
||||
quantityWithCard && selectedAncillary
|
||||
? selectedAncillary.price.total * quantityWithCard
|
||||
? selectedAncillary.price.totalPrice * quantityWithCard
|
||||
: null
|
||||
|
||||
const totalPoints =
|
||||
|
||||
@@ -12,6 +12,7 @@ import Select from "@/components/TempDesignSystem/Form/Select"
|
||||
import styles from "./selectQuantityStep.module.css"
|
||||
|
||||
import type { SelectQuantityStepProps } from "@/types/components/myPages/myStay/ancillaries"
|
||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
|
||||
export default function SelectQuantityStep({ user }: SelectQuantityStepProps) {
|
||||
const intl = useIntl()
|
||||
@@ -46,6 +47,13 @@ export default function SelectQuantityStep({ user }: SelectQuantityStepProps) {
|
||||
? intl.formatMessage({ id: "Insufficient points" })
|
||||
: intl.formatMessage({ id: "Select quantity" })
|
||||
|
||||
// TODO: Remove this when add breakfast is implemented
|
||||
if (
|
||||
selectedAncillary?.id === BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST
|
||||
) {
|
||||
return "Breakfast TBI"
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.selectContainer}>
|
||||
{selectedAncillary?.points && user && (
|
||||
|
||||
@@ -40,6 +40,7 @@ import Steps from "./Steps"
|
||||
import styles from "./addAncillaryFlowModal.module.css"
|
||||
|
||||
import type { AddAncillaryFlowModalProps } from "@/types/components/myPages/myStay/ancillaries"
|
||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
|
||||
export default function AddAncillaryFlowModal({
|
||||
booking,
|
||||
@@ -218,6 +219,7 @@ export default function AddAncillaryFlowModal({
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const modalTitle =
|
||||
currentStep === AncillaryStepEnum.selectAncillary
|
||||
? intl.formatMessage({ id: "Upgrade your stay" })
|
||||
@@ -251,7 +253,7 @@ export default function AddAncillaryFlowModal({
|
||||
<p>
|
||||
{formatPrice(
|
||||
intl,
|
||||
selectedAncillary.price.total,
|
||||
selectedAncillary.price.totalPrice,
|
||||
selectedAncillary.price.currency
|
||||
)}
|
||||
</p>
|
||||
@@ -290,7 +292,10 @@ export default function AddAncillaryFlowModal({
|
||||
<Steps user={user} savedCreditCards={savedCreditCards} />
|
||||
</div>
|
||||
</form>
|
||||
{currentStep === AncillaryStepEnum.selectAncillary ? null : (
|
||||
{/* TODO: Remove the berakfast check when add breakfast is implemented */}
|
||||
{currentStep === AncillaryStepEnum.selectAncillary ||
|
||||
selectedAncillary?.id ===
|
||||
BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST ? null : (
|
||||
<div
|
||||
className={
|
||||
currentStep === AncillaryStepEnum.confirmation
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"use client"
|
||||
import { useMemo } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { Carousel } from "@/components/Carousel"
|
||||
@@ -17,46 +18,145 @@ 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: breakfastPackage.localPrice,
|
||||
// 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,
|
||||
}
|
||||
: undefined
|
||||
|
||||
return breakfastAncillary
|
||||
}, [
|
||||
booking.packages,
|
||||
booking.rateDefinition.breakfastIncluded,
|
||||
intl,
|
||||
packages,
|
||||
])
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
function filterPoints(ancillaries: Ancillaries) {
|
||||
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) =>
|
||||
a.ancillaryContent.map((ancillary) => [ancillary.id, ancillary])
|
||||
)
|
||||
)
|
||||
return [...uniqueAncillaries.values()]
|
||||
}
|
||||
const allAncillaries = filterPoints(ancillaries)
|
||||
const uniqueAncillaries = generateUniqueAncillaries(allAncillaries)
|
||||
|
||||
return (
|
||||
@@ -77,7 +177,7 @@ export function Ancillaries({
|
||||
|
||||
<div className={styles.mobileAncillaries}>
|
||||
<Carousel>
|
||||
<Carousel.Content className={styles.carouselContainer}>
|
||||
<Carousel.Content>
|
||||
{uniqueAncillaries.map((ancillary) => {
|
||||
return (
|
||||
<Carousel.Item key={ancillary.id}>
|
||||
@@ -86,8 +186,8 @@ export function Ancillaries({
|
||||
)
|
||||
})}
|
||||
</Carousel.Content>
|
||||
<Carousel.Previous className={styles.navigationButton} />
|
||||
<Carousel.Next className={styles.navigationButton} />
|
||||
<Carousel.Previous />
|
||||
<Carousel.Next />
|
||||
<Carousel.Dots />
|
||||
</Carousel>
|
||||
</div>
|
||||
|
||||
@@ -109,7 +109,9 @@ export function SingleRoom({ bedType, image, hotel, user }: RoomProps) {
|
||||
const adultsAndChildrenMsg = [adultsMsg, childrenMsg].join(", ")
|
||||
|
||||
const hasPackages = packages?.some((item) =>
|
||||
Object.values(RoomPackageCodeEnum).includes(item.code)
|
||||
Object.values(RoomPackageCodeEnum).includes(
|
||||
item.code as RoomPackageCodeEnum
|
||||
)
|
||||
)
|
||||
|
||||
return (
|
||||
@@ -270,7 +272,7 @@ export function SingleRoom({ bedType, image, hotel, user }: RoomProps) {
|
||||
{packages!
|
||||
.filter((item) =>
|
||||
Object.values(RoomPackageCodeEnum).includes(
|
||||
item.code
|
||||
item.code as RoomPackageCodeEnum
|
||||
)
|
||||
)
|
||||
.map((item) => item.description)
|
||||
|
||||
@@ -9,6 +9,7 @@ import { dt } from "@/lib/dt"
|
||||
import {
|
||||
getAncillaryPackages,
|
||||
getBookingConfirmation,
|
||||
getPackages,
|
||||
getProfileSafely,
|
||||
getSavedPaymentCardsSafely,
|
||||
} from "@/lib/trpc/memoizedRequests"
|
||||
@@ -33,6 +34,8 @@ import Rooms from "./Rooms"
|
||||
|
||||
import styles from "./myStay.module.css"
|
||||
|
||||
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
||||
|
||||
export async function MyStay({ refId }: { refId: string }) {
|
||||
const value = decrypt(refId)
|
||||
if (!value) {
|
||||
@@ -58,6 +61,21 @@ export async function MyStay({ refId }: { refId: string }) {
|
||||
hotelId: hotel.operaId,
|
||||
toDate: dt(booking.checkOutDate).format("YYYY-MM-DD"),
|
||||
})
|
||||
|
||||
const packages = await getPackages({
|
||||
startDate: dt(booking.checkInDate).format("YYYY-MM-DD"),
|
||||
hotelId: hotel.operaId,
|
||||
endDate: dt(booking.checkOutDate).format("YYYY-MM-DD"),
|
||||
adults: booking.adults,
|
||||
children: booking.childrenAges.length,
|
||||
packageCodes: [
|
||||
BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST,
|
||||
BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST,
|
||||
BreakfastPackageEnum.FREE_CHILD_BREAKFAST,
|
||||
],
|
||||
lang,
|
||||
})
|
||||
|
||||
const supportedCards = hotel.merchantInformationData.cards
|
||||
const savedCreditCards = await getSavedPaymentCardsSafely({
|
||||
supportedCards,
|
||||
@@ -97,6 +115,7 @@ export async function MyStay({ refId }: { refId: string }) {
|
||||
<Ancillaries
|
||||
ancillaries={ancillaryPackages}
|
||||
booking={booking}
|
||||
packages={packages}
|
||||
user={user}
|
||||
savedCreditCards={savedCreditCards}
|
||||
refId={refId}
|
||||
|
||||
Reference in New Issue
Block a user