Merged in feat/SW-1308-booking-codes-track-b (pull request #1607)

Feat/SW-1308 booking codes track b

* feat: SW-1308 Booking codes track b

* feat: SW-1308 Booking codes Track B implementation

* feat: SW-1308 Optimized after rebase


Approved-by: Arvid Norlin
This commit is contained in:
Hrishikesh Vaipurkar
2025-03-24 11:23:11 +00:00
parent 5643bcc62a
commit b0674d07f5
66 changed files with 1612 additions and 285 deletions

View File

@@ -0,0 +1,21 @@
.chequeCard {
padding: var(--Spacing-x-one-and-half);
background-color: var(--Base-Surface-Secondary-light-Normal);
border-radius: var(--Corner-radius-Medium);
margin: 0;
width: 100%;
display: grid;
gap: var(--Spacing-x1);
}
.chequeRow,
.cheque {
display: flex;
gap: var(--Spacing-x-half);
justify-content: space-between;
align-items: baseline;
}
.cheque {
justify-content: end;
}

View File

@@ -0,0 +1,59 @@
import { useIntl } from "react-intl"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./hotelChequeCard.module.css"
import { CurrencyEnum } from "@/types/enums/currency"
import type { ProductTypeCheque } from "@/types/trpc/routers/hotel/availability"
export default function HotelChequeCard({
productTypeCheque,
}: {
productTypeCheque: ProductTypeCheque
}) {
const intl = useIntl()
return (
<div className={styles.chequeCard}>
<div className={styles.chequeRow}>
<Caption>{intl.formatMessage({ id: "From" })}</Caption>
<div className={styles.cheque}>
<Subtitle type="two" color="uiTextHighContrast">
{productTypeCheque.localPrice.numberOfBonusCheques}
</Subtitle>
<Caption color="uiTextHighContrast" className={styles.currency}>
{CurrencyEnum.CC}
</Caption>
{productTypeCheque.localPrice.additionalPricePerStay && (
<>
{"+"}
<Subtitle type="two" color="uiTextHighContrast">
{productTypeCheque.localPrice.additionalPricePerStay}
</Subtitle>
<Caption color="uiTextHighContrast">
{productTypeCheque.localPrice.currency}
</Caption>
</>
)}
</div>
</div>
{productTypeCheque.requestedPrice ? (
<div className={styles.chequeRow}>
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Approx." })}
</Caption>
<Caption color={"uiTextMediumContrast"}>
{productTypeCheque.requestedPrice.numberOfBonusCheques}{" "}
{CurrencyEnum.CC}
{productTypeCheque.requestedPrice.additionalPricePerStay
? " + "
: ""}
{productTypeCheque.requestedPrice.additionalPricePerStay}{" "}
{productTypeCheque.requestedPrice.currency}
</Caption>
</div>
) : null}
</div>
)
}

View File

@@ -21,6 +21,11 @@
gap: var(--Spacing-x-half);
}
.voucherChqRate {
justify-content: start;
align-items: baseline;
}
.perNight {
font-weight: 400;
font-size: var(--typography-Caption-Regular-fontSize);

View File

@@ -8,32 +8,37 @@ import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./hotelPriceCard.module.css"
import type { PriceCardProps } from "@/types/components/hotelReservation/selectHotel/priceCardProps"
import { RateTypeEnum } from "@/types/enums/rateType"
export default function HotelPriceCard({
productTypePrices,
isMemberPrice = false,
}: PriceCardProps) {
const intl = useIntl()
const isRegularOrPublicPromotionRate =
productTypePrices.rateType === RateTypeEnum.Regular ||
productTypePrices.rateType === RateTypeEnum.PublicPromotion
return (
<dl className={styles.priceCard}>
{isMemberPrice ? (
<div className={styles.priceRow}>
<dt>
<Caption color="red">
{intl.formatMessage({ id: "Member price" })}
</Caption>
</dt>
</div>
) : (
<div className={styles.priceRow}>
<dt>
<Caption color="uiTextHighContrast">
{intl.formatMessage({ id: "Standard price" })}
</Caption>
</dt>
</div>
)}
{isRegularOrPublicPromotionRate &&
(isMemberPrice ? (
<div className={styles.priceRow}>
<dt>
<Caption color="red">
{intl.formatMessage({ id: "Member price" })}
</Caption>
</dt>
</div>
) : (
<div className={styles.priceRow}>
<dt>
<Caption color="uiTextHighContrast">
{intl.formatMessage({ id: "Standard price" })}
</Caption>
</dt>
</div>
))}
<div className={styles.priceRow}>
<dt>
<Caption
@@ -79,24 +84,26 @@ export default function HotelPriceCard({
</div>
)}
{productTypePrices.localPrice.pricePerStay !==
productTypePrices.localPrice.pricePerNight &&
// Handle undefined scenarios
productTypePrices.localPrice.pricePerNight && (
<>
<Divider color="subtle" className={styles.divider} />
<div className={styles.priceRow}>
<dt>
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Total" })}
</Caption>
</dt>
<dd>
<Caption color={"uiTextMediumContrast"}>
{productTypePrices.localPrice.pricePerStay}{" "}
{productTypePrices.localPrice.currency}
</Caption>
</dd>
</div>
</>
)}
<>
<Divider color="subtle" className={styles.divider} />
<div className={styles.priceRow}>
<dt>
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Total" })}
</Caption>
</dt>
<dd>
<Caption color={"uiTextMediumContrast"}>
{productTypePrices.localPrice.pricePerStay}{" "}
{productTypePrices.localPrice.currency}
</Caption>
</dd>
</div>
</>
)}
</dl>
)
}

View File

@@ -0,0 +1,19 @@
.voucherCard {
padding: var(--Spacing-x-one-and-half);
background-color: var(--Base-Surface-Secondary-light-Normal);
border-radius: var(--Corner-radius-Medium);
margin: 0;
width: 100%;
}
.voucherRow,
.voucher {
display: flex;
gap: var(--Spacing-x-half);
justify-content: space-between;
align-items: baseline;
}
.voucher {
justify-content: end;
}

View File

@@ -0,0 +1,32 @@
import { useIntl } from "react-intl"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./hotelVoucherCard.module.css"
import { CurrencyEnum } from "@/types/enums/currency"
import type { ProductTypeVoucher } from "@/types/trpc/routers/hotel/availability"
export default function HotelVoucherCard({
productTypeVoucher,
}: {
productTypeVoucher: ProductTypeVoucher
}) {
const intl = useIntl()
return (
<div className={styles.voucherCard}>
<div className={styles.voucherRow}>
<Caption>{intl.formatMessage({ id: "From" })}</Caption>
<div className={styles.voucher}>
<Subtitle type="two" color="uiTextHighContrast">
{productTypeVoucher.numberOfVouchers}
</Subtitle>
<Caption color="uiTextHighContrast" className={styles.currency}>
{CurrencyEnum.Voucher}
</Caption>
</div>
</div>
</div>
)
}

View File

@@ -13,6 +13,7 @@ import HotelLogo from "@/components/Icons/Logos"
import ImageGallery from "@/components/ImageGallery"
import Button from "@/components/TempDesignSystem/Button"
import Divider from "@/components/TempDesignSystem/Divider"
import IconChip from "@/components/TempDesignSystem/IconChip"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
@@ -22,8 +23,10 @@ import { getSingleDecimal } from "@/utils/numberFormatting"
import ReadMore from "../ReadMore"
import TripAdvisorChip from "../TripAdvisorChip"
import HotelChequeCard from "./HotelChequeCard"
import HotelPointsRow from "./HotelPointsRow"
import HotelPriceCard from "./HotelPriceCard"
import HotelVoucherCard from "./HotelVoucherCard"
import NoPriceAvailableCard from "./NoPriceAvailableCard"
import { hotelCardVariants } from "./variants"
@@ -31,6 +34,7 @@ import styles from "./hotelCard.module.css"
import { HotelCardListingTypeEnum } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
import { RateTypeEnum } from "@/types/enums/rateType"
import type { Lang } from "@/constants/languages"
function HotelCard({
@@ -64,7 +68,8 @@ function HotelCard({
const addressStr = `${hotel.address.streetAddress}, ${hotel.address.city}`
const galleryImages = mapApiImagesToGalleryImages(hotel.galleryImages || [])
const fullPrice =
availability.productType?.public?.rateType?.toLowerCase() === "regular"
availability.productType?.public?.rateType === RateTypeEnum.Regular ||
availability.productType?.member?.rateType === RateTypeEnum.Regular
const price = availability.productType
return (
@@ -155,8 +160,12 @@ function HotelCard({
<>
{bookingCode && (
<span className={`${fullPrice ? styles.strikedText : ""}`}>
<PriceTagIcon height={20} width={20} />
{bookingCode}
<IconChip
color="blue"
icon={<PriceTagIcon height={20} width={20} />}
>
{bookingCode}
</IconChip>
</span>
)}
{(!isUserLoggedIn ||
@@ -171,6 +180,12 @@ function HotelCard({
isMemberPrice
/>
)}
{price?.voucher && (
<HotelVoucherCard productTypeVoucher={price.voucher} />
)}
{price?.bonusCheque && (
<HotelChequeCard productTypeCheque={price.bonusCheque} />
)}
{!!price?.redemptions?.length && (
<div className={styles.pointsCard}>
<Caption>