PromucFlow_constructor/app/client/src/widgets/MapWidget/component/Map.tsx
Pawan Kumar eba4745965
fix: Upgrade map widget library to support react 17 (#19315)
This PR:
 - updates the react 16 to react 17
 - replaces the underlying library for the map widget
 - adds clustering of markers
 - refactor code for map widget's component
 
## Description

Fixes #16946

## Type of change
- Breaking change


## How Has This Been Tested?
- Manually

### Test Plan
https://github.com/appsmithorg/TestSmith/issues/2149

### Issues raised during DP testing
1.
https://github.com/appsmithorg/appsmith/pull/19315#issuecomment-1378495845


## Checklist:
### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


### QA activity:
- [ ] Test plan has been approved by relevant developers
- [x] Test plan has been peer reviewed by QA
- [ ] Cypress test cases have been added and approved by either SDET or
manual QA
- [ ] Organized project review call with relevant stakeholders after
Round 1/2 of QA
- [ ] Added Test Plan Approved label after reveiwing all Cypress test

Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com>
Co-authored-by: Arsalan <arsalanyaldram0211@outlook.com>
Co-authored-by: rahulramesha <rahul@appsmith.com>
2023-01-14 00:19:21 +05:30

144 lines
3.2 KiB
TypeScript

import styled from "styled-components";
import React, { useCallback, useEffect, useRef, useState } from "react";
import Clusterer from "./Clusterer";
import SearchBox from "./SearchBox";
import { MapComponentProps } from ".";
import PickMyLocation from "./PickMyLocation";
const Wrapper = styled.div`
position: relative;
`;
const StyledMap = styled.div<Pick<MapProps, "borderRadius" | "boxShadow">>`
height: 100%;
width: 100%;
border-radius: ${(props) => props.borderRadius};
box-shadow: ${(props) => props.boxShadow};
`;
type MapProps = {
children?: React.ReactNode;
} & Pick<
MapComponentProps,
| "updateCenter"
| "zoomLevel"
| "updateMarker"
| "selectMarker"
| "saveMarker"
| "markers"
| "center"
| "enableCreateMarker"
| "selectedMarker"
| "borderRadius"
| "boxShadow"
| "clickedMarkerCentered"
| "enableDrag"
>;
const Map = (props: MapProps) => {
const {
borderRadius,
boxShadow,
center,
children,
enableCreateMarker,
enableDrag,
markers,
saveMarker,
selectMarker,
updateCenter,
updateMarker,
zoomLevel,
} = props;
const [map, setMap] = useState<google.maps.Map>();
const mapRef = useRef<HTMLDivElement>(null);
// initialize the map instance
useEffect(() => {
if (!mapRef.current) return;
setMap(
new window.google.maps.Map(mapRef.current, {
streetViewControl: false,
mapTypeControl: false,
fullscreenControl: false,
}),
);
}, [mapRef]);
// set center if center is changed
useEffect(() => {
if (map) {
map.setCenter({ lat: center.lat, lng: center.long });
}
}, [center, map]);
// set zoom if zoomLevel is changed
useEffect(() => {
if (map) {
map.setZoom(Math.floor(zoomLevel / 5));
}
}, [zoomLevel, map]);
/**
* on click map, add marker
*
* @param e
* @returns
*/
const onClickOnMap = useCallback(
(e: google.maps.MapMouseEvent) => {
if (!enableCreateMarker || !saveMarker) return;
// only save marker when lag and long are available
if (e.latLng?.lat() && e.latLng?.lng()) {
saveMarker(Number(e.latLng.lat()), Number(e.latLng.lng()));
}
},
[enableCreateMarker, saveMarker],
);
// NOTE: The event listeners require code to clear existing listeners
// when a handler passed as a prop has been updated.
React.useEffect(() => {
if (map) {
["click", "idle"].forEach((eventName) =>
google.maps.event.clearListeners(map, eventName),
);
map.addListener("click", onClickOnMap);
}
}, [map, onClickOnMap]);
return (
<Wrapper onMouseLeave={enableDrag}>
<StyledMap
borderRadius={borderRadius}
boxShadow={boxShadow}
id="map"
ref={mapRef}
/>
<Clusterer
map={map}
markers={markers}
selectMarker={selectMarker}
updateCenter={updateCenter}
updateMarker={updateMarker}
/>
{React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child as React.ReactElement<any>, {
map,
});
}
})}
</Wrapper>
);
};
Map.PickMyLocation = PickMyLocation;
Map.SearchBox = SearchBox;
export default Map;