Vizzuality/landgriffon

View on GitHub
client/src/components/map/component.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import React, { useEffect, useState, useCallback } from 'react';
import ReactMapGL, { useMap } from 'react-map-gl/maplibre';
import { useDebounce } from 'rooks';

import { INITIAL_VIEW_STATE, MAP_STYLES } from './constants';

import type { ViewState, ViewStateChangeEvent } from 'react-map-gl/maplibre';
import type { FC } from 'react';
import type { CustomMapProps } from './types';

export const Map: FC<CustomMapProps> = ({
  id = 'default',
  mapStyle = 'terrain',
  initialViewState,
  viewState = {},
  bounds,
  onMapViewStateChange = () => null,
  children,
  dragPan,
  dragRotate,
  scrollZoom,
  doubleClickZoom,
  onLoad,
  sidebarCollapsed = false,
  touchZoomRotate, // not supported in MapLibre
  touchPitch, // not supported in MapLibre
  ...otherMapProps
}: CustomMapProps) => {
  /**
   * REFS
   */
  const { [id]: mapRef } = useMap();

  /**
   * STATE
   */
  const [localViewState, setLocalViewState] = useState<Partial<ViewState>>(
    !initialViewState && {
      ...INITIAL_VIEW_STATE,
      ...viewState,
    },
  );
  const onMapViewStateChangeDebounced = useDebounce(onMapViewStateChange, 150);

  const handleMapMove = useCallback(
    ({ viewState: _viewState }: ViewStateChangeEvent) => {
      setLocalViewState(_viewState);
      onMapViewStateChangeDebounced(_viewState);
    },
    [onMapViewStateChangeDebounced],
  );

  useEffect(() => {
    let resizeWhenCollapse: NodeJS.Timeout;

    // Cancel last timeout if a new one it triggered
    clearTimeout(resizeWhenCollapse);

    // Trigger the map resize if the sidebar has been collapsed. There is no need to resize if the sidebar has been expanded because the container will hide the excess width
    if (sidebarCollapsed) {
      resizeWhenCollapse = setTimeout(() => {
        mapRef?.resize();
      }, 150);
    }
  }, [sidebarCollapsed, mapRef]);

  return (
    <ReactMapGL
      id={id}
      mapStyle={MAP_STYLES[mapStyle]}
      initialViewState={initialViewState}
      onMove={handleMapMove}
      {...otherMapProps}
      {...localViewState}
      attributionControl
      minZoom={1}
    >
      {!!mapRef && children(mapRef.getMap())}
    </ReactMapGL>
  );
};

Map.displayName = 'Map';

export default Map;