improved OSM Element selection
This commit is contained in:
@@ -318,6 +318,17 @@ router.post("/:id/validate-hpg", async (req, res) => {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const newMission = await prisma.mission.update({
|
||||||
|
where: {
|
||||||
|
id: Number(id),
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
hpgValidationState: "PENDING",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
io.to("dispatchers").emit("update-mission", newMission);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
message: "HPG validierung gestartet",
|
message: "HPG validierung gestartet",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,14 @@ import { Popup, useMap } from "react-leaflet";
|
|||||||
|
|
||||||
export const ContextMenu = () => {
|
export const ContextMenu = () => {
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
const { contextMenu, setContextMenu, setSearchElements, setSearchPopup } = useMapStore();
|
const {
|
||||||
|
contextMenu,
|
||||||
|
searchElements,
|
||||||
|
setContextMenu,
|
||||||
|
setSearchElements,
|
||||||
|
setSearchPopup,
|
||||||
|
toggleSearchElementSelection,
|
||||||
|
} = useMapStore();
|
||||||
const { missionFormValues, setMissionFormValues, setOpen, isOpen } = usePannelStore(
|
const { missionFormValues, setMissionFormValues, setOpen, isOpen } = usePannelStore(
|
||||||
(state) => state,
|
(state) => state,
|
||||||
);
|
);
|
||||||
@@ -64,7 +71,9 @@ export const ContextMenu = () => {
|
|||||||
const parsed: OSMWay[] = data.elements
|
const parsed: OSMWay[] = data.elements
|
||||||
.filter((e: any) => e.type === "way")
|
.filter((e: any) => e.type === "way")
|
||||||
.map((e: any) => {
|
.map((e: any) => {
|
||||||
|
const elementInMap = searchElements.find((el) => el.wayID === e.id);
|
||||||
return {
|
return {
|
||||||
|
isSelected: 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);
|
||||||
@@ -125,12 +134,15 @@ export const ContextMenu = () => {
|
|||||||
nodeWay.push([node.lat, node.lon]),
|
nodeWay.push([node.lat, node.lon]),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (closestToContext) {
|
||||||
|
toggleSearchElementSelection(closestToContext.wayID);
|
||||||
|
}
|
||||||
|
|
||||||
setMissionFormValues({
|
setMissionFormValues({
|
||||||
...parsed,
|
...parsed,
|
||||||
state: "draft",
|
state: "draft",
|
||||||
addressLat: contextMenu.lat,
|
addressLat: contextMenu.lat,
|
||||||
addressLng: contextMenu.lng,
|
addressLng: contextMenu.lng,
|
||||||
addressOSMways: [closestToContext],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
map.setView([contextMenu.lat, contextMenu.lng], 18, {
|
map.setView([contextMenu.lat, contextMenu.lng], 18, {
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ const MissionPopupContent = ({
|
|||||||
hpgLocationLat: mission.hpgLocationLat ?? undefined,
|
hpgLocationLat: mission.hpgLocationLat ?? undefined,
|
||||||
hpgLocationLng: mission.hpgLocationLng ?? undefined,
|
hpgLocationLng: mission.hpgLocationLng ?? undefined,
|
||||||
});
|
});
|
||||||
setEditingMission(true, String(mission.id));
|
setEditingMission(true, mission.id);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,18 +1,15 @@
|
|||||||
import { useMapStore } from "_store/mapStore";
|
import { useMapStore } from "_store/mapStore";
|
||||||
import { Marker as LMarker } from "leaflet";
|
|
||||||
import { Fragment, useEffect, useRef } from "react";
|
|
||||||
import { Marker, Polygon, Popup } from "react-leaflet";
|
import { Marker, Polygon, Popup } from "react-leaflet";
|
||||||
import L from "leaflet";
|
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { getMissionsAPI } from "_querys/missions";
|
import { getMissionsAPI } from "_querys/missions";
|
||||||
import { OSMWay } from "@repo/db";
|
|
||||||
import { usePannelStore } from "_store/pannelStore";
|
import { usePannelStore } from "_store/pannelStore";
|
||||||
|
import { OSMWay } from "@repo/db";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
export const SearchElements = () => {
|
export const SearchElements = () => {
|
||||||
const { searchElements, searchPopup, setSearchPopup, setContextMenu, openMissionMarker } =
|
const { searchElements, openMissionMarker, setSearchElements } = useMapStore();
|
||||||
useMapStore();
|
const { isOpen: pannelOpen, editingMissionId } = usePannelStore((state) => state);
|
||||||
const { missionFormValues, setMissionFormValues } = usePannelStore((state) => state);
|
const { data: missions } = useQuery({
|
||||||
const missions = useQuery({
|
|
||||||
queryKey: ["missions"],
|
queryKey: ["missions"],
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
getMissionsAPI({
|
getMissionsAPI({
|
||||||
@@ -26,131 +23,59 @@ export const SearchElements = () => {
|
|||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
const poppupRef = useRef<LMarker>(null);
|
|
||||||
const searchPopupElement = searchElements.find(
|
|
||||||
(element) => element.wayID === searchPopup?.elementId,
|
|
||||||
);
|
|
||||||
|
|
||||||
const SearchElement = ({
|
useEffect(() => {
|
||||||
element,
|
if (pannelOpen) {
|
||||||
isActive = false,
|
const missionEdited = missions?.find((m) => m.id === editingMissionId);
|
||||||
}: {
|
console.log("Mission Edited", missionEdited, editingMissionId, missions);
|
||||||
element: (typeof searchElements)[1];
|
if (missionEdited) {
|
||||||
isActive?: boolean;
|
const elements = missionEdited.addressOSMways.map((e) => ({
|
||||||
}) => {
|
...(e as unknown as OSMWay),
|
||||||
const ref = useRef<L.Polygon>(null);
|
isSelected: true,
|
||||||
|
}));
|
||||||
useEffect(() => {
|
setSearchElements(elements);
|
||||||
if (ref.current) {
|
} else {
|
||||||
ref.current.on("click", () => {
|
setSearchElements([]);
|
||||||
const center = ref.current?.getBounds().getCenter();
|
|
||||||
if (center && searchPopup?.elementId !== element.wayID) {
|
|
||||||
setSearchPopup({
|
|
||||||
lat: center.lat,
|
|
||||||
lng: center.lng,
|
|
||||||
elementId: element.wayID,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
setSearchPopup(null);
|
|
||||||
}
|
|
||||||
setContextMenu(null);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [element.wayID]);
|
} else {
|
||||||
|
const openMissions = openMissionMarker.map((m) => {
|
||||||
|
const mission = missions?.find((mi) => mi.id === m.id);
|
||||||
|
return mission;
|
||||||
|
});
|
||||||
|
const elements = openMissions
|
||||||
|
.filter((m) => m?.addressOSMways)
|
||||||
|
.flatMap((m) =>
|
||||||
|
m?.addressOSMways.map((e) => ({
|
||||||
|
...(e as unknown as OSMWay),
|
||||||
|
isSelected: true,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
setSearchElements(elements.filter((e) => !!e));
|
||||||
|
}
|
||||||
|
}, [openMissionMarker, pannelOpen, missions]);
|
||||||
|
|
||||||
|
const SearchElement = ({ element }: { element: OSMWay }) => {
|
||||||
|
const { toggleSearchElementSelection } = useMapStore();
|
||||||
if (!element.nodes) return null;
|
if (!element.nodes) return null;
|
||||||
return (
|
return (
|
||||||
<Polygon
|
<Polygon
|
||||||
positions={element.nodes.map((node) => [node.lat, node.lon])}
|
positions={element.nodes.map((node) => [node.lat, node.lon])}
|
||||||
color={searchPopup?.elementId === element.wayID || isActive ? "#ff4500" : "#46b7a3"}
|
color={element.isSelected ? "#ff4500" : "#46b7a3"}
|
||||||
eventHandlers={{
|
eventHandlers={{
|
||||||
click: () => {
|
click: () => {
|
||||||
const addressOSMways = missionFormValues?.addressOSMways || [];
|
if (!pannelOpen) return;
|
||||||
|
toggleSearchElementSelection(element.wayID);
|
||||||
addressOSMways.push(JSON.parse(JSON.stringify(element)));
|
|
||||||
|
|
||||||
setMissionFormValues({
|
|
||||||
...missionFormValues,
|
|
||||||
addressOSMways,
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
ref={ref}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const SearchElementPopup = ({ element }: { element: (typeof searchElements)[1] }) => {
|
|
||||||
if (!searchPopup) return null;
|
|
||||||
return (
|
|
||||||
<Popup
|
|
||||||
autoPan={false}
|
|
||||||
position={[searchPopup.lat, searchPopup.lng]}
|
|
||||||
autoClose={false}
|
|
||||||
closeOnClick={false}
|
|
||||||
>
|
|
||||||
<div className="bg-base-100/70 border border-rescuetrack w-[250px] text-white pointer-events-auto p-2">
|
|
||||||
<h3 className="text-lg font-bold">
|
|
||||||
{element.tags?.building === "yes" ? "Gebäude" : element.tags?.building}
|
|
||||||
{!element.tags?.building && "unbekannt"}
|
|
||||||
</h3>
|
|
||||||
<p className="">
|
|
||||||
{element.tags?.["addr:street"]} {element.tags?.["addr:housenumber"]}
|
|
||||||
</p>
|
|
||||||
<p className="">
|
|
||||||
{element.tags?.["addr:suburb"]} {element.tags?.["addr:postcode"]}
|
|
||||||
</p>
|
|
||||||
<div className="flex flex-col gap-2 mt-2">
|
|
||||||
<button className="btn bg-rescuetrack-highlight">Zum Einsatz Hinzufügen</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Popup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{openMissionMarker.map(({ id }) => {
|
|
||||||
const mission = missions.data?.find((m) => m.id === id);
|
|
||||||
if (!mission) return null;
|
|
||||||
return (
|
|
||||||
<Fragment key={`mission-osm-${mission.id}`}>
|
|
||||||
{(mission.addressOSMways as (OSMWay | null)[])
|
|
||||||
.filter((element): element is OSMWay => element !== null)
|
|
||||||
.map((element: OSMWay, i) => (
|
|
||||||
<SearchElement
|
|
||||||
key={`mission-elem-${element.wayID}-${i}`}
|
|
||||||
element={element}
|
|
||||||
isActive
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</Fragment>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
{searchElements.map((element, i) => {
|
{searchElements.map((element, i) => {
|
||||||
if (
|
|
||||||
missions.data?.some(
|
|
||||||
(mission) =>
|
|
||||||
(mission.addressOSMways as (OSMWay | null)[])
|
|
||||||
.filter((e): e is OSMWay => e !== null)
|
|
||||||
.some((e) => e.wayID === element.wayID) &&
|
|
||||||
openMissionMarker.some((m) => m.id === mission.id),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return null;
|
|
||||||
return <SearchElement key={`mission-elem-${element.wayID}-${i}`} element={element} />;
|
return <SearchElement key={`mission-elem-${element.wayID}-${i}`} element={element} />;
|
||||||
})}
|
})}
|
||||||
{searchPopup && (
|
|
||||||
<Marker
|
|
||||||
position={[searchPopup.lat, searchPopup.lng]}
|
|
||||||
ref={poppupRef}
|
|
||||||
icon={new L.DivIcon()}
|
|
||||||
opacity={0}
|
|
||||||
>
|
|
||||||
{!searchPopupElement && <div className="w-20 border border-rescuetrack"></div>}
|
|
||||||
</Marker>
|
|
||||||
)}
|
|
||||||
{searchPopupElement && <SearchElementPopup element={searchPopupElement} />}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ const Einsatzdetails = ({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected";
|
const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected";
|
||||||
const { setMissionFormValues, setOpen, setEditingMission } = usePannelStore((state) => state);
|
const { setMissionFormValues, setOpen, setEditingMission } = usePannelStore((state) => state);
|
||||||
const [ignoreHpg, setIgnoreHpg] = useState(false);
|
const [ignoreHpg, setIgnoreHpg] = useState(false);
|
||||||
@@ -191,11 +192,7 @@ const Einsatzdetails = ({
|
|||||||
<div>
|
<div>
|
||||||
<div className="divider mt-0 mb-0" />
|
<div className="divider mt-0 mb-0" />
|
||||||
|
|
||||||
{HPGValidationRequired(
|
{hpgNeedsAttention && (
|
||||||
mission.missionStationIds,
|
|
||||||
aircrafts,
|
|
||||||
mission.hpgMissionString,
|
|
||||||
) && (
|
|
||||||
<div className="form-control mb-2">
|
<div className="form-control mb-2">
|
||||||
<label className="flex items-center gap-2 cursor-pointer">
|
<label className="flex items-center gap-2 cursor-pointer">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ export interface MapStore {
|
|||||||
id: number;
|
id: number;
|
||||||
tab: "home" | "details" | "patient" | "log";
|
tab: "home" | "details" | "patient" | "log";
|
||||||
}[];
|
}[];
|
||||||
setOpenMissionMarker: (mission: {
|
setOpenMissionMarker: (mission: { open: MapStore["openMissionMarker"]; close: number[] }) => void;
|
||||||
open: MapStore["openMissionMarker"];
|
|
||||||
close: number[];
|
|
||||||
}) => void;
|
|
||||||
openAircraftMarker: {
|
openAircraftMarker: {
|
||||||
id: number;
|
id: number;
|
||||||
tab: "home" | "fms" | "aircraft" | "mission" | "chat";
|
tab: "home" | "fms" | "aircraft" | "mission" | "chat";
|
||||||
@@ -29,6 +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;
|
||||||
setContextMenu: (popup: MapStore["contextMenu"]) => void;
|
setContextMenu: (popup: MapStore["contextMenu"]) => void;
|
||||||
searchPopup: {
|
searchPopup: {
|
||||||
lat: number;
|
lat: number;
|
||||||
@@ -39,10 +37,7 @@ export interface MapStore {
|
|||||||
aircraftTabs: {
|
aircraftTabs: {
|
||||||
[aircraftId: string]: "home" | "fms" | "aircraft" | "mission" | "chat";
|
[aircraftId: string]: "home" | "fms" | "aircraft" | "mission" | "chat";
|
||||||
};
|
};
|
||||||
setAircraftTab: (
|
setAircraftTab: (aircraftId: number, tab: MapStore["aircraftTabs"][number]) => void;
|
||||||
aircraftId: number,
|
|
||||||
tab: MapStore["aircraftTabs"][number],
|
|
||||||
) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useMapStore = create<MapStore>((set, get) => ({
|
export const useMapStore = create<MapStore>((set, get) => ({
|
||||||
@@ -88,6 +83,15 @@ export const useMapStore = create<MapStore>((set, get) => ({
|
|||||||
set(() => ({
|
set(() => ({
|
||||||
searchElements: elements,
|
searchElements: elements,
|
||||||
})),
|
})),
|
||||||
|
toggleSearchElementSelection: (elementId) => {
|
||||||
|
const searchElements = get().searchElements;
|
||||||
|
const element = searchElements.find((e) => e.wayID === elementId);
|
||||||
|
if (!element) return;
|
||||||
|
element.isSelected = !element.isSelected;
|
||||||
|
set(() => ({
|
||||||
|
searchElements: [...searchElements],
|
||||||
|
}));
|
||||||
|
},
|
||||||
aircraftTabs: {},
|
aircraftTabs: {},
|
||||||
setAircraftTab: (aircraftId, tab) =>
|
setAircraftTab: (aircraftId, tab) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ interface PannelStore {
|
|||||||
missionFormValues?: Partial<MissionOptionalDefaults>;
|
missionFormValues?: Partial<MissionOptionalDefaults>;
|
||||||
setMissionFormValues: (values: Partial<MissionOptionalDefaults>) => void;
|
setMissionFormValues: (values: Partial<MissionOptionalDefaults>) => void;
|
||||||
isEditingMission: boolean;
|
isEditingMission: boolean;
|
||||||
editingMissionId: string | null;
|
editingMissionId: number | null;
|
||||||
setEditingMission: (isEditing: boolean, missionId: string | null) => void;
|
setEditingMission: (isEditing: boolean, missionId: number | null) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePannelStore = create<PannelStore>((set) => ({
|
export const usePannelStore = create<PannelStore>((set) => ({
|
||||||
|
|||||||
@@ -5,7 +5,11 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { BellRing, BookmarkPlus } from "lucide-react";
|
import { BellRing, BookmarkPlus } from "lucide-react";
|
||||||
import { Select } from "_components/Select";
|
import { Select } from "_components/Select";
|
||||||
import { KEYWORD_CATEGORY, Mission, missionType, Prisma } from "@repo/db";
|
import { KEYWORD_CATEGORY, Mission, missionType, Prisma } from "@repo/db";
|
||||||
import { MissionOptionalDefaults, MissionOptionalDefaultsSchema } from "@repo/db/zod";
|
import {
|
||||||
|
JsonValueType,
|
||||||
|
MissionOptionalDefaults,
|
||||||
|
MissionOptionalDefaultsSchema,
|
||||||
|
} from "@repo/db/zod";
|
||||||
import { usePannelStore } from "_store/pannelStore";
|
import { usePannelStore } from "_store/pannelStore";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
@@ -23,11 +27,12 @@ import { getConnectedAircraftsAPI } from "_querys/aircrafts";
|
|||||||
import { HPGValidationRequired } from "_helpers/hpgValidationRequired";
|
import { HPGValidationRequired } from "_helpers/hpgValidationRequired";
|
||||||
import { selectRandomHPGMissionSzenery } from "_helpers/selectRandomHPGMission";
|
import { selectRandomHPGMissionSzenery } from "_helpers/selectRandomHPGMission";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
import { cn } from "_helpers/cn";
|
||||||
|
|
||||||
export const MissionForm = () => {
|
export const MissionForm = () => {
|
||||||
const { isEditingMission, editingMissionId, setEditingMission } = usePannelStore();
|
const { isEditingMission, editingMissionId, setEditingMission } = usePannelStore();
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const setSeachOSMElements = useMapStore((s) => s.setSearchElements);
|
const { setSearchElements, searchElements } = useMapStore((s) => s);
|
||||||
|
|
||||||
const { data: keywords } = useQuery({
|
const { data: keywords } = useQuery({
|
||||||
queryKey: ["keywords"],
|
queryKey: ["keywords"],
|
||||||
@@ -120,6 +125,13 @@ export const MissionForm = () => {
|
|||||||
}
|
}
|
||||||
}, [session.data?.user.id, form]);
|
}, [session.data?.user.id, form]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
form.setValue(
|
||||||
|
"addressOSMways",
|
||||||
|
searchElements.filter((e) => e.isSelected) as unknown as JsonValueType[],
|
||||||
|
);
|
||||||
|
}, [searchElements, form]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (missionFormValues) {
|
if (missionFormValues) {
|
||||||
if (Object.keys(missionFormValues).length === 0) {
|
if (Object.keys(missionFormValues).length === 0) {
|
||||||
@@ -135,8 +147,6 @@ export const MissionForm = () => {
|
|||||||
}
|
}
|
||||||
}, [missionFormValues, form, defaultFormValues]);
|
}, [missionFormValues, form, defaultFormValues]);
|
||||||
|
|
||||||
console.log("Mission HPG String", form.watch("hpgMissionString"));
|
|
||||||
|
|
||||||
const saveMission = async (
|
const saveMission = async (
|
||||||
mission: MissionOptionalDefaults,
|
mission: MissionOptionalDefaults,
|
||||||
{ alertWhenValid = false, createNewMission = false } = {},
|
{ alertWhenValid = false, createNewMission = false } = {},
|
||||||
@@ -265,7 +275,7 @@ export const MissionForm = () => {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
form.setValue("type", e.target.value as missionType);
|
form.setValue("type", e.target.value as missionType);
|
||||||
form.setValue("missionKeywordName", KEYWORD_CATEGORY.AB_ATMUNG);
|
form.setValue("missionKeywordName", KEYWORD_CATEGORY.AB_ATMUNG);
|
||||||
form.setValue("missionKeywordAbbreviation", "");
|
form.setValue("missionKeywordAbbreviation", null as any);
|
||||||
form.setValue("hpgMissionString", null);
|
form.setValue("hpgMissionString", null);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -278,15 +288,9 @@ export const MissionForm = () => {
|
|||||||
{...form.register("missionKeywordCategory")}
|
{...form.register("missionKeywordCategory")}
|
||||||
className="select select-primary select-bordered w-full mb-4"
|
className="select select-primary select-bordered w-full mb-4"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
const firstKeyword = keywords?.find(
|
|
||||||
(k) => k.category === form.watch("missionKeywordCategory"),
|
|
||||||
);
|
|
||||||
form.setValue("missionKeywordCategory", e.target.value as string);
|
form.setValue("missionKeywordCategory", e.target.value as string);
|
||||||
form.setValue("missionKeywordName", firstKeyword?.name || (null as any));
|
form.setValue("missionKeywordName", null as any);
|
||||||
form.setValue(
|
form.setValue("missionKeywordAbbreviation", null as any);
|
||||||
"missionKeywordAbbreviation",
|
|
||||||
firstKeyword?.abreviation || (null as any),
|
|
||||||
);
|
|
||||||
form.setValue("hpgMissionString", "");
|
form.setValue("hpgMissionString", "");
|
||||||
}}
|
}}
|
||||||
value={form.watch("missionKeywordCategory") || "please_select"}
|
value={form.watch("missionKeywordCategory") || "please_select"}
|
||||||
@@ -310,7 +314,7 @@ export const MissionForm = () => {
|
|||||||
const keyword = keywords?.find((k) => k.abreviation === e.target.value);
|
const keyword = keywords?.find((k) => k.abreviation === e.target.value);
|
||||||
form.setValue("missionKeywordName", keyword?.name || (null as any));
|
form.setValue("missionKeywordName", keyword?.name || (null as any));
|
||||||
form.setValue("missionKeywordAbbreviation", keyword?.abreviation || (null as any));
|
form.setValue("missionKeywordAbbreviation", keyword?.abreviation || (null as any));
|
||||||
form.setValue("hpgMissionString", "default");
|
form.setValue("hpgMissionString", null);
|
||||||
}}
|
}}
|
||||||
value={form.watch("missionKeywordAbbreviation") || "please_select"}
|
value={form.watch("missionKeywordAbbreviation") || "please_select"}
|
||||||
>
|
>
|
||||||
@@ -332,8 +336,18 @@ export const MissionForm = () => {
|
|||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<select
|
<select
|
||||||
{...form.register("hpgMissionString")}
|
{...form.register("hpgMissionString")}
|
||||||
|
onChange={(e) => {
|
||||||
|
form.setValue("hpgMissionString", e.target.value);
|
||||||
|
if (
|
||||||
|
form.watch("missionAdditionalInfo").length === 0 ||
|
||||||
|
form.watch("missionAdditionalInfo").startsWith("HPG-Szenario:")
|
||||||
|
) {
|
||||||
|
const [name] = e.target.value.split(":");
|
||||||
|
form.setValue("missionAdditionalInfo", `HPG-Szenario: ${name}`);
|
||||||
|
}
|
||||||
|
}}
|
||||||
className="select select-primary select-bordered w-full mb-2"
|
className="select select-primary select-bordered w-full mb-2"
|
||||||
value={form.watch("hpgMissionString") || ""}
|
value={form.watch("hpgMissionString") || "please_select"}
|
||||||
>
|
>
|
||||||
<option disabled value="please_select">
|
<option disabled value="please_select">
|
||||||
Einsatz Szenario auswählen...
|
Einsatz Szenario auswählen...
|
||||||
@@ -379,11 +393,11 @@ export const MissionForm = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{missionFormValues?.addressOSMways?.length && (
|
<p
|
||||||
<p className="text-sm text-info">
|
className={cn("text-sm text-gray-500", form.watch("addressOSMways").length && "text-info")}
|
||||||
In diesem Einsatz gibt es {missionFormValues?.addressOSMways?.length} Gebäude
|
>
|
||||||
</p>
|
In diesem Einsatz gibt es {form.watch("addressOSMways").length} Gebäude
|
||||||
)}
|
</p>
|
||||||
|
|
||||||
<div className="form-control min-h-[140px]">
|
<div className="form-control min-h-[140px]">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
@@ -395,7 +409,7 @@ export const MissionForm = () => {
|
|||||||
try {
|
try {
|
||||||
const newMission = await saveMission(mission);
|
const newMission = await saveMission(mission);
|
||||||
toast.success(`Einsatz ${newMission.id} erfolgreich aktualisiert`);
|
toast.success(`Einsatz ${newMission.id} erfolgreich aktualisiert`);
|
||||||
setSeachOSMElements([]); // Reset search elements
|
setSearchElements([]); // Reset search elements
|
||||||
setEditingMission(false, null); // Reset editing state
|
setEditingMission(false, null); // Reset editing state
|
||||||
form.reset(); // Reset the form
|
form.reset(); // Reset the form
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
@@ -425,7 +439,7 @@ export const MissionForm = () => {
|
|||||||
if (!validationRequired) {
|
if (!validationRequired) {
|
||||||
await sendAlertMutation.mutateAsync(newMission.id);
|
await sendAlertMutation.mutateAsync(newMission.id);
|
||||||
}
|
}
|
||||||
setSeachOSMElements([]); // Reset search elements
|
setSearchElements([]); // Reset search elements
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof AxiosError) {
|
if (error instanceof AxiosError) {
|
||||||
@@ -451,7 +465,7 @@ export const MissionForm = () => {
|
|||||||
createNewMission: true,
|
createNewMission: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
setSeachOSMElements([]); // Reset search elements
|
setSearchElements([]); // Reset search elements
|
||||||
toast.success(`Einsatz ${newMission.publicId} erstellt`);
|
toast.success(`Einsatz ${newMission.publicId} erstellt`);
|
||||||
form.reset();
|
form.reset();
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
|||||||
BIN
apps/dispatch/public/HPG_Solid_Transparent_180x.avif
Normal file
BIN
apps/dispatch/public/HPG_Solid_Transparent_180x.avif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
@@ -1,4 +1,5 @@
|
|||||||
export interface OSMWay {
|
export interface OSMWay {
|
||||||
|
isSelected: boolean;
|
||||||
wayID: number;
|
wayID: number;
|
||||||
tags: Record<string, string>;
|
tags: Record<string, string>;
|
||||||
nodes: {
|
nodes: {
|
||||||
|
|||||||
Reference in New Issue
Block a user