This commit is contained in:
PxlLoewe
2025-10-04 19:53:56 +02:00
parent f691eb5f7c
commit 859b8519db
5 changed files with 68 additions and 15 deletions

View File

@@ -6,8 +6,10 @@ export const sendAlert = async (
id: number, id: number,
{ {
stationId, stationId,
desktopOnly,
}: { }: {
stationId?: number; stationId?: number;
desktopOnly?: boolean;
}, },
user: User | "HPG", user: User | "HPG",
): Promise<{ ): Promise<{
@@ -46,10 +48,13 @@ export const sendAlert = async (
}); });
for (const aircraft of connectedAircrafts) { for (const aircraft of connectedAircrafts) {
io.to(`station:${aircraft.stationId}`).emit("mission-alert", { if (!desktopOnly) {
...mission, io.to(`station:${aircraft.stationId}`).emit("mission-alert", {
Stations, ...mission,
}); Stations,
});
}
io.to(`desktop:${aircraft.userId}`).emit("mission-alert", { io.to(`desktop:${aircraft.userId}`).emit("mission-alert", {
missionId: mission.id, missionId: mission.id,
}); });

View File

@@ -113,9 +113,10 @@ router.delete("/:id", async (req, res) => {
router.post("/:id/send-alert", async (req, res) => { router.post("/:id/send-alert", async (req, res) => {
const { id } = req.params; const { id } = req.params;
const { stationId, vehicleName } = req.body as { const { stationId, vehicleName, desktopOnly } = req.body as {
stationId?: number; stationId?: number;
vehicleName?: "RTW" | "POL" | "FW"; vehicleName?: "RTW" | "POL" | "FW";
desktopOnly?: boolean;
}; };
if (!req.user) { if (!req.user) {
@@ -180,7 +181,11 @@ router.post("/:id/send-alert", async (req, res) => {
return; return;
} }
const { connectedAircrafts, mission } = await sendAlert(Number(id), { stationId }, req.user); const { connectedAircrafts, mission } = await sendAlert(
Number(id),
{ stationId, desktopOnly },
req.user,
);
io.to("dispatchers").emit("update-mission", mission); io.to("dispatchers").emit("update-mission", mission);
res.status(200).json({ res.status(200).json({
@@ -189,11 +194,9 @@ router.post("/:id/send-alert", async (req, res) => {
return; return;
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res res.status(500).json({
.status(500) error: `Ein Fehler ist aufgetreten. Bitte melde den Fehler als Bug (${(error as Error).message})`,
.json({ });
error: `Ein Fehler ist aufgetreten. Bitte melde den Fehler als Bug (${(error as Error).message})`,
});
return; return;
} }
}); });

View File

@@ -6,14 +6,17 @@ import { Report } from "../../_components/left/Report";
import { Dme } from "(app)/pilot/_components/dme/Dme"; import { Dme } from "(app)/pilot/_components/dme/Dme";
import dynamic from "next/dynamic"; import dynamic from "next/dynamic";
import { ConnectedDispatcher } from "tracker/_components/ConnectedDispatcher"; import { ConnectedDispatcher } from "tracker/_components/ConnectedDispatcher";
import { useQuery } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import { usePilotConnectionStore } from "_store/pilot/connectionStore"; import { usePilotConnectionStore } from "_store/pilot/connectionStore";
import { getConnectedAircraftsAPI } from "_querys/aircrafts"; import { getConnectedAircraftsAPI } from "_querys/aircrafts";
import { checkSimulatorConnected, useDebounce } from "@repo/shared-components"; import { Button, checkSimulatorConnected, useDebounce } from "@repo/shared-components";
import { SimConnectionAlert } from "(app)/pilot/_components/SimConnectionAlert"; import { SimConnectionAlert } from "(app)/pilot/_components/SimConnectionAlert";
import { SettingsBoard } from "_components/left/SettingsBoard"; import { SettingsBoard } from "_components/left/SettingsBoard";
import { BugReport } from "_components/left/BugReport"; import { BugReport } from "_components/left/BugReport";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { useDmeStore } from "_store/pilot/dmeStore";
import { sendMissionAPI } from "_querys/missions";
import toast from "react-hot-toast";
const Map = dynamic(() => import("_components/map/Map"), { const Map = dynamic(() => import("_components/map/Map"), {
ssr: false, ssr: false,
@@ -21,12 +24,29 @@ const Map = dynamic(() => import("_components/map/Map"), {
const PilotPage = () => { const PilotPage = () => {
const { connectedAircraft, status } = usePilotConnectionStore((state) => state); const { connectedAircraft, status } = usePilotConnectionStore((state) => state);
const { latestMission } = useDmeStore((state) => state);
// Query will be cached anyway, due to this, displayed Markers are in sync with own Aircraft connection-warning // Query will be cached anyway, due to this, displayed Markers are in sync with own Aircraft connection-warning
const { data: aircrafts } = useQuery({ const { data: aircrafts } = useQuery({
queryKey: ["aircrafts"], queryKey: ["aircrafts"],
queryFn: () => getConnectedAircraftsAPI(), queryFn: () => getConnectedAircraftsAPI(),
refetchInterval: 10_000, refetchInterval: 10_000,
}); });
const sendAlertMutation = useMutation({
mutationKey: ["missions"],
mutationFn: (params: {
id: number;
stationId?: number | undefined;
vehicleName?: "RTW" | "POL" | "FW" | undefined;
desktopOnly?: boolean | undefined;
}) => sendMissionAPI(params.id, params),
onError: (error) => {
console.error(error);
toast.error("Fehler beim Alarmieren");
},
onSuccess: (data) => {
toast.success(data.message);
},
});
const [shortlyConnected, setShortlyConnected] = useState(false); const [shortlyConnected, setShortlyConnected] = useState(false);
useDebounce( useDebounce(
() => { () => {
@@ -76,7 +96,27 @@ const PilotPage = () => {
</div> </div>
<div className="flex h-full w-1/3"> <div className="flex h-full w-1/3">
<div className="bg-base-300 flex h-full w-full flex-col p-4"> <div className="bg-base-300 flex h-full w-full flex-col p-4">
<h2 className="card-title mb-2">MRT & DME</h2> <div className="flex justify-between">
<h2 className="card-title mb-2">MRT & DME</h2>
<div
className="tooltip tooltip-left mb-4"
data-tip="Dadurch wird der Einsatz erneut an den Desktop-Client gesendet."
>
<Button
className="btn btn-xs btn-outline"
disabled={!latestMission}
onClick={async () => {
if (!latestMission) return;
await sendAlertMutation.mutateAsync({
id: latestMission.id,
desktopOnly: false,
});
}}
>
Erneut senden
</Button>
</div>
</div>
<div className="card bg-base-200 mb-4 shadow-xl"> <div className="card bg-base-200 mb-4 shadow-xl">
<div className="card-body flex h-full w-full items-center justify-center"> <div className="card-body flex h-full w-full items-center justify-center">
<div className="max-w-150"> <div className="max-w-150">

View File

@@ -55,9 +55,11 @@ export const sendMissionAPI = async (
{ {
stationId, stationId,
vehicleName, vehicleName,
desktopOnly,
}: { }: {
stationId?: number; stationId?: number;
vehicleName?: "RTW" | "POL" | "FW"; vehicleName?: "RTW" | "POL" | "FW";
desktopOnly?: boolean;
}, },
) => { ) => {
const respone = await serverApi.post<{ const respone = await serverApi.post<{
@@ -65,6 +67,7 @@ export const sendMissionAPI = async (
}>(`/mission/${id}/send-alert`, { }>(`/mission/${id}/send-alert`, {
stationId, stationId,
vehicleName, vehicleName,
desktopOnly,
}); });
return respone.data; return respone.data;
}; };

View File

@@ -36,7 +36,7 @@ type SetPageParams =
interface MrtStore { interface MrtStore {
page: SetPageParams["page"]; page: SetPageParams["page"];
latestMission: Mission | null;
lines: DisplayLineProps[]; lines: DisplayLineProps[];
setPage: (pageData: SetPageParams) => void; setPage: (pageData: SetPageParams) => void;
@@ -65,6 +65,7 @@ export const useDmeStore = create<MrtStore>(
}, },
], ],
setLines: (lines) => set({ lines }), setLines: (lines) => set({ lines }),
latestMission: null,
setPage: (pageData) => { setPage: (pageData) => {
if (interval) clearInterval(interval); if (interval) clearInterval(interval);
switch (pageData.page) { switch (pageData.page) {
@@ -122,6 +123,7 @@ export const useDmeStore = create<MrtStore>(
} }
case "mission": { case "mission": {
set({ set({
latestMission: pageData.mission,
page: "mission", page: "mission",
lines: [ lines: [
{ {