Files
web/packages/booking-flow/lib/components/SelectRate/RoomsContainer/RateSummary/MobileSummary/index.tsx
Anton Gunnarsson 16fbdb7ae0 Merged in fix/refactor-currency-display (pull request #3434)
fix(SW-3616): Handle EuroBonus point type everywhere

* Add tests to formatPrice

* formatPrice

* More work replacing config with api points type

* More work replacing config with api points type

* More fixing with currency

* maybe actually fixed it

* Fix MyStay

* Clean up

* Fix comments

* Merge branch 'master' into fix/refactor-currency-display

* Fix calculateTotalPrice for EB points + SF points + cash


Approved-by: Joakim Jäderberg
2026-01-15 09:32:17 +00:00

154 lines
4.7 KiB
TypeScript

"use client"
import { cx } from "class-variance-authority"
import { useEffect, useRef, useState } from "react"
import { Button as ButtonRAC } from "react-aria-components"
import { useIntl } from "react-intl"
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
import { Button } from "@scandic-hotels/design-system/Button"
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { useSelectRateContext } from "../../../../../contexts/SelectRate/SelectRateContext"
import { useIsLoggedIn } from "../../../../../hooks/useIsLoggedIn"
import { isSpecialRate } from "../utils"
import SummaryContent from "./Content"
import styles from "./mobileSummary.module.css"
export function MobileSummary() {
const intl = useIntl()
const scrollY = useRef(0)
const [isSummaryOpen, setIsSummaryOpen] = useState<boolean | undefined>(
undefined
)
const isUserLoggedIn = useIsLoggedIn()
const { selectedRates } = useSelectRateContext()
function toggleSummaryOpen() {
setIsSummaryOpen(!isSummaryOpen)
}
useEffect(() => {
if (isSummaryOpen === undefined) {
return
}
if (isSummaryOpen) {
scrollY.current = window.scrollY
document.body.style.position = "fixed"
document.body.style.top = `-${scrollY.current}px`
document.body.style.width = "100%"
} else {
document.body.style.position = ""
document.body.style.top = ""
document.body.style.width = ""
window.scrollTo({
top: scrollY.current,
left: 0,
behavior: "instant",
})
}
return () => {
document.body.style.position = ""
document.body.style.top = ""
document.body.style.width = ""
}
}, [isSummaryOpen])
const hasSpecialRate = selectedRates.rates.find((r) => r && isSpecialRate(r))
const showDiscounted = hasSpecialRate || isUserLoggedIn
if (!selectedRates.totalPrice) {
return null
}
return (
<div className={styles.wrapper} data-open={isSummaryOpen}>
<div className={styles.content}>
<div className={styles.summaryAccordion}>
<SummaryContent
isUserLoggedIn={isUserLoggedIn}
toggleSummaryOpen={toggleSummaryOpen}
/>
</div>
</div>
<div className={styles.bottomSheet}>
<ButtonRAC
data-open={isSummaryOpen}
onPress={toggleSummaryOpen}
className={styles.priceDetailsButton}
>
<Typography variant="Body/Supporting text (caption)/smRegular">
<span className={styles.priceLabel}>
{intl.formatMessage({
id: "common.totalPrice",
defaultMessage: "Total price",
})}
</span>
</Typography>
<Typography variant="Title/Subtitle/lg">
<span
className={cx(styles.price, {
[styles.discounted]: showDiscounted,
})}
>
{formatPrice(
intl,
selectedRates.totalPrice.local.price,
selectedRates.totalPrice.local.currency,
selectedRates.totalPrice.local.additionalPrice,
selectedRates.totalPrice.local.additionalPriceCurrency,
selectedRates.totalPrice.local.pointsType
)}
</span>
</Typography>
{showDiscounted && selectedRates.totalPrice.local?.regularPrice ? (
<Typography variant="Body/Paragraph/mdRegular">
<p>
<s className={styles.strikeThroughRate}>
{formatPrice(
intl,
selectedRates.totalPrice.local?.regularPrice,
selectedRates.totalPrice.local.currency
)}
</s>
</p>
</Typography>
) : null}
<Typography variant="Body/Supporting text (caption)/smBold">
<span className={styles.seeDetails}>
<span>
{intl.formatMessage({
id: "booking.seeDetails",
defaultMessage: "See details",
})}
</span>
<MaterialIcon
icon="chevron_right"
color="CurrentColor"
size={20}
/>
</span>
</Typography>
</ButtonRAC>
<Button
variant="Primary"
color="Primary"
size="lg"
type="submit"
isDisabled={selectedRates.state !== "ALL_SELECTED"}
>
{intl.formatMessage({
id: "common.continue",
defaultMessage: "Continue",
})}
</Button>
</div>
</div>
)
}