"use client" import { Map, type MapProps, useMap } from "@vis.gl/react-google-maps" import { useEffect, useState } from "react" import { useIntl } from "react-intl" import { IconButton } from "../../IconButton" import { HOTEL_PAGE, MAP_RESTRICTIONS } from "../mapConstants" import { useZoomControls } from "@scandic-hotels/common/hooks/map/useZoomControls" import { HotelListingMapContent } from "./HotelListingMapContent" import PoiMapMarkers from "./PoiMapMarkers" import styles from "./interactiveMap.module.css" import { Lang } from "@scandic-hotels/common/constants/language" import { HotelPin, MarkerInfo, PointOfInterest } from "../types" export type InteractiveMapProps = { lang: Lang coordinates: { lat: number lng: number } activePoi?: string | null hotelPins?: HotelPin[] pointsOfInterest?: PointOfInterest[] markerInfo?: MarkerInfo mapId: string closeButton: React.ReactNode fitBounds?: boolean hoveredHotelPin?: string | null activeHotelPin?: string | null isUserLoggedIn: boolean onTilesLoaded?: () => void onActivePoiChange?: (poi: string | null) => void onClickHotel?: (hotelId: string) => void /** * Called when a hotel pin is hovered. * @param args when null, it means the hover has ended * @returns */ onHoverHotelPin?: ( args: { hotelName: string; hotelId: string } | null ) => void /** * Called when a hotel pin is activated. * @param args when null, it means nothing is active * @returns */ onSetActiveHotelPin?: ( args: { hotelName: string; hotelId: string } | null ) => void } export function InteractiveMap({ lang, coordinates, pointsOfInterest, activePoi, hotelPins, mapId, closeButton, markerInfo, fitBounds = true, hoveredHotelPin, activeHotelPin, isUserLoggedIn, onClickHotel, onHoverHotelPin, onSetActiveHotelPin, onTilesLoaded, onActivePoiChange, }: InteractiveMapProps) { const intl = useIntl() const map = useMap() const [hasInitializedBounds, setHasInitializedBounds] = useState(false) const { zoomIn, zoomOut, isMaxZoom, isMinZoom } = useZoomControls(HOTEL_PAGE) const mapOptions: MapProps = { defaultZoom: HOTEL_PAGE.DEFAULT_ZOOM, minZoom: HOTEL_PAGE.MIN_ZOOM, maxZoom: HOTEL_PAGE.MAX_ZOOM, defaultCenter: coordinates, disableDefaultUI: true, clickableIcons: false, mapId, gestureHandling: "greedy", restriction: MAP_RESTRICTIONS, } useEffect(() => { if (map && hotelPins?.length && !hasInitializedBounds) { if (fitBounds) { const bounds = new google.maps.LatLngBounds() hotelPins.forEach((marker) => { bounds.extend(marker.coordinates) }) map.fitBounds(bounds, 100) } setHasInitializedBounds(true) } }, [map, fitBounds, hotelPins, hasInitializedBounds]) return (