diff --git a/apps/dispatch-server/socket-events/connect-dispatch.ts b/apps/dispatch-server/socket-events/connect-dispatch.ts index 06e485fe..192fd25f 100644 --- a/apps/dispatch-server/socket-events/connect-dispatch.ts +++ b/apps/dispatch-server/socket-events/connect-dispatch.ts @@ -6,7 +6,15 @@ import { Server, Socket } from "socket.io"; export const handleConnectDispatch = (socket: Socket, io: Server) => - async ({ logoffTime, selectedZone }: { logoffTime: string; selectedZone: string }) => { + async ({ + logoffTime, + selectedZone, + ghostMode, + }: { + logoffTime: string; + selectedZone: string; + ghostMode: boolean; + }) => { try { const user: User = socket.data.user; // User ID aus dem JWT-Token @@ -53,6 +61,7 @@ export const handleConnectDispatch = userId: user.id, zone: selectedZone, loginTime: new Date().toISOString(), + ghostMode, }, }); diff --git a/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx b/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx index c7fe631c..f1450f19 100644 --- a/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx +++ b/apps/dispatch/app/(app)/dispatch/_components/navbar/_components/Connection.tsx @@ -7,6 +7,7 @@ import { useMutation } from "@tanstack/react-query"; import { Prisma } from "@repo/db"; import { changeDispatcherAPI } from "_querys/dispatcher"; import { Button, getNextDateWithTime } from "@repo/shared-components"; +import { Ghost } from "lucide-react"; export const ConnectionBtn = () => { const modalRef = useRef(null); @@ -14,6 +15,7 @@ export const ConnectionBtn = () => { const [form, setForm] = useState({ logoffTime: "", selectedZone: "LST_01", + ghostMode: false, }); const changeDispatcherMutation = useMutation({ mutationFn: ({ id, data }: { id: number; data: Prisma.ConnectedDispatcherUpdateInput }) => @@ -45,7 +47,7 @@ export const ConnectionBtn = () => { modalRef.current?.showModal(); }} > - Verbunden + Verbunden {connection.ghostMode && } ) : ( @@ -138,6 +155,7 @@ export const ConnectionBtn = () => { form.logoffTime && logoffHours !== undefined && logoffMinutes !== undefined ? getNextDateWithTime(logoffHours, logoffMinutes).toISOString() : "", + form.ghostMode, ); }} className="btn btn-soft btn-info" diff --git a/apps/dispatch/app/_store/dispatch/connectionStore.ts b/apps/dispatch/app/_store/dispatch/connectionStore.ts index bfa64533..c7a646aa 100644 --- a/apps/dispatch/app/_store/dispatch/connectionStore.ts +++ b/apps/dispatch/app/_store/dispatch/connectionStore.ts @@ -11,7 +11,13 @@ interface ConnectionStore { message: string; selectedZone: string; logoffTime: string; - connect: (uid: string, selectedZone: string, logoffTime: string) => Promise; + ghostMode: boolean; + connect: ( + uid: string, + selectedZone: string, + logoffTime: string, + ghostMode: boolean, + ) => Promise; disconnect: () => void; } @@ -23,11 +29,12 @@ export const useDispatchConnectionStore = create((set) => ({ message: "", selectedZone: "LST_01", logoffTime: "", - connect: async (uid, selectedZone, logoffTime) => + ghostMode: false, + connect: async (uid, selectedZone, logoffTime, ghostMode) => new Promise((resolve) => { set({ status: "connecting", message: "" }); dispatchSocket.auth = { uid }; - set({ selectedZone, logoffTime }); + set({ selectedZone, logoffTime, ghostMode }); dispatchSocket.connect(); dispatchSocket.once("connect", () => { @@ -40,11 +47,12 @@ export const useDispatchConnectionStore = create((set) => ({ })); dispatchSocket.on("connect", () => { - const { logoffTime, selectedZone } = useDispatchConnectionStore.getState(); + const { logoffTime, selectedZone, ghostMode } = useDispatchConnectionStore.getState(); useAudioStore.getState().connect("LST_01", selectedZone || "Leitstelle"); dispatchSocket.emit("connect-dispatch", { logoffTime, selectedZone, + ghostMode, }); useDispatchConnectionStore.setState({ status: "connected", message: "" }); }); diff --git a/apps/dispatch/app/api/dispatcher/route.ts b/apps/dispatch/app/api/dispatcher/route.ts index 68db178c..63761deb 100644 --- a/apps/dispatch/app/api/dispatcher/route.ts +++ b/apps/dispatch/app/api/dispatcher/route.ts @@ -10,6 +10,7 @@ export async function GET(request: Request): Promise { const connectedDispatcher = await prisma.connectedDispatcher.findMany({ where: { logoutTime: null, + ghostMode: false, // Ensure we only get non-ghost mode connections ...filter, // Ensure filter is parsed correctly }, include: { diff --git a/packages/database/prisma/schema/connectedDispatcher.prisma b/packages/database/prisma/schema/connectedDispatcher.prisma index 3879f5fe..3bead33e 100644 --- a/packages/database/prisma/schema/connectedDispatcher.prisma +++ b/packages/database/prisma/schema/connectedDispatcher.prisma @@ -7,6 +7,7 @@ model ConnectedDispatcher { zone String @default("LST_1") esimatedLogoutTime DateTime? logoutTime DateTime? + ghostMode Boolean @default(false) // relations: user User @relation(fields: [userId], references: [id], onDelete: Cascade) diff --git a/packages/database/prisma/schema/migrations/20250724015557_ghost_mode/migration.sql b/packages/database/prisma/schema/migrations/20250724015557_ghost_mode/migration.sql new file mode 100644 index 00000000..7711a5e6 --- /dev/null +++ b/packages/database/prisma/schema/migrations/20250724015557_ghost_mode/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "ConnectedDispatcher" ADD COLUMN "ghostMode" BOOLEAN NOT NULL DEFAULT false;