Revert "PR v2.0.7"
This commit is contained in:
@@ -24,7 +24,6 @@ import { useSounds } from "_components/Audio/useSounds";
|
||||
|
||||
export const Audio = () => {
|
||||
const {
|
||||
selectedRoom,
|
||||
speakingParticipants,
|
||||
resetSpeakingParticipants,
|
||||
isTalking,
|
||||
@@ -38,8 +37,8 @@ export const Audio = () => {
|
||||
room,
|
||||
message,
|
||||
removeMessage,
|
||||
setSelectedRoom,
|
||||
} = useAudioStore();
|
||||
const [selectedRoom, setSelectedRoom] = useState<string>("LST_01");
|
||||
|
||||
useSounds({
|
||||
isReceiving: speakingParticipants.length > 0,
|
||||
@@ -49,7 +48,7 @@ export const Audio = () => {
|
||||
});
|
||||
|
||||
const { selectedStation, status: pilotState } = usePilotConnectionStore((state) => state);
|
||||
const { status: dispatcherState } = useDispatchConnectionStore((state) => state);
|
||||
const { selectedZone, status: dispatcherState } = useDispatchConnectionStore((state) => state);
|
||||
const session = useSession();
|
||||
const [isReceivingBlick, setIsReceivingBlick] = useState(false);
|
||||
const [recentSpeakers, setRecentSpeakers] = useState<typeof speakingParticipants>([]);
|
||||
@@ -94,7 +93,7 @@ export const Audio = () => {
|
||||
const canStopOtherSpeakers = dispatcherState === "connected";
|
||||
|
||||
const role =
|
||||
(dispatcherState === "connected" && "VAR LST") ||
|
||||
(dispatcherState === "connected" && selectedZone) ||
|
||||
(pilotState == "connected" && selectedStation?.bosCallsignShort) ||
|
||||
session.data?.user?.publicId;
|
||||
|
||||
@@ -186,20 +185,20 @@ export const Audio = () => {
|
||||
</summary>
|
||||
<ul className="menu dropdown-content bg-base-200 rounded-box z-[1050] w-52 p-2 shadow-sm">
|
||||
{ROOMS.map((r) => (
|
||||
<li key={r.id}>
|
||||
<li key={r}>
|
||||
<button
|
||||
className="btn btn-sm btn-ghost relative flex items-center justify-start gap-2 text-left"
|
||||
onClick={() => {
|
||||
if (!role) return;
|
||||
if (selectedRoom?.name === r.name) return;
|
||||
if (selectedRoom === r) return;
|
||||
setSelectedRoom(r);
|
||||
connect(r, role);
|
||||
}}
|
||||
>
|
||||
{room?.name === r.name && (
|
||||
{room?.name === r && (
|
||||
<Disc className="text-success absolute left-2 text-sm" width={15} />
|
||||
)}
|
||||
<span className="flex-1 text-center">{r.name}</span>
|
||||
<span className="flex-1 text-center">{r}</span>
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
|
||||
@@ -63,15 +63,14 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
||||
};
|
||||
|
||||
const handleNotification = (notification: NotificationPayload) => {
|
||||
console.log("Received notification:", notification);
|
||||
const playNotificationSound = () => {
|
||||
if (notificationSound.current) {
|
||||
notificationSound.current.currentTime = 0;
|
||||
notificationSound.current
|
||||
.play()
|
||||
.catch((e) => console.error("Notification sound error:", e));
|
||||
}
|
||||
};
|
||||
notificationSound.current.currentTime = 0;
|
||||
notificationSound.current
|
||||
.play()
|
||||
.catch((e) => console.error("Notification sound error:", e));
|
||||
}
|
||||
}
|
||||
|
||||
switch (notification.type) {
|
||||
case "hpg-validation":
|
||||
@@ -91,7 +90,6 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
||||
});
|
||||
break;
|
||||
case "station-status":
|
||||
console.log("station Status", QUICK_RESPONSE[notification.status]);
|
||||
if (!QUICK_RESPONSE[notification.status]) return;
|
||||
toast.custom((e) => <StatusToast event={notification} t={e} />, {
|
||||
duration: 60000,
|
||||
@@ -108,7 +106,7 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
||||
break;
|
||||
case "mission-closed":
|
||||
toast("Dein aktueller Einsatz wurde geschlossen.");
|
||||
|
||||
|
||||
break;
|
||||
default:
|
||||
toast("unbekanntes Notification-Event");
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
import { getPublicUser, MissionSdsStatusLog, StationStatus } from "@repo/db";
|
||||
import { Prisma, StationStatus } from "@repo/db";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { BaseNotification } from "_components/customToasts/BaseNotification";
|
||||
import { FMS_STATUS_COLORS } from "_helpers/fmsStatusColors";
|
||||
import { getConnectedAircraftsAPI } from "_querys/aircrafts";
|
||||
import { editConnectedAircraftAPI, getConnectedAircraftsAPI } from "_querys/aircrafts";
|
||||
import { getLivekitRooms } from "_querys/livekit";
|
||||
import { sendSdsStatusMessageAPI } from "_querys/missions";
|
||||
import { getStationsAPI } from "_querys/stations";
|
||||
import { useAudioStore } from "_store/audioStore";
|
||||
import { useMapStore } from "_store/mapStore";
|
||||
import { X } from "lucide-react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { Toast, toast } from "react-hot-toast";
|
||||
|
||||
export const QUICK_RESPONSE: Record<string, string[]> = {
|
||||
@@ -24,8 +22,6 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) =>
|
||||
const status5Sounds = useRef<HTMLAudioElement | null>(null);
|
||||
const status9Sounds = useRef<HTMLAudioElement | null>(null);
|
||||
|
||||
const session = useSession();
|
||||
|
||||
const { data: livekitRooms } = useQuery({
|
||||
queryKey: ["livekit-rooms"],
|
||||
queryFn: () => getLivekitRooms(),
|
||||
@@ -50,7 +46,7 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) =>
|
||||
status9Sounds.current = new Audio("/sounds/status-9.mp3");
|
||||
}
|
||||
}, []);
|
||||
|
||||
const [aircraftDataAcurate, setAircraftDataAccurate] = useState(false);
|
||||
//const mapStore = useMapStore((s) => s);
|
||||
const { setOpenAircraftMarker, setMap } = useMapStore((store) => store);
|
||||
|
||||
@@ -69,16 +65,29 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) =>
|
||||
const station = stations?.find((s) => s.id === event.data?.stationId);
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const sendSdsStatusMutation = useMutation({
|
||||
mutationFn: async ({ sdsMessage }: { sdsMessage: MissionSdsStatusLog }) => {
|
||||
if (!connectedAircraft?.id) throw new Error("No connected aircraft");
|
||||
await sendSdsStatusMessageAPI({ sdsMessage, aircraftId: connectedAircraft?.id });
|
||||
const changeAircraftMutation = useMutation({
|
||||
mutationFn: async ({
|
||||
id,
|
||||
update,
|
||||
}: {
|
||||
id: number;
|
||||
update: Prisma.ConnectedAircraftUpdateInput;
|
||||
}) => {
|
||||
await editConnectedAircraftAPI(id, update);
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["missions"],
|
||||
queryKey: ["aircrafts"],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (event.status !== connectedAircraft?.fmsStatus && aircraftDataAcurate) {
|
||||
toast.remove(t.id);
|
||||
} else if (event.status == connectedAircraft?.fmsStatus && !aircraftDataAcurate) {
|
||||
setAircraftDataAccurate(true);
|
||||
}
|
||||
}, [aircraftDataAcurate, connectedAircraft, event.status, t.id]);
|
||||
|
||||
useEffect(() => {
|
||||
let soundRef: React.RefObject<HTMLAudioElement | null> | null = null;
|
||||
switch (event.status) {
|
||||
@@ -94,8 +103,7 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) =>
|
||||
default:
|
||||
soundRef = null;
|
||||
}
|
||||
|
||||
if (audioRoom && livekitUser?.roomName && audioRoom !== livekitUser?.roomName) {
|
||||
if (audioRoom !== livekitUser?.roomName) {
|
||||
toast.remove(t.id);
|
||||
return;
|
||||
}
|
||||
@@ -113,8 +121,7 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) =>
|
||||
};
|
||||
}, [event.status, livekitUser?.roomName, audioRoom, t.id]);
|
||||
|
||||
console.log(connectedAircraft, station);
|
||||
if (!connectedAircraft || !station || !session.data) return null;
|
||||
if (!connectedAircraft || !station) return null;
|
||||
return (
|
||||
<BaseNotification>
|
||||
<div className="flex flex-row items-center gap-14">
|
||||
@@ -155,18 +162,10 @@ export const StatusToast = ({ event, t }: { event: StationStatus; t: Toast }) =>
|
||||
toast.error("Keine Flugzeug-ID gefunden");
|
||||
return;
|
||||
}
|
||||
await sendSdsStatusMutation.mutateAsync({
|
||||
sdsMessage: {
|
||||
type: "sds-status-log",
|
||||
auto: false,
|
||||
data: {
|
||||
direction: "to-aircraft",
|
||||
stationId: event.data.stationId!,
|
||||
station: station,
|
||||
user: getPublicUser(session.data?.user),
|
||||
status,
|
||||
},
|
||||
timeStamp: new Date().toISOString(),
|
||||
await changeAircraftMutation.mutateAsync({
|
||||
id: event.data?.aircraftId,
|
||||
update: {
|
||||
fmsStatus: status,
|
||||
},
|
||||
});
|
||||
toast.remove(t.id);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Marker, Polyline, useMap } from "react-leaflet";
|
||||
import { DivIcon, Marker as LMarker, Popup as LPopup } from "leaflet";
|
||||
import { useMapStore } from "_store/mapStore";
|
||||
import { Fragment, useCallback, useEffect, useRef, useState, useMemo } from "react";
|
||||
import { cn } from "@repo/shared-components";
|
||||
import { checkSimulatorConnected, cn } from "@repo/shared-components";
|
||||
import { ChevronsRightLeft, House, MessageSquareText, Minimize2 } from "lucide-react";
|
||||
import { SmartPopup, calculateAnchor, useSmartPopup } from "_components/SmartPopup";
|
||||
import FMSStatusHistory, {
|
||||
@@ -396,11 +396,27 @@ const AircraftMarker = ({ aircraft }: { aircraft: ConnectedAircraft & { Station:
|
||||
};
|
||||
|
||||
export const AircraftLayer = () => {
|
||||
const { data: aircrafts } = useQuery({
|
||||
queryKey: ["connected-aircrafts", "map"],
|
||||
queryFn: () => getConnectedAircraftsAPI(),
|
||||
refetchInterval: 15000,
|
||||
});
|
||||
const [aircrafts, setAircrafts] = useState<(ConnectedAircraft & { Station: Station })[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAircrafts = async () => {
|
||||
try {
|
||||
const res = await fetch("/api/aircrafts");
|
||||
if (!res.ok) {
|
||||
throw new Error("Failed to fetch aircrafts");
|
||||
}
|
||||
const data: (ConnectedAircraft & { Station: Station })[] = await res.json();
|
||||
setAircrafts(data.filter((a) => checkSimulatorConnected(a)));
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch aircrafts:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchAircrafts();
|
||||
const interval = setInterval(fetchAircrafts, 10_000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
const { setMap } = useMapStore((state) => state);
|
||||
const map = useMap();
|
||||
const {
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
Mission,
|
||||
MissionLog,
|
||||
MissionSdsLog,
|
||||
MissionSdsStatusLog,
|
||||
MissionStationLog,
|
||||
Prisma,
|
||||
PublicUser,
|
||||
@@ -41,7 +40,7 @@ import {
|
||||
TextSearch,
|
||||
} from "lucide-react";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { sendSdsMessageAPI, sendSdsStatusMessageAPI } from "_querys/missions";
|
||||
import { sendSdsMessageAPI } from "_querys/missions";
|
||||
import { getLivekitRooms } from "_querys/livekit";
|
||||
import { findLeitstelleForPosition } from "_helpers/findLeitstelleinPoint";
|
||||
import { formatDistance } from "date-fns";
|
||||
@@ -55,13 +54,9 @@ const FMSStatusHistory = ({
|
||||
mission?: Mission;
|
||||
}) => {
|
||||
const log = ((mission?.missionLog as unknown as MissionLog[]) || [])
|
||||
.filter(
|
||||
(entry) =>
|
||||
(entry.type === "station-log" || entry.type == "sds-status-log") &&
|
||||
entry.data.stationId === aircraft.Station.id,
|
||||
)
|
||||
.filter((entry) => entry.type === "station-log" && entry.data.stationId === aircraft.Station.id)
|
||||
.reverse()
|
||||
.splice(0, 6) as (MissionStationLog | MissionSdsStatusLog)[];
|
||||
.splice(0, 6) as MissionStationLog[];
|
||||
|
||||
const aircraftUser: PublicUser =
|
||||
typeof aircraft.publicUser === "string" ? JSON.parse(aircraft.publicUser) : aircraft.publicUser;
|
||||
@@ -108,13 +103,10 @@ const FMSStatusHistory = ({
|
||||
<span
|
||||
className="text-base font-bold"
|
||||
style={{
|
||||
color:
|
||||
FMS_STATUS_TEXT_COLORS[
|
||||
entry.type === "sds-status-log" ? entry.data.status : entry.data.newFMSstatus
|
||||
],
|
||||
color: FMS_STATUS_TEXT_COLORS[entry.data.newFMSstatus],
|
||||
}}
|
||||
>
|
||||
{entry.type === "sds-status-log" ? entry.data.status : entry.data.newFMSstatus}
|
||||
{entry.data.newFMSstatus}
|
||||
</span>
|
||||
<span className="text-base-content">
|
||||
{new Date(entry.timeStamp).toLocaleTimeString([], {
|
||||
@@ -134,7 +126,6 @@ const FMSStatusSelector = ({
|
||||
}: {
|
||||
aircraft: ConnectedAircraft & { Station: Station };
|
||||
}) => {
|
||||
const session = useSession();
|
||||
const dispatcherConnected = useDispatchConnectionStore((s) => s.status) === "connected";
|
||||
const [hoveredStatus, setHoveredStatus] = useState<string | null>(null);
|
||||
const queryClient = useQueryClient();
|
||||
@@ -153,20 +144,6 @@ const FMSStatusSelector = ({
|
||||
},
|
||||
});
|
||||
|
||||
const sendSdsStatusMutation = useMutation({
|
||||
mutationFn: async ({ sdsMessage }: { sdsMessage: MissionSdsStatusLog }) => {
|
||||
if (!aircraft?.id) throw new Error("No connected aircraft");
|
||||
await sendSdsStatusMessageAPI({ sdsMessage, aircraftId: aircraft?.id });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["missions"],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
if (!session.data?.user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="text-base-content mt-2 flex flex-col gap-2 p-4">
|
||||
<div className="flex h-full items-center justify-center gap-2">
|
||||
@@ -236,21 +213,12 @@ const FMSStatusSelector = ({
|
||||
onMouseEnter={() => setHoveredStatus(status)}
|
||||
onMouseLeave={() => setHoveredStatus(null)}
|
||||
onClick={async () => {
|
||||
await sendSdsStatusMutation.mutateAsync({
|
||||
sdsMessage: {
|
||||
type: "sds-status-log",
|
||||
auto: false,
|
||||
timeStamp: new Date().toISOString(),
|
||||
data: {
|
||||
status: status,
|
||||
direction: "to-aircraft",
|
||||
stationId: aircraft.Station.id,
|
||||
station: aircraft.Station,
|
||||
user: getPublicUser(session.data?.user),
|
||||
},
|
||||
await changeAircraftMutation.mutateAsync({
|
||||
id: aircraft.id,
|
||||
update: {
|
||||
fmsStatus: status,
|
||||
},
|
||||
});
|
||||
toast.success(`SDS Status ${status} gesendet`);
|
||||
}}
|
||||
>
|
||||
{status}
|
||||
@@ -410,9 +378,7 @@ const SDSTab = ({
|
||||
?.slice()
|
||||
.reverse()
|
||||
.filter(
|
||||
(entry) =>
|
||||
(entry.type === "sds-log" || entry.type == "sds-status-log") &&
|
||||
entry.data.stationId === aircraft.Station.id,
|
||||
(entry) => entry.type === "sds-log" && entry.data.stationId === aircraft.Station.id,
|
||||
) || [],
|
||||
[mission?.missionLog, aircraft.Station.id],
|
||||
);
|
||||
@@ -505,7 +471,7 @@ const SDSTab = ({
|
||||
)}
|
||||
<ul className="max-h-[300px] space-y-2 overflow-x-auto overflow-y-auto">
|
||||
{log.map((entry, index) => {
|
||||
const sdsEntry = entry as MissionSdsLog | MissionSdsStatusLog;
|
||||
const sdsEntry = entry as MissionSdsLog;
|
||||
return (
|
||||
<li key={index} className="flex items-center gap-2">
|
||||
<span className="text-base-content">
|
||||
@@ -523,9 +489,7 @@ const SDSTab = ({
|
||||
{sdsEntry.data.user.firstname?.[0]?.toUpperCase() ?? "?"}
|
||||
{sdsEntry.data.user.lastname?.[0]?.toUpperCase() ?? "?"}
|
||||
</span>
|
||||
<span className="text-base-content">
|
||||
{sdsEntry.type == "sds-log" ? sdsEntry.data.message : sdsEntry.data.status}
|
||||
</span>
|
||||
<span className="text-base-content">{sdsEntry.data.message}</span>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -726,11 +726,7 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => {
|
||||
<span className="text-base-content">{entry.data.station.bosCallsign}</span>
|
||||
</li>
|
||||
);
|
||||
if (
|
||||
entry.type === "message-log" ||
|
||||
entry.type === "sds-log" ||
|
||||
entry.type === "sds-status-log"
|
||||
)
|
||||
if (entry.type === "message-log" || entry.type === "sds-log")
|
||||
return (
|
||||
<li key={index} className="flex items-center gap-2">
|
||||
<span className="text-base-content">
|
||||
@@ -745,10 +741,9 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => {
|
||||
color: FMS_STATUS_TEXT_COLORS[6],
|
||||
}}
|
||||
>
|
||||
{entry.type == "sds-status-log" && entry.data.direction == "to-lst"
|
||||
? entry.data.station.bosCallsignShort
|
||||
: `${entry.data.user.firstname?.[0]?.toUpperCase() ?? "?"}${entry.data.user.lastname?.[0]?.toUpperCase() ?? "?"}`}
|
||||
{(entry.type === "sds-log" || entry.type === "sds-status-log") && (
|
||||
{entry.data.user.firstname?.[0]?.toUpperCase() ?? "?"}
|
||||
{entry.data.user.lastname?.[0]?.toUpperCase() ?? "?"}
|
||||
{entry.type === "sds-log" && (
|
||||
<>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -765,17 +760,11 @@ const FMSStatusHistory = ({ mission }: { mission: Mission }) => {
|
||||
/>
|
||||
</svg>
|
||||
|
||||
{entry.type == "sds-status-log" && entry.data.direction == "to-aircraft"
|
||||
? entry.data.station.bosCallsignShort
|
||||
: "LST"}
|
||||
{entry.data.station.bosCallsignShort}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
<span className="text-base-content">
|
||||
{entry.type === "sds-log" || entry.type === "message-log"
|
||||
? entry.data.message
|
||||
: entry.data.status}
|
||||
</span>
|
||||
<span className="text-base-content">{entry.data.message}</span>
|
||||
</li>
|
||||
);
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user