154 lines
5.0 KiB
TypeScript
154 lines
5.0 KiB
TypeScript
"use client";
|
|
|
|
import { Mrt } from "(app)/pilot/_components/mrt/Mrt";
|
|
import { Chat } from "../../_components/left/Chat";
|
|
import { Report } from "../../_components/left/Report";
|
|
import { Dme } from "(app)/pilot/_components/dme/Dme";
|
|
import dynamic from "next/dynamic";
|
|
import { ConnectedDispatcher } from "tracker/_components/ConnectedDispatcher";
|
|
import { useMutation, useQuery } from "@tanstack/react-query";
|
|
import { usePilotConnectionStore } from "_store/pilot/connectionStore";
|
|
import { getConnectedAircraftsAPI } from "_querys/aircrafts";
|
|
import { Button, checkSimulatorConnected, useDebounce } from "@repo/shared-components";
|
|
import { SimConnectionAlert } from "(app)/pilot/_components/SimConnectionAlert";
|
|
import { SettingsBoard } from "_components/left/SettingsBoard";
|
|
import { BugReport } from "_components/left/BugReport";
|
|
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"), {
|
|
ssr: false,
|
|
});
|
|
|
|
const PilotPage = () => {
|
|
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
|
|
const { data: aircrafts } = useQuery({
|
|
queryKey: ["aircrafts"],
|
|
queryFn: () => getConnectedAircraftsAPI(),
|
|
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);
|
|
useDebounce(
|
|
() => {
|
|
if (status === "connected") {
|
|
setShortlyConnected(false);
|
|
}
|
|
},
|
|
30_000,
|
|
[status],
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (status === "connected") {
|
|
setShortlyConnected(true);
|
|
}
|
|
}, [status]);
|
|
|
|
const ownAircraft = aircrafts?.find((aircraft) => aircraft.id === connectedAircraft?.id);
|
|
const simulatorConnected = ownAircraft ? checkSimulatorConnected(ownAircraft) : false;
|
|
return (
|
|
<div className="ease relative flex h-screen w-full flex-1 overflow-hidden transition-all duration-500">
|
|
{/* <MapToastCard2 /> */}
|
|
<div className="relative flex h-full w-full flex-1">
|
|
<div className="absolute left-0 top-1/2 z-20 flex -translate-y-1/2 transform flex-col space-y-2 pl-4">
|
|
<Chat />
|
|
<Report />
|
|
<BugReport />
|
|
</div>
|
|
<div className="flex h-full w-2/3">
|
|
<div className="relative flex h-full flex-1">
|
|
<div className="top-19/20 absolute left-0 z-20 -translate-y-1/2 transform pl-4">
|
|
<div className="flex items-center justify-between gap-4">
|
|
<SettingsBoard />
|
|
</div>
|
|
</div>
|
|
<Map />
|
|
<div className="absolute right-10 top-5 z-20 space-y-2">
|
|
{!simulatorConnected &&
|
|
status === "connected" &&
|
|
connectedAircraft &&
|
|
!shortlyConnected && (
|
|
<SimConnectionAlert lastUpdated={ownAircraft?.lastHeartbeat} />
|
|
)}
|
|
<ConnectedDispatcher />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="flex h-full w-1/3 min-w-[500px]">
|
|
<div className="bg-base-300 flex h-full w-full flex-col p-4">
|
|
<div className="flex justify-between">
|
|
<div className="mb-2 flex items-center justify-end gap-2">
|
|
<h2 className="card-title">MRT & DME</h2>
|
|
<a
|
|
href="https://docs.virtualairrescue.com/allgemein/var-systeme/leitstelle/pilot.html"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="link text-xs text-gray-500 hover:underline"
|
|
>
|
|
Hilfe
|
|
</a>
|
|
</div>
|
|
<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-body flex h-full w-full items-center justify-center">
|
|
<div className="max-w-150">
|
|
<Mrt />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div className="card bg-base-200 flex h-1/2 shadow-xl">
|
|
<div className="card-body mb-0 flex h-full w-full items-center justify-center p-4">
|
|
<div className="max-w-140">
|
|
<Dme />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
PilotPage.displayName = "DispatchPage";
|
|
|
|
export default PilotPage;
|