From ba3ecedaee29d4f98ce2d4d08aedf19d3beafd48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20Landstr=C3=B6m?= Date: Tue, 18 Feb 2025 19:05:31 +0000 Subject: [PATCH] Merged in feat/SW-1447-selected-hotel-map-component (pull request #1340) Feat(SW-1447): hotel map card destination page Approved-by: Erik Tiekstra --- .../DestinationCityPage/CityMap/index.tsx | 1 + .../CountryMap/index.tsx | 1 + .../OverviewMapContainer/index.tsx | 2 +- .../DialogImage/dialogImage.module.css | 33 ++++++ .../HotelMapCard/DialogImage/index.tsx | 41 +++++++ .../HotelMapCard/hotelMapCard.module.css | 90 ++++++++++++++ .../DestinationPage/HotelMapCard/index.tsx | 110 ++++++++++++++++++ .../ClusterMarker/clusterMarker.module.css | 8 ++ .../Map/MapContent/Marker/index.tsx | 46 ++++++-- .../DestinationPage/Map/MapContent/index.tsx | 26 ++++- .../DestinationPage/Map/MapProvider.tsx | 10 +- .../DestinationPage/Map/PageTypeProvider.tsx | 29 +++++ .../ContentType/DestinationPage/Map/index.tsx | 4 +- .../ContentType/DestinationPage/Map/utils.ts | 15 ++- i18n/dictionaries/da.json | 1 + i18n/dictionaries/de.json | 1 + i18n/dictionaries/en.json | 1 + i18n/dictionaries/fi.json | 1 + i18n/dictionaries/no.json | 1 + i18n/dictionaries/sv.json | 1 + types/components/maps/destinationMarkers.ts | 7 ++ 21 files changed, 411 insertions(+), 18 deletions(-) create mode 100644 components/ContentType/DestinationPage/HotelMapCard/DialogImage/dialogImage.module.css create mode 100644 components/ContentType/DestinationPage/HotelMapCard/DialogImage/index.tsx create mode 100644 components/ContentType/DestinationPage/HotelMapCard/hotelMapCard.module.css create mode 100644 components/ContentType/DestinationPage/HotelMapCard/index.tsx create mode 100644 components/ContentType/DestinationPage/Map/PageTypeProvider.tsx diff --git a/components/ContentType/DestinationPage/DestinationCityPage/CityMap/index.tsx b/components/ContentType/DestinationPage/DestinationCityPage/CityMap/index.tsx index a1cbb6916..f39853815 100644 --- a/components/ContentType/DestinationPage/DestinationCityPage/CityMap/index.tsx +++ b/components/ContentType/DestinationPage/DestinationCityPage/CityMap/index.tsx @@ -25,6 +25,7 @@ export default async function CityMap({ city, cityIdentifier }: CityMapProps) { hotels={hotels} mapId={env.GOOGLE_DYNAMIC_MAP_ID} apiKey={env.GOOGLE_STATIC_MAP_KEY} + pageType="city" > {intl.formatMessage({ id: `Hotels in {city}` }, { city: city.name })} diff --git a/components/ContentType/DestinationPage/DestinationCountryPage/CountryMap/index.tsx b/components/ContentType/DestinationPage/DestinationCountryPage/CountryMap/index.tsx index e897b305a..85332530c 100644 --- a/components/ContentType/DestinationPage/DestinationCountryPage/CountryMap/index.tsx +++ b/components/ContentType/DestinationPage/DestinationCountryPage/CountryMap/index.tsx @@ -32,6 +32,7 @@ export default async function CountryMap({ country }: CountryMapProps) { hotels={hotels} mapId={env.GOOGLE_DYNAMIC_MAP_ID} apiKey={env.GOOGLE_STATIC_MAP_KEY} + pageType="country" > <Title level="h2" as="h3" textTransform="regular"> {intl.formatMessage({ id: `Destinations in {country}` }, { country })} diff --git a/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx b/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx index 6fddb64d3..75a5d2da5 100644 --- a/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx +++ b/components/ContentType/DestinationPage/DestinationOverviewPage/OverviewMapContainer/index.tsx @@ -21,7 +21,7 @@ export default async function OverviewMapContainer() { const geoJson = mapMarkerDataToGeoJson(markers) return ( - <MapProvider apiKey={googleMapsApiKey}> + <MapProvider apiKey={googleMapsApiKey} pageType="overview"> <InputForm /> <DynamicMap mapId={googleMapId} markers={markers}> <MapContent geojson={geoJson} /> diff --git a/components/ContentType/DestinationPage/HotelMapCard/DialogImage/dialogImage.module.css b/components/ContentType/DestinationPage/HotelMapCard/DialogImage/dialogImage.module.css new file mode 100644 index 000000000..37495a049 --- /dev/null +++ b/components/ContentType/DestinationPage/HotelMapCard/DialogImage/dialogImage.module.css @@ -0,0 +1,33 @@ +.imagePlaceholder { + height: 100%; + width: 100%; + background-color: #fff; + background-image: linear-gradient(45deg, #000000 25%, transparent 25%), + linear-gradient(-45deg, #000000 25%, transparent 25%), + linear-gradient(45deg, transparent 75%, #000000 75%), + linear-gradient(-45deg, transparent 75%, #000000 75%); + background-size: 120px 120px; + background-position: + 0 0, + 0 60px, + 60px -60px, + -60px 0; +} + +.imageContainer { + position: relative; + min-width: 177px; + border-radius: var(--Corner-radius-Medium) 0 0 var(--Corner-radius-Medium); + overflow: hidden; +} + +.imageContainer img { + object-fit: cover; +} + +.imageContainer .tripAdvisor { + position: absolute; + left: 7px; + top: 7px; + border-radius: var(--Corner-radius-Small); +} diff --git a/components/ContentType/DestinationPage/HotelMapCard/DialogImage/index.tsx b/components/ContentType/DestinationPage/HotelMapCard/DialogImage/index.tsx new file mode 100644 index 000000000..6f610e30f --- /dev/null +++ b/components/ContentType/DestinationPage/HotelMapCard/DialogImage/index.tsx @@ -0,0 +1,41 @@ +import { TripAdvisorIcon } from "@/components/Icons" +import Image from "@/components/Image" +import Chip from "@/components/TempDesignSystem/Chip" + +import styles from "./dialogImage.module.css" + +interface DialogImageProps { + image: string | undefined + altText: string | undefined + ratings: number + imageError: boolean + setImageError: (error: boolean) => void +} +export default function DialogImage({ + image, + altText, + ratings, + imageError, + setImageError, +}: DialogImageProps) { + return ( + <div className={styles.imageContainer}> + {!image || imageError ? ( + <div className={styles.imagePlaceholder} /> + ) : ( + <Image + src={image} + alt={altText || ""} + fill + onError={() => setImageError(true)} + /> + )} + <div className={styles.tripAdvisor}> + <Chip className={styles.tripAdvisor}> + <TripAdvisorIcon color="burgundy" /> + {ratings} + </Chip> + </div> + </div> + ) +} diff --git a/components/ContentType/DestinationPage/HotelMapCard/hotelMapCard.module.css b/components/ContentType/DestinationPage/HotelMapCard/hotelMapCard.module.css new file mode 100644 index 000000000..b64d2e97a --- /dev/null +++ b/components/ContentType/DestinationPage/HotelMapCard/hotelMapCard.module.css @@ -0,0 +1,90 @@ +.dialog { + bottom: 0; + left: 50%; + transform: translateX(-50%); + border: none; + background: transparent; +} + +.dialogContent { + border: 1px solid var(--Base-Border-Subtle); + border-radius: var(--Corner-radius-Medium); + min-width: 402px; + background: var(--Base-Surface-Primary-light-Normal); + box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.1); + flex-direction: row; + display: flex; + position: relative; +} + +.dialogContent::after { + content: ""; + display: block; + position: absolute; + bottom: 0; + left: 50%; + width: 0; + height: 0; + border: 20px solid transparent; + border-top-color: var(--Base-Surface-Primary-light-Normal); + border-bottom: 0; + margin-left: -10px; + margin-bottom: -10px; +} + +.name { + height: 48px; + max-width: 180px; + margin-bottom: var(--Spacing-x-half); + display: flex; + align-items: center; +} + +.closeButton { + position: absolute; + top: 8px; + right: 8px; + z-index: 1; +} + +.closeButton:hover .closeIcon { + background-color: var(--Base-Surface-Subtle-Normal); + color: var(--Primary-Dark-Surface-Hover); + border-radius: 50%; +} + +.content { + width: 100%; + min-width: 220px; + padding: var(--Spacing-x-one-and-half); + display: flex; + flex-direction: column; +} + +.hiddenFacilities, +.iconFootnote { + display: none; +} + +.facilitiesItem { + display: flex; + align-items: center; + gap: var(--Spacing-x-half); +} + +.content .button { + margin-top: auto; +} + +.facilities { + display: flex; + flex-wrap: wrap; + gap: 0 var(--Spacing-x1); + padding-bottom: var(--Spacing-x1); +} + +@media (min-width: 768px) { + .iconFootnote { + display: block; + } +} diff --git a/components/ContentType/DestinationPage/HotelMapCard/index.tsx b/components/ContentType/DestinationPage/HotelMapCard/index.tsx new file mode 100644 index 000000000..f59628bda --- /dev/null +++ b/components/ContentType/DestinationPage/HotelMapCard/index.tsx @@ -0,0 +1,110 @@ +"use client" +import Link from "next/link" +import { useState } from "react" +import { useIntl } from "react-intl" + +import CloseLargeIcon from "@/components/Icons/CloseLarge" +import Button from "@/components/TempDesignSystem/Button" +import Body from "@/components/TempDesignSystem/Text/Body" +import Footnote from "@/components/TempDesignSystem/Text/Footnote" + +import { mapFacilityToIcon } from "../../HotelPage/data" +import { usePageType } from "../Map/PageTypeProvider" +import DialogImage from "./DialogImage" + +import styles from "./hotelMapCard.module.css" + +import type { GalleryImage } from "@/types/components/imageGallery" +import type { Amenities } from "@/types/hotel" + +interface HotelMapCardProps { + isActive: boolean + amenities: Amenities + tripadvisorRating: number | undefined + hotelName: string + image: GalleryImage | null + url: string + onClose: () => void +} + +export default function HotelMapCard({ + isActive, + amenities, + tripadvisorRating, + hotelName, + image, + url, + onClose, +}: HotelMapCardProps) { + const intl = useIntl() + const pageType = usePageType() + const [imageError, setImageError] = useState(false) + + return ( + <dialog open={isActive} className={styles.dialog}> + <div className={styles.dialogContent}> + <Button + intent="text" + size="medium" + variant="icon" + className={styles.closeButton} + onClick={onClose} + aria-label={intl.formatMessage({ id: "Close" })} + > + <CloseLargeIcon className={styles.closeIcon} width={16} height={16} /> + </Button> + {image ? ( + <DialogImage + image={image.src} + altText={image.alt} + ratings={tripadvisorRating || 0} + imageError={imageError} + setImageError={setImageError} + /> + ) : ( + <div className={styles.imagePlaceholder} /> + )} + + <div className={styles.content}> + <div className={styles.name}> + <Body asChild textTransform="bold"> + <h4>{hotelName}</h4> + </Body> + </div> + <div + className={ + pageType === "country" + ? styles.hiddenFacilities + : styles.facilities + } + > + {amenities.map((facility) => { + const IconComponent = mapFacilityToIcon(facility.id) + return ( + <div className={styles.facilitiesItem} key={facility.id}> + {IconComponent && ( + <IconComponent width={16} height={16} color="grey80" /> + )} + <Footnote + className={styles.iconFootnote} + color="uiTextMediumContrast" + > + {facility.name} + </Footnote> + </div> + ) + })} + </div> + + {url && ( + <Button intent="tertiary" theme="base" asChild size="small"> + <Link href={url}> + {intl.formatMessage({ id: "See hotel information" })} + </Link> + </Button> + )} + </div> + </div> + </dialog> + ) +} diff --git a/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/clusterMarker.module.css b/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/clusterMarker.module.css index 7271a5a8d..f0fb73506 100644 --- a/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/clusterMarker.module.css +++ b/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/clusterMarker.module.css @@ -13,6 +13,14 @@ transition: all 0.3s; } +.clusterMarker:hover { + background: linear-gradient( + rgba(255, 255, 255, 0.2), + rgba(255, 255, 255, 0.2) + ), + var(--Base-Text-High-contrast); +} + .count { font-family: var(--typography-Body-Regular-fontFamily); font-size: var(--typography-Subtitle-2-fontSize); diff --git a/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx b/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx index 5f6d44a25..ee24710e7 100644 --- a/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx +++ b/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx @@ -5,41 +5,69 @@ import { AdvancedMarkerAnchorPoint, useAdvancedMarkerRef, } from "@vis.gl/react-google-maps" -import { useCallback } from "react" +import { useCallback, useState } from "react" import HotelMarkerByType from "@/components/Maps/Markers" +import HotelMapCard from "../../../HotelMapCard" + import type { MarkerProperties } from "@/types/components/maps/destinationMarkers" interface MarkerProps { position: google.maps.LatLngLiteral properties: MarkerProperties - onMarkerClick?: ( - position: google.maps.LatLngLiteral, - properties: MarkerProperties - ) => void + isActive: boolean + onMarkerClick?: (properties: MarkerProperties) => void + onCloseMapCard?: () => void } export default function Marker({ position, properties, + isActive, onMarkerClick, + onCloseMapCard, }: MarkerProps) { const [markerRef] = useAdvancedMarkerRef() + const [isHovered, setIsHovered] = useState(false) + const handleClick = useCallback(() => { if (onMarkerClick) { - onMarkerClick(position, properties) + onMarkerClick(properties) } - }, [onMarkerClick, position, properties]) + }, [onMarkerClick, properties]) + + function handleCloseCard() { + if (onCloseMapCard) { + onCloseMapCard() + } + } return ( <AdvancedMarker ref={markerRef} position={position} onClick={handleClick} - anchorPoint={AdvancedMarkerAnchorPoint.CENTER} + onMouseEnter={() => setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} + anchorPoint={AdvancedMarkerAnchorPoint.BOTTOM_CENTER} + zIndex={isActive ? 10 : 0} > - <HotelMarkerByType hotelId={properties.id} hotelType={properties.type} /> + <HotelMarkerByType + smallSize={!isHovered && !isActive} + hotelId={properties.id} + hotelType={properties.type} + /> + + <HotelMapCard + isActive={isActive} + amenities={properties.amenities} + tripadvisorRating={properties.tripadvisor} + hotelName={properties.name} + image={properties.image} + url={properties.url} + onClose={handleCloseCard} + /> </AdvancedMarker> ) } diff --git a/components/ContentType/DestinationPage/Map/MapContent/index.tsx b/components/ContentType/DestinationPage/Map/MapContent/index.tsx index f56702ad1..72a3033d0 100644 --- a/components/ContentType/DestinationPage/Map/MapContent/index.tsx +++ b/components/ContentType/DestinationPage/Map/MapContent/index.tsx @@ -1,6 +1,7 @@ "use client" import { useMap } from "@vis.gl/react-google-maps" +import { useEffect, useState } from "react" import { useSupercluster } from "@/hooks/maps/use-supercluster" @@ -27,12 +28,24 @@ const CLUSTER_OPTIONS = { } export default function MapContent({ geojson }: MapContentProps) { + const [activeMarker, setActiveMarker] = useState<string | undefined>( + undefined + ) + const map = useMap() const { clusters } = useSupercluster<MarkerProperties>( geojson, CLUSTER_OPTIONS ) + useEffect(() => { + map?.addListener("click", () => { + if (activeMarker) { + setActiveMarker(undefined) + } + }) + }, [activeMarker, map]) + function handleClusterClick(position: google.maps.LatLngLiteral) { const currentZoom = map && map.getZoom() if (currentZoom) { @@ -41,11 +54,12 @@ export default function MapContent({ geojson }: MapContentProps) { } } - function handleMarkerClick( - position: google.maps.LatLngLiteral, - properties: MarkerProperties - ) { - console.log("Marker clicked", position, properties) + function handleMarkerClick(properties: MarkerProperties) { + setActiveMarker(properties?.id) + } + + function handleCloseMapCard() { + setActiveMarker(undefined) } return clusters.map((feature) => { @@ -69,6 +83,8 @@ export default function MapContent({ geojson }: MapContentProps) { position={{ lat, lng }} properties={markerProperties} onMarkerClick={handleMarkerClick} + onCloseMapCard={handleCloseMapCard} + isActive={activeMarker === feature.id} /> ) }) diff --git a/components/ContentType/DestinationPage/Map/MapProvider.tsx b/components/ContentType/DestinationPage/Map/MapProvider.tsx index e3ce4dcd6..930871174 100644 --- a/components/ContentType/DestinationPage/Map/MapProvider.tsx +++ b/components/ContentType/DestinationPage/Map/MapProvider.tsx @@ -1,15 +1,23 @@ "use client" import { APIProvider } from "@vis.gl/react-google-maps" +import { type PageTypeContextType, PageTypeProvider } from "./PageTypeProvider" + import type { PropsWithChildren } from "react" interface MapContainerProps { apiKey: string + pageType: PageTypeContextType } export default function MapProvider({ apiKey, children, + pageType, }: PropsWithChildren<MapContainerProps>) { - return <APIProvider apiKey={apiKey}>{children}</APIProvider> + return ( + <APIProvider apiKey={apiKey}> + <PageTypeProvider value={pageType}>{children}</PageTypeProvider> + </APIProvider> + ) } diff --git a/components/ContentType/DestinationPage/Map/PageTypeProvider.tsx b/components/ContentType/DestinationPage/Map/PageTypeProvider.tsx new file mode 100644 index 000000000..434b11e73 --- /dev/null +++ b/components/ContentType/DestinationPage/Map/PageTypeProvider.tsx @@ -0,0 +1,29 @@ +"use client" +import { createContext, type PropsWithChildren, useContext } from "react" + +export type PageTypeContextType = PageTypeProviderProps["value"] + +const PageTypeContext = createContext<PageTypeContextType>(null) + +export const usePageType = () => { + const context = useContext(PageTypeContext) + if (!context) { + throw new Error("usePageType must be used within PageTypeProvider") + } + return context +} + +export type PageTypeProviderProps = { + value: "city" | "country" | "overview" | null +} + +export function PageTypeProvider({ + value, + children, +}: PropsWithChildren<PageTypeProviderProps>) { + return ( + <PageTypeContext.Provider value={value}> + {children} + </PageTypeContext.Provider> + ) +} diff --git a/components/ContentType/DestinationPage/Map/index.tsx b/components/ContentType/DestinationPage/Map/index.tsx index 8ab453c8d..f398928b7 100644 --- a/components/ContentType/DestinationPage/Map/index.tsx +++ b/components/ContentType/DestinationPage/Map/index.tsx @@ -26,6 +26,7 @@ interface MapProps { hotels: HotelDataWithUrl[] mapId: string apiKey: string + pageType: "city" | "country" } export default function Map({ @@ -33,6 +34,7 @@ export default function Map({ mapId, apiKey, children, + pageType, }: PropsWithChildren<MapProps>) { const searchParams = useSearchParams() const isMapView = useMemo( @@ -93,7 +95,7 @@ export default function Map({ } return ( - <MapProvider apiKey={apiKey}> + <MapProvider apiKey={apiKey} pageType={pageType}> <div className={styles.wrapper} ref={rootDiv}> <Modal isOpen={isMapView} diff --git a/components/ContentType/DestinationPage/Map/utils.ts b/components/ContentType/DestinationPage/Map/utils.ts index eb250ada7..b5ddb6e6c 100644 --- a/components/ContentType/DestinationPage/Map/utils.ts +++ b/components/ContentType/DestinationPage/Map/utils.ts @@ -30,7 +30,7 @@ export function mapMarkerDataToGeoJson(markers: DestinationMarker[]) { export function getHotelMapMarkers(hotels: HotelDataWithUrl[]) { const markers = hotels - .map(({ hotel }) => ({ + .map(({ hotel, url }) => ({ id: hotel.id, type: hotel.hotelType || "regular", name: hotel.name, @@ -40,7 +40,20 @@ export function getHotelMapMarkers(hotels: HotelDataWithUrl[]) { lng: hotel.location.longitude, } : null, + url: url, + tripadvisor: hotel.ratings?.tripAdvisor.rating, + amenities: hotel.detailedFacilities.slice(0, 3), + image: + hotel.galleryImages && hotel.galleryImages[0] + ? { + src: hotel.galleryImages[0].imageSizes.medium, + alt: + hotel.galleryImages[0].metaData.altText || + hotel.galleryImages[0].metaData.altText_En, + } + : null, })) + .filter((item): item is DestinationMarker => !!item.coordinates) return markers diff --git a/i18n/dictionaries/da.json b/i18n/dictionaries/da.json index 7618ac3d1..949849a86 100644 --- a/i18n/dictionaries/da.json +++ b/i18n/dictionaries/da.json @@ -519,6 +519,7 @@ "See destination": "Se destination", "See details": "Se detaljer", "See hotel details": "Se hoteloplysninger", + "See hotel information": "Se hoteloplysninger", "See map": "Vis kort", "See on map": "Se på kort", "See results ({ count })": "Se resultater ({ count })", diff --git a/i18n/dictionaries/de.json b/i18n/dictionaries/de.json index 37418dbad..e7c8abf1d 100644 --- a/i18n/dictionaries/de.json +++ b/i18n/dictionaries/de.json @@ -520,6 +520,7 @@ "See destination": "Siehe Ziel", "See details": "Siehe Einzelheiten", "See hotel details": "Hotelinformationen ansehen", + "See hotel information": "Siehe Hotelinformationen", "See map": "Karte anzeigen", "See on map": "Karte ansehen", "See results ({ count })": "Ergebnisse anzeigen ({ count })", diff --git a/i18n/dictionaries/en.json b/i18n/dictionaries/en.json index e99b966f2..5f8fd673a 100644 --- a/i18n/dictionaries/en.json +++ b/i18n/dictionaries/en.json @@ -526,6 +526,7 @@ "See destination": "See destination", "See details": "See details", "See hotel details": "See hotel details", + "See hotel information": "See hotel information", "See map": "See map", "See on map": "See on map", "See results ({ count })": "See results ({ count })", diff --git a/i18n/dictionaries/fi.json b/i18n/dictionaries/fi.json index df57296bb..3cb044153 100644 --- a/i18n/dictionaries/fi.json +++ b/i18n/dictionaries/fi.json @@ -520,6 +520,7 @@ "See destination": "Katso kohde", "See details": "Katso tiedot", "See hotel details": "Katso hotellin tiedot", + "See hotel information": "Katso hotellin tiedot", "See map": "Näytä kartta", "See on map": "Näytä kartalla", "See results ({ count })": "Katso tulokset ({ count })", diff --git a/i18n/dictionaries/no.json b/i18n/dictionaries/no.json index b049c8baf..6e4a9c15c 100644 --- a/i18n/dictionaries/no.json +++ b/i18n/dictionaries/no.json @@ -518,6 +518,7 @@ "See destination": "Se destinasjon", "See details": "Se detaljer", "See hotel details": "Se hotellinformasjon", + "See hotel information": "Se hotellinformasjon", "See map": "Vis kart", "See on map": "Se på kart", "See results ({ count })": "Se resultater ({ count })", diff --git a/i18n/dictionaries/sv.json b/i18n/dictionaries/sv.json index 23de44b1f..a4790b948 100644 --- a/i18n/dictionaries/sv.json +++ b/i18n/dictionaries/sv.json @@ -518,6 +518,7 @@ "See destination": "Se destination", "See details": "Se detaljer", "See hotel details": "Se hotellinformation", + "See hotel information": "Se hotellinformation", "See map": "Visa karta", "See on map": "Se på karta", "See results ({ count })": "Se resultat ({ count })", diff --git a/types/components/maps/destinationMarkers.ts b/types/components/maps/destinationMarkers.ts index aa37debb5..2cd0eab76 100644 --- a/types/components/maps/destinationMarkers.ts +++ b/types/components/maps/destinationMarkers.ts @@ -1,10 +1,17 @@ import type { FeatureCollection, Point } from "geojson" +import type { Amenities } from "@/types/hotel" +import type { GalleryImage } from "../imageGallery" + export interface DestinationMarker { id: string type: string name: string coordinates: google.maps.LatLngLiteral + url: string + tripadvisor: number | undefined + amenities: Amenities + image: GalleryImage } export type MarkerProperties = Omit<DestinationMarker, "coordinates">