feat: SW-2028 Points validation redemption city search
This commit is contained in:
@@ -18,6 +18,7 @@ import Link from "@/components/TempDesignSystem/Link"
|
|||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
|
import { Tooltip } from "@/components/TempDesignSystem/Tooltip"
|
||||||
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
import { mapApiImagesToGalleryImages } from "@/utils/imageGallery"
|
||||||
import { getSingleDecimal } from "@/utils/numberFormatting"
|
import { getSingleDecimal } from "@/utils/numberFormatting"
|
||||||
|
|
||||||
@@ -43,6 +44,7 @@ function HotelCard({
|
|||||||
state = "default",
|
state = "default",
|
||||||
type = HotelCardListingTypeEnum.PageListing,
|
type = HotelCardListingTypeEnum.PageListing,
|
||||||
bookingCode = "",
|
bookingCode = "",
|
||||||
|
userPoints,
|
||||||
}: HotelCardProps) {
|
}: HotelCardProps) {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const lang = params.lang as Lang
|
const lang = params.lang as Lang
|
||||||
@@ -72,6 +74,15 @@ function HotelCard({
|
|||||||
availability.productType?.member?.rateType === RateTypeEnum.Regular
|
availability.productType?.member?.rateType === RateTypeEnum.Regular
|
||||||
const price = availability.productType
|
const price = availability.productType
|
||||||
|
|
||||||
|
const userHasEnoughPoints =
|
||||||
|
userPoints !== undefined
|
||||||
|
? !!price?.redemptions?.some(
|
||||||
|
(r) => r.localPrice.pointsPerStay < userPoints
|
||||||
|
)
|
||||||
|
: false
|
||||||
|
|
||||||
|
const notEnoughPointsLabel = intl.formatMessage({ id: "Not enough points" })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<article
|
<article
|
||||||
className={classNames}
|
className={classNames}
|
||||||
@@ -207,6 +218,23 @@ function HotelCard({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
{userPoints !== undefined && !userHasEnoughPoints ? (
|
||||||
|
<Tooltip
|
||||||
|
arrow="left"
|
||||||
|
position="bottom"
|
||||||
|
text={notEnoughPointsLabel}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
theme="base"
|
||||||
|
intent="primary"
|
||||||
|
size="small"
|
||||||
|
className={styles.button}
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{notEnoughPointsLabel}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
<Button
|
<Button
|
||||||
asChild
|
asChild
|
||||||
theme="base"
|
theme="base"
|
||||||
@@ -222,6 +250,7 @@ function HotelCard({
|
|||||||
{intl.formatMessage({ id: "See rooms" })}
|
{intl.formatMessage({ id: "See rooms" })}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { RateTypeEnum } from "@/types/enums/rateType"
|
|||||||
export default function HotelCardListing({
|
export default function HotelCardListing({
|
||||||
hotelData,
|
hotelData,
|
||||||
type = HotelCardListingTypeEnum.PageListing,
|
type = HotelCardListingTypeEnum.PageListing,
|
||||||
|
userPoints,
|
||||||
}: HotelCardListingProps) {
|
}: HotelCardListingProps) {
|
||||||
const { data: session } = useSession()
|
const { data: session } = useSession()
|
||||||
const isUserLoggedIn = isValidClientSession(session)
|
const isUserLoggedIn = isValidClientSession(session)
|
||||||
@@ -121,6 +122,7 @@ export default function HotelCardListing({
|
|||||||
}
|
}
|
||||||
type={type}
|
type={type}
|
||||||
bookingCode={bookingCode}
|
bookingCode={bookingCode}
|
||||||
|
userPoints={userPoints}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -246,6 +246,14 @@ export async function getHotels(
|
|||||||
return hotels
|
return hotels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getUserPoints() {
|
||||||
|
const membershipCard = await serverClient().user.safeMembershipLevel()
|
||||||
|
if (!membershipCard) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
return membershipCard.currentPoints
|
||||||
|
}
|
||||||
|
|
||||||
const hotelSurroundingsFilterNames = [
|
const hotelSurroundingsFilterNames = [
|
||||||
"Hotel surroundings",
|
"Hotel surroundings",
|
||||||
"Hotel omgivelser",
|
"Hotel omgivelser",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import { convertObjToSearchParams } from "@/utils/url"
|
|||||||
|
|
||||||
import HotelCardListing from "../HotelCardListing"
|
import HotelCardListing from "../HotelCardListing"
|
||||||
import BookingCodeFilter from "./BookingCodeFilter"
|
import BookingCodeFilter from "./BookingCodeFilter"
|
||||||
import { getFiltersFromHotels, getHotels } from "./helpers"
|
import { getFiltersFromHotels, getHotels, getUserPoints } from "./helpers"
|
||||||
import HotelCount from "./HotelCount"
|
import HotelCount from "./HotelCount"
|
||||||
import HotelFilter from "./HotelFilter"
|
import HotelFilter from "./HotelFilter"
|
||||||
import HotelSorter from "./HotelSorter"
|
import HotelSorter from "./HotelSorter"
|
||||||
@@ -76,6 +76,11 @@ export default async function SelectHotel({
|
|||||||
!!redemption
|
!!redemption
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let userPoints
|
||||||
|
if (redemption) {
|
||||||
|
userPoints = await getUserPoints()
|
||||||
|
}
|
||||||
|
|
||||||
const arrivalDate = new Date(selectHotelParams.fromDate)
|
const arrivalDate = new Date(selectHotelParams.fromDate)
|
||||||
const departureDate = new Date(selectHotelParams.toDate)
|
const departureDate = new Date(selectHotelParams.toDate)
|
||||||
|
|
||||||
@@ -247,7 +252,10 @@ export default async function SelectHotel({
|
|||||||
isAllUnavailable={isAllUnavailable}
|
isAllUnavailable={isAllUnavailable}
|
||||||
operaId={hotels?.[0]?.hotel.operaId}
|
operaId={hotels?.[0]?.hotel.operaId}
|
||||||
/>
|
/>
|
||||||
<HotelCardListing hotelData={hotels} />
|
<HotelCardListing
|
||||||
|
hotelData={hotels}
|
||||||
|
userPoints={userPoints ? userPoints : undefined}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
<Suspense key={`${suspenseKey}-tracking`} fallback={null}>
|
<Suspense key={`${suspenseKey}-tracking`} fallback={null}>
|
||||||
|
|||||||
@@ -539,6 +539,7 @@
|
|||||||
"Non refundable": "Ikke-refunderbart",
|
"Non refundable": "Ikke-refunderbart",
|
||||||
"Non-refundable": "Ikke-refunderbart",
|
"Non-refundable": "Ikke-refunderbart",
|
||||||
"Nordic Swan Ecolabel": "Svanemærket",
|
"Nordic Swan Ecolabel": "Svanemærket",
|
||||||
|
"Not enough points": "Ikke nok point",
|
||||||
"Not found": "Ikke fundet",
|
"Not found": "Ikke fundet",
|
||||||
"Not included": "Ikke inkluderet",
|
"Not included": "Ikke inkluderet",
|
||||||
"Number of charging points for electric cars: {number}": "Antal ladepunkter til elbiler: {number}",
|
"Number of charging points for electric cars: {number}": "Antal ladepunkter til elbiler: {number}",
|
||||||
|
|||||||
@@ -540,6 +540,7 @@
|
|||||||
"Non refundable": "Nicht erstattungsfähig",
|
"Non refundable": "Nicht erstattungsfähig",
|
||||||
"Non-refundable": "Nicht erstattungsfähig",
|
"Non-refundable": "Nicht erstattungsfähig",
|
||||||
"Nordic Swan Ecolabel": "Nordic Swan Ecolabel",
|
"Nordic Swan Ecolabel": "Nordic Swan Ecolabel",
|
||||||
|
"Not enough points": "Nicht genügend Punkte",
|
||||||
"Not found": "Nicht gefunden",
|
"Not found": "Nicht gefunden",
|
||||||
"Not included": "Nicht inbegriffen",
|
"Not included": "Nicht inbegriffen",
|
||||||
"Number of charging points for electric cars: {number}": "Anzahl der Ladestationen für Elektroautos: {number}",
|
"Number of charging points for electric cars: {number}": "Anzahl der Ladestationen für Elektroautos: {number}",
|
||||||
|
|||||||
@@ -538,6 +538,7 @@
|
|||||||
"Non refundable": "Non refundable",
|
"Non refundable": "Non refundable",
|
||||||
"Non-refundable": "Non-refundable",
|
"Non-refundable": "Non-refundable",
|
||||||
"Nordic Swan Ecolabel": "Nordic Swan Ecolabel",
|
"Nordic Swan Ecolabel": "Nordic Swan Ecolabel",
|
||||||
|
"Not enough points": "Not enough points",
|
||||||
"Not found": "Not found",
|
"Not found": "Not found",
|
||||||
"Not included": "Not included",
|
"Not included": "Not included",
|
||||||
"Number of charging points for electric cars: {number}": "Number of charging points for electric cars: {number}",
|
"Number of charging points for electric cars: {number}": "Number of charging points for electric cars: {number}",
|
||||||
|
|||||||
@@ -539,6 +539,7 @@
|
|||||||
"Non refundable": "Ei palautettavissa",
|
"Non refundable": "Ei palautettavissa",
|
||||||
"Non-refundable": "Ei palautettavissa",
|
"Non-refundable": "Ei palautettavissa",
|
||||||
"Nordic Swan Ecolabel": "Ympäristömerkki Miljömärkt",
|
"Nordic Swan Ecolabel": "Ympäristömerkki Miljömärkt",
|
||||||
|
"Not enough points": "Pisteet eivät riitä",
|
||||||
"Not found": "Ei löydetty",
|
"Not found": "Ei löydetty",
|
||||||
"Not included": "Ei sisälly",
|
"Not included": "Ei sisälly",
|
||||||
"Number of charging points for electric cars: {number}": "Sähköautojen latauspisteiden määrä: {number}",
|
"Number of charging points for electric cars: {number}": "Sähköautojen latauspisteiden määrä: {number}",
|
||||||
|
|||||||
@@ -538,6 +538,7 @@
|
|||||||
"Non refundable": "Ikke-refunderbart",
|
"Non refundable": "Ikke-refunderbart",
|
||||||
"Non-refundable": "Ikke-refunderbart",
|
"Non-refundable": "Ikke-refunderbart",
|
||||||
"Nordic Swan Ecolabel": "Svanemerket",
|
"Nordic Swan Ecolabel": "Svanemerket",
|
||||||
|
"Not enough points": "Ikke nok poeng",
|
||||||
"Not found": "Ikke funnet",
|
"Not found": "Ikke funnet",
|
||||||
"Not included": "Ikke inkludert",
|
"Not included": "Ikke inkludert",
|
||||||
"Number of charging points for electric cars: {number}": "Antall ladepunkter for elbiler: {number}",
|
"Number of charging points for electric cars: {number}": "Antall ladepunkter for elbiler: {number}",
|
||||||
|
|||||||
@@ -538,6 +538,7 @@
|
|||||||
"Non refundable": "Ej återbetalningsbar",
|
"Non refundable": "Ej återbetalningsbar",
|
||||||
"Non-refundable": "Ej återbetalningsbar",
|
"Non-refundable": "Ej återbetalningsbar",
|
||||||
"Nordic Swan Ecolabel": "Svanenmärkt",
|
"Nordic Swan Ecolabel": "Svanenmärkt",
|
||||||
|
"Not enough points": "Inte tillräckligt antal poäng",
|
||||||
"Not found": "Hittades inte",
|
"Not found": "Hittades inte",
|
||||||
"Not included": "Ej inkluderat",
|
"Not included": "Ej inkluderat",
|
||||||
"Number of charging points for electric cars: {number}": "Antal laddplatser för elbilar: {number}",
|
"Number of charging points for electric cars: {number}": "Antal laddplatser för elbilar: {number}",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export type HotelData = {
|
|||||||
export type HotelCardListingProps = {
|
export type HotelCardListingProps = {
|
||||||
hotelData: HotelResponse[]
|
hotelData: HotelResponse[]
|
||||||
type?: HotelCardListingTypeEnum
|
type?: HotelCardListingTypeEnum
|
||||||
|
userPoints?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NullableHotelData extends Omit<HotelData, "hotelData"> {
|
export interface NullableHotelData extends Omit<HotelData, "hotelData"> {
|
||||||
|
|||||||
@@ -7,4 +7,5 @@ export type HotelCardProps = {
|
|||||||
type?: HotelCardListingTypeEnum
|
type?: HotelCardListingTypeEnum
|
||||||
state?: "default" | "active"
|
state?: "default" | "active"
|
||||||
bookingCode?: string | null
|
bookingCode?: string | null
|
||||||
|
userPoints?: number
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user