Added Marker for mission
This commit is contained in:
@@ -7,7 +7,11 @@ export const BaseMaps = () => {
|
|||||||
<TileLayer
|
<TileLayer
|
||||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
className="invert-100"
|
/>
|
||||||
|
<TileLayer
|
||||||
|
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||||
|
className="invert-100 grayscale"
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useMapStore } from "_store/mapStore";
|
|||||||
import { MapContainer } from "react-leaflet";
|
import { MapContainer } from "react-leaflet";
|
||||||
import { BaseMaps } from "(dispatch)/_components/map/BaseMaps";
|
import { BaseMaps } from "(dispatch)/_components/map/BaseMaps";
|
||||||
import { ContextMenu } from "(dispatch)/_components/map/ContextMenu";
|
import { ContextMenu } from "(dispatch)/_components/map/ContextMenu";
|
||||||
|
import { MissionMarkers } from "(dispatch)/_components/map/MissionMarkers";
|
||||||
|
|
||||||
export default ({}) => {
|
export default ({}) => {
|
||||||
const { map } = useMapStore();
|
const { map } = useMapStore();
|
||||||
@@ -12,6 +13,7 @@ export default ({}) => {
|
|||||||
<MapContainer className="flex-1" center={map.center} zoom={map.zoom}>
|
<MapContainer className="flex-1" center={map.center} zoom={map.zoom}>
|
||||||
<BaseMaps />
|
<BaseMaps />
|
||||||
<ContextMenu />
|
<ContextMenu />
|
||||||
|
<MissionMarkers />
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { MissionOptionalDefaults } from "@repo/db/zod";
|
||||||
|
import { useMissionsStore } from "_store/missionsStore";
|
||||||
|
import { Icon, Marker as LMarker } from "leaflet";
|
||||||
|
import { House, Route } from "lucide-react";
|
||||||
|
import { RefObject, useEffect, useRef, useState } from "react";
|
||||||
|
import { Marker, Popup, useMap } from "react-leaflet";
|
||||||
|
|
||||||
|
export const MissionMarker = ({
|
||||||
|
mission,
|
||||||
|
}: {
|
||||||
|
mission: MissionOptionalDefaults;
|
||||||
|
}) => {
|
||||||
|
const [zoom, setZoom] = useState(0);
|
||||||
|
const map = useMap();
|
||||||
|
const markerRef = useRef<LMarker<any>>(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
markerRef.current?.openPopup();
|
||||||
|
|
||||||
|
const handleZoom = () => {
|
||||||
|
setZoom(map.getZoom());
|
||||||
|
};
|
||||||
|
map.on("zoom", handleZoom);
|
||||||
|
return () => {
|
||||||
|
map.off("zoom", handleZoom);
|
||||||
|
};
|
||||||
|
}, [map]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Marker
|
||||||
|
ref={markerRef}
|
||||||
|
position={[mission.addressLat, mission.addressLng]}
|
||||||
|
icon={
|
||||||
|
new Icon({
|
||||||
|
iconUrl: "/icons/MissionIcon.png",
|
||||||
|
iconSize: zoom < 8 ? [30, 30] : [50, 50],
|
||||||
|
popupAnchor: [0, 0],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Popup>
|
||||||
|
<div className="absolute z-1000 opacity-100 pointer-events-auto w-[500px] text-white">
|
||||||
|
<div className="bg-amber-600 pt-2 flex gap-1">
|
||||||
|
<div className="p-2 bg-amber-700">
|
||||||
|
<House className="text-sm" />
|
||||||
|
</div>
|
||||||
|
<div className="p-2">
|
||||||
|
<Route />
|
||||||
|
</div>
|
||||||
|
<div className="bg-red-600 flex justify-center items-center text-2xl p-2">
|
||||||
|
{mission.missionCategory}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popup>
|
||||||
|
</Marker>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const MissionMarkers = () => {
|
||||||
|
const { missions } = useMissionsStore();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{missions.map((mission) => (
|
||||||
|
<MissionMarker key={mission.id} mission={mission} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,27 +1,9 @@
|
|||||||
|
import { MissionOptionalDefaults } from "@repo/db/zod";
|
||||||
import { create } from "zustand";
|
import { create } from "zustand";
|
||||||
|
|
||||||
interface Mission {
|
|
||||||
id: string;
|
|
||||||
addressLat: number;
|
|
||||||
addressLng: number;
|
|
||||||
addressStreet: string;
|
|
||||||
addressCity: string;
|
|
||||||
addressZip: string;
|
|
||||||
missionCategory: string;
|
|
||||||
missionKeyword: string;
|
|
||||||
missionSummary: string;
|
|
||||||
missionPatientInfo: string;
|
|
||||||
missionAdditionalInfo: string;
|
|
||||||
hpgAmbulanceState?: "ready" | "arrived" | "onway";
|
|
||||||
hpgFireEngineState?: "ready" | "arrived" | "onway";
|
|
||||||
hpgPoliceState?: "ready" | "arrived" | "onway";
|
|
||||||
hpgLocationLat?: number;
|
|
||||||
hpgLocationLng?: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MissionStore {
|
interface MissionStore {
|
||||||
missions: Mission[];
|
missions: MissionOptionalDefaults[];
|
||||||
setMissions: (missions: Mission[]) => void;
|
setMissions: (missions: MissionOptionalDefaults[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMissionsStore = create<MissionStore>((set) => ({
|
export const useMissionsStore = create<MissionStore>((set) => ({
|
||||||
@@ -34,9 +16,9 @@ export const useMissionsStore = create<MissionStore>((set) => ({
|
|||||||
addressCity: "Berlin",
|
addressCity: "Berlin",
|
||||||
addressZip: "10178",
|
addressZip: "10178",
|
||||||
missionAdditionalInfo: "Additional info",
|
missionAdditionalInfo: "Additional info",
|
||||||
missionCategory: "Category",
|
missionCategory: "AB_Atmung",
|
||||||
missionKeyword: "Keyword",
|
missionKeyword: "Zunehmende Atemnot",
|
||||||
missionPatientInfo: "Patient info",
|
missionPatientInfo: "M/10",
|
||||||
missionSummary: "Summary",
|
missionSummary: "Summary",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -2,3 +2,24 @@
|
|||||||
@plugin "daisyui" {
|
@plugin "daisyui" {
|
||||||
themes: dark, nord;
|
themes: dark, nord;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.leaflet-popup-tip-container {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.leaflet-popup-content-wrapper {
|
||||||
|
background: transparent !important;
|
||||||
|
pointer-events: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-popup-content {
|
||||||
|
width: 0 !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
.leaflet-popup {
|
||||||
|
left: 0 !important;
|
||||||
|
top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.leaflet-popup-close-button {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|||||||
BIN
apps/dispatch/public/icons/MissionIcon.png
Normal file
BIN
apps/dispatch/public/icons/MissionIcon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
24
packages/database/prisma/schema/mission.prisma
Normal file
24
packages/database/prisma/schema/mission.prisma
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
model Mission {
|
||||||
|
id String @id @default(uuid())
|
||||||
|
addressLat Float
|
||||||
|
addressLng Float
|
||||||
|
addressStreet String
|
||||||
|
addressCity String
|
||||||
|
addressZip String
|
||||||
|
missionCategory String
|
||||||
|
missionKeyword String
|
||||||
|
missionSummary String
|
||||||
|
missionPatientInfo String
|
||||||
|
missionAdditionalInfo String
|
||||||
|
hpgAmbulanceState HpgState? @default(ready)
|
||||||
|
hpgFireEngineState HpgState? @default(ready)
|
||||||
|
hpgPoliceState HpgState? @default(ready)
|
||||||
|
hpgLocationLat Float? @default(0)
|
||||||
|
hpgLocationLng Float? @default(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum HpgState {
|
||||||
|
ready
|
||||||
|
arrived
|
||||||
|
onway
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user