Merged in feat/book-425-optimize-campaign-rate-card (pull request #3015)
Feat/book 425 optimize campaign rate card * feat(BOOK-425): design updates to RateCard * feat(BOOK-425): design updates to campaign BookingCodeChip * feat(BOOK-425): fixed breakfast message & booking code chips on select rate and enter detailss * feat(BOOK-425): fixed booking code chip on Booking Confirmation page * fixed draft comments * fixed more comments * feat(BOOK-425): removed fixed height from RateCard banner * fixed another variable comment * fixed more pr comments * fixed more pr comments * updated ratecard campaign standard rate title color * removed deconstructed props Approved-by: Bianca Widstam Approved-by: Erik Tiekstra
This commit is contained in:
@@ -120,8 +120,10 @@ export default function PriceDetails() {
|
|||||||
requested: undefined,
|
requested: undefined,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const mappedRooms = mapToPrice(rooms, nights)
|
const mappedRooms = mapToPrice(rooms, nights)
|
||||||
|
const isCampaignRate = rooms.every(
|
||||||
|
(room) => room?.rateDefinition.isCampaignRate
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PriceDetailsModal
|
<PriceDetailsModal
|
||||||
@@ -132,6 +134,7 @@ export default function PriceDetails() {
|
|||||||
totalPrice={totalPrice}
|
totalPrice={totalPrice}
|
||||||
vat={vat}
|
vat={vat}
|
||||||
defaultCurrency={currency}
|
defaultCurrency={currency}
|
||||||
|
isCampaignRate={isCampaignRate}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useIntl } from "react-intl"
|
|||||||
|
|
||||||
import { CancellationRuleEnum } from "@scandic-hotels/common/constants/booking"
|
import { CancellationRuleEnum } from "@scandic-hotels/common/constants/booking"
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
|
import { BookingCodeChip } from "@scandic-hotels/design-system/BookingCodeChip"
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
@@ -25,20 +26,22 @@ type BookingConfirmationReceiptRoomProps = {
|
|||||||
room: Room
|
room: Room
|
||||||
roomNumber: number
|
roomNumber: number
|
||||||
roomCount: number
|
roomCount: number
|
||||||
|
showBookingCodeChip?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReceiptRoom({
|
export function ReceiptRoom({
|
||||||
room,
|
room,
|
||||||
roomNumber,
|
roomNumber,
|
||||||
roomCount,
|
roomCount,
|
||||||
|
showBookingCodeChip = false,
|
||||||
}: BookingConfirmationReceiptRoomProps) {
|
}: BookingConfirmationReceiptRoomProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const { currencyCode, isVatCurrency } = useBookingConfirmationStore(
|
const { currencyCode, isVatCurrency, bookingCode } =
|
||||||
(state) => ({
|
useBookingConfirmationStore((state) => ({
|
||||||
currencyCode: state.currencyCode,
|
currencyCode: state.currencyCode,
|
||||||
isVatCurrency: state.isVatCurrency,
|
isVatCurrency: state.isVatCurrency,
|
||||||
})
|
bookingCode: state.bookingCode,
|
||||||
)
|
}))
|
||||||
|
|
||||||
if (!room) {
|
if (!room) {
|
||||||
return <RoomSkeletonLoader />
|
return <RoomSkeletonLoader />
|
||||||
@@ -74,7 +77,8 @@ export function ReceiptRoom({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const guests = guestsParts.join(", ")
|
const guests = guestsParts.join(", ")
|
||||||
const showDiscounted = room.rateDefinition.isMemberRate
|
const showDiscounted =
|
||||||
|
room.rateDefinition.isMemberRate || room.rateDefinition.isCampaignRate
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -276,6 +280,14 @@ export function ReceiptRoom({
|
|||||||
breakfastIncluded={room.breakfastIncluded}
|
breakfastIncluded={room.breakfastIncluded}
|
||||||
guests={guests}
|
guests={guests}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{showBookingCodeChip && (
|
||||||
|
<BookingCodeChip
|
||||||
|
isCampaign={room.rateDefinition.isCampaignRate}
|
||||||
|
bookingCode={bookingCode}
|
||||||
|
alignCenter
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Divider color="Border/Divider/Subtle" />
|
<Divider color="Border/Divider/Subtle" />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
import { cx } from "class-variance-authority"
|
import { cx } from "class-variance-authority"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { BookingCodeChip } from "@scandic-hotels/design-system/BookingCodeChip"
|
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
|
||||||
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
import SkeletonShimmer from "@scandic-hotels/design-system/SkeletonShimmer"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
|
|
||||||
@@ -30,7 +28,6 @@ export default function TotalPrice() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Divider color="Border/Divider/Subtle" />
|
|
||||||
<div className={styles.price}>
|
<div className={styles.price}>
|
||||||
<div className={styles.entry}>
|
<div className={styles.entry}>
|
||||||
<div>
|
<div>
|
||||||
@@ -70,15 +67,13 @@ export default function TotalPrice() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.ctaWrapper}>
|
<div>
|
||||||
{hasAllRoomsLoaded ? (
|
{hasAllRoomsLoaded ? (
|
||||||
<PriceDetails />
|
<PriceDetails />
|
||||||
) : (
|
) : (
|
||||||
<SkeletonShimmer width={"100%"} />
|
<SkeletonShimmer width={"100%"} />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{bookingCode && <BookingCodeChip bookingCode={bookingCode} alignCenter />}
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--Space-x05);
|
gap: var(--Space-x05);
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: var(--Space-x15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.prices {
|
.prices {
|
||||||
@@ -27,7 +26,3 @@
|
|||||||
.approxPrice {
|
.approxPrice {
|
||||||
color: var(--Text-Secondary);
|
color: var(--Text-Secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.ctaWrapper {
|
|
||||||
margin-top: var(--Space-x15);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useIntl } from "react-intl"
|
|||||||
|
|
||||||
import { longDateFormat } from "@scandic-hotels/common/constants/dateFormats"
|
import { longDateFormat } from "@scandic-hotels/common/constants/dateFormats"
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
|
import { BookingCodeChip } from "@scandic-hotels/design-system/BookingCodeChip"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import { Typography } from "@scandic-hotels/design-system/Typography"
|
import { Typography } from "@scandic-hotels/design-system/Typography"
|
||||||
@@ -18,13 +19,19 @@ import styles from "./receipt.module.css"
|
|||||||
export function Receipt() {
|
export function Receipt() {
|
||||||
const lang = useLang()
|
const lang = useLang()
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const { rooms, fromDate, toDate } = useBookingConfirmationStore((state) => ({
|
const { rooms, fromDate, toDate, bookingCode } = useBookingConfirmationStore(
|
||||||
rooms: state.rooms,
|
(state) => ({
|
||||||
fromDate: state.fromDate,
|
rooms: state.rooms,
|
||||||
toDate: state.toDate,
|
fromDate: state.fromDate,
|
||||||
}))
|
toDate: state.toDate,
|
||||||
|
bookingCode: state.bookingCode,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const totalNights = dt(toDate).diff(fromDate, "days")
|
const totalNights = dt(toDate).diff(fromDate, "days")
|
||||||
|
const isCampaignRate = rooms.every(
|
||||||
|
(room) => room?.rateDefinition.isCampaignRate
|
||||||
|
)
|
||||||
|
|
||||||
const nights = intl.formatMessage(
|
const nights = intl.formatMessage(
|
||||||
{
|
{
|
||||||
@@ -67,10 +74,21 @@ export function Receipt() {
|
|||||||
room={room}
|
room={room}
|
||||||
roomNumber={idx + 1}
|
roomNumber={idx + 1}
|
||||||
roomCount={rooms.length}
|
roomCount={rooms.length}
|
||||||
|
showBookingCodeChip={
|
||||||
|
rooms.length !== 1 &&
|
||||||
|
(room.rateDefinition.isCampaignRate || !!bookingCode)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<TotalPrice />
|
<TotalPrice />
|
||||||
|
{rooms.length === 1 && (isCampaignRate || !!bookingCode) && (
|
||||||
|
<BookingCodeChip
|
||||||
|
isCampaign={isCampaignRate}
|
||||||
|
bookingCode={bookingCode}
|
||||||
|
alignCenter
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useIntl } from "react-intl"
|
|||||||
|
|
||||||
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
|
import { BookingCodeChip } from "@scandic-hotels/design-system/BookingCodeChip"
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
@@ -24,6 +25,7 @@ interface RoomProps {
|
|||||||
isUserLoggedIn: boolean
|
isUserLoggedIn: boolean
|
||||||
nightsCount: number
|
nightsCount: number
|
||||||
defaultCurrency: CurrencyEnum
|
defaultCurrency: CurrencyEnum
|
||||||
|
showBookingCodeChip?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Room({
|
export default function Room({
|
||||||
@@ -33,6 +35,7 @@ export default function Room({
|
|||||||
isUserLoggedIn,
|
isUserLoggedIn,
|
||||||
nightsCount,
|
nightsCount,
|
||||||
defaultCurrency,
|
defaultCurrency,
|
||||||
|
showBookingCodeChip = false,
|
||||||
}: RoomProps) {
|
}: RoomProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const adults = room.adults
|
const adults = room.adults
|
||||||
@@ -68,6 +71,7 @@ export default function Room({
|
|||||||
"member" in room.roomRate &&
|
"member" in room.roomRate &&
|
||||||
room.roomRate.member
|
room.roomRate.member
|
||||||
)
|
)
|
||||||
|
|
||||||
const isSpecialRate =
|
const isSpecialRate =
|
||||||
"corporateCheque" in room.roomRate ||
|
"corporateCheque" in room.roomRate ||
|
||||||
"redemption" in room.roomRate ||
|
"redemption" in room.roomRate ||
|
||||||
@@ -344,7 +348,13 @@ export default function Room({
|
|||||||
nights={nightsCount}
|
nights={nightsCount}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{showBookingCodeChip && (
|
||||||
|
<BookingCodeChip
|
||||||
|
isCampaign={room.roomRate.rateDefinition.isCampaignRate}
|
||||||
|
bookingCode={room.roomRate.bookingCode}
|
||||||
|
alignCenter
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Divider color="Border/Divider/Subtle" />
|
<Divider color="Border/Divider/Subtle" />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -84,10 +84,12 @@ export default function SummaryUI({
|
|||||||
const isAllCampaignRate = rooms.every(
|
const isAllCampaignRate = rooms.every(
|
||||||
(room) => room.room.roomRate.rateDefinition.isCampaignRate
|
(room) => room.room.roomRate.rateDefinition.isCampaignRate
|
||||||
)
|
)
|
||||||
|
|
||||||
const containsBookingCodeRate = rooms.find(
|
const containsBookingCodeRate = rooms.find(
|
||||||
(r) => r && isBookingCodeRate(r.room.roomRate)
|
(r) => r && isBookingCodeRate(r.room.roomRate)
|
||||||
)
|
)
|
||||||
|
const containsCampaignRate = rooms.find(
|
||||||
|
(r) => r && r.room.roomRate.rateDefinition.isCampaignRate
|
||||||
|
)
|
||||||
const showDiscounted = containsBookingCodeRate || isUserLoggedIn
|
const showDiscounted = containsBookingCodeRate || isUserLoggedIn
|
||||||
|
|
||||||
const totalCurrency = isVoucherRate
|
const totalCurrency = isVoucherRate
|
||||||
@@ -136,6 +138,11 @@ export default function SummaryUI({
|
|||||||
roomCount={rooms.length}
|
roomCount={rooms.length}
|
||||||
isUserLoggedIn={isUserLoggedIn}
|
isUserLoggedIn={isUserLoggedIn}
|
||||||
nightsCount={nights}
|
nightsCount={nights}
|
||||||
|
showBookingCodeChip={
|
||||||
|
rooms.length !== 1 &&
|
||||||
|
(room.roomRate.rateDefinition.isCampaignRate ||
|
||||||
|
!!room.roomRate.bookingCode)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|
||||||
@@ -223,14 +230,17 @@ export default function SummaryUI({
|
|||||||
toDate={booking.toDate}
|
toDate={booking.toDate}
|
||||||
totalPrice={totalPrice}
|
totalPrice={totalPrice}
|
||||||
vat={vat}
|
vat={vat}
|
||||||
|
isCampaignRate={!!containsCampaignRate}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<BookingCodeChip
|
{rooms.length === 1 && (isAllCampaignRate || booking.bookingCode) && (
|
||||||
isCampaign={isAllCampaignRate}
|
<BookingCodeChip
|
||||||
bookingCode={booking.bookingCode}
|
isCampaign={isAllCampaignRate}
|
||||||
alignCenter
|
bookingCode={booking.bookingCode}
|
||||||
/>
|
alignCenter
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Divider className={styles.bottomDivider} color="Border/Divider/Subtle" />
|
<Divider className={styles.bottomDivider} color="Border/Divider/Subtle" />
|
||||||
{showSignupPromo && roomOneMemberPrice && !isUserLoggedIn ? (
|
{showSignupPromo && roomOneMemberPrice && !isUserLoggedIn ? (
|
||||||
<SignupPromoDesktop
|
<SignupPromoDesktop
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ export function mapToPrice(rooms: RoomState[], isMember: boolean) {
|
|||||||
...room,
|
...room,
|
||||||
packages: room.roomFeatures,
|
packages: room.roomFeatures,
|
||||||
rateDefinition: {
|
rateDefinition: {
|
||||||
|
...room.roomRate.rateDefinition,
|
||||||
isMemberRate: false,
|
isMemberRate: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -86,6 +87,7 @@ export function mapToPrice(rooms: RoomState[], isMember: boolean) {
|
|||||||
return {
|
return {
|
||||||
...roomWithoutPrice,
|
...roomWithoutPrice,
|
||||||
rateDefinition: {
|
rateDefinition: {
|
||||||
|
...roomWithoutPrice.rateDefinition,
|
||||||
isMemberRate: true,
|
isMemberRate: true,
|
||||||
},
|
},
|
||||||
price: {
|
price: {
|
||||||
@@ -104,6 +106,7 @@ export function mapToPrice(rooms: RoomState[], isMember: boolean) {
|
|||||||
return {
|
return {
|
||||||
...roomWithoutPrice,
|
...roomWithoutPrice,
|
||||||
rateDefinition: {
|
rateDefinition: {
|
||||||
|
...roomWithoutPrice.rateDefinition,
|
||||||
isMemberRate: true,
|
isMemberRate: true,
|
||||||
},
|
},
|
||||||
price: {
|
price: {
|
||||||
|
|||||||
@@ -14,14 +14,15 @@ export default function BookingCodeRow({
|
|||||||
bookingCode,
|
bookingCode,
|
||||||
isCampaignRate,
|
isCampaignRate,
|
||||||
}: BookingCodeRowProps) {
|
}: BookingCodeRowProps) {
|
||||||
if (!bookingCode) {
|
if (!bookingCode && !isCampaignRate) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className={styles.row}>
|
<tr className={styles.row}>
|
||||||
<td colSpan={2} align="left">
|
<td colSpan={2} align="center" className={styles.bookingCodeCell}>
|
||||||
<BookingCodeChip
|
<BookingCodeChip
|
||||||
|
alignCenter
|
||||||
bookingCode={bookingCode}
|
bookingCode={bookingCode}
|
||||||
isCampaign={isCampaignRate}
|
isCampaign={isCampaignRate}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -23,12 +23,14 @@ export interface RegularPriceType {
|
|||||||
|
|
||||||
interface RegularPriceProps extends SharedPriceRowProps {
|
interface RegularPriceProps extends SharedPriceRowProps {
|
||||||
isMemberRate: boolean
|
isMemberRate: boolean
|
||||||
|
isCampaignRate?: boolean
|
||||||
price: RegularPriceType["regular"]
|
price: RegularPriceType["regular"]
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RegularPrice({
|
export default function RegularPrice({
|
||||||
bedType,
|
bedType,
|
||||||
isMemberRate,
|
isMemberRate,
|
||||||
|
isCampaignRate,
|
||||||
nights,
|
nights,
|
||||||
packages,
|
packages,
|
||||||
price,
|
price,
|
||||||
@@ -58,7 +60,8 @@ export default function RegularPrice({
|
|||||||
if (regularPriceIsHigherThanPrice) {
|
if (regularPriceIsHigherThanPrice) {
|
||||||
regularCharge = formatPrice(intl, price.regularPricePerStay, price.currency)
|
regularCharge = formatPrice(intl, price.regularPricePerStay, price.currency)
|
||||||
}
|
}
|
||||||
const isDiscounted = isMemberRate || regularPriceIsHigherThanPrice
|
const isDiscounted =
|
||||||
|
isMemberRate || isCampaignRate || regularPriceIsHigherThanPrice
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -19,3 +19,8 @@
|
|||||||
text-decoration: line-through;
|
text-decoration: line-through;
|
||||||
color: var(--Text-Secondary);
|
color: var(--Text-Secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bookingCodeCell {
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ interface Room {
|
|||||||
childrenInRoom: Child[] | undefined
|
childrenInRoom: Child[] | undefined
|
||||||
packages: Packages | null
|
packages: Packages | null
|
||||||
price: RoomPrice
|
price: RoomPrice
|
||||||
rateDefinition: Pick<RateDefinition, "isMemberRate">
|
rateDefinition: Pick<RateDefinition, "isMemberRate" | "isCampaignRate">
|
||||||
roomType: string
|
roomType: string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +101,9 @@ export default function PriceDetailsTable({
|
|||||||
if (room.rateDefinition.isMemberRate) {
|
if (room.rateDefinition.isMemberRate) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if (room.rateDefinition.isCampaignRate) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if (!room.price.regular) {
|
if (!room.price.regular) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -108,6 +111,9 @@ export default function PriceDetailsTable({
|
|||||||
return room.price.regular.pricePerStay > room.price.regular.pricePerStay
|
return room.price.regular.pricePerStay > room.price.regular.pricePerStay
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const allRoomsHasCampaignRate = rooms.every(
|
||||||
|
(room) => room.rateDefinition.isCampaignRate
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
<table className={styles.priceDetailsTable}>
|
<table className={styles.priceDetailsTable}>
|
||||||
{rooms.map((room, idx) => {
|
{rooms.map((room, idx) => {
|
||||||
@@ -176,6 +182,7 @@ export default function PriceDetailsTable({
|
|||||||
bedType={room.bedType}
|
bedType={room.bedType}
|
||||||
packages={room.packages}
|
packages={room.packages}
|
||||||
isMemberRate={isMemberRate}
|
isMemberRate={isMemberRate}
|
||||||
|
isCampaignRate={room.rateDefinition.isCampaignRate}
|
||||||
nights={nights}
|
nights={nights}
|
||||||
price={price}
|
price={price}
|
||||||
/>
|
/>
|
||||||
@@ -211,6 +218,15 @@ export default function PriceDetailsTable({
|
|||||||
currency={currency}
|
currency={currency}
|
||||||
nights={nights}
|
nights={nights}
|
||||||
/>
|
/>
|
||||||
|
{rooms.length !== 1 &&
|
||||||
|
(room.rateDefinition.isCampaignRate || !!bookingCode) && (
|
||||||
|
<Tbody>
|
||||||
|
<BookingCodeRow
|
||||||
|
isCampaignRate={room.rateDefinition.isCampaignRate}
|
||||||
|
bookingCode={bookingCode}
|
||||||
|
/>
|
||||||
|
</Tbody>
|
||||||
|
)}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -223,9 +239,8 @@ export default function PriceDetailsTable({
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<VatRow totalPrice={totalPrice} vat={vat} />
|
<VatRow totalPrice={totalPrice} vat={vat} />
|
||||||
|
|
||||||
<LargeRow
|
<LargeRow
|
||||||
allPricesIsDiscounted={allPricesIsDiscounted}
|
allPricesIsDiscounted={!!allPricesIsDiscounted || !!isCampaignRate}
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: "booking.priceIncludingVat",
|
id: "booking.priceIncludingVat",
|
||||||
defaultMessage: "Price including VAT",
|
defaultMessage: "Price including VAT",
|
||||||
@@ -233,10 +248,15 @@ export default function PriceDetailsTable({
|
|||||||
price={totalPrice}
|
price={totalPrice}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<BookingCodeRow
|
{rooms.length === 1 && (allRoomsHasCampaignRate || bookingCode) && (
|
||||||
isCampaignRate={isCampaignRate}
|
<>
|
||||||
bookingCode={bookingCode}
|
<tr className={styles.bookingCode} />
|
||||||
/>
|
<BookingCodeRow
|
||||||
|
isCampaignRate={isCampaignRate}
|
||||||
|
bookingCode={bookingCode}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Tbody>
|
</Tbody>
|
||||||
</table>
|
</table>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,3 +8,7 @@
|
|||||||
min-width: 512px;
|
min-width: 512px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bookingCode {
|
||||||
|
padding-top: var(--Space-x3);
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ function Trigger({ title }: { title: string }) {
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
variant="Text"
|
variant="Text"
|
||||||
typography="Body/Supporting text (caption)/smBold"
|
size="Medium"
|
||||||
|
typography="Body/Paragraph/mdBold"
|
||||||
wrapping={false}
|
wrapping={false}
|
||||||
>
|
>
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { CurrencyEnum } from "@scandic-hotels/common/constants/currency"
|
|||||||
import { longDateFormat } from "@scandic-hotels/common/constants/dateFormats"
|
import { longDateFormat } from "@scandic-hotels/common/constants/dateFormats"
|
||||||
import { dt } from "@scandic-hotels/common/dt"
|
import { dt } from "@scandic-hotels/common/dt"
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
|
import { BookingCodeChip } from "@scandic-hotels/design-system/BookingCodeChip"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
@@ -58,6 +59,11 @@ export default function SummaryContent({
|
|||||||
(r) => r && isBookingCodeRate(r)
|
(r) => r && isBookingCodeRate(r)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const cointainsCode = selectedRates.rates.find((r) => r?.type === "code")
|
||||||
|
const containsCampaignRate = selectedRates.rates.some(
|
||||||
|
(r) => r?.type === "campaign"
|
||||||
|
)
|
||||||
|
|
||||||
if (!selectedRates?.totalPrice) {
|
if (!selectedRates?.totalPrice) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -129,6 +135,10 @@ export default function SummaryContent({
|
|||||||
roomNumber={idx + 1}
|
roomNumber={idx + 1}
|
||||||
roomCount={selectedRates.rates.length}
|
roomCount={selectedRates.rates.length}
|
||||||
isMember={isUserLoggedIn && idx === 0}
|
isMember={isUserLoggedIn && idx === 0}
|
||||||
|
showBookingCodeChip={
|
||||||
|
selectedRates.rates.length !== 1 &&
|
||||||
|
(room.rateDefinition.isCampaignRate || isBookingCodeRate(room))
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -216,6 +226,9 @@ export default function SummaryContent({
|
|||||||
selectedRates.totalPrice.requested?.currency ??
|
selectedRates.totalPrice.requested?.currency ??
|
||||||
selectedRates.totalPrice.local.currency
|
selectedRates.totalPrice.local.currency
|
||||||
}
|
}
|
||||||
|
isCampaignRate={selectedRates?.rates?.some(
|
||||||
|
(room) => room != null && room.type === "campaign"
|
||||||
|
)}
|
||||||
rooms={selectedRates.rates
|
rooms={selectedRates.rates
|
||||||
.map((room, idx) => {
|
.map((room, idx) => {
|
||||||
if (!room) {
|
if (!room) {
|
||||||
@@ -308,6 +321,7 @@ export default function SummaryContent({
|
|||||||
breakfastIncluded:
|
breakfastIncluded:
|
||||||
room?.rateDefinition.breakfastIncluded ?? false,
|
room?.rateDefinition.breakfastIncluded ?? false,
|
||||||
rateDefinition: room.rateDefinition,
|
rateDefinition: room.rateDefinition,
|
||||||
|
bookingCode: room.bookingCode,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter((x) => !!x)}
|
.filter((x) => !!x)}
|
||||||
@@ -317,6 +331,17 @@ export default function SummaryContent({
|
|||||||
vat={selectedRates.vat}
|
vat={selectedRates.vat}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{selectedRates.rates.length === 1 &&
|
||||||
|
(containsBookingCodeRate || cointainsCode) && (
|
||||||
|
<div>
|
||||||
|
<BookingCodeChip
|
||||||
|
alignCenter
|
||||||
|
bookingCode={input.bookingCode}
|
||||||
|
isCampaign={containsCampaignRate}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{!isUserLoggedIn && memberPrice ? (
|
{!isUserLoggedIn && memberPrice ? (
|
||||||
<SignupPromoDesktop
|
<SignupPromoDesktop
|
||||||
memberPrice={{
|
memberPrice={{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { cx } from "class-variance-authority"
|
|||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
import { formatPrice } from "@scandic-hotels/common/utils/numberFormatting"
|
||||||
|
import { BookingCodeChip } from "@scandic-hotels/design-system/BookingCodeChip"
|
||||||
import { Button } from "@scandic-hotels/design-system/Button"
|
import { Button } from "@scandic-hotels/design-system/Button"
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
import { Divider } from "@scandic-hotels/design-system/Divider"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
@@ -33,6 +34,7 @@ interface RoomProps {
|
|||||||
cancellationText: string
|
cancellationText: string
|
||||||
packages?: Packages
|
packages?: Packages
|
||||||
}
|
}
|
||||||
|
showBookingCodeChip: boolean
|
||||||
roomNumber: number
|
roomNumber: number
|
||||||
roomCount: number
|
roomCount: number
|
||||||
isMember: boolean
|
isMember: boolean
|
||||||
@@ -43,6 +45,7 @@ export default function Room({
|
|||||||
roomNumber,
|
roomNumber,
|
||||||
roomCount,
|
roomCount,
|
||||||
isMember,
|
isMember,
|
||||||
|
showBookingCodeChip,
|
||||||
}: RoomProps) {
|
}: RoomProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const adults = room.adults
|
const adults = room.adults
|
||||||
@@ -271,6 +274,13 @@ export default function Room({
|
|||||||
</Typography>
|
</Typography>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
{showBookingCodeChip && (
|
||||||
|
<BookingCodeChip
|
||||||
|
isCampaign={room.roomRate.rateDefinition.isCampaignRate}
|
||||||
|
bookingCode={room.roomRate.bookingCode}
|
||||||
|
alignCenter
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Divider color="Border/Divider/Subtle" />
|
<Divider color="Border/Divider/Subtle" />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export function RemoveBookingCodeButton() {
|
|||||||
const {
|
const {
|
||||||
input: { bookingCode },
|
input: { bookingCode },
|
||||||
actions: { removeBookingCode },
|
actions: { removeBookingCode },
|
||||||
|
hasCampaignRates,
|
||||||
} = useSelectRateContext()
|
} = useSelectRateContext()
|
||||||
|
|
||||||
if (!bookingCode) {
|
if (!bookingCode) {
|
||||||
@@ -16,6 +17,7 @@ export function RemoveBookingCodeButton() {
|
|||||||
<BookingCodeChip
|
<BookingCodeChip
|
||||||
bookingCode={bookingCode}
|
bookingCode={bookingCode}
|
||||||
filledIcon
|
filledIcon
|
||||||
|
isCampaign={hasCampaignRates}
|
||||||
withCloseButton={true}
|
withCloseButton={true}
|
||||||
withText={false}
|
withText={false}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
|
|||||||
@@ -148,8 +148,9 @@ function Inner({
|
|||||||
id: "booking.campaign",
|
id: "booking.campaign",
|
||||||
defaultMessage: "Campaign",
|
defaultMessage: "Campaign",
|
||||||
})
|
})
|
||||||
|
|
||||||
if (product.bookingCode) {
|
if (product.bookingCode) {
|
||||||
bannerText = product.bookingCode
|
bannerText = `${bannerText} ∙ ${product.bookingCode.trim()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (product.rateDefinition.breakfastIncluded) {
|
if (product.rateDefinition.breakfastIncluded) {
|
||||||
@@ -157,11 +158,6 @@ function Inner({
|
|||||||
id: "booking.breakfastIncluded",
|
id: "booking.breakfastIncluded",
|
||||||
defaultMessage: "Breakfast included",
|
defaultMessage: "Breakfast included",
|
||||||
})}`
|
})}`
|
||||||
} else {
|
|
||||||
bannerText = `${bannerText} ∙ ${intl.formatMessage({
|
|
||||||
id: "booking.breakfastExcluded",
|
|
||||||
defaultMessage: "Breakfast excluded",
|
|
||||||
})}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const pkgsSum = sumPackages(selectedPackages)
|
const pkgsSum = sumPackages(selectedPackages)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { Divider } from "@scandic-hotels/design-system/Divider"
|
|
||||||
|
|
||||||
import { useSelectRateContext } from "../../../../../../../contexts/SelectRate/SelectRateContext"
|
import { useSelectRateContext } from "../../../../../../../contexts/SelectRate/SelectRateContext"
|
||||||
import { BookingCodeFilterEnum } from "../../../../../../../stores/bookingCode-filter"
|
import { BookingCodeFilterEnum } from "../../../../../../../stores/bookingCode-filter"
|
||||||
import { BreakfastMessage } from "./BreakfastMessage"
|
import { BreakfastMessage } from "./BreakfastMessage"
|
||||||
@@ -44,22 +42,38 @@ export function Rates({
|
|||||||
selectedPackages,
|
selectedPackages,
|
||||||
}
|
}
|
||||||
const showAllRates = bookingCodeFilter === BookingCodeFilterEnum.All
|
const showAllRates = bookingCodeFilter === BookingCodeFilterEnum.All
|
||||||
const hasBookingCodeRates = !!(campaign.length || code.length)
|
|
||||||
const hasRegularRates = !!regular.length
|
const hasRegularRates = !!regular.length
|
||||||
const showDivider = showAllRates && hasBookingCodeRates && hasRegularRates
|
|
||||||
|
const showSeparateCampaignBreakfastMessage = campaign.some((camp) => {
|
||||||
|
return (
|
||||||
|
camp.rateDefinition.breakfastIncluded ||
|
||||||
|
camp.rateDefinitionMember?.breakfastIncluded
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Code {...sharedProps} code={code} />
|
<Code {...sharedProps} code={code} />
|
||||||
|
|
||||||
|
{!showSeparateCampaignBreakfastMessage && showAllRates && (
|
||||||
|
<BreakfastMessage
|
||||||
|
breakfastIncludedMember={breakfastIncludedInAllRatesMember}
|
||||||
|
breakfastIncludedStandard={breakfastIncludedInAllRates}
|
||||||
|
hasRegularRates={hasRegularRates && showAllRates}
|
||||||
|
roomIndex={roomIndex}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Campaign {...sharedProps} campaign={campaign} />
|
<Campaign {...sharedProps} campaign={campaign} />
|
||||||
<Redemptions {...sharedProps} redemptions={redemptions} />
|
<Redemptions {...sharedProps} redemptions={redemptions} />
|
||||||
{showDivider ? <Divider color="Border/Divider/Subtle" /> : null}
|
|
||||||
<BreakfastMessage
|
{showSeparateCampaignBreakfastMessage && showAllRates && (
|
||||||
breakfastIncludedMember={breakfastIncludedInAllRatesMember}
|
<BreakfastMessage
|
||||||
breakfastIncludedStandard={breakfastIncludedInAllRates}
|
breakfastIncludedMember={breakfastIncludedInAllRatesMember}
|
||||||
hasRegularRates={hasRegularRates && showAllRates}
|
breakfastIncludedStandard={breakfastIncludedInAllRates}
|
||||||
roomIndex={roomIndex}
|
hasRegularRates={hasRegularRates && showAllRates}
|
||||||
/>
|
roomIndex={roomIndex}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<RegularRate {...sharedProps} regular={regular} />
|
<RegularRate {...sharedProps} regular={regular} />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -413,6 +413,9 @@ export function SelectRateProvider({
|
|||||||
? "ALL_SELECTED"
|
? "ALL_SELECTED"
|
||||||
: "PARTIALLY_SELECTED",
|
: "PARTIALLY_SELECTED",
|
||||||
},
|
},
|
||||||
|
hasCampaignRates: roomAvailability.some((roomConfig) =>
|
||||||
|
roomConfig.some((room) => (room?.campaign.length ?? 0) > 0)
|
||||||
|
),
|
||||||
activeRoomIndex: activeRoomIndex,
|
activeRoomIndex: activeRoomIndex,
|
||||||
actions: {
|
actions: {
|
||||||
setActiveRoom: setActiveRoomIndex,
|
setActiveRoom: setActiveRoomIndex,
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ export type SelectRateContext = {
|
|||||||
|
|
||||||
bookingCodeFilter: BookingCodeFilterEnum
|
bookingCodeFilter: BookingCodeFilterEnum
|
||||||
activeRoomIndex: number
|
activeRoomIndex: number
|
||||||
|
hasCampaignRates: boolean
|
||||||
actions: {
|
actions: {
|
||||||
setActiveRoom: (roomIndex: number | "deselect" | "next") => void
|
setActiveRoom: (roomIndex: number | "deselect" | "next") => void
|
||||||
selectPackages: (args: {
|
selectPackages: (args: {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { Button as ButtonRAC } from 'react-aria-components'
|
|
||||||
import { useIntl } from 'react-intl'
|
import { useIntl } from 'react-intl'
|
||||||
|
|
||||||
import IconChip from '../IconChip'
|
import IconChip from '../IconChip'
|
||||||
@@ -8,6 +7,7 @@ import { MaterialIcon } from '../Icons/MaterialIcon'
|
|||||||
import { Typography } from '../Typography'
|
import { Typography } from '../Typography'
|
||||||
|
|
||||||
import styles from './bookingCodeChip.module.css'
|
import styles from './bookingCodeChip.module.css'
|
||||||
|
import { IconButton } from '../IconButton'
|
||||||
|
|
||||||
type BaseBookingCodeChipProps = {
|
type BaseBookingCodeChipProps = {
|
||||||
alignCenter?: boolean
|
alignCenter?: boolean
|
||||||
@@ -19,6 +19,7 @@ type BaseBookingCodeChipProps = {
|
|||||||
}
|
}
|
||||||
type BookingCodeChipWithoutCloseButtonProps = BaseBookingCodeChipProps & {
|
type BookingCodeChipWithoutCloseButtonProps = BaseBookingCodeChipProps & {
|
||||||
withCloseButton?: false
|
withCloseButton?: false
|
||||||
|
onClose?: undefined
|
||||||
}
|
}
|
||||||
type BookingCodeChipWithCloseButtonProps = BaseBookingCodeChipProps & {
|
type BookingCodeChipWithCloseButtonProps = BaseBookingCodeChipProps & {
|
||||||
withCloseButton: true
|
withCloseButton: true
|
||||||
@@ -36,7 +37,8 @@ export function BookingCodeChip({
|
|||||||
isUnavailable,
|
isUnavailable,
|
||||||
withText = true,
|
withText = true,
|
||||||
filledIcon = false,
|
filledIcon = false,
|
||||||
...props
|
withCloseButton,
|
||||||
|
onClose,
|
||||||
}: BookingCodeChipProps) {
|
}: BookingCodeChipProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
@@ -46,9 +48,13 @@ export function BookingCodeChip({
|
|||||||
color="green"
|
color="green"
|
||||||
icon={
|
icon={
|
||||||
filledIcon ? (
|
filledIcon ? (
|
||||||
<FilledDiscountIcon color="Icon/Feedback/Success" />
|
<MaterialIcon
|
||||||
|
icon="sell"
|
||||||
|
color="Icon/Feedback/Success"
|
||||||
|
isFilled={!!filledIcon}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DiscountIcon color="Icon/Feedback/Success" />
|
<MaterialIcon icon="sell" color="Icon/Feedback/Success" />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
className={alignCenter ? styles.center : undefined}
|
className={alignCenter ? styles.center : undefined}
|
||||||
@@ -64,10 +70,30 @@ export function BookingCodeChip({
|
|||||||
</Typography>
|
</Typography>
|
||||||
{bookingCode && (
|
{bookingCode && (
|
||||||
<Typography variant="Body/Supporting text (caption)/smRegular">
|
<Typography variant="Body/Supporting text (caption)/smRegular">
|
||||||
<span>{bookingCode}</span>
|
{/*eslint-disable-next-line formatjs/no-literal-string-in-jsx*/}
|
||||||
|
<span>∙ {bookingCode}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
|
{withCloseButton && (
|
||||||
|
<IconButton
|
||||||
|
style="Muted"
|
||||||
|
theme="Inverted"
|
||||||
|
wrapping
|
||||||
|
className={styles.removeButton}
|
||||||
|
onPress={onClose}
|
||||||
|
aria-label={intl.formatMessage({
|
||||||
|
id: 'booking.removeBookingCode',
|
||||||
|
defaultMessage: 'Remove booking code',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<MaterialIcon
|
||||||
|
icon="close"
|
||||||
|
size={16}
|
||||||
|
color="Icon/Feedback/Success"
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
|
)}
|
||||||
</IconChip>
|
</IconChip>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -105,12 +131,24 @@ export function BookingCodeChip({
|
|||||||
<span>{bookingCode}</span>
|
<span>{bookingCode}</span>
|
||||||
</Typography>
|
</Typography>
|
||||||
</p>
|
</p>
|
||||||
{props.withCloseButton && (
|
{withCloseButton && (
|
||||||
<>
|
<IconButton
|
||||||
<ButtonRAC className={styles.removeButton} onPress={props.onClose}>
|
style="Muted"
|
||||||
<MaterialIcon icon="close" size={16} color="CurrentColor" />
|
theme="Inverted"
|
||||||
</ButtonRAC>
|
wrapping
|
||||||
</>
|
className={styles.removeButton}
|
||||||
|
onPress={onClose}
|
||||||
|
aria-label={intl.formatMessage({
|
||||||
|
id: 'booking.removeBookingCode',
|
||||||
|
defaultMessage: 'Remove booking code',
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<MaterialIcon
|
||||||
|
icon="close"
|
||||||
|
size={16}
|
||||||
|
color="Icon/Feedback/Information"
|
||||||
|
/>
|
||||||
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
</IconChip>
|
</IconChip>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import { cx } from 'class-variance-authority'
|
||||||
|
|
||||||
import { Typography } from '../../Typography'
|
import { Typography } from '../../Typography'
|
||||||
import { Rate, RateTermDetails } from '../types'
|
import { Rate, RateTermDetails } from '../types'
|
||||||
|
|
||||||
@@ -56,9 +58,12 @@ export default function CampaignRateCard({
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
/>
|
/>
|
||||||
<div className={classNames}>
|
<div className={classNames}>
|
||||||
<Typography variant="Label/xsBold">
|
<div className={styles.banner}>
|
||||||
<p className={styles.banner}>{bannerText}</p>
|
<MaterialIcon size={16} icon="sell" color="CurrentColor" />
|
||||||
</Typography>
|
<Typography variant="Label/xsBold">
|
||||||
|
<p>{bannerText}</p>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
<header>
|
<header>
|
||||||
<Typography variant="Tag/sm">
|
<Typography variant="Tag/sm">
|
||||||
@@ -67,7 +72,7 @@ export default function CampaignRateCard({
|
|||||||
title={rateTitle}
|
title={rateTitle}
|
||||||
subtitle={paymentTerm}
|
subtitle={paymentTerm}
|
||||||
trigger={
|
trigger={
|
||||||
<IconButton theme="Black" style="Muted">
|
<IconButton theme="Black" style="Muted" wrapping>
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="info"
|
icon="info"
|
||||||
size={20}
|
size={20}
|
||||||
@@ -109,14 +114,17 @@ export default function CampaignRateCard({
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<div
|
<div className={styles.rateRow}>
|
||||||
className={`${styles.rateRow} ${isHighlightedRate ? styles.highlightedRate : ''}`}
|
|
||||||
>
|
|
||||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||||
<p>{rate.label}</p>
|
<p>{rate.label}</p>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="Title/Subtitle/md">
|
<Typography variant="Title/Subtitle/md">
|
||||||
<p>
|
<p
|
||||||
|
className={cx(
|
||||||
|
styles.rate,
|
||||||
|
isHighlightedRate && styles.highlightedRate
|
||||||
|
)}
|
||||||
|
>
|
||||||
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
{/* eslint-disable-next-line formatjs/no-literal-string-in-jsx */}
|
||||||
{`${rate.price} `}
|
{`${rate.price} `}
|
||||||
<Typography variant="Body/Supporting text (caption)/smBold">
|
<Typography variant="Body/Supporting text (caption)/smBold">
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ export default function CodeRateCard({
|
|||||||
title={rateTitle}
|
title={rateTitle}
|
||||||
subtitle={paymentTerm}
|
subtitle={paymentTerm}
|
||||||
trigger={
|
trigger={
|
||||||
<IconButton theme="Black" style="Muted">
|
<IconButton theme="Black" style="Muted" wrapping>
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="info"
|
icon="info"
|
||||||
size={20}
|
size={20}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export default function PointsRateCard({
|
|||||||
title={rateTitle}
|
title={rateTitle}
|
||||||
subtitle={paymentTerm}
|
subtitle={paymentTerm}
|
||||||
trigger={
|
trigger={
|
||||||
<IconButton theme="Black" style="Muted">
|
<IconButton theme="Black" style="Muted" wrapping>
|
||||||
<MaterialIcon icon="info" size={20} color="Icon/Default" />
|
<MaterialIcon icon="info" size={20} color="Icon/Default" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export default function RegularRateCard({
|
|||||||
title={rateTitle}
|
title={rateTitle}
|
||||||
subtitle={paymentTerm}
|
subtitle={paymentTerm}
|
||||||
trigger={
|
trigger={
|
||||||
<IconButton theme="Black" style="Muted">
|
<IconButton theme="Black" style="Muted" wrapping>
|
||||||
<MaterialIcon
|
<MaterialIcon
|
||||||
icon="info"
|
icon="info"
|
||||||
size={20}
|
size={20}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ label:not(:has(.radio:checked)) .checkIcon {
|
|||||||
border-top-right-radius: var(--Corner-radius-md);
|
border-top-right-radius: var(--Corner-radius-md);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--Text-Inverted);
|
color: var(--Text-Inverted);
|
||||||
padding: var(--Space-x05) 0;
|
padding: var(--Space-x05) var(--Space-x1);
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,6 @@ label:not(:has(.radio:checked)) .checkIcon {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--Space-x1);
|
gap: var(--Space-x1);
|
||||||
|
|
||||||
padding: var(--Space-x1) var(--Space-x15) var(--Space-x15);
|
padding: var(--Space-x1) var(--Space-x15) var(--Space-x15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +99,7 @@ label:not(:has(.radio:checked)) .checkIcon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.highlightedRate {
|
.highlightedRate {
|
||||||
color: var(--Surface-Brand-Primary-1-OnSurface-Accent);
|
color: var(--Text-Accent-Primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.textSecondary {
|
.textSecondary {
|
||||||
@@ -160,7 +159,19 @@ label:not(:has(.radio:checked)) .checkIcon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.variant-campaign .banner {
|
.variant-campaign .banner {
|
||||||
background-color: var(--Surface-Accent-3);
|
background-color: var(
|
||||||
|
--Surface-Feedback-Succes-light,
|
||||||
|
var(--Scandic-Green-60)
|
||||||
|
); /*Should be updated to only use the new token --Surface-Feedback-Succes-light when tokens are up to date*/
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--Space-x05);
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variant-campaign .rate {
|
||||||
|
color: var(--Text-Accent-Primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.variant-code .banner {
|
.variant-code .banner {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ const rateDefinitionSchema = z.object({
|
|||||||
mustBeGuaranteed: z.boolean().default(false),
|
mustBeGuaranteed: z.boolean().default(false),
|
||||||
rateCode: z.string().default(""),
|
rateCode: z.string().default(""),
|
||||||
title: z.string().nullable().default(""),
|
title: z.string().nullable().default(""),
|
||||||
|
isCampaignRate: z.boolean().default(false),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const linkedReservationSchema = z.object({
|
export const linkedReservationSchema = z.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user