Fix Pilot-conenction

This commit is contained in:
PxlLoewe
2025-07-10 10:19:36 -07:00
parent 3b1ceb8f8c
commit b9eef5252e
6 changed files with 135 additions and 102 deletions

View File

@@ -3,11 +3,10 @@
import { useSession } from "next-auth/react"; import { useSession } from "next-auth/react";
import { useDispatchConnectionStore } from "../../../../../_store/dispatch/connectionStore"; import { useDispatchConnectionStore } from "../../../../../_store/dispatch/connectionStore";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { toast } from "react-hot-toast";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { Prisma } from "@repo/db"; import { Prisma } from "@repo/db";
import { changeDispatcherAPI } from "_querys/dispatcher"; import { changeDispatcherAPI } from "_querys/dispatcher";
import { getNextDateWithTime } from "@repo/shared-components"; import { Button, getNextDateWithTime } from "@repo/shared-components";
export const ConnectionBtn = () => { export const ConnectionBtn = () => {
const modalRef = useRef<HTMLDialogElement>(null); const modalRef = useRef<HTMLDialogElement>(null);
@@ -20,44 +19,19 @@ export const ConnectionBtn = () => {
mutationFn: ({ id, data }: { id: number; data: Prisma.ConnectedDispatcherUpdateInput }) => mutationFn: ({ id, data }: { id: number; data: Prisma.ConnectedDispatcherUpdateInput }) =>
changeDispatcherAPI(id, data), changeDispatcherAPI(id, data),
}); });
const [logoffDebounce, setLogoffDebounce] = useState<NodeJS.Timeout | null>(null);
const session = useSession(); const session = useSession();
const uid = session.data?.user?.id; const uid = session.data?.user?.id;
// useEffect für die Logoff-Zeit // useEffect für die Logoff-Zeit
const [logoffHours, logoffMinutes] = form.logoffTime?.split(":").map(Number) || []; const [logoffHours, logoffMinutes] = form.logoffTime?.split(":").map(Number) || [];
useEffect(() => {
if (!logoffHours || !logoffMinutes) return;
if (logoffDebounce) clearTimeout(logoffDebounce);
const timeout = setTimeout(async () => {
if (!logoffHours || !logoffMinutes || !connection.connectedDispatcher) return;
await changeDispatcherMutation.mutateAsync({
id: connection.connectedDispatcher?.id,
data: {
esimatedLogoutTime:
logoffHours && logoffMinutes ? getNextDateWithTime(logoffHours, logoffMinutes) : null,
},
});
toast.success("Änderung gespeichert!");
modalRef.current?.close();
}, 2000);
setLogoffDebounce(timeout);
// Cleanup function
return () => {
if (logoffDebounce) clearTimeout(logoffDebounce);
};
}, [form.logoffTime, connection.connectedDispatcher]);
useEffect(() => { useEffect(() => {
// Disconnect the socket when the component unmounts // Disconnect the socket when the component unmounts
return () => { return () => {
connection.disconnect(); connection.disconnect();
}; };
}, [connection.disconnect]); }, [connection.disconnect]);
if (!uid) return null; if (!uid) return null;
return ( return (
<div className="rounded-box bg-base-200 flex justify-center items-center gap-2 p-1"> <div className="rounded-box bg-base-200 flex justify-center items-center gap-2 p-1">
@@ -122,16 +96,36 @@ export const ConnectionBtn = () => {
<form method="dialog" className="w-full flex justify-between"> <form method="dialog" className="w-full flex justify-between">
<button className="btn btn-soft">Zurück</button> <button className="btn btn-soft">Zurück</button>
{connection.status == "connected" ? ( {connection.status == "connected" ? (
<button <>
className="btn btn-soft btn-error" <Button
type="submit" className="btn"
onSubmit={() => false} onClick={async () => {
onClick={() => { if (!connection.connectedDispatcher?.id) return;
connection.disconnect(); await changeDispatcherMutation.mutateAsync({
}} id: connection.connectedDispatcher?.id,
> data: {
Verbindung Trennen esimatedLogoutTime:
</button> logoffHours && logoffMinutes
? getNextDateWithTime(logoffHours, logoffMinutes)
: null,
},
});
modalRef.current?.close();
}}
>
Logoff-Zeit speichern
</Button>
<button
className="btn btn-soft btn-error"
type="submit"
onSubmit={() => false}
onClick={() => {
connection.disconnect();
}}
>
Verbindung Trennen
</button>
</>
) : ( ) : (
<button <button
type="submit" type="submit"

View File

@@ -4,10 +4,9 @@ import { usePilotConnectionStore } from "_store/pilot/connectionStore";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { useMutation, useQuery } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import { getStationsAPI } from "_querys/stations"; import { getStationsAPI } from "_querys/stations";
import toast from "react-hot-toast";
import { editConnectedAircraftAPI, getConnectedAircraftsAPI } from "_querys/aircrafts"; import { editConnectedAircraftAPI, getConnectedAircraftsAPI } from "_querys/aircrafts";
import { Prisma } from "@repo/db"; import { Prisma } from "@repo/db";
import { getNextDateWithTime } from "@repo/shared-components"; import { Button, getNextDateWithTime } from "@repo/shared-components";
import { Select } from "_components/Select"; import { Select } from "_components/Select";
import { Radio } from "lucide-react"; import { Radio } from "lucide-react";
@@ -23,7 +22,6 @@ export const ConnectionBtn = () => {
selectedStationId: null, selectedStationId: null,
debugPosition: false, debugPosition: false,
}); });
const [logoffDebounce, setLogoffDebounce] = useState<NodeJS.Timeout | null>(null);
const { data: stations } = useQuery({ const { data: stations } = useQuery({
queryKey: ["stations"], queryKey: ["stations"],
@@ -53,7 +51,8 @@ export const ConnectionBtn = () => {
return () => { return () => {
connection.disconnect(); connection.disconnect();
}; };
}, [connection, connection.disconnect]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [connection.disconnect]);
const [logoffHours, logoffMinutes] = form.logoffTime?.split(":").map(Number) || []; const [logoffHours, logoffMinutes] = form.logoffTime?.split(":").map(Number) || [];
@@ -62,32 +61,6 @@ export const ConnectionBtn = () => {
queryFn: () => getConnectedAircraftsAPI(), queryFn: () => getConnectedAircraftsAPI(),
}); });
useEffect(() => {
if (!logoffHours || !logoffMinutes || !connection.connectedAircraft) return;
if (logoffDebounce) clearTimeout(logoffDebounce);
const timeout = setTimeout(async () => {
if (!connection.connectedAircraft?.id) return;
await aircraftMutation.mutateAsync({
sessionId: connection.connectedAircraft.id,
change: {
esimatedLogoutTime:
logoffHours && logoffMinutes ? getNextDateWithTime(logoffHours, logoffMinutes) : null,
},
});
modalRef.current?.close();
toast.success("Änderung gespeichert!");
}, 2000);
setLogoffDebounce(timeout);
// Cleanup function to clear timeout
return () => {
if (logoffDebounce) clearTimeout(logoffDebounce);
};
}, [logoffHours, logoffMinutes, connection.connectedAircraft, aircraftMutation, logoffDebounce]);
const session = useSession(); const session = useSession();
const uid = session.data?.user?.id; const uid = session.data?.user?.id;
if (!uid) return null; if (!uid) return null;
@@ -185,45 +158,66 @@ export const ConnectionBtn = () => {
)} )}
</fieldset> </fieldset>
{session.data?.user.permissions.includes("ADMIN_STATION") && ( {session.data?.user.permissions.includes("ADMIN_STATION") &&
<fieldset className="fieldset bg-base-100 border-base-300 rounded-box w-full border p-4"> connection.status === "disconnected" && (
<legend className="fieldset-legend">Debug-optionen</legend> <fieldset className="fieldset bg-base-100 border-base-300 rounded-box w-full border p-4">
<label className="label"> <legend className="fieldset-legend">Debug-optionen</legend>
<input <label className="label">
checked={form.debugPosition} <input
onChange={(e) => setForm({ ...form, debugPosition: e.target.checked })} checked={form.debugPosition}
type="checkbox" onChange={(e) => setForm({ ...form, debugPosition: e.target.checked })}
className="checkbox" type="checkbox"
/> className="checkbox"
Zufalls Position für 2h anzeigen />
</label> Zufalls Position für 2h anzeigen
</fieldset> </label>
)} </fieldset>
)}
<div className="modal-action flex justify-between w-full"> <div className="modal-action flex justify-between w-full">
<form method="dialog" className="w-full flex justify-between"> <form method="dialog" className="w-full flex justify-between">
<button className="btn btn-soft">Zurück</button> <button className="btn btn-soft">Zurück</button>
{connection.status == "connected" ? ( {connection.status == "connected" ? (
<button <>
className="btn btn-soft btn-error" <Button
type="submit" className="btn"
onSubmit={() => false} onClick={async () => {
onClick={() => { if (!connection.connectedAircraft) return;
connection.disconnect(); await aircraftMutation.mutateAsync({
}} sessionId: connection.connectedAircraft.id,
> change: {
Verbindung Trennen esimatedLogoutTime:
</button> logoffHours && logoffMinutes
? getNextDateWithTime(logoffHours, logoffMinutes)
: null,
},
});
modalRef.current?.close();
}}
>
Logoff-Zeit speichern
</Button>
<button
className="btn btn-soft btn-error"
type="submit"
onSubmit={() => false}
onClick={() => {
connection.disconnect();
}}
>
Verbindung Trennen
</button>
</>
) : ( ) : (
<button <Button
type="submit" type="submit"
onSubmit={() => false} onSubmit={() => false}
onClick={() => { onClick={async () => {
const selectedStation = stations?.find( const selectedStation = stations?.find(
(station) => (station) =>
station.id === parseInt(form.selectedStationId?.toString() || ""), station.id === parseInt(form.selectedStationId?.toString() || ""),
); );
if (selectedStation) { if (selectedStation) {
connection.connect( await connection.connect(
uid, uid,
form.selectedStationId?.toString() || "", form.selectedStationId?.toString() || "",
form.logoffTime || "", form.logoffTime || "",
@@ -232,11 +226,12 @@ export const ConnectionBtn = () => {
form.debugPosition, form.debugPosition,
); );
} }
modalRef.current?.close();
}} }}
className="btn btn-soft btn-info" className="btn btn-soft btn-info"
> >
{connection.status == "disconnected" ? "Verbinden" : connection.status} {connection.status == "disconnected" ? "Verbinden" : connection.status}
</button> </Button>
)} )}
</form> </form>
</div> </div>

View File

@@ -0,0 +1,43 @@
"use client";
import React, {
ButtonHTMLAttributes,
DetailedHTMLProps,
useEffect,
useState,
forwardRef,
} from "react";
import { cn } from "@repo/shared-components";
export const Button = forwardRef<
HTMLButtonElement,
DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> & {
isLoading?: boolean;
}
>(({ isLoading, ...props }, ref) => {
const [isLoadingState, setIsLoadingState] = useState(isLoading);
useEffect(() => {
setIsLoadingState(isLoading);
}, [isLoading]);
return (
<button
{...props}
ref={ref}
className={cn("btn", props.className)}
disabled={isLoadingState || props.disabled}
onClick={async (e) => {
if (props.onClick) {
setIsLoadingState(true);
await props.onClick(e);
setIsLoadingState(false);
}
}}
>
{isLoadingState && <span className="loading loading-spinner loading-sm"></span>}
{props.children}
</button>
);
});
Button.displayName = "Button";

View File

@@ -1,3 +1,4 @@
export * from "./Badge"; export * from "./Badge";
export * from "./PenaltyDropdown"; export * from "./PenaltyDropdown";
export * from "./Maintenance"; export * from "./Maintenance";
export * from "./Button";

View File

@@ -15,7 +15,7 @@
"tailwind-merge": "^3.3.0" "tailwind-merge": "^3.3.0"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^19.1.6", "@types/react": "^19.1.8",
"@types/react-dom": "^19.1.5", "@types/react-dom": "^19.1.5",
"react": "^19.1.0", "react": "^19.1.0",
"react-dom": "^19.1.0" "react-dom": "^19.1.0"

10
pnpm-lock.yaml generated
View File

@@ -630,11 +630,11 @@ importers:
version: 3.3.0 version: 3.3.0
devDependencies: devDependencies:
'@types/react': '@types/react':
specifier: ^19.1.6 specifier: ^19.1.8
version: 19.1.6 version: 19.1.8
'@types/react-dom': '@types/react-dom':
specifier: ^19.1.5 specifier: ^19.1.5
version: 19.1.5(@types/react@19.1.6) version: 19.1.5(@types/react@19.1.8)
react: react:
specifier: ^19.1.0 specifier: ^19.1.0
version: 19.1.0 version: 19.1.0
@@ -8668,9 +8668,9 @@ snapshots:
'@types/range-parser@1.2.7': {} '@types/range-parser@1.2.7': {}
'@types/react-dom@19.1.5(@types/react@19.1.6)': '@types/react-dom@19.1.5(@types/react@19.1.8)':
dependencies: dependencies:
'@types/react': 19.1.6 '@types/react': 19.1.8
'@types/react-dom@19.1.6(@types/react@19.1.8)': '@types/react-dom@19.1.6(@types/react@19.1.8)':
dependencies: dependencies: