feat(SW-340): Added HotelCardDialog component
This commit is contained in:
@@ -95,14 +95,15 @@ export function getHotelPins(hotels: HotelData[]): HotelPin[] {
|
|||||||
lng: hotel.hotelData.location.longitude,
|
lng: hotel.hotelData.location.longitude,
|
||||||
},
|
},
|
||||||
name: hotel.hotelData.name,
|
name: hotel.hotelData.name,
|
||||||
price: hotel.price
|
publicPrice: hotel.price?.regularAmount ?? null,
|
||||||
? `${Math.min(
|
memberPrice: hotel.price?.memberAmount ?? null,
|
||||||
parseFloat(hotel.price.memberAmount ?? "Infinity"),
|
currency: hotel.price?.currency || null,
|
||||||
parseFloat(hotel.price.regularAmount ?? "Infinity")
|
images: [
|
||||||
)}`
|
hotel.hotelData.hotelContent.images,
|
||||||
: "N/A",
|
...(hotel.hotelData.gallery?.heroImages ?? []),
|
||||||
currency: hotel.price?.currency || "Unknown",
|
],
|
||||||
image: "default-image-url",
|
amenities: hotel.hotelData.detailedFacilities.slice(0, 3),
|
||||||
|
ratings: hotel.hotelData.ratings?.tripAdvisor.rating ?? null,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1367px) {
|
@media screen and (min-width: 1367px) {
|
||||||
.card.listing {
|
.card.pageListing {
|
||||||
grid-template-areas:
|
grid-template-areas:
|
||||||
"image header"
|
"image header"
|
||||||
"image hotel"
|
"image hotel"
|
||||||
@@ -76,30 +76,30 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing .imageContainer {
|
.pageListing .imageContainer {
|
||||||
position: relative;
|
position: relative;
|
||||||
min-height: 200px;
|
min-height: 200px;
|
||||||
width: 518px;
|
width: 518px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing .tripAdvisor {
|
.pageListing .tripAdvisor {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
display: block;
|
display: block;
|
||||||
left: 7px;
|
left: 7px;
|
||||||
top: 7px;
|
top: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing .hotelInformation {
|
.pageListing .hotelInformation {
|
||||||
padding-top: var(--Spacing-x2);
|
padding-top: var(--Spacing-x2);
|
||||||
padding-right: var(--Spacing-x2);
|
padding-right: var(--Spacing-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing .hotel {
|
.pageListing .hotel {
|
||||||
gap: var(--Spacing-x2);
|
gap: var(--Spacing-x2);
|
||||||
padding-right: var(--Spacing-x2);
|
padding-right: var(--Spacing-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing .prices {
|
.pageListing .prices {
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@@ -107,11 +107,11 @@
|
|||||||
padding-bottom: var(--Spacing-x2);
|
padding-bottom: var(--Spacing-x2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing .detailsButton {
|
.pageListing .detailsButton {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.listing .button {
|
.pageListing .button {
|
||||||
width: 160px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,13 @@ import { hotelCardVariants } from "./variants"
|
|||||||
|
|
||||||
import styles from "./hotelCard.module.css"
|
import styles from "./hotelCard.module.css"
|
||||||
|
|
||||||
|
import { HotelCardListingType } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
||||||
import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
|
import type { HotelCardProps } from "@/types/components/hotelReservation/selectHotel/hotelCardProps"
|
||||||
|
|
||||||
export default function HotelCard({ hotel, type = "listing" }: HotelCardProps) {
|
export default function HotelCard({
|
||||||
|
hotel,
|
||||||
|
type = HotelCardListingType.PageListing,
|
||||||
|
}: HotelCardProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
const { hotelData } = hotel
|
const { hotelData } = hotel
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import styles from "./hotelCard.module.css"
|
|||||||
export const hotelCardVariants = cva(styles.card, {
|
export const hotelCardVariants = cva(styles.card, {
|
||||||
variants: {
|
variants: {
|
||||||
type: {
|
type: {
|
||||||
listing: styles.listing,
|
pageListing: styles.pageListing,
|
||||||
map: styles.map,
|
mapListing: styles.mapListing,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
type: "listing",
|
type: "pageListing",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
.dialog {
|
||||||
|
padding-bottom: var(--Spacing-x1);
|
||||||
|
bottom: 32px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dialogContainer {
|
||||||
|
border: 1px solid var(--Base-Border-Subtle);
|
||||||
|
border-radius: var(--Corner-radius-Medium);
|
||||||
|
width: 402px;
|
||||||
|
min-height: 227px;
|
||||||
|
background: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
flex-direction: row;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageContainer {
|
||||||
|
position: relative;
|
||||||
|
min-height: 227px;
|
||||||
|
width: 177px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tripAdvisor {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.imageContainer img {
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
width: 100%;
|
||||||
|
padding: var(--Spacing-x-one-and-half);
|
||||||
|
gap: var(--Spacing-x1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.facilities {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--Spacing-x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.facilitiesItem {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--Spacing-x-half);
|
||||||
|
}
|
||||||
|
|
||||||
|
.prices {
|
||||||
|
border-radius: var(--Corner-radius-Medium);
|
||||||
|
padding: var(--Spacing-x-half) var(--Spacing-x1);
|
||||||
|
background: var(--Base-Surface-Secondary-light-Normal);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--Spacing-x-half);
|
||||||
|
}
|
||||||
|
|
||||||
|
.perNight {
|
||||||
|
color: var(--Base-Text-Subtle-light-Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
90
components/HotelReservation/HotelCardDialog/index.tsx
Normal file
90
components/HotelReservation/HotelCardDialog/index.tsx
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { mapFacilityToIcon } from "@/components/ContentType/HotelPage/data"
|
||||||
|
import TripAdvisorIcon from "@/components/Icons/TripAdvisor"
|
||||||
|
import Image from "@/components/Image"
|
||||||
|
import Button from "@/components/TempDesignSystem/Button"
|
||||||
|
import Chip from "@/components/TempDesignSystem/Chip"
|
||||||
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
|
|
||||||
|
import styles from "./hotelCardDialog.module.css"
|
||||||
|
|
||||||
|
import { HotelPin } from "@/types/components/hotelReservation/selectHotel/map"
|
||||||
|
|
||||||
|
export default function HotelCardDialog({
|
||||||
|
pin,
|
||||||
|
isOpen,
|
||||||
|
}: {
|
||||||
|
isOpen: boolean
|
||||||
|
pin: HotelPin
|
||||||
|
}) {
|
||||||
|
const intl = useIntl()
|
||||||
|
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
publicPrice,
|
||||||
|
memberPrice,
|
||||||
|
currency,
|
||||||
|
amenities,
|
||||||
|
images,
|
||||||
|
ratings,
|
||||||
|
} = pin
|
||||||
|
|
||||||
|
return (
|
||||||
|
<dialog open={isOpen} className={styles.dialog}>
|
||||||
|
<div className={styles.dialogContainer}>
|
||||||
|
<div className={styles.imageContainer}>
|
||||||
|
<Image
|
||||||
|
src={images[0].imageSizes.small}
|
||||||
|
alt={images[0].metaData.altText}
|
||||||
|
fill
|
||||||
|
/>
|
||||||
|
<div className={styles.tripAdvisor}>
|
||||||
|
<Chip intent="primary" className={styles.tripAdvisor}>
|
||||||
|
<TripAdvisorIcon color="white" />
|
||||||
|
{ratings}
|
||||||
|
</Chip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<Body textTransform="bold">{name}</Body>
|
||||||
|
<div className={styles.facilities}>
|
||||||
|
{amenities.map((facility) => {
|
||||||
|
const IconComponent = mapFacilityToIcon(facility.id)
|
||||||
|
return (
|
||||||
|
<div className={styles.facilitiesItem} key={facility.id}>
|
||||||
|
{IconComponent && <IconComponent color="grey80" />}
|
||||||
|
<Caption color="textMediumContrast">{facility.name}</Caption>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div className={styles.prices}>
|
||||||
|
<Caption type="bold">{intl.formatMessage({ id: "From" })}</Caption>
|
||||||
|
<Subtitle type="two">
|
||||||
|
{publicPrice} {currency}
|
||||||
|
<Body asChild>
|
||||||
|
<span>/{intl.formatMessage({ id: "night" })}</span>
|
||||||
|
</Body>
|
||||||
|
</Subtitle>
|
||||||
|
{memberPrice && (
|
||||||
|
<Subtitle type="two" color="red">
|
||||||
|
{memberPrice} {currency}
|
||||||
|
<Body asChild color="red">
|
||||||
|
<span>/{intl.formatMessage({ id: "night" })}</span>
|
||||||
|
</Body>
|
||||||
|
</Subtitle>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Button size="small" theme="base" className={styles.button}>
|
||||||
|
{intl.formatMessage({ id: "See rooms" })}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -8,11 +8,14 @@ import HotelCard from "../HotelCard"
|
|||||||
|
|
||||||
import styles from "./hotelCardListing.module.css"
|
import styles from "./hotelCardListing.module.css"
|
||||||
|
|
||||||
import { HotelCardListingProps } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
import {
|
||||||
|
HotelCardListingProps,
|
||||||
|
HotelCardListingType,
|
||||||
|
} from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
||||||
|
|
||||||
export default function HotelCardListing({
|
export default function HotelCardListing({
|
||||||
hotelData,
|
hotelData,
|
||||||
type = "listing",
|
type = HotelCardListingType.PageListing,
|
||||||
}: HotelCardListingProps) {
|
}: HotelCardListingProps) {
|
||||||
const searchParams = useSearchParams()
|
const searchParams = useSearchParams()
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ import HotelCardListing from "@/components/HotelReservation/HotelCardListing"
|
|||||||
|
|
||||||
import styles from "./hotelListing.module.css"
|
import styles from "./hotelListing.module.css"
|
||||||
|
|
||||||
|
import { HotelCardListingType } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
||||||
import type { HotelListingProps } from "@/types/components/hotelReservation/selectHotel/map"
|
import type { HotelListingProps } from "@/types/components/hotelReservation/selectHotel/map"
|
||||||
|
|
||||||
export default function HotelListing({ hotels }: HotelListingProps) {
|
export default function HotelListing({ hotels }: HotelListingProps) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.hotelListing}>
|
<div className={styles.hotelListing}>
|
||||||
<HotelCardListing hotelData={hotels} type="map" />
|
<HotelCardListing
|
||||||
|
hotelData={hotels}
|
||||||
|
type={HotelCardListingType.MapListing}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ export default function SelectHotelMap({
|
|||||||
closeButton={closeButton}
|
closeButton={closeButton}
|
||||||
coordinates={coordinates}
|
coordinates={coordinates}
|
||||||
hotelPins={hotelPins}
|
hotelPins={hotelPins}
|
||||||
|
hotels={hotels}
|
||||||
activeHotelPin={activeHotelPin}
|
activeHotelPin={activeHotelPin}
|
||||||
onActiveHotelPinChange={setActiveHotelPin}
|
onActiveHotelPinChange={setActiveHotelPin}
|
||||||
mapId={mapId}
|
mapId={mapId}
|
||||||
|
|||||||
@@ -4,10 +4,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.advancedMarker.active {
|
.advancedMarker.active {
|
||||||
height: var(--Spacing-x5);
|
height: 32px;
|
||||||
width: var(
|
min-width: 109px !important; /* Overwriting the default width of the @vis.gl/react-google-maps AdvancedMarker */
|
||||||
--Spacing-x5
|
|
||||||
) !important; /* Overwriting the default width of the @vis.gl/react-google-maps AdvancedMarker */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pin {
|
.pin {
|
||||||
@@ -23,10 +21,11 @@
|
|||||||
background-color: var(--Base-Surface-Primary-light-Normal);
|
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||||
box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 0 4px 2px rgba(0, 0, 0, 0.1);
|
||||||
gap: var(--Spacing-x1);
|
gap: var(--Spacing-x1);
|
||||||
|
width: max-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pin.active {
|
.pin.active {
|
||||||
padding-right: var(--Spacing-x-one-and-half);
|
background-color: var(--Primary-Dark-Surface-Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
.pinLabel {
|
.pinLabel {
|
||||||
@@ -49,3 +48,22 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
background: var(--Primary-Dark-Surface-Normal);
|
background: var(--Primary-Dark-Surface-Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pin.active .pinIcon {
|
||||||
|
background: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 32px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 402px;
|
||||||
|
height: 181px;
|
||||||
|
background-color: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.card.active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,21 +3,31 @@ import {
|
|||||||
AdvancedMarkerAnchorPoint,
|
AdvancedMarkerAnchorPoint,
|
||||||
} from "@vis.gl/react-google-maps"
|
} from "@vis.gl/react-google-maps"
|
||||||
|
|
||||||
|
import HotelCardDialog from "@/components/HotelReservation/HotelCardDialog"
|
||||||
import Body from "@/components/TempDesignSystem/Text/Body"
|
import Body from "@/components/TempDesignSystem/Text/Body"
|
||||||
|
|
||||||
import HotelMarker from "../../Markers/Hotel"
|
import HotelMarker from "../../Markers/HotelMarker"
|
||||||
|
|
||||||
import styles from "./hotelListingMapContent.module.css"
|
import styles from "./hotelListingMapContent.module.css"
|
||||||
|
|
||||||
|
import { HotelData } from "@/types/components/hotelReservation/selectHotel/hotelCardListingProps"
|
||||||
import { HotelPin } from "@/types/components/hotelReservation/selectHotel/map"
|
import { HotelPin } from "@/types/components/hotelReservation/selectHotel/map"
|
||||||
|
|
||||||
export default function HotelListingMapContent({
|
export default function HotelListingMapContent({
|
||||||
activeHotelPin,
|
activeHotelPin,
|
||||||
hotelPins,
|
hotelPins,
|
||||||
|
hotels,
|
||||||
|
onActiveHotelPinChange,
|
||||||
}: {
|
}: {
|
||||||
activeHotelPin?: HotelPin["name"] | null
|
activeHotelPin?: HotelPin["name"] | null
|
||||||
hotelPins: HotelPin[]
|
hotelPins: HotelPin[]
|
||||||
|
hotels?: HotelData[]
|
||||||
|
onActiveHotelPinChange?: (pinName: string | null) => void
|
||||||
}) {
|
}) {
|
||||||
|
function toggleActiveHotelPin(pinName: string) {
|
||||||
|
onActiveHotelPinChange?.(activeHotelPin === pinName ? null : pinName)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{hotelPins.map((pin) => (
|
{hotelPins.map((pin) => (
|
||||||
@@ -27,16 +37,27 @@ export default function HotelListingMapContent({
|
|||||||
position={pin.coordinates}
|
position={pin.coordinates}
|
||||||
anchorPoint={AdvancedMarkerAnchorPoint.CENTER}
|
anchorPoint={AdvancedMarkerAnchorPoint.CENTER}
|
||||||
zIndex={activeHotelPin === pin.name ? 2 : 0}
|
zIndex={activeHotelPin === pin.name ? 2 : 0}
|
||||||
|
onMouseEnter={() => onActiveHotelPinChange?.(pin.name)}
|
||||||
|
onMouseLeave={() => onActiveHotelPinChange?.(null)}
|
||||||
|
onClick={() => toggleActiveHotelPin(pin.name)}
|
||||||
>
|
>
|
||||||
|
<HotelCardDialog isOpen={activeHotelPin === pin.name} pin={pin} />
|
||||||
|
|
||||||
<span
|
<span
|
||||||
className={`${styles.pin} ${activeHotelPin === pin.name ? styles.active : ""}`}
|
className={`${styles.pin} ${activeHotelPin === pin.name ? styles.active : ""}`}
|
||||||
>
|
>
|
||||||
<span className={styles.pinIcon}>
|
<span className={styles.pinIcon}>
|
||||||
<HotelMarker width={16} />
|
<HotelMarker
|
||||||
|
width={16}
|
||||||
|
color={activeHotelPin === pin.name ? "burgundy" : "white"}
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
<Body asChild>
|
<Body
|
||||||
|
asChild
|
||||||
|
color={activeHotelPin === pin.name ? "white" : "textHighContrast"}
|
||||||
|
>
|
||||||
<span>
|
<span>
|
||||||
{pin.price} {pin.currency}
|
{pin.memberPrice} {pin.currency}
|
||||||
</span>
|
</span>
|
||||||
</Body>
|
</Body>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export default function InteractiveMap({
|
|||||||
activePoi,
|
activePoi,
|
||||||
hotelPins,
|
hotelPins,
|
||||||
activeHotelPin,
|
activeHotelPin,
|
||||||
|
hotels,
|
||||||
mapId,
|
mapId,
|
||||||
closeButton,
|
closeButton,
|
||||||
onActivePoiChange,
|
onActivePoiChange,
|
||||||
@@ -54,6 +55,8 @@ export default function InteractiveMap({
|
|||||||
<HotelListingMapContent
|
<HotelListingMapContent
|
||||||
activeHotelPin={activeHotelPin}
|
activeHotelPin={activeHotelPin}
|
||||||
hotelPins={hotelPins}
|
hotelPins={hotelPins}
|
||||||
|
onActiveHotelPinChange={onActiveHotelPinChange}
|
||||||
|
hotels={hotels}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{pointsOfInterest && (
|
{pointsOfInterest && (
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
.white * {
|
||||||
|
fill: var(--Base-Surface-Primary-light-Normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
.burgundy * {
|
||||||
|
fill: var(--Scandic-Brand-Burgundy);
|
||||||
|
}
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
|
import { hotelMarkerVariants } from "./variants"
|
||||||
|
|
||||||
export default function HotelMarker({
|
export default function HotelMarker({
|
||||||
className,
|
className,
|
||||||
|
color,
|
||||||
...props
|
...props
|
||||||
}: React.SVGAttributes<HTMLOrSVGElement>) {
|
}: React.SVGAttributes<HTMLOrSVGElement> & {
|
||||||
|
color?: "burgundy" | "white"
|
||||||
|
}) {
|
||||||
|
const classNames = hotelMarkerVariants({ color, className })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
className={className}
|
className={classNames}
|
||||||
width="16"
|
width="16"
|
||||||
height="11"
|
height="11"
|
||||||
viewBox="0 0 16 11"
|
viewBox="0 0 16 11"
|
||||||
15
components/Maps/Markers/HotelMarker/variants.ts
Normal file
15
components/Maps/Markers/HotelMarker/variants.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { cva } from "class-variance-authority"
|
||||||
|
|
||||||
|
import styles from "./hotelMarker.module.css"
|
||||||
|
|
||||||
|
export const hotelMarkerVariants = cva(styles.icon, {
|
||||||
|
variants: {
|
||||||
|
color: {
|
||||||
|
burgundy: styles.burgundy,
|
||||||
|
white: styles.white,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
color: "white",
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ReactElement } from "react"
|
import { ReactElement } from "react"
|
||||||
|
|
||||||
|
import { HotelData } from "../../hotelReservation/selectHotel/hotelCardListingProps"
|
||||||
import { HotelPin } from "../../hotelReservation/selectHotel/map"
|
import { HotelPin } from "../../hotelReservation/selectHotel/map"
|
||||||
|
|
||||||
import type { Coordinates } from "@/types/components/maps/coordinates"
|
import type { Coordinates } from "@/types/components/maps/coordinates"
|
||||||
@@ -11,8 +12,9 @@ export interface InteractiveMapProps {
|
|||||||
activePoi?: PointOfInterest["name"] | null
|
activePoi?: PointOfInterest["name"] | null
|
||||||
hotelPins?: HotelPin[]
|
hotelPins?: HotelPin[]
|
||||||
activeHotelPin?: HotelPin["name"] | null
|
activeHotelPin?: HotelPin["name"] | null
|
||||||
|
hotels?: HotelData[]
|
||||||
mapId: string
|
mapId: string
|
||||||
closeButton: ReactElement
|
closeButton: ReactElement
|
||||||
onActivePoiChange?: (poi: PointOfInterest["name"] | null) => void
|
onActivePoiChange?: (poi: PointOfInterest["name"] | null) => void
|
||||||
onActiveHotelPinChange?: (hotelPin: PointOfInterest["name"] | null) => void
|
onActiveHotelPinChange?: (hotelPin: HotelPin["name"] | null) => void
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,14 @@ import { HotelsAvailabilityPrices } from "@/server/routers/hotels/output"
|
|||||||
|
|
||||||
import { Hotel } from "@/types/hotel"
|
import { Hotel } from "@/types/hotel"
|
||||||
|
|
||||||
|
export enum HotelCardListingType {
|
||||||
|
MapListing = "mapListing",
|
||||||
|
PageListing = "pageListing",
|
||||||
|
}
|
||||||
|
|
||||||
export type HotelCardListingProps = {
|
export type HotelCardListingProps = {
|
||||||
hotelData: HotelData[]
|
hotelData: HotelData[]
|
||||||
type?: "map" | "listing"
|
type?: HotelCardListingType
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HotelData = {
|
export type HotelData = {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { HotelData } from "./hotelCardListingProps"
|
import { HotelCardListingType, HotelData } from "./hotelCardListingProps"
|
||||||
|
|
||||||
export type HotelCardProps = {
|
export type HotelCardProps = {
|
||||||
hotel: HotelData
|
hotel: HotelData
|
||||||
type?: "map" | "listing"
|
type?: HotelCardListingType
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
import {
|
||||||
|
imageMetaDataSchema,
|
||||||
|
imageSizesSchema,
|
||||||
|
} from "@/server/routers/hotels/schemas/image"
|
||||||
|
|
||||||
import { HotelData } from "./hotelCardListingProps"
|
import { HotelData } from "./hotelCardListingProps"
|
||||||
|
import { Filter } from "./hotelFilters"
|
||||||
|
|
||||||
import type { Coordinates } from "@/types/components/maps/coordinates"
|
import type { Coordinates } from "@/types/components/maps/coordinates"
|
||||||
|
|
||||||
@@ -18,10 +26,19 @@ export interface SelectHotelMapProps {
|
|||||||
hotels: HotelData[]
|
hotels: HotelData[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ImageSizes = z.infer<typeof imageSizesSchema>
|
||||||
|
type ImageMetaData = z.infer<typeof imageMetaDataSchema>
|
||||||
|
|
||||||
export type HotelPin = {
|
export type HotelPin = {
|
||||||
name: string
|
name: string
|
||||||
coordinates: Coordinates
|
coordinates: Coordinates
|
||||||
price: string
|
publicPrice: string | null
|
||||||
currency: string
|
memberPrice: string | null
|
||||||
image: string
|
currency: string | null
|
||||||
|
images: {
|
||||||
|
imageSizes: ImageSizes
|
||||||
|
metaData: ImageMetaData
|
||||||
|
}[]
|
||||||
|
amenities: Filter[]
|
||||||
|
ratings: number | null
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user