fix/SW-902-update-response-city-availability (pull request #917)

Fix/SW-902 update response city availability

* fix(SW-902): update response for API changes

* fix(SW-902): add total row for pricePerStay

* fix(SW-902): fix optional requestedPrice

* fix(SW-902): fix bookingCode output

* feat(SW-903): fix sorting


Approved-by: Pontus Dreij
Approved-by: Niclas Edenvin
This commit is contained in:
Bianca Widstam
2024-11-18 15:08:12 +00:00
parent f6b14ced8f
commit 3c4907efce
27 changed files with 217 additions and 227 deletions

View File

@@ -80,7 +80,9 @@ export default function Summary({
) || { local: 0, euro: 0 }
const roomsPriceLocal = room.localPrice.price + additionalPackageCost.local
const roomsPriceEuro = room.euroPrice.price + additionalPackageCost.euro
const roomsPriceEuro = room.euroPrice
? room.euroPrice.price + additionalPackageCost.euro
: undefined
useEffect(() => {
setChosenBed(bedType)
@@ -92,10 +94,15 @@ export default function Summary({
price: roomsPriceLocal + parseInt(breakfast.localPrice.totalPrice),
currency: room.localPrice.currency,
},
euro: {
price: roomsPriceEuro + parseInt(breakfast.requestedPrice.totalPrice),
currency: room.euroPrice.currency,
},
euro:
room.euroPrice && roomsPriceEuro
? {
price:
roomsPriceEuro +
parseInt(breakfast.requestedPrice.totalPrice),
currency: room.euroPrice.currency,
}
: undefined,
})
} else {
setTotalPrice({
@@ -103,10 +110,13 @@ export default function Summary({
price: roomsPriceLocal,
currency: room.localPrice.currency,
},
euro: {
price: roomsPriceEuro,
currency: room.euroPrice.currency,
},
euro:
room.euroPrice && roomsPriceEuro
? {
price: roomsPriceEuro,
currency: room.euroPrice.currency,
}
: undefined,
})
}
}, [
@@ -114,7 +124,7 @@ export default function Summary({
breakfast,
roomsPriceLocal,
room.localPrice.currency,
room.euroPrice.currency,
room.euroPrice,
roomsPriceEuro,
setTotalPrice,
])
@@ -269,16 +279,18 @@ export default function Summary({
}
)}
</Body>
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Approx." })}{" "}
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: intl.formatNumber(totalPrice.euro.price),
currency: totalPrice.euro.currency,
}
)}
</Caption>
{totalPrice.euro && (
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Approx." })}{" "}
{intl.formatMessage(
{ id: "{amount} {currency}" },
{
amount: intl.formatNumber(totalPrice.euro.price),
currency: totalPrice.euro.currency,
}
)}
</Caption>
)}
</div>
</div>
<Divider className={styles.bottomDivider} color="primaryLightSubtle" />

View File

@@ -1,5 +1,6 @@
import { useIntl } from "react-intl"
import Divider from "@/components/TempDesignSystem/Divider"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
@@ -9,15 +10,14 @@ import styles from "../hotelPriceList.module.css"
import type { PriceCardProps } from "@/types/components/hotelReservation/selectHotel/priceCardProps"
export default function HotelPriceCard({
currency,
memberAmount,
regularAmount,
productTypePrices,
isMemberPrice = false,
}: PriceCardProps) {
const intl = useIntl()
return (
<dl className={styles.priceCard}>
{memberAmount && (
{isMemberPrice && (
<div className={styles.priceRow}>
<dt>
<Caption color="red">
@@ -30,7 +30,7 @@ export default function HotelPriceCard({
<dt>
<Caption
type="bold"
color={memberAmount ? "red" : "uiTextHighContrast"}
color={isMemberPrice ? "red" : "uiTextHighContrast"}
>
{intl.formatMessage({ id: "From" })}
</Caption>
@@ -39,15 +39,15 @@ export default function HotelPriceCard({
<div className={styles.price}>
<Subtitle
type="two"
color={memberAmount ? "red" : "uiTextHighContrast"}
color={isMemberPrice ? "red" : "uiTextHighContrast"}
>
{memberAmount ? memberAmount : regularAmount}
{productTypePrices.localPrice.pricePerNight}
</Subtitle>
<Body
color={memberAmount ? "red" : "uiTextHighContrast"}
color={isMemberPrice ? "red" : "uiTextHighContrast"}
textTransform="bold"
>
{currency}
{productTypePrices.localPrice.currency}
<span className={styles.perNight}>
/{intl.formatMessage({ id: "night" })}
</span>
@@ -55,17 +55,40 @@ export default function HotelPriceCard({
</div>
</dd>
</div>
{/* TODO add correct local price when API change */}
<div className={styles.priceRow}>
<dt>
<Caption color={"disabled"}>
{intl.formatMessage({ id: "Approx." })}
</Caption>
</dt>
<dd>
<Caption color="disabled"> - EUR</Caption>
</dd>
</div>
{productTypePrices?.requestedPrice && (
<div className={styles.priceRow}>
<dt>
<Caption color="uiTextMediumContrast">
{intl.formatMessage({ id: "Approx." })}
</Caption>
</dt>
<dd>
<Caption color={"uiTextMediumContrast"}>
{productTypePrices.requestedPrice.pricePerNight}{" "}
{productTypePrices.requestedPrice.currency}
</Caption>
</dd>
</div>
)}
{productTypePrices.localPrice.pricePerStay !==
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>
</>
)}
</dl>
)
}

View File

@@ -11,6 +11,17 @@
gap: var(--Spacing-x1);
}
.prices {
display: flex;
flex-direction: column;
gap: var(--Spacing-x-one-and-half);
max-width: 260px;
}
.divider {
margin: var(--Spacing-x-half) 0;
}
.priceRow {
display: flex;
justify-content: space-between;

View File

@@ -1,6 +1,12 @@
import { useParams } from "next/dist/client/components/navigation"
import { useIntl } from "react-intl"
import { Lang } from "@/constants/languages"
import { selectRate } from "@/constants/routes/hotelReservation"
import { ErrorCircleIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import HotelPriceCard from "./HotelPriceCard"
@@ -9,34 +15,52 @@ import styles from "./hotelPriceList.module.css"
import { HotelPriceListProps } from "@/types/components/hotelReservation/selectHotel/hotePriceListProps"
export default function HotelPriceList({ price }: HotelPriceListProps) {
export default function HotelPriceList({
price,
hotelId,
}: HotelPriceListProps) {
const intl = useIntl()
const params = useParams()
const lang = params.lang as Lang
return (
<>
<div className={styles.prices}>
{price ? (
<>
<HotelPriceCard
currency={price?.currency}
regularAmount={price?.regularAmount}
/>
<HotelPriceCard
currency={price?.currency}
memberAmount={price?.memberAmount}
/>
{price.public && <HotelPriceCard productTypePrices={price.public} />}
{price.member && (
<HotelPriceCard productTypePrices={price.member} isMemberPrice />
)}
<Button
asChild
theme="base"
intent="primary"
size="small"
className={styles.button}
>
<Link
href={`${selectRate[lang]}?hotel=${hotelId}`}
color="none"
keepSearchParams
>
{intl.formatMessage({ id: "See rooms" })}
</Link>
</Button>
</>
) : (
<div className={styles.priceCard}>
<div className={styles.noRooms}>
<ErrorCircleIcon color="red" />
<div>
<ErrorCircleIcon color="red" />
</div>
<Body>
{intl.formatMessage({
id: "There are no rooms available that match your request",
id: "There are no rooms available that match your request.",
})}
</Body>
</div>
</div>
)}
</>
</div>
)
}

View File

@@ -70,13 +70,6 @@
gap: var(--Spacing-x-half);
}
.prices {
display: flex;
flex-direction: column;
gap: var(--Spacing-x-one-and-half);
width: 100%;
}
.detailsButton {
border-bottom: none;
}

View File

@@ -141,25 +141,7 @@ export default function HotelCard({
</div>
)}
</section>
<div className={styles.prices}>
<HotelPriceList price={price} />
<Button
asChild
theme="base"
intent="primary"
size="small"
className={styles.button}
>
{/* TODO: use correct search params */}
<Link
href={`${selectRate[lang]}?hotel=${hotelData.operaId}`}
color="none"
keepSearchParams
>
{intl.formatMessage({ id: "See rooms" })}
</Link>
</Button>
</div>
<HotelPriceList price={price} hotelId={hotel.hotelData.operaId} />
</div>
</article>
)

View File

@@ -8,9 +8,9 @@ export function getHotelPins(hotels: HotelData[]): HotelPin[] {
lng: hotel.hotelData.location.longitude,
},
name: hotel.hotelData.name,
publicPrice: hotel.price?.regularAmount ?? null,
memberPrice: hotel.price?.memberAmount ?? null,
currency: hotel.price?.currency || null,
publicPrice: hotel.price?.public?.localPrice.pricePerNight ?? null,
memberPrice: hotel.price?.member?.localPrice.pricePerNight ?? null,
currency: hotel.price?.public?.localPrice.currency || null,
images: [
hotel.hotelData.hotelContent.images,
...(hotel.hotelData.gallery?.heroImages ?? []),

View File

@@ -12,6 +12,7 @@ import styles from "./hotelCardListing.module.css"
import {
type HotelCardListingProps,
HotelCardListingTypeEnum,
type HotelData,
} from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
import { SortOrder } from "@/types/components/hotelReservation/selectHotel/hotelSorter"
@@ -43,10 +44,15 @@ export default function HotelCardListing({
(a.hotelData.ratings?.tripAdvisor.rating ?? 0)
)
case SortOrder.Price:
const getPricePerNight = (hotel: HotelData): number => {
return (
hotel.price?.member?.localPrice?.pricePerNight ??
hotel.price?.public?.localPrice?.pricePerNight ??
0
)
}
return [...hotelData].sort(
(a, b) =>
parseInt(a.price?.memberAmount ?? "0", 10) -
parseInt(b.price?.memberAmount ?? "0", 10)
(a, b) => getPricePerNight(a) - getPricePerNight(b)
)
case SortOrder.Distance:
default:

View File

@@ -49,7 +49,7 @@ export function filterDuplicateRoomTypesByLowestPrice(
const previousLowest = roomMap.get(roomType)
const currentRequestedPrice = Math.min(
Number(publicRequestedPrice.pricePerNight) ?? Infinity,
Number(publicRequestedPrice?.pricePerNight) ?? Infinity,
Number(memberRequestedPrice?.pricePerNight) ?? Infinity
)
const currentLocalPrice = Math.min(