Merged in feat/SW-2041-map-zoom-buttons (pull request #2550)
Feat(SW-661): Hotel page map zoom restrictions * fix(SW-2041): update tokens * chore(SW-2041): restrict zooming * fix(SW-2041): remove ref * fix(SW-2041): create map zoom hook Approved-by: Erik Tiekstra Approved-by: Hrishikesh Vaipurkar
This commit is contained in:
@@ -4,10 +4,17 @@ import { Map, type MapProps, useMap } from "@vis.gl/react-google-maps"
|
|||||||
import { useEffect, useState } from "react"
|
import { useEffect, useState } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
|
import { IconButton } from "@scandic-hotels/design-system/IconButton"
|
||||||
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
import { MaterialIcon } from "@scandic-hotels/design-system/Icons/MaterialIcon"
|
||||||
import { OldDSButton as Button } from "@scandic-hotels/design-system/OldDSButton"
|
|
||||||
|
|
||||||
import { MAP_RESTRICTIONS } from "@/constants/map"
|
import {
|
||||||
|
DEFAULT_ZOOM,
|
||||||
|
MAP_RESTRICTIONS,
|
||||||
|
MAX_ZOOM,
|
||||||
|
MIN_ZOOM,
|
||||||
|
} from "@/constants/map"
|
||||||
|
|
||||||
|
import { useZoomControls } from "@/hooks/maps/useZoomControls"
|
||||||
|
|
||||||
import HotelListingMapContent from "./HotelListingMapContent"
|
import HotelListingMapContent from "./HotelListingMapContent"
|
||||||
import PoiMapMarkers from "./PoiMapMarkers"
|
import PoiMapMarkers from "./PoiMapMarkers"
|
||||||
@@ -31,9 +38,12 @@ export default function InteractiveMap({
|
|||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const map = useMap()
|
const map = useMap()
|
||||||
const [hasInitializedBounds, setHasInitializedBounds] = useState(false)
|
const [hasInitializedBounds, setHasInitializedBounds] = useState(false)
|
||||||
|
const { zoomIn, zoomOut, isMaxZoom, isMinZoom } = useZoomControls()
|
||||||
|
|
||||||
const mapOptions: MapProps = {
|
const mapOptions: MapProps = {
|
||||||
defaultZoom: 14,
|
defaultZoom: DEFAULT_ZOOM,
|
||||||
|
minZoom: MIN_ZOOM,
|
||||||
|
maxZoom: MAX_ZOOM,
|
||||||
defaultCenter: coordinates,
|
defaultCenter: coordinates,
|
||||||
disableDefaultUI: true,
|
disableDefaultUI: true,
|
||||||
clickableIcons: false,
|
clickableIcons: false,
|
||||||
@@ -42,19 +52,6 @@ export default function InteractiveMap({
|
|||||||
restriction: MAP_RESTRICTIONS,
|
restriction: MAP_RESTRICTIONS,
|
||||||
}
|
}
|
||||||
|
|
||||||
function zoomIn() {
|
|
||||||
const currentZoom = map && map.getZoom()
|
|
||||||
if (currentZoom) {
|
|
||||||
map.setZoom(currentZoom + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function zoomOut() {
|
|
||||||
const currentZoom = map && map.getZoom()
|
|
||||||
if (currentZoom) {
|
|
||||||
map.setZoom(currentZoom - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (map && hotelPins?.length && !hasInitializedBounds) {
|
if (map && hotelPins?.length && !hasInitializedBounds) {
|
||||||
if (fitBounds) {
|
if (fitBounds) {
|
||||||
@@ -62,7 +59,6 @@ export default function InteractiveMap({
|
|||||||
hotelPins.forEach((marker) => {
|
hotelPins.forEach((marker) => {
|
||||||
bounds.extend(marker.coordinates)
|
bounds.extend(marker.coordinates)
|
||||||
})
|
})
|
||||||
|
|
||||||
map.fitBounds(bounds, 100)
|
map.fitBounds(bounds, 100)
|
||||||
}
|
}
|
||||||
setHasInitializedBounds(true)
|
setHasInitializedBounds(true)
|
||||||
@@ -86,32 +82,31 @@ export default function InteractiveMap({
|
|||||||
<div className={styles.ctaButtons}>
|
<div className={styles.ctaButtons}>
|
||||||
{closeButton}
|
{closeButton}
|
||||||
<div className={styles.zoomButtons}>
|
<div className={styles.zoomButtons}>
|
||||||
<Button
|
<IconButton
|
||||||
theme="base"
|
theme="Inverted"
|
||||||
intent="inverted"
|
style="Elevated"
|
||||||
variant="icon"
|
|
||||||
size="small"
|
|
||||||
className={styles.zoomButton}
|
className={styles.zoomButton}
|
||||||
onClick={zoomOut}
|
onClick={zoomOut}
|
||||||
aria-label={intl.formatMessage({
|
aria-label={intl.formatMessage({
|
||||||
defaultMessage: "Zoom in",
|
defaultMessage: "Zoom out",
|
||||||
})}
|
})}
|
||||||
|
isDisabled={isMinZoom}
|
||||||
>
|
>
|
||||||
<MaterialIcon icon="remove" color="CurrentColor" />
|
<MaterialIcon icon="remove" color="CurrentColor" />
|
||||||
</Button>
|
</IconButton>
|
||||||
<Button
|
|
||||||
theme="base"
|
<IconButton
|
||||||
intent="inverted"
|
theme="Inverted"
|
||||||
variant="icon"
|
style="Elevated"
|
||||||
size="small"
|
|
||||||
className={styles.zoomButton}
|
className={styles.zoomButton}
|
||||||
onClick={zoomIn}
|
onClick={zoomIn}
|
||||||
aria-label={intl.formatMessage({
|
aria-label={intl.formatMessage({
|
||||||
defaultMessage: "Zoom out",
|
defaultMessage: "Zoom in",
|
||||||
})}
|
})}
|
||||||
|
isDisabled={isMaxZoom}
|
||||||
>
|
>
|
||||||
<MaterialIcon icon="add" color="CurrentColor" />
|
<MaterialIcon icon="add" color="CurrentColor" />
|
||||||
</Button>
|
</IconButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,8 +59,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.zoomButton {
|
.zoomButton {
|
||||||
width: var(--Spacing-x5);
|
width: var(--Space-x5);
|
||||||
height: var(--Spacing-x5);
|
height: var(--Space-x5);
|
||||||
padding: 0;
|
padding: 0;
|
||||||
pointer-events: initial;
|
pointer-events: initial;
|
||||||
box-shadow: var(--button-box-shadow);
|
box-shadow: var(--button-box-shadow);
|
||||||
|
|||||||
@@ -3,3 +3,7 @@ export const MAP_RESTRICTIONS = {
|
|||||||
// See https://developers.google.com/maps/documentation/javascript/reference/map#MapRestriction.latLngBounds
|
// See https://developers.google.com/maps/documentation/javascript/reference/map#MapRestriction.latLngBounds
|
||||||
latLngBounds: { north: 85, south: -85, west: -180, east: 180 },
|
latLngBounds: { north: 85, south: -85, west: -180, east: 180 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const DEFAULT_ZOOM = 14
|
||||||
|
export const MAX_ZOOM = 18
|
||||||
|
export const MIN_ZOOM = 8
|
||||||
|
|||||||
43
apps/scandic-web/hooks/maps/useZoomControls.ts
Normal file
43
apps/scandic-web/hooks/maps/useZoomControls.ts
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
import { useMap } from "@vis.gl/react-google-maps"
|
||||||
|
import { useEffect, useState } from "react"
|
||||||
|
|
||||||
|
import { DEFAULT_ZOOM, MAX_ZOOM, MIN_ZOOM } from "@/constants/map"
|
||||||
|
|
||||||
|
export function useZoomControls() {
|
||||||
|
const map = useMap()
|
||||||
|
const [zoomLevel, setZoomLevel] = useState(DEFAULT_ZOOM)
|
||||||
|
|
||||||
|
const zoomIn = () => {
|
||||||
|
if (map && zoomLevel < MAX_ZOOM) {
|
||||||
|
map.setZoom(zoomLevel + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const zoomOut = () => {
|
||||||
|
if (map && zoomLevel > MIN_ZOOM) {
|
||||||
|
map.setZoom(zoomLevel - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!map) return
|
||||||
|
|
||||||
|
const handleZoomChanged = () => {
|
||||||
|
const currentZoom = map.getZoom()
|
||||||
|
if (currentZoom != null) {
|
||||||
|
setZoomLevel(currentZoom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const listener = map.addListener("zoom_changed", handleZoomChanged)
|
||||||
|
return () => listener.remove()
|
||||||
|
}, [map])
|
||||||
|
|
||||||
|
return {
|
||||||
|
zoomLevel,
|
||||||
|
zoomIn,
|
||||||
|
zoomOut,
|
||||||
|
isMinZoom: zoomLevel <= MIN_ZOOM,
|
||||||
|
isMaxZoom: zoomLevel >= MAX_ZOOM,
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user