shlink-web-client/src/visits/helpers/MapModal.tsx

58 lines
1.8 KiB
TypeScript
Raw Normal View History

2020-11-14 00:44:26 +03:00
import { FC } from 'react';
2019-01-09 22:30:59 +03:00
import { Modal, ModalBody } from 'reactstrap';
2020-11-14 13:00:41 +03:00
import { MapContainer, TileLayer, Marker, Popup, MapContainerProps } from 'react-leaflet';
import { prop } from 'ramda';
import { CityStats } from '../types';
import './MapModal.scss';
interface MapModalProps {
toggle: () => void;
isOpen: boolean;
title: string;
locations?: CityStats[];
}
const OpenStreetMapTile: FC = () => (
<TileLayer
attribution='&amp;copy <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
);
2020-11-14 13:00:41 +03:00
const calculateMapProps = (locations: CityStats[]): MapContainerProps => {
if (locations.length === 0) {
return {};
}
if (locations.length > 1) {
return { bounds: locations.map(prop('latLong')) };
}
// When there's only one location, an error is thrown if trying to calculate the bounds.
// When that happens, we use zoom and center as a workaround
const [{ latLong: center }] = locations;
return { zoom: 10, center };
};
2019-03-03 13:47:19 +03:00
const MapModal = ({ toggle, isOpen, title, locations = [] }: MapModalProps) => (
<Modal toggle={toggle} isOpen={isOpen} className="map-modal__modal" contentClassName="map-modal__modal-content">
<ModalBody className="map-modal__modal-body">
2019-01-09 22:30:59 +03:00
<h3 className="map-modal__modal-title">
{title}
<button type="button" className="close" onClick={toggle}>&times;</button>
</h3>
2020-11-14 13:00:41 +03:00
<MapContainer {...calculateMapProps(locations)}>
<OpenStreetMapTile />
{locations.map(({ cityName, latLong, count }, index) => (
<Marker key={index} position={latLong}>
<Popup><b>{count}</b> visit{count > 1 ? 's' : ''} from <b>{cityName}</b></Popup>
</Marker>
))}
2020-11-14 13:00:41 +03:00
</MapContainer>
</ModalBody>
</Modal>
);
export default MapModal;