From 92b5ccef5e84d0c894d55f4ecd11bf238217c6a4 Mon Sep 17 00:00:00 2001 From: Wojtek Bednarzak Date: Tue, 22 Aug 2023 00:29:50 +0100 Subject: [PATCH] Add a map view for viewing incidents --- packages/pwa/package.json | 3 + packages/pwa/src/locale/en.ts | 1 + packages/pwa/src/locale/index.ts | 1 + packages/pwa/src/locale/pl.ts | 1 + packages/pwa/src/main.tsx | 4 + packages/pwa/src/routes/home.tsx | 1 + packages/pwa/src/routes/incident/map.tsx | 111 +++++++++++++++++++++++ pnpm-lock.yaml | 9 ++ 8 files changed, 131 insertions(+) create mode 100644 packages/pwa/src/routes/incident/map.tsx diff --git a/packages/pwa/package.json b/packages/pwa/package.json index f05f9d5..60d4eff 100644 --- a/packages/pwa/package.json +++ b/packages/pwa/package.json @@ -21,12 +21,15 @@ "@saferplace/api": "0.0.15", "i18next": "^23.4.4", "i18next-browser-languagedetector": "^7.1.0", + "leaflet": "^1.9.4", "react": "^18.2.0", "react-dom": "^18.2.0", "react-i18next": "^13.1.2", + "react-leaflet": "^4.2.0", "react-router-dom": "^6.15.0" }, "devDependencies": { + "@types/leaflet": "^1.9.0", "@types/react": "^18.2.15", "@types/react-dom": "^18.2.7", "@vitejs/plugin-basic-ssl": "^1.0.1", diff --git a/packages/pwa/src/locale/en.ts b/packages/pwa/src/locale/en.ts index 6632ee8..5c20e0b 100644 --- a/packages/pwa/src/locale/en.ts +++ b/packages/pwa/src/locale/en.ts @@ -12,6 +12,7 @@ export default { useEmail: "Use Email", useBackend: "Use Backend", viewIncidents: "View Incidents", + viewIncident: "View Incident", submitReport: "Submit Report", }, phrases: { diff --git a/packages/pwa/src/locale/index.ts b/packages/pwa/src/locale/index.ts index 78eb913..ee2f5c7 100644 --- a/packages/pwa/src/locale/index.ts +++ b/packages/pwa/src/locale/index.ts @@ -10,6 +10,7 @@ export type TranslationFile = { useEmail: string useBackend: string viewIncidents: string + viewIncident: string submitReport: string }>, phrases: Partial<{ diff --git a/packages/pwa/src/locale/pl.ts b/packages/pwa/src/locale/pl.ts index 931ecca..e0b59e6 100644 --- a/packages/pwa/src/locale/pl.ts +++ b/packages/pwa/src/locale/pl.ts @@ -12,6 +12,7 @@ export default { useEmail: "Użyj e-mail", useBackend: "Użyj Backendu", viewIncidents: "Zobacz Zdarzenia", + viewIncident: "Zobacz Zdarzenie", submitReport: "Zgłos Zdarzenie", }, phrases: { diff --git a/packages/pwa/src/main.tsx b/packages/pwa/src/main.tsx index 680a5f2..aa2701e 100644 --- a/packages/pwa/src/main.tsx +++ b/packages/pwa/src/main.tsx @@ -14,6 +14,7 @@ import Incident from './routes/incident/single' import { incidentLoader, incidentsInRadiusLoader } from './routes/incident/loaders' import Report from './routes/report' import { reportLoader } from './routes/loaders' +import Map from './routes/incident/map' const router = createBrowserRouter([ { @@ -40,6 +41,9 @@ const router = createBrowserRouter([ }, { path: '/login', Component: Login, + }, { + path: '/map', + Component: Map, } ]) diff --git a/packages/pwa/src/routes/home.tsx b/packages/pwa/src/routes/home.tsx index 1817979..39bc78c 100644 --- a/packages/pwa/src/routes/home.tsx +++ b/packages/pwa/src/routes/home.tsx @@ -9,6 +9,7 @@ export default function Home() { {t('action:viewIncidents')} {t('action:submitReport')} + {t('action:viewMap')} ) } diff --git a/packages/pwa/src/routes/incident/map.tsx b/packages/pwa/src/routes/incident/map.tsx new file mode 100644 index 0000000..23d9202 --- /dev/null +++ b/packages/pwa/src/routes/incident/map.tsx @@ -0,0 +1,111 @@ +import { Coordinates, Incident } from "@saferplace/api/incident/v1/incident_pb" +import { MapContainer, Marker, TileLayer, LayerGroup, Popup } from 'react-leaflet' +import { useMapEvents } from 'react-leaflet/hooks' +import { Box, Button, Skeleton } from "@mui/material" +import React from 'react' +import { usePosition } from "../../hooks/position" +import useClient from "../../hooks/client" +import { ViewerService } from "@saferplace/api/viewer/v1/viewer_connect" +import 'leaflet/dist/leaflet.css' +import { useTranslation } from "react-i18next" +import { useNavigate } from "react-router-dom" + +export type Props = { + center?: Coordinates + setCenter: (coordinates: Coordinates) => void + setZoom: (zoom: number) => void +} + +export default function Map() { + const [ initialPosition ] = usePosition() + const [ incidents, setIncidents ] = React.useState([]) + const [ center, setCenter ] = React.useState() + const { t } = useTranslation() + const navigate = useNavigate() + + const [ zoom, setZoom ] = React.useState(13) + const client = useClient(ViewerService) + + React.useEffect(() => { + if (!initialPosition) { + return + } + setCenter(new Coordinates(initialPosition)) + }, [initialPosition]) + + React.useEffect(() => { + if (!center) { + return + } + console.debug(`viewing incident at ${center.lat}, ${center.lon} at zoom ${zoom} with radius ${zoomToRadius(center.lat, zoom)}m`) + client.viewInRadius({ + radius: zoomToRadius(center.lat, zoom), // Static until we know how to convert zoom to radius + center, + }) + .then(resp => setIncidents(resp.incidents)) + .catch(err => console.error(err)) + }, [center]) + + return ( + + { center ? ( + + + + { incidents.map(incident => ( + + + + + + )) } + {/* Enable for debugging */} + {/* */} + + + + ) : ( + + )} + + + + ) +} + +function MapDescendant({setCenter, setZoom }: Props) { + const map = useMapEvents({ + zoomend: () => { + setZoom(map.getZoom()) + }, + moveend: () => { + const {lat, lng} = map.getCenter() + setCenter(new Coordinates({lat, lon: lng})) + }, + }) + return null +} + +function latlon(coords: Coordinates | undefined): [number, number] { + return [coords?.lat || 0, coords?.lon || 0] +} + +function zoomToRadius(lat: number, zoom: number): number { + return ((80_000_000*Math.cos(lat * Math.PI / 180)) / Math.pow(2, zoom)) * 2 +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2a19bf..b732585 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: i18next-browser-languagedetector: specifier: ^7.1.0 version: 7.1.0 + leaflet: + specifier: ^1.9.4 + version: 1.9.4 react: specifier: ^18.2.0 version: 18.2.0 @@ -68,10 +71,16 @@ importers: react-i18next: specifier: ^13.1.2 version: 13.1.2(i18next@23.4.4)(react-dom@18.2.0)(react@18.2.0) + react-leaflet: + specifier: ^4.2.0 + version: 4.2.0(leaflet@1.9.4)(react-dom@18.2.0)(react@18.2.0) react-router-dom: specifier: ^6.15.0 version: 6.15.0(react-dom@18.2.0)(react@18.2.0) devDependencies: + '@types/leaflet': + specifier: ^1.9.0 + version: 1.9.0 '@types/react': specifier: ^18.2.15 version: 18.2.15