dev
This commit is contained in:
@@ -96,6 +96,7 @@ export const handleConnectPilot =
|
|||||||
lastHeartbeat: debug ? nowPlus2h.toISOString() : undefined,
|
lastHeartbeat: debug ? nowPlus2h.toISOString() : undefined,
|
||||||
posLat: randomPos?.lat,
|
posLat: randomPos?.lat,
|
||||||
posLng: randomPos?.lng,
|
posLng: randomPos?.lng,
|
||||||
|
posXplanePluginActive: debug ? true : undefined,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ export const MissionForm = () => {
|
|||||||
hpgSelectedMissionString: null,
|
hpgSelectedMissionString: null,
|
||||||
hpg: null,
|
hpg: null,
|
||||||
missionLog: [],
|
missionLog: [],
|
||||||
|
xPlaneObjects: [],
|
||||||
}) as MissionOptionalDefaults,
|
}) as MissionOptionalDefaults,
|
||||||
[session.data?.user.id],
|
[session.data?.user.id],
|
||||||
);
|
);
|
||||||
@@ -415,6 +416,12 @@ export const MissionForm = () => {
|
|||||||
In diesem Einsatz gibt es {form.watch("addressOSMways").length} Gebäude
|
In diesem Einsatz gibt es {form.watch("addressOSMways").length} Gebäude
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p
|
||||||
|
className={cn("text-sm text-gray-500", form.watch("addressOSMways").length && "text-info")}
|
||||||
|
>
|
||||||
|
In diesem Einsatz gibt es {form.watch("xPlaneObjects").length} Objekte
|
||||||
|
</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">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -3,15 +3,32 @@ import { OSMWay } 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";
|
||||||
import { MapPin, MapPinned, Radius, Ruler, Search, RulerDimensionLine, Scan } from "lucide-react";
|
import { XplaneObject } from "@repo/db";
|
||||||
|
import {
|
||||||
|
MapPin,
|
||||||
|
MapPinned,
|
||||||
|
Radius,
|
||||||
|
Search,
|
||||||
|
RulerDimensionLine,
|
||||||
|
Scan,
|
||||||
|
Car,
|
||||||
|
Ambulance,
|
||||||
|
} from "lucide-react";
|
||||||
import { getOsmAddress } from "_querys/osm";
|
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 { findClosestPolygon } from "_helpers/findClosestPolygon";
|
import { findClosestPolygon } from "_helpers/findClosestPolygon";
|
||||||
|
import { xPlaneObjectsAvailable } from "_helpers/xPlaneObjectsAvailable";
|
||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
|
import { getConnectedAircraftsAPI } from "_querys/aircrafts";
|
||||||
|
|
||||||
export const ContextMenu = () => {
|
export const ContextMenu = () => {
|
||||||
const map = useMap();
|
const map = useMap();
|
||||||
|
const { data: aircrafts } = useQuery({
|
||||||
|
queryKey: ["connectedAircrafts"],
|
||||||
|
queryFn: getConnectedAircraftsAPI,
|
||||||
|
});
|
||||||
const {
|
const {
|
||||||
contextMenu,
|
contextMenu,
|
||||||
searchElements,
|
searchElements,
|
||||||
@@ -150,9 +167,12 @@ export const ContextMenu = () => {
|
|||||||
style={{ transform: "translateY(-50%)" }}
|
style={{ transform: "translateY(-50%)" }}
|
||||||
onMouseEnter={() => setRulerHover(true)}
|
onMouseEnter={() => setRulerHover(true)}
|
||||||
onMouseLeave={() => setRulerHover(false)}
|
onMouseLeave={() => setRulerHover(false)}
|
||||||
disabled
|
disabled={
|
||||||
|
!isPannelOpen ||
|
||||||
|
!xPlaneObjectsAvailable(missionFormValues?.missionStationIds, aircrafts)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<Ruler size={20} />
|
<Car size={20} />
|
||||||
</button>
|
</button>
|
||||||
{/* Bottom Button */}
|
{/* Bottom Button */}
|
||||||
<button
|
<button
|
||||||
@@ -181,40 +201,31 @@ export const ContextMenu = () => {
|
|||||||
{/* Ruler Options - shown when Ruler button is hovered or options are hovered */}
|
{/* Ruler Options - shown when Ruler button is hovered or options are hovered */}
|
||||||
{showRulerOptions && (
|
{showRulerOptions && (
|
||||||
<div
|
<div
|
||||||
className="pointer-events-auto absolute flex flex-col items-center"
|
className="pointer-events-auto absolute -left-[100px] top-1/2 z-10 flex h-[200px] w-[120px] -translate-y-1/2 flex-col items-center justify-center py-5"
|
||||||
style={{
|
|
||||||
left: "-100px", // position to the right of the left button
|
|
||||||
top: "50%",
|
|
||||||
transform: "translateY(-50%)",
|
|
||||||
zIndex: 10,
|
|
||||||
width: "120px", // Make the hover area wider
|
|
||||||
height: "200px", // Make the hover area taller
|
|
||||||
padding: "20px 0", // Add vertical padding
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "center",
|
|
||||||
pointerEvents: "auto",
|
|
||||||
}}
|
|
||||||
onMouseEnter={() => setRulerOptionsHover(true)}
|
onMouseEnter={() => setRulerOptionsHover(true)}
|
||||||
onMouseLeave={() => setRulerOptionsHover(false)}
|
onMouseLeave={() => setRulerOptionsHover(false)}
|
||||||
>
|
>
|
||||||
<div
|
<div className="flex w-full flex-col">
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
flexDirection: "column",
|
|
||||||
width: "100%",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
className="btn btn-circle bg-rescuetrack tooltip tooltip-left tooltip-accent mb-2 h-10 w-10 opacity-80"
|
className="btn btn-circle bg-rescuetrack tooltip tooltip-left tooltip-accent mb-2 h-10 w-10 translate-x-full opacity-80"
|
||||||
data-tip="Strecke Messen"
|
data-tip="Rettungswagen Platzieren"
|
||||||
style={{
|
|
||||||
transform: "translateX(100%)",
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
/* ... */
|
console.log("Add Ambulance");
|
||||||
|
setMissionFormValues({
|
||||||
|
...missionFormValues,
|
||||||
|
xPlaneObjects: [
|
||||||
|
...(missionFormValues?.xPlaneObjects ?? []),
|
||||||
|
{
|
||||||
|
objectName: "test",
|
||||||
|
alt: 0,
|
||||||
|
lat: contextMenu.lat,
|
||||||
|
lon: contextMenu.lng,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RulerDimensionLine size={20} />
|
<Ambulance size={20} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-circle bg-rescuetrack tooltip tooltip-left tooltip-accent mb-2 h-10 w-10 opacity-80"
|
className="btn btn-circle bg-rescuetrack tooltip tooltip-left tooltip-accent mb-2 h-10 w-10 opacity-80"
|
||||||
@@ -226,11 +237,8 @@ export const ContextMenu = () => {
|
|||||||
<Radius size={20} />
|
<Radius size={20} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn btn-circle bg-rescuetrack tooltip tooltip-left tooltip-accent h-10 w-10 opacity-80"
|
className="btn btn-circle bg-rescuetrack tooltip tooltip-left tooltip-accent h-10 w-10 translate-x-full opacity-80"
|
||||||
data-tip="Fläche Messen"
|
data-tip="Fläche Messen"
|
||||||
style={{
|
|
||||||
transform: "translateX(100%)",
|
|
||||||
}}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
/* ... */
|
/* ... */
|
||||||
}}
|
}}
|
||||||
|
|||||||
3
apps/dispatch/app/_components/map/XPlaneObject.tsx
Normal file
3
apps/dispatch/app/_components/map/XPlaneObject.tsx
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export const XPlaneObjects = () => {
|
||||||
|
return <div>XPlaneObjects</div>;
|
||||||
|
};
|
||||||
12
apps/dispatch/app/_helpers/xPlaneObjectsAvailable.ts
Normal file
12
apps/dispatch/app/_helpers/xPlaneObjectsAvailable.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { ConnectedAircraft } from "@repo/db";
|
||||||
|
|
||||||
|
export const xPlaneObjectsAvailable = (
|
||||||
|
missionStationIds?: number[],
|
||||||
|
aircrafts?: ConnectedAircraft[],
|
||||||
|
) => {
|
||||||
|
return missionStationIds?.some((id) => {
|
||||||
|
const aircraft = aircrafts?.find((a) => a.stationId === id);
|
||||||
|
|
||||||
|
return aircraft?.posXplanePluginActive;
|
||||||
|
});
|
||||||
|
};
|
||||||
7
packages/database/prisma/json/MissionXplaneObjects.ts
Normal file
7
packages/database/prisma/json/MissionXplaneObjects.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export interface XplaneObject {
|
||||||
|
objectName: string;
|
||||||
|
lat: number;
|
||||||
|
lon: number;
|
||||||
|
heading: number;
|
||||||
|
alt: number;
|
||||||
|
}
|
||||||
@@ -3,3 +3,4 @@ export * from "./MissionVehicleLog";
|
|||||||
export * from "./User";
|
export * from "./User";
|
||||||
export * from "./OSMway";
|
export * from "./OSMway";
|
||||||
export * from "./SocketEvents";
|
export * from "./SocketEvents";
|
||||||
|
export * from "./MissionXplaneObjects";
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Mission" ADD COLUMN "xPlaneObjects" JSONB[] DEFAULT ARRAY[]::JSONB[];
|
||||||
@@ -19,6 +19,7 @@ model Mission {
|
|||||||
missionStationIds Int[] @default([])
|
missionStationIds Int[] @default([])
|
||||||
missionStationUserIds String[] @default([])
|
missionStationUserIds String[] @default([])
|
||||||
missionLog Json[] @default([])
|
missionLog Json[] @default([])
|
||||||
|
xPlaneObjects Json[] @default([])
|
||||||
hpgMissionString String?
|
hpgMissionString String?
|
||||||
hpgSelectedMissionString String?
|
hpgSelectedMissionString String?
|
||||||
hpgAmbulanceState HpgState? @default(NOT_REQUESTED)
|
hpgAmbulanceState HpgState? @default(NOT_REQUESTED)
|
||||||
|
|||||||
Reference in New Issue
Block a user