Files
web/apps/scandic-web/hooks/useAncillaries.ts
Anton Gunnarsson f79ff9b570 Merged in chore/cleanup-unused (pull request #3461)
chore: Cleanup unused vars, exports, types

* Cleanup some unused exports

* Remove more

* Readd CampaignPageIncludedHotelsRef

* Add alias comment to procedure exports

* Remove unused exports


Approved-by: Linus Flood
2026-01-22 12:34:07 +00:00

221 lines
5.8 KiB
TypeScript

import { use } from "react"
import { type IntlShape, useIntl } from "react-intl"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import { useMyStayStore } from "@/stores/my-stay"
import type { User } from "@scandic-hotels/trpc/types/user"
import type {
Ancillaries,
Ancillary,
Packages,
SelectedAncillary,
} from "@/types/components/myPages/myStay/ancillaries"
export function useAncillaries(
ancillariesPromise: Promise<Ancillaries | null>,
packages: Packages | null,
user: User | null,
alreadyAcquiredAncillaryCodes: string[]
) {
const intl = useIntl()
const bookedRoom = useMyStayStore((state) => state.bookedRoom)
if (!bookedRoom || bookedRoom.isCancelled || !bookedRoom.showAncillaries) {
return null
}
const ancillaries = use(ancillariesPromise)
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
*
* 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: SelectedAncillary | undefined =
breakfastPackageAdults
? {
description: intl.formatMessage({
id: "common.buffet",
defaultMessage: "Buffet",
}),
id: breakfastPackageAdults.code,
title: intl.formatMessage({
id: "common.breakfast",
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),
internalCategoryName: "Food",
translatedCategoryName: intl.formatMessage({
id: "common.food",
defaultMessage: "Food",
}),
requiresQuantity: false,
unitName: intl.formatMessage({
id: "common.person",
defaultMessage: "person",
}),
}
: undefined
const allAncillaries = mapAncillaries(
intl,
ancillaries,
breakfastAncillary,
user
)
if (!allAncillaries.length) {
return null
}
const allUniqueAncillaries = generateUniqueAncillaries(allAncillaries)
const availableByCategory = alreadyAcquiredAncillaryCodes.length
? filterOutAlreadyAcquiredAncillaries(
allAncillaries,
alreadyAcquiredAncillaryCodes
)
: allAncillaries
const availableUniqueAncillaries =
generateUniqueAncillaries(availableByCategory)
return {
availableByCategory,
allUnique: allUniqueAncillaries,
availableUnique: availableUniqueAncillaries,
}
}
function mapAncillaries(
intl: IntlShape,
ancillaries: Ancillaries | null,
breakfastAncillary: SelectedAncillary | undefined,
user: User | null
) {
const withBreakfastPopular = addBreakfastPackage(
ancillaries ?? [],
breakfastAncillary,
"Popular",
intl.formatMessage({
defaultMessage: "Popular",
id: "myStay.ancillaries.popularCategory",
})
)
const withBreakfastFood = addBreakfastPackage(
withBreakfastPopular,
breakfastAncillary,
"Food",
intl.formatMessage({
id: "common.food",
defaultMessage: "Food",
})
)
return filterPoints(withBreakfastFood, 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,
internalCategoryName: string,
translatedCategoryName: string
): Ancillaries {
if (!breakfast) return ancillaries
const category = ancillaries.find(
(a) => a.internalCategoryName === internalCategoryName
)
if (category) {
const newCategory = {
...category,
ancillaryContent: [breakfast, ...category.ancillaryContent],
}
return ancillaries.map((ancillary) =>
ancillary.internalCategoryName === internalCategoryName
? newCategory
: ancillary
)
}
return [
{
internalCategoryName,
translatedCategoryName,
ancillaryContent: [breakfast],
},
...ancillaries,
]
}
function filterOutAlreadyAcquiredAncillaries(
ancillaries: Ancillaries,
alreadyAcquiredAncillaryCodes: string[]
): Ancillaries {
return ancillaries.map((cat) => ({
...cat,
ancillaryContent: cat.ancillaryContent.filter((ancillary) =>
ancillary.requiresQuantity
? true
: !alreadyAcquiredAncillaryCodes.includes(
ancillary.loyaltyCode || ancillary.id
)
),
}))
}