Ban Message Design
This commit is contained in:
@@ -171,7 +171,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
data: {
|
data: {
|
||||||
userId: aircraft.userId,
|
userId: aircraft.userId,
|
||||||
type: bann ? (until ? "TIME_BAN" : "BAN") : "KICK",
|
type: bann ? (until ? "TIME_BAN" : "BAN") : "KICK",
|
||||||
until: until ? new Date(until) : null,
|
until: until ? new Date(until) : new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 50),
|
||||||
reason: reason,
|
reason: reason,
|
||||||
createdUserId: req.user.id,
|
createdUserId: req.user.id,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ router.delete("/:id", async (req, res) => {
|
|||||||
data: {
|
data: {
|
||||||
userId: dispatcher.userId,
|
userId: dispatcher.userId,
|
||||||
type: bann ? (until ? "TIME_BAN" : "BAN") : "KICK",
|
type: bann ? (until ? "TIME_BAN" : "BAN") : "KICK",
|
||||||
until: until ? new Date(until) : null,
|
until: until ? new Date(until) : new Date(Date.now() + 1000 * 60 * 60 * 24 * 365 * 50),
|
||||||
reason: reason,
|
reason: reason,
|
||||||
createdUserId: req.user.id,
|
createdUserId: req.user.id,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default async function RootLayout({
|
|||||||
until: {
|
until: {
|
||||||
gte: new Date(),
|
gte: new Date(),
|
||||||
},
|
},
|
||||||
type: "TIME_BAN",
|
type: { in: ["TIME_BAN", "BAN"] },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -30,13 +30,16 @@ export default async function RootLayout({
|
|||||||
redirect("/login");
|
redirect("/login");
|
||||||
}
|
}
|
||||||
|
|
||||||
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} />;
|
|
||||||
|
|
||||||
if (openPenaltys[0]) {
|
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 (
|
return (
|
||||||
<Error
|
<Error
|
||||||
title="Du hast eine aktive Strafe"
|
title="Du hast eine aktive Strafe"
|
||||||
@@ -46,6 +49,12 @@ export default async function RootLayout({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
|||||||
@@ -22,21 +22,24 @@ export default async function RootLayout({
|
|||||||
until: {
|
until: {
|
||||||
gte: new Date(),
|
gte: new Date(),
|
||||||
},
|
},
|
||||||
type: "TIME_BAN",
|
type: { in: ["TIME_BAN", "BAN"] },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!session || !session.user.firstname) {
|
if (!session || !session.user.firstname) {
|
||||||
redirect("/login");
|
redirect("/login");
|
||||||
}
|
}
|
||||||
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} />;
|
|
||||||
|
|
||||||
if (openPenaltys[0]) {
|
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 (
|
return (
|
||||||
<Error
|
<Error
|
||||||
title="Du hast eine aktive Strafe"
|
title="Du hast eine aktive Strafe"
|
||||||
@@ -46,6 +49,13 @@ 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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<Navbar />
|
<Navbar />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { prisma } from "@repo/db";
|
import { prisma } from "@repo/db";
|
||||||
import { TriangleAlert } from "lucide-react";
|
import { TriangleAlert } from "lucide-react";
|
||||||
import { getServerSession } from "next-auth";
|
import { getServerSession } from "next-auth";
|
||||||
|
import { PenaltyCountdown } from "./PenaltyCountdown";
|
||||||
|
|
||||||
export const Penalty = async () => {
|
export const Penalty = async () => {
|
||||||
const session = await getServerSession();
|
const session = await getServerSession();
|
||||||
@@ -10,7 +11,7 @@ export const Penalty = async () => {
|
|||||||
until: {
|
until: {
|
||||||
gte: new Date(),
|
gte: new Date(),
|
||||||
},
|
},
|
||||||
type: "TIME_BAN",
|
type: { in: ["TIME_BAN", "BAN"] },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!openPenaltys[0]) {
|
if (!openPenaltys[0]) {
|
||||||
@@ -18,18 +19,33 @@ export const Penalty = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="card bg-base-200 shadow-xl mb-4 col-span-6 xl:col-span-3">
|
<div className="card bg-error shadow-xl mb-4 col-span-6 xl:col-span-3">
|
||||||
<div className="card-body">
|
{openPenaltys[0].type === "TIME_BAN" && (
|
||||||
<h2 className="card-title text-3xl text-center text-error">
|
<div className="card-body text-base-300">
|
||||||
|
<h2 className="card-title text-3xl">
|
||||||
<TriangleAlert />
|
<TriangleAlert />
|
||||||
Aktive Strafe
|
Aktive Strafe - <PenaltyCountdown until={openPenaltys[0].until ?? new Date()} />{" "}
|
||||||
|
verbleibend
|
||||||
</h2>
|
</h2>
|
||||||
<p>Du hast eine aktive Strafe, die dich daran hindert, an Flügen teilzunehmen.</p>
|
<p className="text-left font-bold">
|
||||||
<p>Strafe: {openPenaltys[0].reason}</p>
|
Du hast eine aktive Strafe und kannst dich deshalb nicht mit dem Netzwerk verbinden.
|
||||||
{openPenaltys[0].until && (
|
</p>
|
||||||
<p>Bis: {new Date(openPenaltys[0].until).toLocaleDateString()}</p>
|
<p className="text-left font-bold">Grund: {openPenaltys[0].reason}</p>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{openPenaltys[0].type === "BAN" && (
|
||||||
|
<div className="card-body text-base-300">
|
||||||
|
<h2 className="card-title text-3xl">
|
||||||
|
<TriangleAlert />
|
||||||
|
Du wurdest permanent von VirtualAirRescue ausgeschlossen.
|
||||||
|
</h2>
|
||||||
|
<p className="text-left font-bold">
|
||||||
|
Dein Fehlverhalten war so schwerwiegend, dass du dauerhaft von VirtualAirRescue
|
||||||
|
ausgeschlossen wurdest. Du kannst dich nicht mehr mit dem Netzwerk verbinden.
|
||||||
|
</p>
|
||||||
|
<p className="text-left font-bold">Grund: {openPenaltys[0].reason}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
46
apps/hub/app/(app)/_components/PenaltyCountdown.tsx
Normal file
46
apps/hub/app/(app)/_components/PenaltyCountdown.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"use client";
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
interface PenaltyCountdownProps {
|
||||||
|
until: string | Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTimeLeft(until: string | Date) {
|
||||||
|
const untilDate = new Date(until).getTime();
|
||||||
|
const now = Date.now();
|
||||||
|
let diff = Math.max(0, untilDate - now);
|
||||||
|
const hours = Math.floor(diff / (1000 * 60 * 60));
|
||||||
|
diff -= hours * 1000 * 60 * 60;
|
||||||
|
const minutes = Math.floor(diff / (1000 * 60));
|
||||||
|
diff -= minutes * 1000 * 60;
|
||||||
|
const seconds = Math.floor(diff / 1000);
|
||||||
|
return { hours, minutes, seconds };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PenaltyCountdown: React.FC<PenaltyCountdownProps> = ({ until }) => {
|
||||||
|
const [timeLeft, setTimeLeft] = useState(() => getTimeLeft(until));
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setTimeLeft(getTimeLeft(until));
|
||||||
|
}, 1000);
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, [until]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<span className="countdown text-3xl">
|
||||||
|
<span style={{ "--value": timeLeft.hours } as React.CSSProperties} aria-live="polite">
|
||||||
|
{timeLeft.hours}
|
||||||
|
</span>
|
||||||
|
h
|
||||||
|
<span style={{ "--value": timeLeft.minutes } as React.CSSProperties} aria-live="polite">
|
||||||
|
{timeLeft.minutes}
|
||||||
|
</span>
|
||||||
|
m
|
||||||
|
<span style={{ "--value": timeLeft.seconds } as React.CSSProperties} aria-live="polite">
|
||||||
|
{timeLeft.seconds}
|
||||||
|
</span>
|
||||||
|
s
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user