XPlane objecte können wegebt und per rechts-click gelöscht werden
This commit is contained in:
@@ -117,7 +117,7 @@ export const MissionForm = () => {
|
||||
resolver: zodResolver(MissionOptionalDefaultsSchema),
|
||||
defaultValues: defaultFormValues,
|
||||
});
|
||||
const { missionFormValues, setOpen } = usePannelStore((state) => state);
|
||||
const { missionFormValues, setOpen, setMissionFormValues } = usePannelStore((state) => state);
|
||||
|
||||
const validationRequired =
|
||||
HPGValidationRequired(
|
||||
@@ -156,6 +156,21 @@ export const MissionForm = () => {
|
||||
}
|
||||
}, [missionFormValues, form, defaultFormValues]);
|
||||
|
||||
// Sync form state to store (avoid infinity loops by using watch)
|
||||
useEffect(() => {
|
||||
const subscription = form.watch((values) => {
|
||||
// Only update store if values actually changed to prevent loops
|
||||
const currentStoreValues = JSON.stringify(missionFormValues);
|
||||
const newFormValues = JSON.stringify(values);
|
||||
|
||||
if (currentStoreValues !== newFormValues) {
|
||||
setMissionFormValues(values as MissionOptionalDefaults);
|
||||
}
|
||||
});
|
||||
|
||||
return () => subscription.unsubscribe();
|
||||
}, [form, setMissionFormValues, missionFormValues]);
|
||||
|
||||
const saveMission = async (
|
||||
mission: MissionOptionalDefaults,
|
||||
{ alertWhenValid = false, createNewMission = false } = {},
|
||||
@@ -449,7 +464,11 @@ export const MissionForm = () => {
|
||||
setSearchElements([]); // Reset search elements
|
||||
setEditingMission(null);
|
||||
setContextMenu(null);
|
||||
toast.success(`Einsatz ${newMission.publicId} erstellt`);
|
||||
if (editingMissionId) {
|
||||
toast.success(`Einsatz ${newMission.publicId} bearbeitet`);
|
||||
} else {
|
||||
toast.success(`Einsatz ${newMission.publicId} erstellt`);
|
||||
}
|
||||
form.reset();
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
@@ -474,7 +493,11 @@ export const MissionForm = () => {
|
||||
|
||||
setSearchElements([]); // Reset search elements
|
||||
setContextMenu(null);
|
||||
toast.success(`Einsatz ${newMission.publicId} erstellt`);
|
||||
if (editingMissionId) {
|
||||
toast.success(`Einsatz ${newMission.publicId} bearbeitet`);
|
||||
} else {
|
||||
toast.success(`Einsatz ${newMission.publicId} erstellt`);
|
||||
}
|
||||
form.reset();
|
||||
setOpen(false);
|
||||
} catch (error) {
|
||||
|
||||
@@ -201,7 +201,6 @@ export const ContextMenu = () => {
|
||||
className="btn btn-circle bg-rescuetrack tooltip tooltip-left tooltip-accent mb-2 ml-[30px] h-10 w-10 opacity-80"
|
||||
data-tip="Rettungswagen platzieren"
|
||||
onClick={() => {
|
||||
console.log("Add Ambulance");
|
||||
setMissionFormValues({
|
||||
...missionFormValues,
|
||||
xPlaneObjects: [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
import { usePannelStore } from "_store/pannelStore";
|
||||
import { Marker } from "react-leaflet";
|
||||
import { Marker, useMap } from "react-leaflet";
|
||||
import L from "leaflet";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getMissionsAPI } from "_querys/missions";
|
||||
@@ -8,12 +8,13 @@ import { HPGValidationRequired } from "_helpers/hpgValidationRequired";
|
||||
import { getConnectedAircraftsAPI } from "_querys/aircrafts";
|
||||
import { useMapStore } from "_store/mapStore";
|
||||
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
||||
import { is } from "date-fns/locale";
|
||||
import { XplaneObject } from "@repo/db";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export const MapAdditionals = () => {
|
||||
const { isOpen, missionFormValues } = usePannelStore((state) => state);
|
||||
const { isOpen, missionFormValues, setMissionFormValues } = usePannelStore((state) => state);
|
||||
const dispatcherConnectionState = useDispatchConnectionStore((state) => state.status);
|
||||
const { openMissionMarker } = useMapStore((state) => state);
|
||||
|
||||
const { data: missions = [] } = useQuery({
|
||||
queryKey: ["missions"],
|
||||
@@ -23,13 +24,28 @@ export const MapAdditionals = () => {
|
||||
}),
|
||||
refetchInterval: 10_000,
|
||||
});
|
||||
const mapStore = useMapStore((state) => state);
|
||||
const { setOpenMissionMarker } = useMapStore((state) => state);
|
||||
const [showDetailedAdditionals, setShowDetailedAdditionals] = useState(false);
|
||||
|
||||
const { data: aircrafts } = useQuery({
|
||||
queryKey: ["aircrafts"],
|
||||
queryFn: () => getConnectedAircraftsAPI(),
|
||||
refetchInterval: 10000,
|
||||
});
|
||||
const leafletMap = useMap();
|
||||
|
||||
useEffect(() => {
|
||||
const handleZoomEnd = () => {
|
||||
const currentZoom = leafletMap.getZoom();
|
||||
setShowDetailedAdditionals(currentZoom > 10);
|
||||
};
|
||||
|
||||
leafletMap.on("zoomend", handleZoomEnd);
|
||||
|
||||
return () => {
|
||||
leafletMap.off("zoomend", handleZoomEnd);
|
||||
};
|
||||
}, [leafletMap]);
|
||||
|
||||
const markersNeedingAttention = missions.filter(
|
||||
(m) =>
|
||||
@@ -39,9 +55,11 @@ export const MapAdditionals = () => {
|
||||
m.hpgLocationLat &&
|
||||
dispatcherConnectionState === "connected" &&
|
||||
m.hpgLocationLng &&
|
||||
mapStore.openMissionMarker.find((openMission) => openMission.id === m.id),
|
||||
openMissionMarker.find((openMission) => openMission.id === m.id),
|
||||
);
|
||||
|
||||
console.log("markersNeedingAttention", showDetailedAdditionals);
|
||||
|
||||
return (
|
||||
<>
|
||||
{missionFormValues?.addressLat && missionFormValues?.addressLng && isOpen && (
|
||||
@@ -55,6 +73,24 @@ export const MapAdditionals = () => {
|
||||
interactive={false}
|
||||
/>
|
||||
)}
|
||||
{showDetailedAdditionals &&
|
||||
openMissionMarker.map((mission) => {
|
||||
if (missionFormValues?.id === mission.id) return null;
|
||||
const missionData = missions.find((m) => m.id === mission.id);
|
||||
if (!missionData?.addressLat || !missionData?.addressLng) return null;
|
||||
return (missionData.xPlaneObjects as unknown as XplaneObject[]).map((obj, index) => (
|
||||
<Marker
|
||||
key={`${mission.id}-additional-${index}`}
|
||||
position={[obj.lat, obj.lon]}
|
||||
icon={L.icon({
|
||||
iconUrl: `/icons/${obj.objectName}.png`,
|
||||
iconSize: [40, 40],
|
||||
iconAnchor: [20, 35],
|
||||
})}
|
||||
interactive={false}
|
||||
/>
|
||||
));
|
||||
})}
|
||||
{isOpen &&
|
||||
missionFormValues?.xPlaneObjects &&
|
||||
(missionFormValues.xPlaneObjects as unknown as XplaneObject[]).map((obj, index) => (
|
||||
@@ -66,7 +102,33 @@ export const MapAdditionals = () => {
|
||||
iconSize: [40, 40],
|
||||
iconAnchor: [20, 35],
|
||||
})}
|
||||
interactive={false}
|
||||
draggable={true}
|
||||
eventHandlers={{
|
||||
dragend: (e) => {
|
||||
const marker = e.target;
|
||||
const position = marker.getLatLng();
|
||||
console.log("Marker dragged to:", position);
|
||||
setMissionFormValues({
|
||||
...missionFormValues,
|
||||
xPlaneObjects: (missionFormValues.xPlaneObjects as unknown as XplaneObject[]).map(
|
||||
(obj, objIndex) =>
|
||||
objIndex === index ? { ...obj, lat: position.lat, lon: position.lng } : obj,
|
||||
),
|
||||
});
|
||||
},
|
||||
|
||||
contextmenu: (e) => {
|
||||
e.originalEvent.preventDefault();
|
||||
const updatedObjects = (
|
||||
missionFormValues.xPlaneObjects as unknown as XplaneObject[]
|
||||
).filter((_, objIndex) => objIndex !== index);
|
||||
setMissionFormValues({
|
||||
...missionFormValues,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
xPlaneObjects: updatedObjects as unknown as any[],
|
||||
});
|
||||
},
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{markersNeedingAttention.map((mission) => (
|
||||
@@ -80,7 +142,7 @@ export const MapAdditionals = () => {
|
||||
})}
|
||||
eventHandlers={{
|
||||
click: () =>
|
||||
mapStore.setOpenMissionMarker({
|
||||
setOpenMissionMarker({
|
||||
open: [
|
||||
{
|
||||
id: mission.id,
|
||||
|
||||
Reference in New Issue
Block a user