Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, {
- useEffect, useState, useMemo, useCallback, useRef,
- } from 'react';
- import { useDispatch, useSelector } from 'react-redux';
- import { useLocation } from 'react-router-dom';
- import { useTranslation } from 'react-i18next';
- import sizeMe from 'react-sizeme';
- import * as rootSelectors from 'ducks/selectors';
- import {
- operations as locationOperations,
- selectors as locationSelectors,
- actions as locationActions,
- } from 'ducks/Location';
- import { actions as mapActions } from 'ducks/Map';
- import { callTotalLocations } from 'ducks/Tool/utils';
- import { selectors as toolSelectors, operations as toolOperations } from 'ducks/Tool';
- import { operations as modalOperations } from 'ducks/Modal';
- import { EDIT_TOOL, LOCATION } from 'constants/modalTypes';
- import getMapBounds from 'utils/getMapBounds';
- import useAnalytics from 'shared/hooks/useAnalytics';
- import Map from 'shared/Map';
- import FilterDropdown from 'components/FilterDropdown/FilterDropdown';
- import {
- Paper, Grid, styled, useTheme,
- } from '@mui/material';
- import useGlobalSelectors from 'shared/hooks/globals/selectors';
- import SearchResultMarker from 'shared/SearchResultMarker/SearchResultMarker';
- import LocationMarker from 'shared/LocationMarker';
- import { useLoadingBar } from 'react-top-loading-bar';
- import useApig from 'shared/hooks/useApig';
- import { AppDispatch } from 'store/types';
- import { TOOL_MAP_FETCH_REQUEST } from 'ducks/types';
- import HideApigLoading from 'components/HideApigLoading';
- import { createRoot } from 'react-dom/client';
- import { MarkerClusterer } from '@googlemaps/markerclusterer';
- import store from '../../index';
- import MapSearch from './_/MapSearch';
- import ToolMarker from './_/ToolMarker';
- import './MapPage.scss';
- const StyledPaper = styled(Paper)(({ theme }) => ({
- position: 'absolute',
- zIndex: 1,
- width: '600px',
- padding: '18px 13px',
- top: '60px',
- left: '40px',
- backgroundColor: theme.palette.background.paper,
- boxShadow: theme.shadows[3],
- borderRadius: theme.shape.borderRadius,
- }));
- const StyledDropdown = styled(FilterDropdown)({
- minWidth: '500px',
- });
- const MapPage = ({ size }: any) => {
- const dispatch = useDispatch<AppDispatch>();
- const { t } = useTranslation();
- const routeLocation = useLocation();
- const { companyId } = useGlobalSelectors();
- const audits = useSelector((state: any) => state.orm.Audit.itemsById);
- const tools = useSelector(rootSelectors.getMapTools);
- const locations = useSelector(locationSelectors.getMappedLocations);
- const mapType = useSelector((state: any) => state.map.mapType);
- const status = useApig(TOOL_MAP_FETCH_REQUEST);
- const theme = useTheme();
- const {
- start, complete,
- } = useLoadingBar({ color: theme.palette.primary.main, height: 5, shadow: false });
- const [showTools, setShowTools] = useState(true);
- const [showLocations, setShowLocations] = useState(true);
- const [shownItem, setShownItem] = useState<string | null>(null);
- const [searchResult, setSearchResult] = useState<any>(null);
- const clusterRef = useRef<MarkerClusterer | null>(null);
- const googleMarkersRef = useRef<google.maps.Marker[]>([]);
- const mapOptions = useMemo(() => [
- { value: 'showTools', label: t('Map.Dropdown.Tools') },
- { value: 'showLocations', label: t('Map.Dropdown.Locations') },
- ], [t]);
- const mapAllOption = { value: 'all', label: t('Map.Dropdown.All') };
- useEffect(() => {
- if (status) {
- if (status === 'loading') {
- start();
- return;
- }
- complete();
- }
- }, [status]);
- useEffect(() => {
- const initializeMapData = async () => {
- setSearchResult(null);
- dispatch(toolOperations.loadMapTools());
- dispatch(locationActions.clearLocationsList());
- callTotalLocations(() => dispatch(locationOperations.loadLocations()));
- dispatch(mapActions.addMapFilter(mapOptions.map(o => o.value)));
- };
- initializeMapData();
- }, [dispatch, companyId]);
- const newLocations = useMemo(() => locations.map((loc: any) => ({
- ...loc,
- audit: audits[loc.audit],
- })), [locations, audits]);
- const makeToggle = (id: string) => () => setShownItem(prev => (prev === id ? null : id));
- const { logEvent } = useAnalytics();
- const locationParam = routeLocation.pathname.split('/')[2];
- const locationId = locationParam || false;
- const bounds = getMapBounds([], size);
- const zoom = !searchResult ? bounds.zoom : Math.max(bounds.zoom - 1, 0);
- const center = !searchResult ? bounds.center : {
- lat: searchResult.latitude,
- lng: searchResult.longitude,
- };
- const handleChangeDropdown = useCallback(
- ({ target: { value } }: { target: { value: string[] } }) => {
- const wantSelectAll = value.includes('all');
- const selectedValues = wantSelectAll ? mapOptions.map(o => o.value) : value;
- dispatch(mapActions.addMapFilter(selectedValues));
- setShowTools(wantSelectAll || selectedValues.includes('showTools'));
- setShowLocations(wantSelectAll || selectedValues.includes('showLocations'));
- },
- [dispatch, mapOptions],
- );
- const handleInitialize = ({ map, maps }: any) => {
- if (clusterRef.current) clusterRef.current.clearMarkers();
- googleMarkersRef.current.forEach(marker => marker.setMap(null));
- googleMarkersRef.current = [];
- const markers: google.maps.Marker[] = [];
- const createMarker = (position: google.maps.LatLngLiteral, content: HTMLElement) => {
- const scaledSize = maps?.Size ? new maps.Size(40, 40) : undefined;
- const marker = new google.maps.Marker({
- position,
- map: null,
- icon: {
- url: 'https://maps.google.com/mapfiles/ms/icons/red-dot.png',
- scaledSize,
- },
- });
- markers.push(marker);
- };
- if (showTools && !locationId) {
- tools.forEach((tool: any) => {
- const linkedDumbTool = toolSelectors.getLinkedDumbToolById(store.getState(), tool.thingId);
- const node = document.createElement('div');
- createRoot(node).render(
- <ToolMarker
- tool={tool}
- linkedDumbTool={linkedDumbTool}
- showPopup={tool.thingId === shownItem}
- toggle={makeToggle(tool.thingId)}
- action={id => dispatch(modalOperations.showModal(EDIT_TOOL, { id }))}
- />,
- );
- createMarker({ lat: +tool.latitude, lng: +tool.longitude }, node);
- });
- }
- if (showLocations) {
- const filtered = locationId
- ? newLocations.filter((loc: any) => loc.locationId === locationId)
- : newLocations;
- filtered.forEach((loc: any) => {
- const node = document.createElement('div');
- createRoot(node).render(
- <LocationMarker
- location={loc}
- lat={+loc.latitude}
- lng={+loc.longitude}
- showPopup={loc.locationId === shownItem}
- toggle={makeToggle(loc.locationId)}
- />,
- );
- createMarker({ lat: +loc.latitude, lng: +loc.longitude }, node);
- });
- }
- if (searchResult) {
- const { locationName, ...result } = searchResult;
- const node = document.createElement('div');
- createRoot(node).render(
- <SearchResultMarker
- lat={+searchResult.latitude}
- lng={+searchResult.longitude}
- onSearchClear={() => setSearchResult(null)}
- onCreate={() => {
- logEvent('search_result_popup_assignment');
- dispatch(modalOperations.showModal(LOCATION, {
- location: result,
- showModal: true,
- isNewLocation: true,
- onSuccess: () => setSearchResult(null),
- }));
- }}
- description={locationName}
- />,
- );
- createMarker({ lat: +searchResult.latitude, lng: +searchResult.longitude }, node);
- }
- googleMarkersRef.current = markers;
- clusterRef.current = new MarkerClusterer({ map, markers: googleMarkersRef.current });
- };
- return (
- <section className="map-page">
- <HideApigLoading />
- <StyledPaper>
- <Grid container spacing={1} sx={{ alignItems: 'center' }}>
- <Grid item xs={7}>
- <MapSearch onSelect={value => setSearchResult(value)} />
- </Grid>
- <Grid item xs={5}>
- <StyledDropdown
- options={mapOptions}
- title={t('Map.Dropdown.Title')}
- handleChange={handleChangeDropdown}
- allOption={mapAllOption}
- selectedValues={mapType}
- />
- </Grid>
- </Grid>
- </StyledPaper>
- <Map
- center={center}
- zoom={zoom}
- options={(maps: any) => ({
- mapTypeControl: true,
- mapTypeControlOptions: {
- position: maps.ControlPosition.LEFT_BOTTOM,
- },
- fullscreenControlOptions: {
- position: maps.ControlPosition.RIGHT_BOTTOM,
- },
- })}
- onInitialize={handleInitialize}
- />
- </section>
- );
- };
- export default sizeMe({ monitorHeight: true })(MapPage);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement