Alter Maintenance-Screen hinzugefügt

This commit is contained in:
PxlLoewe
2025-07-03 21:17:23 -07:00
parent 2ff2c3274a
commit 7c050cf42e
16 changed files with 168 additions and 199 deletions

View File

@@ -5,54 +5,39 @@ import { Notam } from "@repo/db";
import { NotamOptionalDefaults, NotamOptionalDefaultsSchema } from "@repo/db/zod";
import { useForm } from "react-hook-form";
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 { Button } from "_components/ui/Button";
import { PaginatedTableRef } from "_components/PaginatedTable";
import { RefObject } from "react";
export const MessageForm = ({ message }: { message?: Notam }) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const getDefaultShowUntilDate = () => {
const date = new Date();
return date;
};
export const MessageForm = ({ tableRef }: { tableRef: RefObject<PaginatedTableRef | null> }) => {
const disableMessageClient = async () => {
await disableMessage();
window.location.reload();
tableRef?.current?.refresh();
};
const form = useForm<NotamOptionalDefaults>({
resolver: zodResolver(NotamOptionalDefaultsSchema),
defaultValues: {
message: message?.message,
color: message?.color,
active: true,
wartungsmodus: message?.wartungsmodus,
disableHPG: message?.disableHPG,
showUntil: getDefaultShowUntilDate(),
},
});
return (
<form
onSubmit={form.handleSubmit(async (values) => {
setIsSubmitting(true);
try {
await addMessage(values);
window.location.reload();
tableRef?.current?.refresh();
form.reset();
} catch (error) {
setIsSubmitting(false);
console.error("Failed to add message", error);
}
})}
className="grid grid-cols-6 gap-3"
>
<label className="floating-label col-span-6">
<span>Globale Service Nachricht</span>
<span>Notam</span>
<input
type="text"
placeholder="Globale Service Nachricht"
placeholder="Globales Notam"
className="input input-md w-full mb-2"
{...form.register("message")}
/>
@@ -94,7 +79,7 @@ export const MessageForm = ({ message }: { message?: Notam }) => {
<input
type="checkbox"
className="checkbox checkbox-primary"
{...form.register("wartungsmodus")}
{...form.register("maintenanceEnabled")}
/>
Wartungsmodus einschalten
</label>
@@ -107,26 +92,24 @@ export const MessageForm = ({ message }: { message?: Notam }) => {
HPG Alarmierung deaktivieren
</label>
</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 className="flex flex-col justify-end">
<div className="flex justify-center gap-2">
<button type="submit" className="btn btn-soft" onClick={disableMessageClient}>
Aktuelle Nachricht deaktivieren
</button>
<button type="submit" className="btn btn-primary" disabled={isSubmitting}>
<Button
type="button"
onSubmit={() => false}
className="btn btn-soft"
onClick={disableMessageClient}
>
Config zurücksetzen
</Button>
<Button
type="submit"
className="btn btn-primary"
isLoading={form.formState.isSubmitting}
>
Speichern
</button>
</Button>
</div>
</div>
</div>

View 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");
}
};

View File

@@ -1,27 +1,30 @@
"use client";
import { Check, MessageSquareWarning } from "lucide-react";
import { MessageForm } from "./_components/messageForm";
import { PaginatedTable } from "_components/PaginatedTable";
import { Check, MessageSquareWarning, Settings } from "lucide-react";
import { MessageForm } from "./_components/MessageForm";
import { PaginatedTable, PaginatedTableRef } from "_components/PaginatedTable";
import { ColumnDef } from "@tanstack/react-table";
import { Notam } from "@repo/db";
import { useRef } from "react";
export default function MessagePage() {
const tableRef = useRef<PaginatedTableRef | null>(null);
return (
<>
<div className="grid grid-cols-6 gap-4">
<div className="col-span-full">
<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>
</div>
<div className="card bg-base-200 shadow-xl mb-4 col-span-6">
<div className="card-body">
<MessageForm />
<MessageForm tableRef={tableRef} />
</div>
</div>
</div>
<PaginatedTable
ref={tableRef}
prismaModel="notam"
initialOrderBy={[{ id: "createdAt", desc: true }]}
columns={
@@ -42,7 +45,7 @@ export default function MessagePage() {
accessorKey: "wartungsmodus",
header: "Wartungsmodus",
cell: ({ row }) => {
const wartungsmodus = row.getValue("wartungsmodus");
const wartungsmodus = row.original.maintenanceEnabled;
return wartungsmodus ? <Check /> : "";
},
},
@@ -50,28 +53,11 @@ export default function MessagePage() {
accessorKey: "disableHPG",
header: "HPG deaktiviert",
cell: ({ row }) => {
const disableHPG = row.getValue("disableHPG");
const disableHPG = row.original.disableHPG;
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",
header: "Erstellt am",

View File

@@ -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");
}
};

View File

@@ -80,7 +80,7 @@ export const VerticalNav = async () => {
)}
{session.user.permissions.includes("ADMIN_MESSAGE") && (
<li>
<Link href="/admin/message">Service Nachrichten</Link>
<Link href="/admin/config">Config</Link>
</li>
)}
{session.user.permissions.includes("ADMIN_USER") && (

View File

@@ -1,19 +1,12 @@
import { prisma } from "@repo/db";
import { MessageCircleWarning } from "lucide-react";
const fetchMainMessage = async () => {
return await prisma.notam.findFirst({
where: {
active: true,
},
});
};
export const WarningAlert = async () => {
const mainMessage = await fetchMainMessage();
if (mainMessage?.showUntilActive && new Date(mainMessage.showUntil) < new Date()) {
return <></>;
}
const mainMessage = await await prisma.notam.findFirst({
orderBy: {
createdAt: "desc",
},
});
let msgColor;
switch (mainMessage?.color) {
@@ -33,14 +26,14 @@ export const WarningAlert = async () => {
msgColor = "alert alert-soft ml-3 py-2 flex items-center gap-2";
}
if ((mainMessage?.message == "" && !mainMessage?.wartungsmodus) || !mainMessage) {
return <></>;
if ((mainMessage?.message == "" && !mainMessage?.maintenanceEnabled) || !mainMessage) {
return null;
} else {
return (
<div role="alert" className={msgColor}>
<MessageCircleWarning />
<span className="font-bold m-0">
{mainMessage?.wartungsmodus ? "Wartungsmodus aktiv!" : mainMessage?.message}
{mainMessage?.maintenanceEnabled ? "Wartungsmodus aktiv!" : mainMessage?.message}
</span>
</div>
);

View File

@@ -8,6 +8,7 @@ import { QueryProvider } from "_components/QueryClient";
import { prisma } from "@repo/db";
import React from "react";
import { Error as ErrorComp } from "_components/Error";
import { Maintenance } from "@repo/shared-components";
const geistSans = Geist({
variable: "--font-geist-sans",
@@ -30,31 +31,16 @@ const RootLayout = async ({
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 (
<html lang="en" data-theme="dark">
<NextAuthSessionProvider session={session}>
<body className={`${geistSans.variable} ${geistMono.variable} antialiased`}>
{wartungsarbeiten && !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}
/>
)}
{(!wartungsarbeiten || session?.user.permissions.includes("ADMIN_MESSAGE")) && (
{latestNotam?.maintenanceEnabled &&
!session?.user.permissions.includes("ADMIN_MESSAGE") && (
<Maintenance message={latestNotam?.message} />
)}
{(!latestNotam?.maintenanceEnabled ||
session?.user.permissions.includes("ADMIN_MESSAGE")) && (
<>
<div>
<Toaster