Dispatch Router-Struktur; AddPenalty Layout gefixed
@@ -1,6 +1,6 @@
|
||||
import { Connection } from "./_components/Connection";
|
||||
/* import { ThemeSwap } from "./_components/ThemeSwap"; */
|
||||
import { Audio } from "../../../_components/Audio/Audio";
|
||||
import { Audio } from "../../../../_components/Audio/Audio";
|
||||
/* import { useState } from "react"; */
|
||||
import { ExitIcon, ExternalLinkIcon } from "@radix-ui/react-icons";
|
||||
import Link from "next/link";
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
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 { toast } from "react-hot-toast";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
27
apps/dispatch/app/(app)/dispatch/layout.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { Metadata } from "next";
|
||||
import Navbar from "./_components/navbar/Navbar";
|
||||
import { getServerSession } from "api/auth/[...nextauth]/auth";
|
||||
import { Error } from "_components/Error";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "VAR: Disponent",
|
||||
description: "Die neue VAR Leitstelle.",
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const session = await getServerSession();
|
||||
|
||||
if (!session?.user.permissions.includes("DISPO"))
|
||||
return <Error title="Zugriff verweigert" statusCode={403} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { Pannel } from "dispatch/_components/pannel/Pannel";
|
||||
import { Pannel } from "(app)/dispatch/_components/pannel/Pannel";
|
||||
import { usePannelStore } from "_store/pannelStore";
|
||||
import { cn } from "@repo/shared-components";
|
||||
import dynamic from "next/dynamic";
|
||||
import { Chat } from "../_components/left/Chat";
|
||||
import { Report } from "../_components/left/Report";
|
||||
import { Chat } from "../../_components/left/Chat";
|
||||
import { Report } from "../../_components/left/Report";
|
||||
import { SituationBoard } from "_components/left/SituationBoard";
|
||||
|
||||
const Map = dynamic(() => import("../_components/map/Map"), { ssr: false });
|
||||
const Map = dynamic(() => import("../../_components/map/Map"), { ssr: false });
|
||||
|
||||
const DispatchPage = () => {
|
||||
const { isOpen } = usePannelStore();
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { Metadata } from "next";
|
||||
import Navbar from "./_components/navbar/Navbar";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getServerSession } from "../api/auth/[...nextauth]/auth";
|
||||
import { getServerSession } from "api/auth/[...nextauth]/auth";
|
||||
import { Error } from "_components/Error";
|
||||
import { prisma } from "@repo/db";
|
||||
|
||||
@@ -27,8 +26,9 @@ export default async function RootLayout({
|
||||
},
|
||||
});
|
||||
|
||||
if (!session || !session.user.firstname) {
|
||||
redirect("/login");
|
||||
if (!session) {
|
||||
console.log(session);
|
||||
return redirect("/logout");
|
||||
}
|
||||
|
||||
if (openPenaltys[0]) {
|
||||
@@ -37,7 +37,7 @@ export default async function RootLayout({
|
||||
<Error
|
||||
title="Du wurdest permanent ausgeschlossen"
|
||||
statusCode={403}
|
||||
description={`Dein Fehlverhalten war so schwerwiegend, dass du dauerhaft von VirtualAirRescue ausgeschlossen wurdest.`}
|
||||
description={`Dein Fehlverhalten war so schwerwiegend, dass du dauerhaft von VirtualAirRescue ausgeschlossen wurdest. Du kannst im Hub weitere Informationen finden.`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -45,7 +45,7 @@ export default async function RootLayout({
|
||||
<Error
|
||||
title="Du hast eine aktive Strafe"
|
||||
statusCode={403}
|
||||
description={`Du bist bis zum ${new Date(openPenaltys[0].until!).toLocaleString()} gesperrt.`}
|
||||
description={`Du bist bis zum ${new Date(openPenaltys[0].until!).toLocaleString()} gesperrt. Du kannst im Hub weitere Informationen finden.`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -53,14 +53,5 @@ export default async function RootLayout({
|
||||
if (!session.user.emailVerified) {
|
||||
return <Error title="E-Mail-Adresse nicht verifiziert" statusCode={403} />;
|
||||
}
|
||||
|
||||
if (!session.user.permissions.includes("PILOT"))
|
||||
return <Error title="Zugriff verweigert" statusCode={403} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 626 KiB After Width: | Height: | Size: 626 KiB |
|
Before Width: | Height: | Size: 167 KiB After Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 610 KiB After Width: | Height: | Size: 610 KiB |
|
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 322 KiB After Width: | Height: | Size: 322 KiB |
@@ -1,7 +1,7 @@
|
||||
import { ConnectedAircraft, Prisma } from "@repo/db";
|
||||
import { usePilotConnectionStore } from "_store/pilot/connectionStore";
|
||||
import { useMrtStore } from "_store/pilot/MrtStore";
|
||||
import { pilotSocket } from "pilot/socket";
|
||||
import { pilotSocket } from "(app)/pilot/socket";
|
||||
import { editConnectedAircraftAPI } from "_querys/aircrafts";
|
||||
import { useEffect } from "react";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
@@ -1,9 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { Connection } from "./_components/Connection";
|
||||
/* import { ThemeSwap } from "./ThemeSwap"; */
|
||||
import { Audio } from "../../../_components/Audio/Audio";
|
||||
/* import { useState } from "react"; */
|
||||
import { Audio } from "_components/Audio/Audio";
|
||||
import { ExitIcon, ExternalLinkIcon } from "@radix-ui/react-icons";
|
||||
import Link from "next/link";
|
||||
import { Settings } from "_components/navbar/Settings";
|
||||
27
apps/dispatch/app/(app)/pilot/layout.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import type { Metadata } from "next";
|
||||
import Navbar from "./_components/navbar/Navbar";
|
||||
import { getServerSession } from "api/auth/[...nextauth]/auth";
|
||||
import { Error } from "_components/Error";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "VAR: Pilot",
|
||||
description: "Die neue VAR Leitstelle.",
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const session = await getServerSession();
|
||||
|
||||
if (!session?.user.permissions.includes("PILOT"))
|
||||
return <Error title="Zugriff verweigert" statusCode={403} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { Mrt } from "pilot/_components/mrt/Mrt";
|
||||
import { Chat } from "../_components/left/Chat";
|
||||
import { Report } from "../_components/left/Report";
|
||||
import { Dme } from "pilot/_components/dme/Dme";
|
||||
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";
|
||||
|
||||
const Map = dynamic(() => import("../_components/map/Map"), {
|
||||
const Map = dynamic(() => import("_components/map/Map"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
@@ -7,11 +7,11 @@ import { Toaster } from "react-hot-toast";
|
||||
export const Login = () => {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const searchParams = useSearchParams();
|
||||
const { data: session } = useSession();
|
||||
const { data: session, status } = useSession();
|
||||
const navigate = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (session) {
|
||||
if (status === "authenticated") {
|
||||
navigate.push("/");
|
||||
}
|
||||
}, [session, navigate]);
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
import { toast } from "react-hot-toast";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { ReactNode, useEffect, useState } from "react";
|
||||
import { dispatchSocket } from "dispatch/socket";
|
||||
import { dispatchSocket } from "(app)/dispatch/socket";
|
||||
import { Mission, NotificationPayload } from "@repo/db";
|
||||
import { HPGnotificationToast } from "_components/customToasts/HPGnotification";
|
||||
import { useMapStore } from "_store/mapStore";
|
||||
import { AdminMessageToast } from "_components/customToasts/AdminMessage";
|
||||
import { pilotSocket } from "pilot/socket";
|
||||
import { pilotSocket } from "(app)/pilot/socket";
|
||||
|
||||
export function QueryProvider({ children }: { children: ReactNode }) {
|
||||
const mapStore = useMapStore((s) => s);
|
||||
|
||||
@@ -150,21 +150,29 @@ export default function AdminPanel() {
|
||||
</td>
|
||||
<td className="flex gap-2">
|
||||
<PenaltyDropdown
|
||||
btnName="Verbindung trennen"
|
||||
btnClassName="btn-warning"
|
||||
btnTip="Kick"
|
||||
btnTip="Die Verbindung zur Leitstelle wird für diesesn Nutzer unterbrochen"
|
||||
Icon={<RedoDot size={15} />}
|
||||
onClick={({ reason }) =>
|
||||
kickPilotMutation.mutate({ id: p.id, reason })
|
||||
}
|
||||
/>
|
||||
<PenaltyDropdown
|
||||
btnName="Kick + Berechtigungen entfernen"
|
||||
btnClassName="btn-error tooltip-error"
|
||||
btnTip="Kick + Berechtigungen entfernen"
|
||||
btnTip="Dadurch wird sich der Pilot nicht mehr mit dem VAR verbinden können."
|
||||
showDatePicker
|
||||
Icon={<LockKeyhole size={15} />}
|
||||
onClick={({ reason, until }) =>
|
||||
kickPilotMutation.mutate({ id: p.id, reason, bann: true, until })
|
||||
}
|
||||
onClick={({ reason, until }) => {
|
||||
if (!until) {
|
||||
toast.error(
|
||||
"Bitte wähle ein Datum aus. Ein permanenter Bann ist nur vom HUB aus möglich.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
kickPilotMutation.mutate({ id: p.id, reason, bann: true, until });
|
||||
}}
|
||||
/>
|
||||
<a
|
||||
href={`${process.env.NEXT_PUBLIC_HUB_URL}/admin/user/${p.userId}`}
|
||||
@@ -203,16 +211,18 @@ export default function AdminPanel() {
|
||||
</td>
|
||||
<td className="flex gap-2">
|
||||
<PenaltyDropdown
|
||||
btnName="Verbindung trennen"
|
||||
btnClassName="btn-warning"
|
||||
btnTip="Kick"
|
||||
btnTip="Die Verbindung zur Leitstelle wird für diesesn Nutzer unterbrochen"
|
||||
Icon={<RedoDot size={15} />}
|
||||
onClick={({ reason }) =>
|
||||
kickDispatchMutation.mutate({ id: d.id, reason })
|
||||
}
|
||||
/>
|
||||
<PenaltyDropdown
|
||||
btnName="Kick + Berechtigungen entfernen"
|
||||
btnClassName="btn-error tooltip-error"
|
||||
btnTip="Kick + Berechtigungen entfernen"
|
||||
btnTip="Dadurch wird sich der Pilot nicht mehr mit dem VAR verbinden können."
|
||||
showDatePicker
|
||||
Icon={<LockKeyhole size={15} />}
|
||||
onClick={({ reason, until }) =>
|
||||
@@ -264,12 +274,6 @@ export default function AdminPanel() {
|
||||
>
|
||||
<RedoDot size={15} />
|
||||
</button>
|
||||
<button
|
||||
className="btn btn-xs btn-square btn-error btn-soft tooltip tooltip-bottom tooltip-error"
|
||||
data-tip="Kick + Berechtigungen entfernen"
|
||||
>
|
||||
<LockKeyhole size={15} />
|
||||
</button>
|
||||
<a
|
||||
href={`${process.env.NEXT_PUBLIC_HUB_URL}/admin/user/${p.participant.attributes.userId}`}
|
||||
target="_blank"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { dispatchSocket } from "dispatch/socket";
|
||||
import { dispatchSocket } from "(app)/dispatch/socket";
|
||||
import {
|
||||
handleDisconnect,
|
||||
handleLocalTrackUnpublished,
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
handleTrackUnsubscribed,
|
||||
} from "_helpers/liveKitEventHandler";
|
||||
import { ConnectionQuality, Participant, Room, RoomEvent, RpcInvocationData } from "livekit-client";
|
||||
import { pilotSocket } from "pilot/socket";
|
||||
import { pilotSocket } from "(app)/pilot/socket";
|
||||
import { create } from "zustand";
|
||||
import axios from "axios";
|
||||
import { useDispatchConnectionStore } from "_store/dispatch/connectionStore";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { create } from "zustand";
|
||||
import { dispatchSocket } from "../../dispatch/socket";
|
||||
import { dispatchSocket } from "../../(app)/dispatch/socket";
|
||||
import { useAudioStore } from "_store/audioStore";
|
||||
import { ConnectedDispatcher } from "@repo/db";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { create } from "zustand";
|
||||
import { ChatMessage } from "@repo/db";
|
||||
import { dispatchSocket } from "dispatch/socket";
|
||||
import { pilotSocket } from "pilot/socket";
|
||||
import { dispatchSocket } from "(app)/dispatch/socket";
|
||||
import { pilotSocket } from "(app)/pilot/socket";
|
||||
|
||||
interface ChatStore {
|
||||
situationTabOpen: boolean;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { MissionSdsLog, Station } from "@repo/db";
|
||||
import { fmsStatusDescription } from "_data/fmsStatusDescription";
|
||||
import { DisplayLineProps } from "pilot/_components/mrt/Mrt";
|
||||
import { DisplayLineProps } from "(app)/pilot/_components/mrt/Mrt";
|
||||
import { create } from "zustand";
|
||||
import { syncTabs } from "zustand-sync-tabs";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { create } from "zustand";
|
||||
import { dispatchSocket } from "../../dispatch/socket";
|
||||
import { dispatchSocket } from "../../(app)/dispatch/socket";
|
||||
import { ConnectedAircraft, Mission, MissionSdsLog, Station, User } from "@repo/db";
|
||||
import { pilotSocket } from "pilot/socket";
|
||||
import { pilotSocket } from "(app)/pilot/socket";
|
||||
import { useDmeStore } from "_store/pilot/dmeStore";
|
||||
import { useMrtStore } from "_store/pilot/MrtStore";
|
||||
import { useAudioStore } from "_store/audioStore";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Mission, Station, User } from "@repo/db";
|
||||
import { DisplayLineProps } from "pilot/_components/dme/Dme";
|
||||
import { DisplayLineProps } from "(app)/pilot/_components/dme/Dme";
|
||||
import { create } from "zustand";
|
||||
import { syncTabs } from "zustand-sync-tabs";
|
||||
|
||||
|
||||
@@ -76,15 +76,7 @@ export const options: AuthOptions = {
|
||||
},
|
||||
});
|
||||
if (!dbUser) {
|
||||
return {
|
||||
...session,
|
||||
user: {
|
||||
name: null,
|
||||
email: null,
|
||||
image: null,
|
||||
},
|
||||
expires: new Date().toISOString(),
|
||||
};
|
||||
return null as any;
|
||||
}
|
||||
return {
|
||||
...session,
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
import type { Metadata } from "next";
|
||||
import Navbar from "./_components/navbar/Navbar";
|
||||
import { redirect } from "next/navigation";
|
||||
import { getServerSession } from "../api/auth/[...nextauth]/auth";
|
||||
import { Error } from "_components/Error";
|
||||
import { prisma } from "@repo/db";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "VAR: Disponent",
|
||||
description: "Die neue VAR Leitstelle.",
|
||||
};
|
||||
|
||||
export default async function RootLayout({
|
||||
children,
|
||||
}: Readonly<{
|
||||
children: React.ReactNode;
|
||||
}>) {
|
||||
const session = await getServerSession();
|
||||
const openPenaltys = await prisma.penalty.findMany({
|
||||
where: {
|
||||
userId: session?.user.id,
|
||||
until: {
|
||||
gte: new Date(),
|
||||
},
|
||||
suspended: false,
|
||||
|
||||
type: { in: ["TIME_BAN", "BAN"] },
|
||||
},
|
||||
});
|
||||
|
||||
if (!session || !session.user) {
|
||||
redirect("/login");
|
||||
}
|
||||
|
||||
if (openPenaltys[0]) {
|
||||
if (openPenaltys[0].type === "BAN") {
|
||||
return (
|
||||
<Error
|
||||
title="Du wurdest permanent ausgeschlossen"
|
||||
statusCode={403}
|
||||
description={`Dein Fehlverhalten war so schwerwiegend, dass du dauerhaft von VirtualAirRescue ausgeschlossen wurdest.`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Error
|
||||
title="Du hast eine aktive Strafe"
|
||||
statusCode={403}
|
||||
description={`Du bist bis zum ${new Date(openPenaltys[0].until!).toLocaleString()} gesperrt.`}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!session.user.emailVerified)
|
||||
return <Error title="E-Mail-Adresse nicht verifiziert" statusCode={403} />;
|
||||
|
||||
if (!session.user.permissions.includes("DISPO"))
|
||||
return <Error title="Zugriff verweigert" statusCode={403} />;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Navbar />
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -42,8 +42,9 @@ export default async function RootLayout({
|
||||
style: {
|
||||
background: "var(--color-base-100)",
|
||||
color: "var(--color-base-content)",
|
||||
zIndex: 9999,
|
||||
},
|
||||
duration: 4000,
|
||||
duration: 5000,
|
||||
}}
|
||||
position="top-left"
|
||||
reverseOrder={false}
|
||||
|
||||
@@ -8,7 +8,7 @@ export default () => {
|
||||
const session = useSession();
|
||||
|
||||
useEffect(() => {
|
||||
if (session.status !== "authenticated") {
|
||||
if (session.status === "unauthenticated") {
|
||||
router.replace("/login");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
import ModeSwitchDropdown from "_components/navbar/ModeSwitchDropdown";
|
||||
import { useSession } from "next-auth/react";
|
||||
import dynamic from "next/dynamic";
|
||||
import { ConnectedDispatcher } from "tracker/_components/ConnectedDispatcher";
|
||||
import { ConnectedDispatcher } from "./_components/ConnectedDispatcher";
|
||||
|
||||
const Map = dynamic(() => import("../_components/map/Map"), {
|
||||
const Map = dynamic(() => import("_components/map/Map"), {
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
|
||||