Alter Maintenance-Screen hinzugefügt
This commit is contained in:
@@ -1,22 +1,13 @@
|
|||||||
import { prisma } from "@repo/db";
|
import { prisma } from "@repo/db";
|
||||||
import { MessageCircleWarning } from "lucide-react";
|
import { MessageCircleWarning } from "lucide-react";
|
||||||
const fetchMainMessage = async () => {
|
|
||||||
return await prisma.notam.findFirst({
|
|
||||||
where: {
|
|
||||||
active: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const WarningAlert = async () => {
|
export const WarningAlert = async () => {
|
||||||
const mainMessage = await fetchMainMessage();
|
const config = await prisma.notam.findFirst({
|
||||||
|
orderBy: [{ createdAt: "desc" }],
|
||||||
if (mainMessage?.showUntilActive && new Date(mainMessage.showUntil) < new Date()) {
|
});
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
|
|
||||||
let msgColor;
|
let msgColor;
|
||||||
switch (mainMessage?.color) {
|
switch (config?.color) {
|
||||||
case "WARNING":
|
case "WARNING":
|
||||||
msgColor = "alert alert-soft alert-warning ml-3 py-2 flex items-center gap-2";
|
msgColor = "alert alert-soft alert-warning ml-3 py-2 flex items-center gap-2";
|
||||||
break;
|
break;
|
||||||
@@ -33,15 +24,11 @@ export const WarningAlert = async () => {
|
|||||||
msgColor = "alert alert-soft ml-3 py-2 flex items-center gap-2";
|
msgColor = "alert alert-soft ml-3 py-2 flex items-center gap-2";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mainMessage?.message == "" && !mainMessage?.wartungsmodus) || !mainMessage) {
|
if (config?.message || config?.maintenanceEnabled) {
|
||||||
return <></>;
|
|
||||||
} else {
|
|
||||||
return (
|
return (
|
||||||
<div role="alert" className={msgColor}>
|
<div className={msgColor}>
|
||||||
<MessageCircleWarning />
|
<MessageCircleWarning className="w-5 h-5" />
|
||||||
<span className="font-bold m-0">
|
{config?.message}
|
||||||
{mainMessage?.wartungsmodus ? "Wartungsmodus aktiv!" : mainMessage?.message}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Toaster } from "react-hot-toast";
|
|||||||
import { QueryProvider } from "_components/QueryProvider";
|
import { QueryProvider } from "_components/QueryProvider";
|
||||||
import { prisma } from "@repo/db";
|
import { prisma } from "@repo/db";
|
||||||
import { Error as ErrorComp } from "_components/Error";
|
import { Error as ErrorComp } from "_components/Error";
|
||||||
|
import { Maintenance } from "@repo/shared-components";
|
||||||
|
|
||||||
const geistSans = localFont({
|
const geistSans = localFont({
|
||||||
src: "./fonts/GeistVF.woff",
|
src: "./fonts/GeistVF.woff",
|
||||||
@@ -29,21 +30,10 @@ export default async function RootLayout({
|
|||||||
}>) {
|
}>) {
|
||||||
const session = await getServerSession();
|
const session = await getServerSession();
|
||||||
|
|
||||||
const latestNotam = await prisma.notam.findFirst({
|
const config = await prisma.notam.findFirst({
|
||||||
orderBy: { createdAt: "desc" },
|
orderBy: [{ createdAt: "desc" }],
|
||||||
});
|
});
|
||||||
|
|
||||||
let wartungsarbeiten = false;
|
|
||||||
if (
|
|
||||||
latestNotam &&
|
|
||||||
latestNotam.wartungsmodus &&
|
|
||||||
latestNotam.active &&
|
|
||||||
((latestNotam.showUntilActive && new Date(latestNotam.showUntil) > new Date()) ||
|
|
||||||
!latestNotam.showUntilActive)
|
|
||||||
) {
|
|
||||||
wartungsarbeiten = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="de" data-theme="dark">
|
<html lang="de" data-theme="dark">
|
||||||
<body
|
<body
|
||||||
@@ -70,19 +60,12 @@ export default async function RootLayout({
|
|||||||
{session?.user.isBanned && (
|
{session?.user.isBanned && (
|
||||||
<ErrorComp title="You are banned from using this service" statusCode={403} />
|
<ErrorComp title="You are banned from using this service" statusCode={403} />
|
||||||
)}
|
)}
|
||||||
|
{config?.maintenanceEnabled && !session?.user.permissions.includes("ADMIN_MESSAGE") && (
|
||||||
|
<Maintenance message={config?.message} />
|
||||||
|
)}
|
||||||
{!session?.user.isBanned &&
|
{!session?.user.isBanned &&
|
||||||
wartungsarbeiten &&
|
(!config?.maintenanceEnabled ||
|
||||||
!session?.user.permissions.includes("ADMIN_MESSAGE") && (
|
session?.user.permissions.includes("ADMIN_MESSAGE")) &&
|
||||||
<ErrorComp
|
|
||||||
title={
|
|
||||||
latestNotam?.message ||
|
|
||||||
"Wir führen aktuell Wartungsarbeiten am System durch, versuche es später erneut."
|
|
||||||
}
|
|
||||||
statusCode={503}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!session?.user.isBanned &&
|
|
||||||
(!wartungsarbeiten || session?.user.permissions.includes("ADMIN_MESSAGE")) &&
|
|
||||||
children}
|
children}
|
||||||
</NextAuthSessionProvider>
|
</NextAuthSessionProvider>
|
||||||
</QueryProvider>
|
</QueryProvider>
|
||||||
|
|||||||
@@ -5,54 +5,39 @@ import { Notam } from "@repo/db";
|
|||||||
import { NotamOptionalDefaults, NotamOptionalDefaultsSchema } from "@repo/db/zod";
|
import { NotamOptionalDefaults, NotamOptionalDefaultsSchema } from "@repo/db/zod";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { addMessage, disableMessage } from "../action";
|
import { addMessage, disableMessage } from "../action";
|
||||||
import { useState } from "react";
|
|
||||||
import { DateInput } from "_components/ui/DateInput";
|
|
||||||
import "react-datepicker/dist/react-datepicker.css"; // <-- Add this line at the top if using react-datepicker
|
import "react-datepicker/dist/react-datepicker.css"; // <-- Add this line at the top if using react-datepicker
|
||||||
|
import { Button } from "_components/ui/Button";
|
||||||
|
import { PaginatedTableRef } from "_components/PaginatedTable";
|
||||||
|
import { RefObject } from "react";
|
||||||
|
|
||||||
export const MessageForm = ({ message }: { message?: Notam }) => {
|
export const MessageForm = ({ tableRef }: { tableRef: RefObject<PaginatedTableRef | null> }) => {
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
||||||
|
|
||||||
const getDefaultShowUntilDate = () => {
|
|
||||||
const date = new Date();
|
|
||||||
return date;
|
|
||||||
};
|
|
||||||
|
|
||||||
const disableMessageClient = async () => {
|
const disableMessageClient = async () => {
|
||||||
await disableMessage();
|
await disableMessage();
|
||||||
window.location.reload();
|
tableRef?.current?.refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
const form = useForm<NotamOptionalDefaults>({
|
const form = useForm<NotamOptionalDefaults>({
|
||||||
resolver: zodResolver(NotamOptionalDefaultsSchema),
|
resolver: zodResolver(NotamOptionalDefaultsSchema),
|
||||||
defaultValues: {
|
|
||||||
message: message?.message,
|
|
||||||
color: message?.color,
|
|
||||||
active: true,
|
|
||||||
wartungsmodus: message?.wartungsmodus,
|
|
||||||
disableHPG: message?.disableHPG,
|
|
||||||
showUntil: getDefaultShowUntilDate(),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form
|
<form
|
||||||
onSubmit={form.handleSubmit(async (values) => {
|
onSubmit={form.handleSubmit(async (values) => {
|
||||||
setIsSubmitting(true);
|
|
||||||
try {
|
try {
|
||||||
await addMessage(values);
|
await addMessage(values);
|
||||||
window.location.reload();
|
tableRef?.current?.refresh();
|
||||||
|
form.reset();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setIsSubmitting(false);
|
|
||||||
console.error("Failed to add message", error);
|
console.error("Failed to add message", error);
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
className="grid grid-cols-6 gap-3"
|
className="grid grid-cols-6 gap-3"
|
||||||
>
|
>
|
||||||
<label className="floating-label col-span-6">
|
<label className="floating-label col-span-6">
|
||||||
<span>Globale Service Nachricht</span>
|
<span>Notam</span>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Globale Service Nachricht"
|
placeholder="Globales Notam"
|
||||||
className="input input-md w-full mb-2"
|
className="input input-md w-full mb-2"
|
||||||
{...form.register("message")}
|
{...form.register("message")}
|
||||||
/>
|
/>
|
||||||
@@ -94,7 +79,7 @@ export const MessageForm = ({ message }: { message?: Notam }) => {
|
|||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="checkbox checkbox-primary"
|
className="checkbox checkbox-primary"
|
||||||
{...form.register("wartungsmodus")}
|
{...form.register("maintenanceEnabled")}
|
||||||
/>
|
/>
|
||||||
Wartungsmodus einschalten
|
Wartungsmodus einschalten
|
||||||
</label>
|
</label>
|
||||||
@@ -107,26 +92,24 @@ export const MessageForm = ({ message }: { message?: Notam }) => {
|
|||||||
HPG Alarmierung deaktivieren
|
HPG Alarmierung deaktivieren
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2 ml-2">
|
|
||||||
<label className="label">Nachricht & Effekte bis (optional)</label>
|
|
||||||
<DateInput
|
|
||||||
control={form.control}
|
|
||||||
name="showUntil"
|
|
||||||
showTimeInput
|
|
||||||
timeCaption="Uhrzeit"
|
|
||||||
showTimeCaption
|
|
||||||
className="input input-md"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col justify-end">
|
<div className="flex flex-col justify-end">
|
||||||
<div className="flex justify-center gap-2">
|
<div className="flex justify-center gap-2">
|
||||||
<button type="submit" className="btn btn-soft" onClick={disableMessageClient}>
|
<Button
|
||||||
Aktuelle Nachricht deaktivieren
|
type="button"
|
||||||
</button>
|
onSubmit={() => false}
|
||||||
<button type="submit" className="btn btn-primary" disabled={isSubmitting}>
|
className="btn btn-soft"
|
||||||
|
onClick={disableMessageClient}
|
||||||
|
>
|
||||||
|
Config zurücksetzen
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
className="btn btn-primary"
|
||||||
|
isLoading={form.formState.isSubmitting}
|
||||||
|
>
|
||||||
Speichern
|
Speichern
|
||||||
</button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
22
apps/hub/app/(app)/admin/config/action.tsx
Normal file
22
apps/hub/app/(app)/admin/config/action.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"use server";
|
||||||
|
import { prisma, Prisma } from "@repo/db";
|
||||||
|
|
||||||
|
export const addMessage = async (notam: Prisma.NotamCreateInput) => {
|
||||||
|
try {
|
||||||
|
await prisma.notam.create({
|
||||||
|
data: notam,
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Failed to add message");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const disableMessage = async () => {
|
||||||
|
try {
|
||||||
|
await prisma.notam.create({
|
||||||
|
data: {},
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error("Failed to disable message");
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,27 +1,30 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { Check, MessageSquareWarning } from "lucide-react";
|
import { Check, MessageSquareWarning, Settings } from "lucide-react";
|
||||||
import { MessageForm } from "./_components/messageForm";
|
import { MessageForm } from "./_components/MessageForm";
|
||||||
import { PaginatedTable } from "_components/PaginatedTable";
|
import { PaginatedTable, PaginatedTableRef } from "_components/PaginatedTable";
|
||||||
import { ColumnDef } from "@tanstack/react-table";
|
import { ColumnDef } from "@tanstack/react-table";
|
||||||
import { Notam } from "@repo/db";
|
import { Notam } from "@repo/db";
|
||||||
|
import { useRef } from "react";
|
||||||
|
|
||||||
export default function MessagePage() {
|
export default function MessagePage() {
|
||||||
|
const tableRef = useRef<PaginatedTableRef | null>(null);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="grid grid-cols-6 gap-4">
|
<div className="grid grid-cols-6 gap-4">
|
||||||
<div className="col-span-full">
|
<div className="col-span-full">
|
||||||
<p className="text-2xl font-semibold text-left flex items-center gap-2">
|
<p className="text-2xl font-semibold text-left flex items-center gap-2">
|
||||||
<MessageSquareWarning className="w-5 h-5" /> Service Nachrichten
|
<Settings className="w-5 h-5" /> Config
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="card bg-base-200 shadow-xl mb-4 col-span-6">
|
<div className="card bg-base-200 shadow-xl mb-4 col-span-6">
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<MessageForm />
|
<MessageForm tableRef={tableRef} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<PaginatedTable
|
<PaginatedTable
|
||||||
|
ref={tableRef}
|
||||||
prismaModel="notam"
|
prismaModel="notam"
|
||||||
initialOrderBy={[{ id: "createdAt", desc: true }]}
|
initialOrderBy={[{ id: "createdAt", desc: true }]}
|
||||||
columns={
|
columns={
|
||||||
@@ -42,7 +45,7 @@ export default function MessagePage() {
|
|||||||
accessorKey: "wartungsmodus",
|
accessorKey: "wartungsmodus",
|
||||||
header: "Wartungsmodus",
|
header: "Wartungsmodus",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const wartungsmodus = row.getValue("wartungsmodus");
|
const wartungsmodus = row.original.maintenanceEnabled;
|
||||||
return wartungsmodus ? <Check /> : "";
|
return wartungsmodus ? <Check /> : "";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -50,28 +53,11 @@ export default function MessagePage() {
|
|||||||
accessorKey: "disableHPG",
|
accessorKey: "disableHPG",
|
||||||
header: "HPG deaktiviert",
|
header: "HPG deaktiviert",
|
||||||
cell: ({ row }) => {
|
cell: ({ row }) => {
|
||||||
const disableHPG = row.getValue("disableHPG");
|
const disableHPG = row.original.disableHPG;
|
||||||
return disableHPG ? <Check /> : "";
|
return disableHPG ? <Check /> : "";
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
|
||||||
accessorKey: "showUntil",
|
|
||||||
header: "Zeitlimit",
|
|
||||||
cell: ({ row, cell }) => {
|
|
||||||
const showUntil = new Date(cell.getValue() as string);
|
|
||||||
const createdAt = new Date(row.getValue("createdAt") as string);
|
|
||||||
if (showUntil > createdAt) {
|
|
||||||
return showUntil.toLocaleDateString("de-DE", {
|
|
||||||
year: "numeric",
|
|
||||||
month: "2-digit",
|
|
||||||
day: "2-digit",
|
|
||||||
hour: "2-digit",
|
|
||||||
minute: "2-digit",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
accessorKey: "createdAt",
|
accessorKey: "createdAt",
|
||||||
header: "Erstellt am",
|
header: "Erstellt am",
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
"use server";
|
|
||||||
import { prisma, Prisma } from "@repo/db";
|
|
||||||
|
|
||||||
export const addMessage = async (message: Prisma.NotamCreateInput) => {
|
|
||||||
try {
|
|
||||||
await prisma.notam.updateMany({
|
|
||||||
where: { active: true },
|
|
||||||
data: { active: false },
|
|
||||||
});
|
|
||||||
|
|
||||||
const showUntil = new Date(message.showUntil);
|
|
||||||
const showUntilActive = showUntil > new Date();
|
|
||||||
|
|
||||||
await prisma.notam.create({
|
|
||||||
data: {
|
|
||||||
message: message.message,
|
|
||||||
color: message.color,
|
|
||||||
active: true,
|
|
||||||
wartungsmodus: message.wartungsmodus,
|
|
||||||
disableHPG: message.disableHPG,
|
|
||||||
showUntilActive,
|
|
||||||
showUntil,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error("Failed to add message");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const disableMessage = async () => {
|
|
||||||
try {
|
|
||||||
await prisma.notam.updateMany({
|
|
||||||
where: { active: true },
|
|
||||||
data: { active: false },
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
throw new Error("Failed to disable message");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -80,7 +80,7 @@ export const VerticalNav = async () => {
|
|||||||
)}
|
)}
|
||||||
{session.user.permissions.includes("ADMIN_MESSAGE") && (
|
{session.user.permissions.includes("ADMIN_MESSAGE") && (
|
||||||
<li>
|
<li>
|
||||||
<Link href="/admin/message">Service Nachrichten</Link>
|
<Link href="/admin/config">Config</Link>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
{session.user.permissions.includes("ADMIN_USER") && (
|
{session.user.permissions.includes("ADMIN_USER") && (
|
||||||
|
|||||||
@@ -1,19 +1,12 @@
|
|||||||
import { prisma } from "@repo/db";
|
import { prisma } from "@repo/db";
|
||||||
import { MessageCircleWarning } from "lucide-react";
|
import { MessageCircleWarning } from "lucide-react";
|
||||||
const fetchMainMessage = async () => {
|
|
||||||
return await prisma.notam.findFirst({
|
|
||||||
where: {
|
|
||||||
active: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
export const WarningAlert = async () => {
|
export const WarningAlert = async () => {
|
||||||
const mainMessage = await fetchMainMessage();
|
const mainMessage = await await prisma.notam.findFirst({
|
||||||
|
orderBy: {
|
||||||
if (mainMessage?.showUntilActive && new Date(mainMessage.showUntil) < new Date()) {
|
createdAt: "desc",
|
||||||
return <></>;
|
},
|
||||||
}
|
});
|
||||||
|
|
||||||
let msgColor;
|
let msgColor;
|
||||||
switch (mainMessage?.color) {
|
switch (mainMessage?.color) {
|
||||||
@@ -33,14 +26,14 @@ export const WarningAlert = async () => {
|
|||||||
msgColor = "alert alert-soft ml-3 py-2 flex items-center gap-2";
|
msgColor = "alert alert-soft ml-3 py-2 flex items-center gap-2";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((mainMessage?.message == "" && !mainMessage?.wartungsmodus) || !mainMessage) {
|
if ((mainMessage?.message == "" && !mainMessage?.maintenanceEnabled) || !mainMessage) {
|
||||||
return <></>;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div role="alert" className={msgColor}>
|
<div role="alert" className={msgColor}>
|
||||||
<MessageCircleWarning />
|
<MessageCircleWarning />
|
||||||
<span className="font-bold m-0">
|
<span className="font-bold m-0">
|
||||||
{mainMessage?.wartungsmodus ? "Wartungsmodus aktiv!" : mainMessage?.message}
|
{mainMessage?.maintenanceEnabled ? "Wartungsmodus aktiv!" : mainMessage?.message}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { QueryProvider } from "_components/QueryClient";
|
|||||||
import { prisma } from "@repo/db";
|
import { prisma } from "@repo/db";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Error as ErrorComp } from "_components/Error";
|
import { Error as ErrorComp } from "_components/Error";
|
||||||
|
import { Maintenance } from "@repo/shared-components";
|
||||||
|
|
||||||
const geistSans = Geist({
|
const geistSans = Geist({
|
||||||
variable: "--font-geist-sans",
|
variable: "--font-geist-sans",
|
||||||
@@ -30,31 +31,16 @@ const RootLayout = async ({
|
|||||||
orderBy: { createdAt: "desc" },
|
orderBy: { createdAt: "desc" },
|
||||||
});
|
});
|
||||||
|
|
||||||
let wartungsarbeiten = false;
|
|
||||||
if (
|
|
||||||
latestNotam &&
|
|
||||||
latestNotam.wartungsmodus &&
|
|
||||||
latestNotam.active &&
|
|
||||||
((latestNotam.showUntilActive && new Date(latestNotam.showUntil) > new Date()) ||
|
|
||||||
!latestNotam.showUntilActive)
|
|
||||||
) {
|
|
||||||
wartungsarbeiten = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<html lang="en" data-theme="dark">
|
<html lang="en" data-theme="dark">
|
||||||
<NextAuthSessionProvider session={session}>
|
<NextAuthSessionProvider session={session}>
|
||||||
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
|
||||||
{wartungsarbeiten && !session?.user.permissions.includes("ADMIN_MESSAGE") && (
|
{latestNotam?.maintenanceEnabled &&
|
||||||
<ErrorComp
|
!session?.user.permissions.includes("ADMIN_MESSAGE") && (
|
||||||
title={
|
<Maintenance message={latestNotam?.message} />
|
||||||
latestNotam?.message ||
|
)}
|
||||||
"Wir führen aktuell Wartungsarbeiten am System durch, versuche es später erneut."
|
{(!latestNotam?.maintenanceEnabled ||
|
||||||
}
|
session?.user.permissions.includes("ADMIN_MESSAGE")) && (
|
||||||
statusCode={503}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{(!wartungsarbeiten || session?.user.permissions.includes("ADMIN_MESSAGE")) && (
|
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
<Toaster
|
<Toaster
|
||||||
|
|||||||
BIN
apps/hub/public/logo.png
Normal file
BIN
apps/hub/public/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 420 KiB |
@@ -16,5 +16,5 @@
|
|||||||
".next/types/**/*.ts",
|
".next/types/**/*.ts",
|
||||||
"types/.d.ts"
|
"types/.d.ts"
|
||||||
],
|
],
|
||||||
"exclude": ["node_modules"]
|
"exclude": ["node_modules", ".next"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `active` on the `Notam` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `showUntil` on the `Notam` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `updatedAt` on the `Notam` table. All the data in the column will be lost.
|
||||||
|
- You are about to drop the column `wartungsmodus` on the `Notam` table. All the data in the column will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Notam" DROP COLUMN "active",
|
||||||
|
DROP COLUMN "showUntil",
|
||||||
|
DROP COLUMN "updatedAt",
|
||||||
|
DROP COLUMN "wartungsmodus",
|
||||||
|
ADD COLUMN "maintenanceEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
ALTER COLUMN "color" DROP NOT NULL,
|
||||||
|
ALTER COLUMN "message" SET DEFAULT '';
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- You are about to drop the column `showUntilActive` on the `Notam` table. All the data in the column will be lost.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "Notam" DROP COLUMN "showUntilActive";
|
||||||
@@ -8,14 +8,10 @@ enum GlobalColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model Notam {
|
model Notam {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
color GlobalColor
|
color GlobalColor?
|
||||||
message String
|
message String @default("")
|
||||||
showUntil DateTime
|
maintenanceEnabled Boolean @default(false)
|
||||||
showUntilActive Boolean @default(false)
|
disableHPG Boolean @default(false)
|
||||||
wartungsmodus Boolean @default(false)
|
createdAt DateTime @default(now())
|
||||||
disableHPG Boolean @default(false)
|
|
||||||
active Boolean
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
updatedAt DateTime @updatedAt
|
|
||||||
}
|
}
|
||||||
|
|||||||
46
packages/shared-components/components/Maintenance.tsx
Normal file
46
packages/shared-components/components/Maintenance.tsx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
"use client";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
export const Maintenance = ({ message }: { message?: string }) => {
|
||||||
|
const [rotationSpeed, setRotationSpeed] = useState(0);
|
||||||
|
const [rotationDeg, setRotationDeg] = useState(0);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setRotationDeg(rotationDeg + rotationSpeed);
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, [rotationDeg, rotationSpeed]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-[10px] min-h-0 bg-base-300 shadow-lg p-8">
|
||||||
|
<h1 className="text-4xl font-bold text-center">Wartungsarbeiten</h1>
|
||||||
|
<p className="text-base text-center mx-6">
|
||||||
|
{message || "Unsere Website wird derzeit gewartet. Bitte versuchen Sie es später erneut."}
|
||||||
|
</p>
|
||||||
|
<div className="flex flex-col items-center gap-6 mt-6">
|
||||||
|
<img
|
||||||
|
src={`${process.env.NEXT_PUBLIC_HUB_URL}/logo.png`}
|
||||||
|
width={150}
|
||||||
|
alt="logo"
|
||||||
|
style={{
|
||||||
|
transform: `rotate(${rotationDeg}deg)`,
|
||||||
|
cursor: "pointer",
|
||||||
|
boxShadow: `0 0 ${rotationSpeed * 20}px rgba(255, 0, 0, ${rotationSpeed - 0})`,
|
||||||
|
borderRadius: "50%",
|
||||||
|
}}
|
||||||
|
onClick={() => {
|
||||||
|
setRotationSpeed(rotationSpeed + 0.1);
|
||||||
|
}}
|
||||||
|
onContextMenu={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setRotationSpeed(Math.max(rotationSpeed - 0.1, 0));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
export * from "./Badge";
|
export * from "./Badge";
|
||||||
export * from "./PenaltyDropdown";
|
export * from "./PenaltyDropdown";
|
||||||
|
export * from "./Maintenance";
|
||||||
|
|||||||
Reference in New Issue
Block a user