From c5ad3cba34f5ec7d72dd98eff98ea55792c82ff6 Mon Sep 17 00:00:00 2001 From: Erik Tiekstra Date: Mon, 17 Mar 2025 13:18:38 +0000 Subject: [PATCH] feat(SW-1940): Added functionality to see hotel on map from city pages Approved-by: Fredrik Thorsson --- .../CityMap/HotelListItem/index.tsx | 8 ++--- .../HotelCardCarousel/index.tsx | 6 ++-- .../HotelListing/HotelListingItem/index.tsx | 29 ++++++++++++++++--- .../DestinationPage/HotelMapCard/index.tsx | 10 +++---- .../DestinationPage/Map/DynamicMap/index.tsx | 6 ++-- .../Map/MapContent/ClusterMarker/index.tsx | 4 +-- .../Map/MapContent/Marker/index.tsx | 8 ++--- .../DestinationPage/Map/MapContent/index.tsx | 8 ++--- .../ContentType/DestinationPage/Map/index.tsx | 24 +++++++++++---- .../stores/destination-page-hotels-map.ts | 8 ++--- 10 files changed, 73 insertions(+), 38 deletions(-) diff --git a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx index fa5a12f47..8d97c99c2 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/DestinationCityPage/CityMap/HotelListItem/index.tsx @@ -32,10 +32,10 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) { const amenities = hotel.detailedFacilities.slice(0, 5) const itemRef = useRef(null) - const { setHoveredHotel, clickedHotel } = useDestinationPageHotelsMapStore() + const { setHoveredHotel, activeHotel } = useDestinationPageHotelsMapStore() useEffect(() => { - if (clickedHotel === hotel.operaId) { + if (activeHotel === hotel.operaId) { const element = itemRef.current if (element) { element.scrollIntoView({ @@ -45,7 +45,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) { }) } } - }, [clickedHotel, hotel.operaId]) + }, [activeHotel, hotel.operaId]) const handleMouseEnter = useCallback(() => { if (hotel.operaId) { @@ -62,7 +62,7 @@ export default function HotelListItem({ hotel, url }: HotelListItemProps) { ref={itemRef} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} - className={`${styles.hotelListItem} ${clickedHotel === hotel.operaId ? styles.activeCard : ""}`} + className={`${styles.hotelListItem} ${activeHotel === hotel.operaId ? styles.activeCard : ""}`} >
hotel.operaId === clickedHotel + ({ hotel }) => hotel.operaId === activeHotel ) return ( @@ -35,7 +35,7 @@ export default function HotelCardCarousel({ (null) + + useEffect(() => { + const url = new URL(window.location.href) + url.searchParams.set("view", "map") + setMapUrl(url.toString()) + }, [params, hotel.name]) return (
@@ -90,10 +103,18 @@ export default function HotelListingItem({ ) })} - + {mapUrl && ( + + )} {url && ( <> diff --git a/apps/scandic-web/components/ContentType/DestinationPage/HotelMapCard/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/HotelMapCard/index.tsx index 1bea77f8e..812b9ad0c 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/HotelMapCard/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/HotelMapCard/index.tsx @@ -1,7 +1,7 @@ "use client" import { cx } from "class-variance-authority" import Link from "next/link" -import { useCallback, useState } from "react" +import { useState } from "react" import { useIntl } from "react-intl" import { useDestinationPageHotelsMapStore } from "@/stores/destination-page-hotels-map" @@ -44,11 +44,11 @@ export default function HotelMapCard({ const intl = useIntl() const pageType = usePageType() const [imageError, setImageError] = useState(false) - const { setClickedHotel } = useDestinationPageHotelsMapStore() + const { setActiveHotel } = useDestinationPageHotelsMapStore() - const handleClose = useCallback(() => { - setClickedHotel(null) - }, [setClickedHotel]) + function handleClose() { + setActiveHotel(null) + } function Wrapper({ children }: React.PropsWithChildren) { if (type === "dialog") { diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx index 7084a6e8c..b705bc58f 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/Map/DynamicMap/index.tsx @@ -25,6 +25,7 @@ interface DynamicMapProps { mapId: string defaultCoordinates: google.maps.LatLngLiteral | null defaultZoom: number + fitBounds?: boolean onClose?: () => void } @@ -33,6 +34,7 @@ export default function DynamicMap({ mapId, defaultCoordinates, defaultZoom, + fitBounds = true, onClose, children, }: PropsWithChildren) { @@ -40,7 +42,7 @@ export default function DynamicMap({ const map = useMap() useEffect(() => { - if (map) { + if (map && fitBounds) { if (markers.length) { const bounds = new google.maps.LatLngBounds() markers.forEach((marker) => { @@ -51,7 +53,7 @@ export default function DynamicMap({ map.setCenter(defaultCoordinates) } } - }, [map, markers, defaultCoordinates]) + }, [map, markers, defaultCoordinates, fitBounds]) useHandleKeyUp((event: KeyboardEvent) => { if (event.key === "Escape" && onClose) { diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/index.tsx index 00b847563..b45164b37 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/ClusterMarker/index.tsx @@ -27,10 +27,10 @@ export default function ClusterMarker({ onMarkerClick, hotelIds, }: ClusterMarkerProps) { - const { hoveredHotel, clickedHotel } = useDestinationPageHotelsMapStore() + const { hoveredHotel, activeHotel } = useDestinationPageHotelsMapStore() const isActive = hotelIds.includes(Number(hoveredHotel)) || - hotelIds.includes(Number(clickedHotel)) + hotelIds.includes(Number(activeHotel)) const handleClick = useCallback(() => { if (onMarkerClick) { diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx index 4b974a640..8be23def5 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/Map/MapContent/Marker/index.tsx @@ -24,13 +24,13 @@ interface MarkerProps { export default function Marker({ position, properties }: MarkerProps) { const [markerRef] = useAdvancedMarkerRef() - const { setHoveredHotel, setClickedHotel, hoveredHotel, clickedHotel } = + const { setHoveredHotel, setActiveHotel, hoveredHotel, activeHotel } = useDestinationPageHotelsMapStore() const handleClick = useCallback(() => { - setClickedHotel(properties.id) + setActiveHotel(properties.id) trackMapClick(properties.name) - }, [setClickedHotel, properties]) + }, [setActiveHotel, properties]) const handleMouseEnter = useCallback(() => { setHoveredHotel(properties.id) @@ -41,7 +41,7 @@ export default function Marker({ position, properties }: MarkerProps) { }, [setHoveredHotel]) const isHovered = hoveredHotel === properties.id - const isActive = clickedHotel === properties.id + const isActive = activeHotel === properties.id return ( ( @@ -47,11 +47,11 @@ export default function MapContent({ useEffect(() => { map?.addListener("click", () => { - if (clickedHotel) { - setClickedHotel(null) + if (activeHotel) { + setActiveHotel(null) } }) - }, [clickedHotel, map, setClickedHotel]) + }, [activeHotel, map, setActiveHotel]) function handleClusterClick(position: google.maps.LatLngLiteral) { const currentZoom = map && map.getZoom() diff --git a/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx b/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx index cebb839ca..5abadea5e 100644 --- a/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx +++ b/apps/scandic-web/components/ContentType/DestinationPage/Map/index.tsx @@ -13,6 +13,7 @@ import { Dialog, Modal } from "react-aria-components" import { useIntl } from "react-intl" import { useDestinationDataStore } from "@/stores/destination-data" +import { useDestinationPageHotelsMapStore } from "@/stores/destination-page-hotels-map" import DestinationFilterAndSort from "@/components/DestinationFilterAndSort" import { ChevronLeftSmallIcon } from "@/components/Icons" @@ -47,10 +48,14 @@ export default function Map({ }: PropsWithChildren) { const router = useRouter() const searchParams = useSearchParams() + const { activeHotel: activeHotelId } = useDestinationPageHotelsMapStore() const isMapView = useMemo( () => searchParams.get("view") === "map", [searchParams] ) + const activeHotel = hotels.find( + ({ hotel }) => hotel.operaId === activeHotelId + ) const rootDiv = useRef(null) const [mapHeight, setMapHeight] = useState("0px") const [scrollHeightWhenOpened, setScrollHeightWhenOpened] = useState(0) @@ -65,14 +70,20 @@ export default function Map({ const markers = getHotelMapMarkers(hotels) const geoJson = mapMarkerDataToGeoJson(markers) - const defaultCoordinates = defaultLocation + const defaultCoordinates = activeHotel ? { - lat: defaultLocation.latitude, - lng: defaultLocation.longitude, + lat: activeHotel.hotel.location.latitude, + lng: activeHotel.hotel.location.longitude, } - : null - const defaultZoom = - defaultLocation?.default_zoom ?? (pageType === "city" ? 10 : 3) + : defaultLocation + ? { + lat: defaultLocation.latitude, + lng: defaultLocation.longitude, + } + : null + const defaultZoom = activeHotel + ? 15 + : (defaultLocation?.default_zoom ?? (pageType === "city" ? 10 : 3)) // Calculate the height of the map based on the viewport height from the start-point (below the header and booking widget) const handleMapHeight = useCallback(() => { @@ -157,6 +168,7 @@ export default function Map({ onClose={handleClose} defaultCoordinates={defaultCoordinates} defaultZoom={defaultZoom} + fitBounds={!activeHotel} > void - setClickedHotel: (hotelId: string | null) => void + setActiveHotel: (hotelId: string | null) => void } export const useDestinationPageHotelsMapStore = create((set) => ({ hoveredHotel: null, - clickedHotel: null, + activeHotel: null, setHoveredHotel: (hotelId) => set({ hoveredHotel: hotelId }), - setClickedHotel: (hotelId) => set({ clickedHotel: hotelId }), + setActiveHotel: (hotelId) => set({ activeHotel: hotelId }), }))