Position übernehmen beim bearbeiten von Einsätzen ändert nun die Position von Einsätzen
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { OSMWay } from "@repo/db";
|
import { OSMWay, Prisma } from "@repo/db";
|
||||||
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
||||||
import { useMapStore } from "_store/mapStore";
|
import { useMapStore } from "_store/mapStore";
|
||||||
import { usePannelStore } from "_store/pannelStore";
|
import { usePannelStore } from "_store/pannelStore";
|
||||||
@@ -8,6 +8,8 @@ import { getOsmAddress } from "_querys/osm";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import toast from "react-hot-toast";
|
import toast from "react-hot-toast";
|
||||||
import { Popup, useMap } from "react-leaflet";
|
import { Popup, useMap } from "react-leaflet";
|
||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { editMissionAPI } from "_querys/missions";
|
||||||
|
|
||||||
export const ContextMenu = () => {
|
export const ContextMenu = () => {
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
@@ -19,9 +21,8 @@ export const ContextMenu = () => {
|
|||||||
setSearchPopup,
|
setSearchPopup,
|
||||||
toggleSearchElementSelection,
|
toggleSearchElementSelection,
|
||||||
} = useMapStore();
|
} = useMapStore();
|
||||||
const { missionFormValues, setMissionFormValues, setOpen, isOpen } = usePannelStore(
|
const { missionFormValues, setMissionFormValues, setOpen, isOpen, editingMissionId } =
|
||||||
(state) => state,
|
usePannelStore((state) => state);
|
||||||
);
|
|
||||||
const [showRulerOptions, setShowRulerOptions] = useState(false);
|
const [showRulerOptions, setShowRulerOptions] = useState(false);
|
||||||
const [rulerHover, setRulerHover] = useState(false);
|
const [rulerHover, setRulerHover] = useState(false);
|
||||||
const [rulerOptionsHover, setRulerOptionsHover] = useState(false);
|
const [rulerOptionsHover, setRulerOptionsHover] = useState(false);
|
||||||
@@ -54,7 +55,7 @@ export const ContextMenu = () => {
|
|||||||
|
|
||||||
const einsatzBtnText = missionFormValues && isOpen ? "Position übernehmen" : "Einsatz erstellen";
|
const einsatzBtnText = missionFormValues && isOpen ? "Position übernehmen" : "Einsatz erstellen";
|
||||||
|
|
||||||
const addOSMobjects = async () => {
|
const addOSMobjects = async (ignorePreviosSelected?: boolean) => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
`https://overpass-api.de/api/interpreter?data=${encodeURIComponent(`
|
`https://overpass-api.de/api/interpreter?data=${encodeURIComponent(`
|
||||||
[out:json];
|
[out:json];
|
||||||
@@ -73,7 +74,7 @@ export const ContextMenu = () => {
|
|||||||
.map((e: any) => {
|
.map((e: any) => {
|
||||||
const elementInMap = searchElements.find((el) => el.wayID === e.id);
|
const elementInMap = searchElements.find((el) => el.wayID === e.id);
|
||||||
return {
|
return {
|
||||||
isSelected: elementInMap?.isSelected ?? false,
|
isSelected: ignorePreviosSelected ? false : (elementInMap?.isSelected ?? false),
|
||||||
wayID: e.id,
|
wayID: e.id,
|
||||||
nodes: e.nodes.map((nodeId: string) => {
|
nodes: e.nodes.map((nodeId: string) => {
|
||||||
const node = data.elements.find((element: any) => element.id === nodeId);
|
const node = data.elements.find((element: any) => element.id === nodeId);
|
||||||
@@ -111,7 +112,7 @@ export const ContextMenu = () => {
|
|||||||
style={{ transform: "translateX(-50%)" }}
|
style={{ transform: "translateX(-50%)" }}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const { parsed } = await getOsmAddress(contextMenu.lat, contextMenu.lng);
|
const { parsed } = await getOsmAddress(contextMenu.lat, contextMenu.lng);
|
||||||
const objects = await addOSMobjects();
|
const objects = await addOSMobjects(true);
|
||||||
const closestToContext = objects.reduce((prev, curr) => {
|
const closestToContext = objects.reduce((prev, curr) => {
|
||||||
const prevLat = prev.nodes?.[0]?.lat ?? 0;
|
const prevLat = prev.nodes?.[0]?.lat ?? 0;
|
||||||
const prevLon = prev.nodes?.[0]?.lon ?? 0;
|
const prevLon = prev.nodes?.[0]?.lon ?? 0;
|
||||||
@@ -135,10 +136,11 @@ export const ContextMenu = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (closestToContext) {
|
if (closestToContext) {
|
||||||
toggleSearchElementSelection(closestToContext.wayID);
|
toggleSearchElementSelection(closestToContext.wayID, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
setMissionFormValues({
|
setMissionFormValues({
|
||||||
|
...missionFormValues,
|
||||||
...parsed,
|
...parsed,
|
||||||
state: "draft",
|
state: "draft",
|
||||||
addressLat: contextMenu.lat,
|
addressLat: contextMenu.lat,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Marker, useMap } from "react-leaflet";
|
import { Marker, useMap } from "react-leaflet";
|
||||||
import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet";
|
import { DivIcon, LatLngExpression, Marker as LMarker, Popup as LPopup } from "leaflet";
|
||||||
import { useMapStore } from "_store/mapStore";
|
import { useMapStore } from "_store/mapStore";
|
||||||
import { usePannelStore } from "_store/pannelStore";
|
import { usePannelStore } from "_store/pannelStore";
|
||||||
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { Fragment, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
@@ -175,7 +175,7 @@ const MissionPopupContent = ({
|
|||||||
hpgLocationLat: mission.hpgLocationLat ?? undefined,
|
hpgLocationLat: mission.hpgLocationLat ?? undefined,
|
||||||
hpgLocationLng: mission.hpgLocationLng ?? undefined,
|
hpgLocationLng: mission.hpgLocationLng ?? undefined,
|
||||||
});
|
});
|
||||||
setEditingMission(true, mission.id);
|
setEditingMission(mission.id);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -208,6 +208,7 @@ const MissionPopupContent = ({
|
|||||||
const MissionMarker = ({ mission }: { mission: Mission }) => {
|
const MissionMarker = ({ mission }: { mission: Mission }) => {
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
const [hideMarker, setHideMarker] = useState(false);
|
const [hideMarker, setHideMarker] = useState(false);
|
||||||
|
const { editingMissionId, missionFormValues } = usePannelStore((state) => state);
|
||||||
const markerRef = useRef<LMarker>(null);
|
const markerRef = useRef<LMarker>(null);
|
||||||
const popupRef = useRef<LPopup>(null);
|
const popupRef = useRef<LPopup>(null);
|
||||||
|
|
||||||
@@ -329,11 +330,28 @@ const MissionMarker = ({ mission }: { mission: Mission }) => {
|
|||||||
</div>`;
|
</div>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const markerPosition = useMemo<LatLngExpression>(() => {
|
||||||
|
return [
|
||||||
|
editingMissionId === mission.id && missionFormValues?.addressLat
|
||||||
|
? missionFormValues.addressLat
|
||||||
|
: mission.addressLat,
|
||||||
|
editingMissionId === mission.id && missionFormValues?.addressLng
|
||||||
|
? missionFormValues.addressLng
|
||||||
|
: mission.addressLng,
|
||||||
|
];
|
||||||
|
}, [
|
||||||
|
editingMissionId,
|
||||||
|
mission.addressLat,
|
||||||
|
mission.addressLng,
|
||||||
|
missionFormValues?.addressLat,
|
||||||
|
missionFormValues?.addressLng,
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment key={mission.id}>
|
<Fragment key={mission.id}>
|
||||||
<Marker
|
<Marker
|
||||||
ref={markerRef}
|
ref={markerRef}
|
||||||
position={[mission.addressLat, mission.addressLng]}
|
position={markerPosition}
|
||||||
icon={
|
icon={
|
||||||
new DivIcon({
|
new DivIcon({
|
||||||
iconAnchor: [0, 0],
|
iconAnchor: [0, 0],
|
||||||
@@ -348,7 +366,7 @@ const MissionMarker = ({ mission }: { mission: Mission }) => {
|
|||||||
}}
|
}}
|
||||||
id={`mission-${mission.id.toString()}`}
|
id={`mission-${mission.id.toString()}`}
|
||||||
ref={popupRef}
|
ref={popupRef}
|
||||||
position={[mission.addressLat, mission.addressLng]}
|
position={markerPosition}
|
||||||
autoClose={false}
|
autoClose={false}
|
||||||
closeOnClick={false}
|
closeOnClick={false}
|
||||||
autoPan={false}
|
autoPan={false}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMapStore } from "_store/mapStore";
|
import { useMapStore } from "_store/mapStore";
|
||||||
import { Marker, Polygon, Popup } from "react-leaflet";
|
import { Polygon } from "react-leaflet";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { getMissionsAPI } from "_querys/missions";
|
import { getMissionsAPI } from "_querys/missions";
|
||||||
import { usePannelStore } from "_store/pannelStore";
|
import { usePannelStore } from "_store/pannelStore";
|
||||||
@@ -26,14 +26,7 @@ export const SearchElements = () => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (pannelOpen) {
|
if (pannelOpen) {
|
||||||
const missionEdited = missions?.find((m) => m.id === editingMissionId);
|
// OSM Elements wirden in ContextMenu.tsx gesetzt
|
||||||
if (missionEdited) {
|
|
||||||
const elements = missionEdited.addressOSMways.map((e) => ({
|
|
||||||
...(e as unknown as OSMWay),
|
|
||||||
isSelected: true,
|
|
||||||
}));
|
|
||||||
setSearchElements(elements);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const openMissions = openMissionMarker.map((m) => {
|
const openMissions = openMissionMarker.map((m) => {
|
||||||
const mission = missions?.find((mi) => mi.id === m.id);
|
const mission = missions?.find((mi) => mi.id === m.id);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export interface MapStore {
|
|||||||
}) => void;
|
}) => void;
|
||||||
searchElements: OSMWay[];
|
searchElements: OSMWay[];
|
||||||
setSearchElements: (elements: MapStore["searchElements"]) => void;
|
setSearchElements: (elements: MapStore["searchElements"]) => void;
|
||||||
toggleSearchElementSelection: (elementId: number) => void;
|
toggleSearchElementSelection: (elementId: number, forceState?: boolean) => void;
|
||||||
setContextMenu: (popup: MapStore["contextMenu"]) => void;
|
setContextMenu: (popup: MapStore["contextMenu"]) => void;
|
||||||
searchPopup: {
|
searchPopup: {
|
||||||
lat: number;
|
lat: number;
|
||||||
@@ -83,11 +83,11 @@ export const useMapStore = create<MapStore>((set, get) => ({
|
|||||||
set(() => ({
|
set(() => ({
|
||||||
searchElements: elements,
|
searchElements: elements,
|
||||||
})),
|
})),
|
||||||
toggleSearchElementSelection: (elementId) => {
|
toggleSearchElementSelection: (elementId, forceState) => {
|
||||||
const searchElements = get().searchElements;
|
const searchElements = get().searchElements;
|
||||||
const element = searchElements.find((e) => e.wayID === elementId);
|
const element = searchElements.find((e) => e.wayID === elementId);
|
||||||
if (!element) return;
|
if (!element) return;
|
||||||
element.isSelected = !element.isSelected;
|
element.isSelected = forceState ? forceState : !element.isSelected;
|
||||||
set(() => ({
|
set(() => ({
|
||||||
searchElements: [...searchElements],
|
searchElements: [...searchElements],
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ interface PannelStore {
|
|||||||
setOpen: (isOpen: boolean) => void;
|
setOpen: (isOpen: boolean) => void;
|
||||||
missionFormValues?: Partial<MissionOptionalDefaults>;
|
missionFormValues?: Partial<MissionOptionalDefaults>;
|
||||||
setMissionFormValues: (values: Partial<MissionOptionalDefaults>) => void;
|
setMissionFormValues: (values: Partial<MissionOptionalDefaults>) => void;
|
||||||
isEditingMission: boolean;
|
|
||||||
editingMissionId: number | null;
|
editingMissionId: number | null;
|
||||||
setEditingMission: (isEditing: boolean, missionId: number | null) => void;
|
setEditingMission: (missionId: number | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePannelStore = create<PannelStore>((set) => ({
|
export const usePannelStore = create<PannelStore>((set) => ({
|
||||||
@@ -17,8 +16,6 @@ export const usePannelStore = create<PannelStore>((set) => ({
|
|||||||
setOpen: (isOpen) => set({ isOpen }),
|
setOpen: (isOpen) => set({ isOpen }),
|
||||||
missionFormValues: undefined,
|
missionFormValues: undefined,
|
||||||
setMissionFormValues: (values) => set({ missionFormValues: values }),
|
setMissionFormValues: (values) => set({ missionFormValues: values }),
|
||||||
isEditingMission: false,
|
|
||||||
editingMissionId: null,
|
editingMissionId: null,
|
||||||
setEditingMission: (isEditing, missionId) =>
|
setEditingMission: (missionId) => set({ editingMissionId: missionId }),
|
||||||
set({ isEditingMission: isEditing, editingMissionId: missionId }),
|
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { AxiosError } from "axios";
|
|||||||
import { cn } from "_helpers/cn";
|
import { cn } from "_helpers/cn";
|
||||||
|
|
||||||
export const MissionForm = () => {
|
export const MissionForm = () => {
|
||||||
const { isEditingMission, editingMissionId, setEditingMission } = usePannelStore();
|
const { editingMissionId, setEditingMission } = usePannelStore();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { setSearchElements, searchElements, setContextMenu } = useMapStore((s) => s);
|
const { setSearchElements, searchElements, setContextMenu } = useMapStore((s) => s);
|
||||||
|
|
||||||
@@ -130,7 +130,9 @@ export const MissionForm = () => {
|
|||||||
"addressOSMways",
|
"addressOSMways",
|
||||||
searchElements.filter((e) => e.isSelected) as unknown as JsonValueType[],
|
searchElements.filter((e) => e.isSelected) as unknown as JsonValueType[],
|
||||||
);
|
);
|
||||||
}, [searchElements, form]);
|
}, [searchElements, form, missionFormValues]);
|
||||||
|
|
||||||
|
console.log("addressOSMways", form.watch("addressOSMways"));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (missionFormValues) {
|
if (missionFormValues) {
|
||||||
@@ -139,6 +141,7 @@ export const MissionForm = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (const key in missionFormValues) {
|
for (const key in missionFormValues) {
|
||||||
|
if (key === "addressOSMways") continue; // Skip addressOSMways as it is handled separately
|
||||||
form.setValue(
|
form.setValue(
|
||||||
key as keyof MissionOptionalDefaults,
|
key as keyof MissionOptionalDefaults,
|
||||||
missionFormValues[key as keyof MissionOptionalDefaults],
|
missionFormValues[key as keyof MissionOptionalDefaults],
|
||||||
@@ -416,16 +419,17 @@ export const MissionForm = () => {
|
|||||||
|
|
||||||
<div className="form-control min-h-[140px]">
|
<div className="form-control min-h-[140px]">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{isEditingMission && editingMissionId ? (
|
{editingMissionId ? (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="btn btn-primary flex-1"
|
className="btn btn-primary flex-1"
|
||||||
onClick={form.handleSubmit(async (mission: MissionOptionalDefaults) => {
|
onClick={form.handleSubmit(async (mission: MissionOptionalDefaults) => {
|
||||||
try {
|
try {
|
||||||
|
console.log("Saving mission", mission.addressOSMways);
|
||||||
const newMission = await saveMission(mission);
|
const newMission = await saveMission(mission);
|
||||||
toast.success(`Einsatz ${newMission.id} erfolgreich aktualisiert`);
|
toast.success(`Einsatz ${newMission.id} erfolgreich aktualisiert`);
|
||||||
setSearchElements([]); // Reset search elements
|
setSearchElements([]); // Reset search elements
|
||||||
setEditingMission(false, null); // Reset editing state
|
setEditingMission(null); // Reset editing state
|
||||||
form.reset(); // Reset the form
|
form.reset(); // Reset the form
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { getMissionsAPI } from "_querys/missions";
|
|||||||
|
|
||||||
export const Pannel = () => {
|
export const Pannel = () => {
|
||||||
const { setOpen, setMissionFormValues } = usePannelStore();
|
const { setOpen, setMissionFormValues } = usePannelStore();
|
||||||
const { isEditingMission, setEditingMission, missionFormValues } = usePannelStore();
|
const { editingMissionId, setEditingMission, missionFormValues } = usePannelStore();
|
||||||
const missions = useQuery({
|
const missions = useQuery({
|
||||||
queryKey: ["missions"],
|
queryKey: ["missions"],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
@@ -18,36 +18,29 @@ export const Pannel = () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isEditingMission && missionFormValues) {
|
if (editingMissionId && missionFormValues) {
|
||||||
const mission = missions.data?.find((mission) => mission.id === missionFormValues.id);
|
const mission = missions.data?.find((mission) => mission.id === missionFormValues.id);
|
||||||
if (!mission) {
|
if (!mission) {
|
||||||
setEditingMission(false, null);
|
setEditingMission(null);
|
||||||
setMissionFormValues({});
|
setMissionFormValues({});
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [
|
}, [missions, setMissionFormValues, setEditingMission, setOpen, missionFormValues]);
|
||||||
isEditingMission,
|
|
||||||
missions,
|
|
||||||
setMissionFormValues,
|
|
||||||
setEditingMission,
|
|
||||||
setOpen,
|
|
||||||
missionFormValues,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("flex-1 max-w-[600px] z-9999999")}>
|
<div className={cn("flex-1 max-w-[600px] z-9999999")}>
|
||||||
<div className="bg-base-100 min-h-screen h-full max-h-screen w-full overflow-auto">
|
<div className="bg-base-100 min-h-screen h-full max-h-screen w-full overflow-auto">
|
||||||
<div className="flex flex-row justify-between items-center p-4">
|
<div className="flex flex-row justify-between items-center p-4">
|
||||||
<h1 className="text-xl font-bold flex items-center gap-2">
|
<h1 className="text-xl font-bold flex items-center gap-2">
|
||||||
<Rss /> {isEditingMission ? "Einsatz bearbeiten" : "Neuer Einsatz"}
|
<Rss /> {editingMissionId ? "Einsatz bearbeiten" : "Neuer Einsatz"}
|
||||||
</h1>
|
</h1>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
className="btn btn-ghost btn-sm mr-2 btn-warning"
|
className="btn btn-ghost btn-sm mr-2 btn-warning"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setMissionFormValues({});
|
setMissionFormValues({});
|
||||||
setEditingMission(false, null);
|
setEditingMission(null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Trash2Icon size={18} />
|
<Trash2Icon size={18} />
|
||||||
@@ -56,7 +49,7 @@ export const Pannel = () => {
|
|||||||
className="btn"
|
className="btn"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
setEditingMission(false, null);
|
setEditingMission(null);
|
||||||
setMissionFormValues({});
|
setMissionFormValues({});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user