frontend: visualize markers on map

This commit is contained in:
Johannes Lötzsch 2022-03-14 19:22:17 +01:00
parent 13e493f5d1
commit 687e79b3c4
3 changed files with 63 additions and 11 deletions

View File

@ -1,9 +1,11 @@
import React from 'react'
import React, { useEffect } from 'react'
import { useGetOffersQuery, useGetRwQuery } from "../../codegen/generates"
import HostOfferLookupTable, {HostOfferLookupTableProps} from "./HostOfferLookupTable"
import { Box } from "@mui/material"
import { useTranslation } from 'react-i18next'
import { Login, useAuthStore } from '../Login'
import { useLeafletStore } from './LeafletStore'
import { filterUndefOrNull } from '../util/notEmpty'
type HostOfferLookupWrapperProps = Partial<HostOfferLookupTableProps>
@ -13,8 +15,21 @@ const HostOfferLookupWrapper = (props: HostOfferLookupWrapperProps) => {
const staleTimeMinutes_ro = 5
const staleTimeMinutes_rw = 1
const queryResult_ro = useGetOffersQuery({auth}, {staleTime: staleTimeMinutes_ro * 60 * 1000})
const queryResult_rw = useGetRwQuery({auth}, {staleTime: staleTimeMinutes_rw * 60 * 1000})
const queryResult_ro = useGetOffersQuery({auth}, {enabled: !!auth.jwt, staleTime: staleTimeMinutes_ro * 60 * 1000})
const queryResult_rw = useGetRwQuery({auth}, {enabled: !!auth.jwt, staleTime: staleTimeMinutes_rw * 60 * 1000})
const {data: data_ro} = queryResult_ro
const {data: data_rw} = queryResult_rw
const leafletStore = useLeafletStore()
useEffect(() => {
const markers = data_ro?.get_offers?.map(row => (row.id && row.place_lon && row.place_lat
&& ({id: row.id,
lat: row.place_lat,
lng: row.place_lon,
radius: 1000, // TODO
content: 'TODO'}) || undefined))
leafletStore.setMarkers(filterUndefOrNull(markers))
}, [data_ro])
return <>
<Box sx={{
@ -25,16 +40,16 @@ const HostOfferLookupWrapper = (props: HostOfferLookupWrapperProps) => {
<div style={{minHeight: '2em', display: 'flex'}}>
{ (queryResult_ro.isFetching || queryResult_rw.isFetching) && t('loading…') }
{ (queryResult_ro.error || queryResult_rw.error) && t('An error occurred while trying to get data from the backend.') }
{ (queryResult_ro.data && !queryResult_ro.data.get_offers || queryResult_rw.data && !queryResult_rw.data.get_rw)
{ (data_ro && !data_ro.get_offers || data_rw && !data_rw.get_rw)
&& t('Seems like you have no permissions. Please try to login again.') }
<Login/>
</div>
{queryResult_ro.data && <div
{data_ro && <div
style={{flex: '1 1', height: '100%'}}>
<HostOfferLookupTable
{...props}
data_ro={queryResult_ro.data.get_offers}
data_rw={queryResult_rw.data?.get_rw}
data_ro={data_ro.get_offers}
data_rw={data_rw?.get_rw}
refetch_rw={queryResult_rw.refetch}
/>
</div>}

View File

@ -5,15 +5,18 @@ import 'leaflet/dist/leaflet.css'
import {
LayersControl,
MapContainer,
Marker,
Polygon,
Polyline,
//Marker,
//Polygon,
//Polyline,
Popup,
Circle,
TileLayer,
useMap,
useMapEvent
} from '@monsonjeremy/react-leaflet'
import * as L from 'leaflet'
import { useLeafletStore } from './LeafletStore'
type LeafletMapProps = {onBoundsChange?: (bounds: L.LatLngBounds) => void}
const BoundsChangeListener = ({onBoundsChange}: {onBoundsChange?: (bounds: L.LatLngBounds) => void}) => {
@ -26,7 +29,7 @@ const BoundsChangeListener = ({onBoundsChange}: {onBoundsChange?: (bounds: L.Lat
)
},
[map, onBoundsChange],
);
)
useEffect(() => {
updateBounds()
@ -36,12 +39,14 @@ const BoundsChangeListener = ({onBoundsChange}: {onBoundsChange?: (bounds: L.Lat
useMapEvent('load', (e) => updateBounds())
return null
}
const LeafletMap = ({onBoundsChange}: LeafletMapProps) => {
const [zoom, setZoom] = useState<number>( 8 )
const [position, setPosition] = useState<L.LatLngExpression>( {
lat: 51.0833,
lng: 13.73126,
} )
const leafletStore = useLeafletStore()
return (
<>
@ -80,6 +85,19 @@ const LeafletMap = ({onBoundsChange}: LeafletMapProps) => {
maxNativeZoom={20}
/>
</LayersControl.BaseLayer>
{leafletStore.markers.map(m =>
/** TODO: Maybe a clustered marker would be helpfull, but we loose the possibility of showing the radius (display accuracy of the coordinate).
* Probably the best solution is showing Circle and clustered marker.
**/
<Circle key={m.id}
center={[m.lat, m.lng]}
radius={m.radius}
pathOptions={{color: 'grey'}}>
<Popup><a href={`#${m.id}`}>{ m.content }</a></Popup>
</Circle>
)}
</LayersControl>
</MapContainer>
</>)

View File

@ -0,0 +1,19 @@
import create from 'zustand'
export interface Marker
{id: string,
lat: number,
lng: number,
radius: number, // in meters
content: string // TODO react-child?
}
export interface LeafletState {
markers: Marker[]
setMarkers: (markers: Marker[]) => void
}
export const useLeafletStore = create<LeafletState>(set => ({
markers: [],
setMarkers: (markers: Marker[]) => set( _orig => ({markers}) )
}))