frontend: visualize markers on map
This commit is contained in:
parent
13e493f5d1
commit
687e79b3c4
|
@ -1,9 +1,11 @@
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { useGetOffersQuery, useGetRwQuery } from "../../codegen/generates"
|
import { useGetOffersQuery, useGetRwQuery } from "../../codegen/generates"
|
||||||
import HostOfferLookupTable, {HostOfferLookupTableProps} from "./HostOfferLookupTable"
|
import HostOfferLookupTable, {HostOfferLookupTableProps} from "./HostOfferLookupTable"
|
||||||
import { Box } from "@mui/material"
|
import { Box } from "@mui/material"
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Login, useAuthStore } from '../Login'
|
import { Login, useAuthStore } from '../Login'
|
||||||
|
import { useLeafletStore } from './LeafletStore'
|
||||||
|
import { filterUndefOrNull } from '../util/notEmpty'
|
||||||
|
|
||||||
type HostOfferLookupWrapperProps = Partial<HostOfferLookupTableProps>
|
type HostOfferLookupWrapperProps = Partial<HostOfferLookupTableProps>
|
||||||
|
|
||||||
|
@ -13,8 +15,21 @@ const HostOfferLookupWrapper = (props: HostOfferLookupWrapperProps) => {
|
||||||
|
|
||||||
const staleTimeMinutes_ro = 5
|
const staleTimeMinutes_ro = 5
|
||||||
const staleTimeMinutes_rw = 1
|
const staleTimeMinutes_rw = 1
|
||||||
const queryResult_ro = useGetOffersQuery({auth}, {staleTime: staleTimeMinutes_ro * 60 * 1000})
|
const queryResult_ro = useGetOffersQuery({auth}, {enabled: !!auth.jwt, staleTime: staleTimeMinutes_ro * 60 * 1000})
|
||||||
const queryResult_rw = useGetRwQuery({auth}, {staleTime: staleTimeMinutes_rw * 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 <>
|
return <>
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
|
@ -25,16 +40,16 @@ const HostOfferLookupWrapper = (props: HostOfferLookupWrapperProps) => {
|
||||||
<div style={{minHeight: '2em', display: 'flex'}}>
|
<div style={{minHeight: '2em', display: 'flex'}}>
|
||||||
{ (queryResult_ro.isFetching || queryResult_rw.isFetching) && t('loading…') }
|
{ (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.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.') }
|
&& t('Seems like you have no permissions. Please try to login again.') }
|
||||||
<Login/>
|
<Login/>
|
||||||
</div>
|
</div>
|
||||||
{queryResult_ro.data && <div
|
{data_ro && <div
|
||||||
style={{flex: '1 1', height: '100%'}}>
|
style={{flex: '1 1', height: '100%'}}>
|
||||||
<HostOfferLookupTable
|
<HostOfferLookupTable
|
||||||
{...props}
|
{...props}
|
||||||
data_ro={queryResult_ro.data.get_offers}
|
data_ro={data_ro.get_offers}
|
||||||
data_rw={queryResult_rw.data?.get_rw}
|
data_rw={data_rw?.get_rw}
|
||||||
refetch_rw={queryResult_rw.refetch}
|
refetch_rw={queryResult_rw.refetch}
|
||||||
/>
|
/>
|
||||||
</div>}
|
</div>}
|
||||||
|
|
|
@ -5,15 +5,18 @@ import 'leaflet/dist/leaflet.css'
|
||||||
import {
|
import {
|
||||||
LayersControl,
|
LayersControl,
|
||||||
MapContainer,
|
MapContainer,
|
||||||
Marker,
|
//Marker,
|
||||||
Polygon,
|
//Polygon,
|
||||||
Polyline,
|
//Polyline,
|
||||||
Popup,
|
Popup,
|
||||||
|
Circle,
|
||||||
TileLayer,
|
TileLayer,
|
||||||
useMap,
|
useMap,
|
||||||
useMapEvent
|
useMapEvent
|
||||||
} from '@monsonjeremy/react-leaflet'
|
} from '@monsonjeremy/react-leaflet'
|
||||||
import * as L from 'leaflet'
|
import * as L from 'leaflet'
|
||||||
|
import { useLeafletStore } from './LeafletStore'
|
||||||
|
|
||||||
type LeafletMapProps = {onBoundsChange?: (bounds: L.LatLngBounds) => void}
|
type LeafletMapProps = {onBoundsChange?: (bounds: L.LatLngBounds) => void}
|
||||||
|
|
||||||
const BoundsChangeListener = ({onBoundsChange}: {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],
|
[map, onBoundsChange],
|
||||||
);
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateBounds()
|
updateBounds()
|
||||||
|
@ -36,12 +39,14 @@ const BoundsChangeListener = ({onBoundsChange}: {onBoundsChange?: (bounds: L.Lat
|
||||||
useMapEvent('load', (e) => updateBounds())
|
useMapEvent('load', (e) => updateBounds())
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const LeafletMap = ({onBoundsChange}: LeafletMapProps) => {
|
const LeafletMap = ({onBoundsChange}: LeafletMapProps) => {
|
||||||
const [zoom, setZoom] = useState<number>( 8 )
|
const [zoom, setZoom] = useState<number>( 8 )
|
||||||
const [position, setPosition] = useState<L.LatLngExpression>( {
|
const [position, setPosition] = useState<L.LatLngExpression>( {
|
||||||
lat: 51.0833,
|
lat: 51.0833,
|
||||||
lng: 13.73126,
|
lng: 13.73126,
|
||||||
} )
|
} )
|
||||||
|
const leafletStore = useLeafletStore()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -80,6 +85,19 @@ const LeafletMap = ({onBoundsChange}: LeafletMapProps) => {
|
||||||
maxNativeZoom={20}
|
maxNativeZoom={20}
|
||||||
/>
|
/>
|
||||||
</LayersControl.BaseLayer>
|
</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>
|
</LayersControl>
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
</>)
|
</>)
|
||||||
|
|
|
@ -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}) )
|
||||||
|
}))
|
Loading…
Reference in New Issue