Files
web/apps/scandic-web/components/HotelReservation/MyStay/Receipt/Specification/index.tsx
Joakim Jäderberg aafad9781f Merged in feat/lokalise-rebuild (pull request #2993)
Feat/lokalise rebuild

* chore(lokalise): update translation ids

* chore(lokalise): easier to switch between projects

* chore(lokalise): update translation ids

* .

* .

* .

* .

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* .

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* .

* .

* chore(lokalise): update translation ids

* chore(lokalise): update translation ids

* chore(lokalise): new translations

* merge

* switch to errors for missing id's

* merge

* sync translations


Approved-by: Linus Flood
2025-10-22 11:00:03 +00:00

260 lines
9.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { calculateVat } from "@scandic-hotels/booking-flow/utils/SelectRate"
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
import { Divider } from "@scandic-hotels/design-system/Divider"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { RoomPackageCodeEnum } from "@scandic-hotels/trpc/enums/roomFilter"
import { getIntl } from "@/i18n"
import styles from "./specification.module.css"
import type { SpecificationProps } from "@/types/components/hotelReservation/myStay/receipt"
export default async function Specification({
ancillaryPackages,
booking,
currency,
}: SpecificationProps) {
const intl = await getIntl()
const breakfastPackages = booking.packages.filter(
(p) => p.type === "Breakfast"
)
const breakfastTotalPriceInMoney = breakfastPackages
.filter((p) => p.currency !== CurrencyEnum.POINTS)
.reduce((acc, curr) => acc + curr.totalPrice, 0)
const breakfastTotalPriceInPoints = breakfastPackages
.filter((p) => p.currency === CurrencyEnum.POINTS)
.reduce((acc, curr) => acc + curr.totalPrice, 0)
const breakfastCount = breakfastPackages.reduce(
(acc, curr) => acc + curr.unit,
0
)
const displayBreakfastPrice =
breakfastCount > 0 && !booking.rateDefinition.breakfastIncluded
const breakfastMoneyString =
breakfastTotalPriceInMoney > 0
? `${breakfastTotalPriceInMoney} ${currency}`
: ""
const breakfastPointsString =
breakfastTotalPriceInPoints > 0
? intl.formatMessage(
{
id: "common.numberOfPoints",
defaultMessage: "{points, plural, one {# point} other {# points}}",
},
{ points: breakfastTotalPriceInPoints }
)
: ""
const breakfastPlusString =
breakfastMoneyString && breakfastPointsString ? " + " : ""
const petRoomPackage = booking.packages.find(
(p) => p.code === RoomPackageCodeEnum.PET_ROOM
)
const { vatAmount, priceExclVat } = calculateVat(
booking.roomPrice,
booking.vatPercentage
)
return (
<div className={styles.container}>
<div>
{/****** The room ********/}
<Typography variant="Body/Supporting text (caption)/smBold">
<span>
{intl.formatMessage({
id: "myStay.receipt.accommodation",
defaultMessage: "Accommodation",
})}
{!booking.rateDefinition.mustBeGuaranteed && (
<>
{" - "}
{intl.formatMessage({
id: "myStay.receipt.prepaidRoom",
defaultMessage: "Room is prepaid",
})}
</>
)}
</span>
</Typography>
<dl className={styles.dl}>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dt>
{intl.formatMessage({
id: "booking.priceIncludingVat",
defaultMessage: "Price including VAT",
})}
</dt>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dd>
{!booking.rateDefinition.mustBeGuaranteed
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
`(${intl.formatMessage({
id: "myStay.receipt.prepaid",
defaultMessage: "PREPAID",
})}) `
: null}
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`${booking.roomPrice} ${currency}`}
</dd>
</Typography>
{petRoomPackage && (
<>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dt>
{intl.formatMessage({
id: "myStay.receipt.petRoomChargeIncludingVat",
defaultMessage: "Pet room charge including VAT",
})}
</dt>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<dd>{`${petRoomPackage.totalPrice} ${petRoomPackage.currency}`}</dd>
</Typography>
</>
)}
<Typography variant="Body/Supporting text (caption)/smRegular">
<dt className={styles.tertiary}>
{intl.formatMessage({
id: "booking.priceExcludingVat",
defaultMessage: "Price excluding VAT",
})}
</dt>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dd className={styles.tertiary}>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`${priceExclVat.toFixed(2)} ${currency}`}
</dd>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dt className={styles.tertiary}>
{intl.formatMessage({
id: "common.vat",
defaultMessage: "VAT",
})}
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{` ${booking.vatPercentage} %`}
</dt>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dd className={styles.tertiary}>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`${vatAmount.toFixed(2)} ${currency}`}
</dd>
</Typography>
</dl>
</div>
{/****** Ancillaries ********/}
{booking.ancillaries.map((ancillary) => (
<>
<Divider />
<div>
<div className={styles.quantifyingHeader}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span>
{ancillaryPackages?.flatMap((a) =>
a.ancillaryContent.filter(
(aa) =>
aa.id === ancillary.code ||
aa.loyaltyCode === ancillary.code
)
)[0]?.title ??
intl.formatMessage({
id: "myStay.receipt.unknownItem",
defaultMessage: "Unknown item",
})}
</span>
</Typography>
<Typography variant="Body/Supporting text (caption)/smBold">
<span>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`× ${ancillary.unit}`}
</span>
</Typography>
</div>
<dl className={styles.dl}>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dt>
{ancillary.currency !== CurrencyEnum.POINTS
? intl.formatMessage({
id: "booking.priceIncludingVat",
defaultMessage: "Price including VAT",
})
: intl.formatMessage({
id: "common.price",
defaultMessage: "Price",
})}
</dt>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dd>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`${ancillary.totalPrice} ${ancillary.currency}`}
</dd>
</Typography>
</dl>
</div>
</>
))}
{/****** Breakfast ********/}
{displayBreakfastPrice && (
<>
<Divider />
<div>
<div className={styles.quantifyingHeader}>
<Typography variant="Body/Supporting text (caption)/smBold">
<span>
{intl.formatMessage({
id: "common.breakfast",
defaultMessage: "Breakfast",
})}
</span>
</Typography>
<Typography variant="Body/Supporting text (caption)/smBold">
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
<span>{`× ${breakfastCount}`}</span>
</Typography>
</div>
<dl className={styles.dl}>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dt>
{breakfastTotalPriceInMoney > 0
? intl.formatMessage({
id: "booking.priceIncludingVat",
defaultMessage: "Price including VAT",
})
: intl.formatMessage({
id: "common.price",
defaultMessage: "Price",
})}
</dt>
</Typography>
<Typography variant="Body/Supporting text (caption)/smRegular">
<dd>
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
{`${breakfastMoneyString}${breakfastPlusString}${breakfastPointsString}`}
</dd>
</Typography>
</dl>
</div>
</>
)}
</div>
)
}