Merged in fix/SW-2642-select-hotel-corporate-ch (pull request #2003)
fix: SW-2642 Fixed corporate chq and voucher rates city search * fix: SW-2642 Fixed corporate chq and voucher rates city search * fix: SW-2642 Fixed no availability alert for all hotels * fix: SW-2642 Combined flags to suitable variable * fix: SW-2642 Fixed map view to show prices Approved-by: Arvid Norlin
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
gap: var(--Space-x05);
|
gap: var(--Space-x05);
|
||||||
}
|
}
|
||||||
|
|
||||||
.bookingCodeChip .unavailable {
|
.unavailable {
|
||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,24 +65,16 @@ export default function BookingCodeChip({
|
|||||||
icon={<DiscountIcon color="Icon/Feedback/Information" />}
|
icon={<DiscountIcon color="Icon/Feedback/Information" />}
|
||||||
className={alignCenter ? styles.center : undefined}
|
className={alignCenter ? styles.center : undefined}
|
||||||
>
|
>
|
||||||
<p className={styles.bookingCodeChip}>
|
<p
|
||||||
|
className={`${styles.bookingCodeChip} ${isUnavailable ? styles.unavailable : ""}`}
|
||||||
|
>
|
||||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||||
<strong>
|
<strong>
|
||||||
{intl.formatMessage({ defaultMessage: "Booking code" })}
|
{intl.formatMessage({ defaultMessage: "Booking code" })}
|
||||||
</strong>
|
</strong>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
<span className={`${isUnavailable ? styles.unavailable : ""}`}>
|
<span>{bookingCode}</span>
|
||||||
{isUnavailable
|
|
||||||
? intl.formatMessage(
|
|
||||||
{ defaultMessage: "{code} unavailable" },
|
|
||||||
{ code: bookingCode }
|
|
||||||
)
|
|
||||||
: intl.formatMessage(
|
|
||||||
{ defaultMessage: "{code} applied" },
|
|
||||||
{ code: bookingCode }
|
|
||||||
)}
|
|
||||||
</span>
|
|
||||||
</Typography>
|
</Typography>
|
||||||
</p>
|
</p>
|
||||||
</IconChip>
|
</IconChip>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export default function HotelChequeCard({
|
|||||||
{productTypeCheque.localPrice.numberOfCheques}
|
{productTypeCheque.localPrice.numberOfCheques}
|
||||||
</Subtitle>
|
</Subtitle>
|
||||||
<Caption color="uiTextHighContrast">{CurrencyEnum.CC}</Caption>
|
<Caption color="uiTextHighContrast">{CurrencyEnum.CC}</Caption>
|
||||||
{productTypeCheque.localPrice.additionalPricePerStay && (
|
{productTypeCheque.localPrice.additionalPricePerStay > 0 ? (
|
||||||
<>
|
<>
|
||||||
{"+"}
|
{"+"}
|
||||||
<Subtitle type="two" color="uiTextHighContrast">
|
<Subtitle type="two" color="uiTextHighContrast">
|
||||||
@@ -37,10 +37,11 @@ export default function HotelChequeCard({
|
|||||||
{productTypeCheque.localPrice.currency}
|
{productTypeCheque.localPrice.currency}
|
||||||
</Caption>
|
</Caption>
|
||||||
</>
|
</>
|
||||||
)}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{productTypeCheque.requestedPrice ? (
|
{productTypeCheque.requestedPrice &&
|
||||||
|
productTypeCheque.requestedPrice.additionalPricePerStay > 0 ? (
|
||||||
<div className={styles.chequeRow}>
|
<div className={styles.chequeRow}>
|
||||||
<Caption color="uiTextMediumContrast">
|
<Caption color="uiTextMediumContrast">
|
||||||
{intl.formatMessage({
|
{intl.formatMessage({
|
||||||
|
|||||||
@@ -69,9 +69,7 @@ function HotelCard({
|
|||||||
|
|
||||||
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
|
||||||
const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || [])
|
const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || [])
|
||||||
const fullPrice =
|
const fullPrice = !availability.bookingCode
|
||||||
!availability.productType?.public?.bookingCode &&
|
|
||||||
!availability.productType?.member?.bookingCode
|
|
||||||
const price = availability.productType
|
const price = availability.productType
|
||||||
|
|
||||||
const hasInsufficientPoints = !price?.redemptions?.some(
|
const hasInsufficientPoints = !price?.redemptions?.some(
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
import { useSession } from "next-auth/react"
|
import { useSession } from "next-auth/react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
import { selectRate } from "@/constants/routes/hotelReservation"
|
import { selectRate } from "@/constants/routes/hotelReservation"
|
||||||
|
|
||||||
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
import { FacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||||
@@ -47,6 +49,8 @@ export default function ListingHotelCardDialog({
|
|||||||
ratings,
|
ratings,
|
||||||
operaId,
|
operaId,
|
||||||
redemptionPrice,
|
redemptionPrice,
|
||||||
|
chequePrice,
|
||||||
|
voucherPrice,
|
||||||
} = data
|
} = data
|
||||||
|
|
||||||
const firstImage = images[0]?.imageSizes?.small
|
const firstImage = images[0]?.imageSizes?.small
|
||||||
@@ -81,7 +85,11 @@ export default function ListingHotelCardDialog({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{publicPrice || memberPrice || redemptionPrice ? (
|
{publicPrice ||
|
||||||
|
memberPrice ||
|
||||||
|
redemptionPrice ||
|
||||||
|
voucherPrice ||
|
||||||
|
chequePrice ? (
|
||||||
<div className={styles.bottomContainer}>
|
<div className={styles.bottomContainer}>
|
||||||
<div className={styles.pricesContainer}>
|
<div className={styles.pricesContainer}>
|
||||||
{redemptionPrice ? (
|
{redemptionPrice ? (
|
||||||
@@ -130,6 +138,63 @@ export default function ListingHotelCardDialog({
|
|||||||
{redemptionPrice && (
|
{redemptionPrice && (
|
||||||
<HotelPointsRow pointsPerStay={redemptionPrice} />
|
<HotelPointsRow pointsPerStay={redemptionPrice} />
|
||||||
)}
|
)}
|
||||||
|
{chequePrice && (
|
||||||
|
<Subtitle type="two">
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{price} {currency}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: chequePrice.numberOfCheques,
|
||||||
|
currency: "CC",
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
{chequePrice.additionalPricePerStay > 0
|
||||||
|
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
||||||
|
" + " +
|
||||||
|
intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{price} {currency}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: chequePrice.additionalPricePerStay,
|
||||||
|
currency: chequePrice.currency,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
|
<span>
|
||||||
|
/
|
||||||
|
{intl.formatMessage({
|
||||||
|
defaultMessage: "night",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</Typography>
|
||||||
|
</Subtitle>
|
||||||
|
)}
|
||||||
|
{voucherPrice && (
|
||||||
|
<Subtitle type="two">
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{price} {currency}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: voucherPrice,
|
||||||
|
currency,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
|
<span>
|
||||||
|
/
|
||||||
|
{intl.formatMessage({
|
||||||
|
defaultMessage: "night",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</Typography>
|
||||||
|
</Subtitle>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button asChild theme="base" size="small" className={styles.button}>
|
<Button asChild theme="base" size="small" className={styles.button}>
|
||||||
|
|||||||
@@ -40,9 +40,11 @@ export default function StandaloneHotelCardDialog({
|
|||||||
const isUserLoggedIn = isValidClientSession(session)
|
const isUserLoggedIn = isValidClientSession(session)
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
|
chequePrice,
|
||||||
publicPrice,
|
publicPrice,
|
||||||
memberPrice,
|
memberPrice,
|
||||||
redemptionPrice,
|
redemptionPrice,
|
||||||
|
voucherPrice,
|
||||||
currency,
|
currency,
|
||||||
amenities,
|
amenities,
|
||||||
images,
|
images,
|
||||||
@@ -85,7 +87,11 @@ export default function StandaloneHotelCardDialog({
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.pricesContainer}>
|
<div className={styles.pricesContainer}>
|
||||||
{publicPrice || memberPrice || redemptionPrice ? (
|
{publicPrice ||
|
||||||
|
memberPrice ||
|
||||||
|
redemptionPrice ||
|
||||||
|
voucherPrice ||
|
||||||
|
chequePrice ? (
|
||||||
<>
|
<>
|
||||||
<div className={styles.priceCard}>
|
<div className={styles.priceCard}>
|
||||||
{redemptionPrice ? (
|
{redemptionPrice ? (
|
||||||
@@ -101,6 +107,63 @@ export default function StandaloneHotelCardDialog({
|
|||||||
})}
|
})}
|
||||||
</Caption>
|
</Caption>
|
||||||
)}
|
)}
|
||||||
|
{chequePrice && (
|
||||||
|
<Subtitle type="two">
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{price} {currency}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: chequePrice.numberOfCheques,
|
||||||
|
currency: "CC",
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
{chequePrice.additionalPricePerStay > 0
|
||||||
|
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
||||||
|
" + " +
|
||||||
|
intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{price} {currency}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: chequePrice.additionalPricePerStay,
|
||||||
|
currency: chequePrice.currency,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
: null}
|
||||||
|
<Body asChild>
|
||||||
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
|
<span>
|
||||||
|
/
|
||||||
|
{intl.formatMessage({
|
||||||
|
defaultMessage: "night",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</Body>
|
||||||
|
</Subtitle>
|
||||||
|
)}
|
||||||
|
{voucherPrice && (
|
||||||
|
<Subtitle type="two">
|
||||||
|
{intl.formatMessage(
|
||||||
|
{
|
||||||
|
defaultMessage: "{price} {currency}",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
price: voucherPrice,
|
||||||
|
currency,
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
<Body asChild>
|
||||||
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
|
<span>
|
||||||
|
/
|
||||||
|
{intl.formatMessage({
|
||||||
|
defaultMessage: "night",
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
</Body>
|
||||||
|
</Subtitle>
|
||||||
|
)}
|
||||||
{publicPrice && !isUserLoggedIn && (
|
{publicPrice && !isUserLoggedIn && (
|
||||||
<Subtitle type="two">
|
<Subtitle type="two">
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
|
|||||||
@@ -14,17 +14,23 @@ export function getHotelPins(
|
|||||||
const redemptionRate = productType?.redemptions?.find(
|
const redemptionRate = productType?.redemptions?.find(
|
||||||
(r) => r?.localPrice.pointsPerStay
|
(r) => r?.localPrice.pointsPerStay
|
||||||
)
|
)
|
||||||
|
const chequePrice = productType?.bonusCheque?.localPrice
|
||||||
|
const voucherPrice = productType?.voucher?.numberOfVouchers
|
||||||
|
if (chequePrice || voucherPrice) {
|
||||||
|
currencyValue = chequePrice ? "CC" : "Voucher"
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
bookingCode:
|
bookingCode: availability.bookingCode,
|
||||||
productType?.public?.bookingCode ?? productType?.member?.bookingCode,
|
|
||||||
coordinates: {
|
coordinates: {
|
||||||
lat: hotel.location.latitude,
|
lat: hotel.location.latitude,
|
||||||
lng: hotel.location.longitude,
|
lng: hotel.location.longitude,
|
||||||
},
|
},
|
||||||
name: hotel.name,
|
name: hotel.name,
|
||||||
|
chequePrice: chequePrice ?? null,
|
||||||
publicPrice: productType?.public?.localPrice.pricePerNight ?? null,
|
publicPrice: productType?.public?.localPrice.pricePerNight ?? null,
|
||||||
memberPrice: productType?.member?.localPrice.pricePerNight ?? null,
|
memberPrice: productType?.member?.localPrice.pricePerNight ?? null,
|
||||||
redemptionPrice: redemptionRate?.localPrice.pointsPerStay ?? null,
|
redemptionPrice: redemptionRate?.localPrice.pointsPerStay ?? null,
|
||||||
|
voucherPrice: voucherPrice ?? null,
|
||||||
rateType:
|
rateType:
|
||||||
productType?.public?.rateType ?? productType?.member?.rateType ?? null,
|
productType?.public?.rateType ?? productType?.member?.rateType ?? null,
|
||||||
currency:
|
currency:
|
||||||
|
|||||||
@@ -56,11 +56,7 @@ export default function HotelCardListing({
|
|||||||
)
|
)
|
||||||
const isBookingCodeRateAvailable =
|
const isBookingCodeRateAvailable =
|
||||||
bookingCode && !isSpecialRate
|
bookingCode && !isSpecialRate
|
||||||
? hotelData.some(
|
? hotelData.some((hotel) => hotel.availability.bookingCode)
|
||||||
(hotel) =>
|
|
||||||
hotel.availability.productType?.public?.bookingCode ||
|
|
||||||
hotel.availability.productType?.member?.bookingCode
|
|
||||||
)
|
|
||||||
: false
|
: false
|
||||||
const showOnlyBookingCodeRates =
|
const showOnlyBookingCodeRates =
|
||||||
isBookingCodeRateAvailable &&
|
isBookingCodeRateAvailable &&
|
||||||
@@ -74,11 +70,7 @@ export default function HotelCardListing({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const updatedHotelsList = showOnlyBookingCodeRates
|
const updatedHotelsList = showOnlyBookingCodeRates
|
||||||
? sortedHotels.filter(
|
? sortedHotels.filter((hotel) => hotel.availability.bookingCode)
|
||||||
(hotel) =>
|
|
||||||
hotel.availability.productType?.public?.bookingCode ||
|
|
||||||
hotel.availability.productType?.member?.bookingCode
|
|
||||||
)
|
|
||||||
: sortedHotels
|
: sortedHotels
|
||||||
|
|
||||||
if (!activeFilters.length) {
|
if (!activeFilters.length) {
|
||||||
|
|||||||
@@ -48,14 +48,10 @@ export function getSortedHotels({
|
|||||||
|
|
||||||
if (bookingCode) {
|
if (bookingCode) {
|
||||||
const bookingCodeRateHotels = availableHotels.filter(
|
const bookingCodeRateHotels = availableHotels.filter(
|
||||||
(hotel) =>
|
(hotel) => hotel.availability.bookingCode
|
||||||
hotel.availability.productType?.public?.bookingCode ||
|
|
||||||
hotel.availability.productType?.member?.bookingCode
|
|
||||||
)
|
)
|
||||||
const regularRateHotels = availableHotels.filter(
|
const regularRateHotels = availableHotels.filter(
|
||||||
(hotel) =>
|
(hotel) => !hotel.availability.bookingCode
|
||||||
!hotel.availability.productType?.public?.bookingCode &&
|
|
||||||
!hotel?.availability.productType?.member?.bookingCode
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return bookingCodeRateHotels
|
return bookingCodeRateHotels
|
||||||
|
|||||||
@@ -79,11 +79,7 @@ export async function SelectHotelMapContainer({
|
|||||||
: false
|
: false
|
||||||
|
|
||||||
const isBookingCodeRateAvailable = bookingCode
|
const isBookingCodeRateAvailable = bookingCode
|
||||||
? hotels?.some(
|
? hotels?.some((hotel) => hotel.availability.bookingCode)
|
||||||
(hotel) =>
|
|
||||||
hotel.availability.productType?.public?.bookingCode ||
|
|
||||||
hotel.availability.productType?.member?.bookingCode
|
|
||||||
)
|
|
||||||
: false
|
: false
|
||||||
|
|
||||||
const { hotelsTrackingData, pageTrackingData } = getTracking(
|
const { hotelsTrackingData, pageTrackingData } = getTracking(
|
||||||
|
|||||||
@@ -140,15 +140,23 @@ export default function SelectHotelContent({
|
|||||||
)
|
)
|
||||||
|
|
||||||
const isRegularRateAvailable = bookingCode
|
const isRegularRateAvailable = bookingCode
|
||||||
|
? hotels.some((hotel) => !hotel.availability.bookingCode)
|
||||||
|
: false
|
||||||
|
|
||||||
|
const isSpecialRate = bookingCode
|
||||||
? hotels.some(
|
? hotels.some(
|
||||||
(hotel) =>
|
(hotel) =>
|
||||||
!(
|
hotel.availability.productType?.bonusCheque ||
|
||||||
hotel.availability.productType?.public?.bookingCode ||
|
hotel.availability.productType?.voucher
|
||||||
hotel.availability.productType?.member?.bookingCode
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
: false
|
: false
|
||||||
|
|
||||||
|
const showBookingCodeFilter =
|
||||||
|
bookingCode &&
|
||||||
|
isBookingCodeRateAvailable &&
|
||||||
|
isRegularRateAvailable &&
|
||||||
|
!isSpecialRate
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<div className={styles.listingContainer} ref={listingContainerRef}>
|
<div className={styles.listingContainer} ref={listingContainerRef}>
|
||||||
@@ -170,9 +178,7 @@ export default function SelectHotelContent({
|
|||||||
filters={filterList}
|
filters={filterList}
|
||||||
setShowSkeleton={setShowSkeleton}
|
setShowSkeleton={setShowSkeleton}
|
||||||
/>
|
/>
|
||||||
{bookingCode &&
|
{showBookingCodeFilter ? (
|
||||||
isBookingCodeRateAvailable &&
|
|
||||||
isRegularRateAvailable ? (
|
|
||||||
<div className={styles.bookingCodeFilter}>
|
<div className={styles.bookingCodeFilter}>
|
||||||
<BookingCodeFilter />
|
<BookingCodeFilter />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -101,16 +101,16 @@ export default async function SelectHotel({
|
|||||||
const isFullPriceHotelAvailable = bookingCode
|
const isFullPriceHotelAvailable = bookingCode
|
||||||
? hotels?.some(
|
? hotels?.some(
|
||||||
(hotel) =>
|
(hotel) =>
|
||||||
!hotel.availability.productType?.public?.bookingCode &&
|
!hotel.availability.bookingCode &&
|
||||||
!hotel.availability.productType?.member?.bookingCode
|
hotel.availability.status === "Available"
|
||||||
)
|
)
|
||||||
: false
|
: false
|
||||||
|
|
||||||
const isBookingCodeRateAvailable = bookingCode
|
const isBookingCodeRateAvailable = bookingCode
|
||||||
? hotels?.some(
|
? hotels?.some(
|
||||||
(hotel) =>
|
(hotel) =>
|
||||||
hotel.availability.productType?.public?.bookingCode ||
|
hotel.availability.bookingCode &&
|
||||||
hotel.availability.productType?.member?.bookingCode
|
hotel.availability.status === "Available"
|
||||||
)
|
)
|
||||||
: false
|
: false
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default function Code({
|
|||||||
const pkgsSumRequested = sumPackagesRequestedPrice(selectedPackages)
|
const pkgsSumRequested = sumPackagesRequestedPrice(selectedPackages)
|
||||||
|
|
||||||
if ("corporateCheque" in product) {
|
if ("corporateCheque" in product) {
|
||||||
const { localPrice, rateCode } = product.corporateCheque
|
const { localPrice, rateCode, requestedPrice } = product.corporateCheque
|
||||||
let price = `${localPrice.numberOfCheques} CC`
|
let price = `${localPrice.numberOfCheques} CC`
|
||||||
if (localPrice.additionalPricePerStay) {
|
if (localPrice.additionalPricePerStay) {
|
||||||
price = `${price} + ${localPrice.additionalPricePerStay + pkgsSum.price}`
|
price = `${price} + ${localPrice.additionalPricePerStay + pkgsSum.price}`
|
||||||
@@ -90,11 +90,28 @@ export default function Code({
|
|||||||
roomTypeCode
|
roomTypeCode
|
||||||
)
|
)
|
||||||
|
|
||||||
const currency = localPrice.currency ?? pkgsSum.currency?.toString() ?? ""
|
const currency =
|
||||||
|
localPrice.additionalPricePerStay > 0 || pkgsSum.price > 0
|
||||||
|
? (localPrice.currency ?? pkgsSum.currency ?? "")
|
||||||
|
: ""
|
||||||
|
|
||||||
|
const approximateRate =
|
||||||
|
requestedPrice?.additionalPricePerStay && requestedPrice?.currency
|
||||||
|
? {
|
||||||
|
label: intl.formatMessage({
|
||||||
|
defaultMessage: "Approx.",
|
||||||
|
}),
|
||||||
|
price:
|
||||||
|
`${requestedPrice.numberOfCheques} CC + ` +
|
||||||
|
requestedPrice.additionalPricePerStay,
|
||||||
|
unit: requestedPrice.currency,
|
||||||
|
}
|
||||||
|
: undefined
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CodeRateCard
|
<CodeRateCard
|
||||||
key={product.rate}
|
key={product.rate}
|
||||||
|
approximateRate={approximateRate}
|
||||||
bannerText={bannerText}
|
bannerText={bannerText}
|
||||||
handleChange={() => handleSelectRate(product)}
|
handleChange={() => handleSelectRate(product)}
|
||||||
isSelected={isSelected}
|
isSelected={isSelected}
|
||||||
|
|||||||
@@ -12,12 +12,16 @@ interface HotelPinProps {
|
|||||||
isActive: boolean
|
isActive: boolean
|
||||||
hotelPrice: number | null
|
hotelPrice: number | null
|
||||||
currency: string
|
currency: string
|
||||||
|
hotelAdditionalPrice?: number
|
||||||
|
hotelAdditionalCurrency?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function HotelPin({
|
export default function HotelPin({
|
||||||
isActive,
|
isActive,
|
||||||
hotelPrice,
|
hotelPrice,
|
||||||
currency,
|
currency,
|
||||||
|
hotelAdditionalPrice,
|
||||||
|
hotelAdditionalCurrency,
|
||||||
}: HotelPinProps) {
|
}: HotelPinProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const isNotAvailable = !hotelPrice
|
const isNotAvailable = !hotelPrice
|
||||||
@@ -39,8 +43,18 @@ export default function HotelPin({
|
|||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<Typography variant="Body/Paragraph/mdRegular">
|
<Typography variant="Body/Paragraph/mdRegular">
|
||||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
<p>
|
||||||
<p>{isNotAvailable ? "—" : formatPrice(intl, hotelPrice, currency)}</p>
|
{isNotAvailable
|
||||||
|
? // eslint-disable-next-line formatjs/no-literal-string-in-jsx
|
||||||
|
"—"
|
||||||
|
: formatPrice(
|
||||||
|
intl,
|
||||||
|
hotelPrice,
|
||||||
|
currency,
|
||||||
|
hotelAdditionalPrice,
|
||||||
|
hotelAdditionalCurrency
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -36,7 +36,19 @@ function HotelListingMapContent({ hotelPins }: HotelListingMapContentProps) {
|
|||||||
const isActiveOrHovered =
|
const isActiveOrHovered =
|
||||||
activeHotel === pin.name || hoveredHotel === pin.name
|
activeHotel === pin.name || hoveredHotel === pin.name
|
||||||
const hotelPrice =
|
const hotelPrice =
|
||||||
pin.memberPrice ?? pin.publicPrice ?? pin.redemptionPrice
|
pin.memberPrice ??
|
||||||
|
pin.publicPrice ??
|
||||||
|
pin.redemptionPrice ??
|
||||||
|
pin.voucherPrice ??
|
||||||
|
pin.chequePrice?.numberOfCheques ??
|
||||||
|
null
|
||||||
|
|
||||||
|
const hotelAdditionalPrice = pin.chequePrice
|
||||||
|
? pin.chequePrice.additionalPricePerStay
|
||||||
|
: undefined
|
||||||
|
const hotelAdditionalCurrency = pin.chequePrice
|
||||||
|
? pin.chequePrice.currency?.toString()
|
||||||
|
: undefined
|
||||||
return (
|
return (
|
||||||
<AdvancedMarker
|
<AdvancedMarker
|
||||||
key={pin.name}
|
key={pin.name}
|
||||||
@@ -63,6 +75,8 @@ function HotelListingMapContent({ hotelPins }: HotelListingMapContentProps) {
|
|||||||
isActive={isActiveOrHovered}
|
isActive={isActiveOrHovered}
|
||||||
hotelPrice={hotelPrice}
|
hotelPrice={hotelPrice}
|
||||||
currency={pin.currency}
|
currency={pin.currency}
|
||||||
|
hotelAdditionalPrice={hotelAdditionalPrice}
|
||||||
|
hotelAdditionalCurrency={hotelAdditionalCurrency}
|
||||||
/>
|
/>
|
||||||
</AdvancedMarker>
|
</AdvancedMarker>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -95,25 +95,15 @@ export const hotelSchema = z
|
|||||||
export const hotelsAvailabilitySchema = z.object({
|
export const hotelsAvailabilitySchema = z.object({
|
||||||
data: z.array(
|
data: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
attributes: z
|
attributes: z.object({
|
||||||
.object({
|
bookingCode: z.string().nullish(),
|
||||||
bookingCode: z.string().nullish(),
|
checkInDate: z.string(),
|
||||||
checkInDate: z.string(),
|
checkOutDate: z.string(),
|
||||||
checkOutDate: z.string(),
|
hotelId: z.number(),
|
||||||
hotelId: z.number(),
|
occupancy: occupancySchema,
|
||||||
occupancy: occupancySchema,
|
productType: productTypeSchema,
|
||||||
productType: productTypeSchema,
|
status: z.string(),
|
||||||
status: z.string(),
|
}),
|
||||||
})
|
|
||||||
.transform((data) => {
|
|
||||||
if (data.bookingCode && data.productType?.public) {
|
|
||||||
data.productType.public.bookingCode = data.bookingCode
|
|
||||||
}
|
|
||||||
if (data.bookingCode && data.productType?.member) {
|
|
||||||
data.productType.member.bookingCode = data.bookingCode
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}),
|
|
||||||
relationships: relationshipsSchema.optional(),
|
relationships: relationshipsSchema.optional(),
|
||||||
type: z.string().optional(),
|
type: z.string().optional(),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ const partialPriceSchema = z.object({
|
|||||||
}
|
}
|
||||||
return RateTypeEnum.Regular
|
return RateTypeEnum.Regular
|
||||||
}),
|
}),
|
||||||
bookingCode: z.string().nullish(),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const productTypeCorporateChequeSchema = z
|
export const productTypeCorporateChequeSchema = z
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import type { z } from "zod"
|
|||||||
|
|
||||||
import type { Coordinates } from "@/types/components/maps/coordinates"
|
import type { Coordinates } from "@/types/components/maps/coordinates"
|
||||||
import type { Amenities } from "@/types/hotel"
|
import type { Amenities } from "@/types/hotel"
|
||||||
|
import type { ProductTypeCheque } from "@/types/trpc/routers/hotel/availability"
|
||||||
import type { HotelResponse } from "@/components/HotelReservation/SelectHotel/helpers"
|
import type { HotelResponse } from "@/components/HotelReservation/SelectHotel/helpers"
|
||||||
import type { imageSchema } from "@/server/routers/hotels/schemas/image"
|
import type { imageSchema } from "@/server/routers/hotels/schemas/image"
|
||||||
import type { CategorizedFilters } from "./hotelFilters"
|
import type { CategorizedFilters } from "./hotelFilters"
|
||||||
@@ -32,9 +33,11 @@ export type HotelPin = {
|
|||||||
bookingCode?: string | null
|
bookingCode?: string | null
|
||||||
name: string
|
name: string
|
||||||
coordinates: Coordinates
|
coordinates: Coordinates
|
||||||
|
chequePrice: ProductTypeCheque["localPrice"] | null
|
||||||
publicPrice: number | null
|
publicPrice: number | null
|
||||||
memberPrice: number | null
|
memberPrice: number | null
|
||||||
redemptionPrice: number | null
|
redemptionPrice: number | null
|
||||||
|
voucherPrice: number | null
|
||||||
rateType: string | null
|
rateType: string | null
|
||||||
currency: string
|
currency: string
|
||||||
images: {
|
images: {
|
||||||
|
|||||||
Reference in New Issue
Block a user