Global Messages
This commit is contained in:
107
apps/hub/app/(app)/admin/message/_components/messageForm.tsx
Normal file
107
apps/hub/app/(app)/admin/message/_components/messageForm.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
"use client";
|
||||
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Message } from "@repo/db";
|
||||
import { MessageOptionalDefaultsSchema } from "@repo/db/zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
import { addMessage, disableMessage } from "../action";
|
||||
import { useState } from "react";
|
||||
|
||||
export const MessageForm = ({ message }: { message?: Message }) => {
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
const getDefaultShowUntilDate = () => {
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 5);
|
||||
return date;
|
||||
};
|
||||
|
||||
const disableMessageClient = async () => {
|
||||
disableMessage();
|
||||
};
|
||||
|
||||
const form = useForm<z.infer<typeof MessageOptionalDefaultsSchema>>({
|
||||
resolver: zodResolver(MessageOptionalDefaultsSchema),
|
||||
defaultValues: {
|
||||
message: message?.message,
|
||||
color: message?.color,
|
||||
isMainMsg: true,
|
||||
active: true,
|
||||
showUntil: getDefaultShowUntilDate(),
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={form.handleSubmit(async (values) => {
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
const msg = await addMessage(values);
|
||||
} 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>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Globale Service Nachricht"
|
||||
className="input input-md w-full mb-2"
|
||||
{...form.register("message")}
|
||||
/>
|
||||
</label>
|
||||
<div className="gap-2 flex justify-between col-span-6">
|
||||
<div className="content-center">
|
||||
<input
|
||||
type="radio"
|
||||
value="INFO"
|
||||
{...form.register("color")}
|
||||
className="radio radio-info ml-2 mr-2"
|
||||
/>
|
||||
<span>Info</span>
|
||||
<input
|
||||
type="radio"
|
||||
value="SUCCESS"
|
||||
{...form.register("color")}
|
||||
className="radio radio-success ml-2 mr-2"
|
||||
/>
|
||||
<span>Success</span>
|
||||
<input
|
||||
type="radio"
|
||||
value="WARNING"
|
||||
{...form.register("color")}
|
||||
className="radio radio-warning ml-2 mr-2"
|
||||
/>
|
||||
<span>Warning</span>
|
||||
<input
|
||||
type="radio"
|
||||
value="ERROR"
|
||||
{...form.register("color")}
|
||||
className="radio radio-error ml-2 mr-2"
|
||||
/>
|
||||
<span>Error</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-soft mr-2"
|
||||
onClick={disableMessageClient}
|
||||
>
|
||||
Aktuelle Nachricht deaktivieren
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="btn btn-primary"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
Speichern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
36
apps/hub/app/(app)/admin/message/action.tsx
Normal file
36
apps/hub/app/(app)/admin/message/action.tsx
Normal file
@@ -0,0 +1,36 @@
|
||||
"use server";
|
||||
import { prisma, Prisma } from "@repo/db";
|
||||
|
||||
export const addMessage = async (message: Prisma.MessageCreateInput) => {
|
||||
try {
|
||||
// Set all current messages with isMainMsg=true to active=false
|
||||
await prisma.message.updateMany({
|
||||
where: { isMainMsg: true },
|
||||
data: { active: false },
|
||||
});
|
||||
|
||||
await prisma.message.create({
|
||||
data: {
|
||||
message: message.message,
|
||||
color: message.color,
|
||||
isMainMsg: true,
|
||||
active: true,
|
||||
showUntil: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error("Failed to add message");
|
||||
}
|
||||
};
|
||||
|
||||
export const disableMessage = async () => {
|
||||
try {
|
||||
// Set all current messages with isMainMsg=true to active=false
|
||||
await prisma.message.updateMany({
|
||||
where: { isMainMsg: true },
|
||||
data: { active: false },
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error("Failed to disable message");
|
||||
}
|
||||
};
|
||||
19
apps/hub/app/(app)/admin/message/page.tsx
Normal file
19
apps/hub/app/(app)/admin/message/page.tsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import { MessageSquareWarning } from "lucide-react";
|
||||
import { MessageForm } from "./_components/messageForm";
|
||||
|
||||
export default function MessagePage() {
|
||||
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
|
||||
</p>
|
||||
</div>
|
||||
<div className="card bg-base-200 shadow-xl mb-4 col-span-6">
|
||||
<div className="card-body">
|
||||
<MessageForm />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -7,10 +7,11 @@ import {
|
||||
ReaderIcon,
|
||||
} from "@radix-ui/react-icons";
|
||||
import Link from "next/link";
|
||||
import { WarningAlert } from "./ui/PageAlert";
|
||||
|
||||
export const VerticalNav = () => {
|
||||
return (
|
||||
<ul className="menu w-64 bg-base-300 p-4 rounded-lg shadow-md">
|
||||
<ul className="menu w-64 bg-base-300 p-3 rounded-lg shadow-md font-semibold">
|
||||
<li>
|
||||
<Link href="/">
|
||||
<HomeIcon /> Dashboard
|
||||
@@ -50,6 +51,9 @@ export const VerticalNav = () => {
|
||||
<li>
|
||||
<Link href="/admin/event">Events</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link href="/admin/message">Service Nachrichten</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</details>
|
||||
</li>
|
||||
@@ -63,6 +67,7 @@ export const HorizontalNav = () => (
|
||||
<a className="btn btn-ghost normal-case text-xl">
|
||||
Virtual Air Rescue - HUB
|
||||
</a>
|
||||
<WarningAlert />
|
||||
</div>
|
||||
<div className="flex items-center ml-auto">
|
||||
<ul className="flex space-x-2 px-1">
|
||||
|
||||
57
apps/hub/app/_components/ui/PageAlert.tsx
Normal file
57
apps/hub/app/_components/ui/PageAlert.tsx
Normal file
@@ -0,0 +1,57 @@
|
||||
import { prisma } from "@repo/db";
|
||||
const fetchMainMessage = async () => {
|
||||
return await prisma.message.findFirst({
|
||||
where: {
|
||||
active: true,
|
||||
isMainMsg: true,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const mainMessage = await fetchMainMessage();
|
||||
|
||||
let msgColor;
|
||||
switch (mainMessage?.color) {
|
||||
case "WARNING":
|
||||
msgColor = "alert alert-warning ml-3";
|
||||
break;
|
||||
case "INFO":
|
||||
msgColor = "alert alert-info ml-3";
|
||||
break;
|
||||
case "SUCCESS":
|
||||
msgColor = "alert alert-success ml-3";
|
||||
break;
|
||||
case "ERROR":
|
||||
msgColor = "alert alert-error ml-3";
|
||||
break;
|
||||
default:
|
||||
msgColor = "alert ml-3";
|
||||
}
|
||||
|
||||
export const WarningAlert = () => {
|
||||
if (mainMessage?.message == "" || !mainMessage) {
|
||||
return <></>;
|
||||
} else {
|
||||
return (
|
||||
<div role="alert" className={msgColor}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="h-6 w-6 shrink-0 stroke-current"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"
|
||||
/>
|
||||
</svg>
|
||||
<span className="font-bold">{mainMessage?.message}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/* ACHTUNG! Wir führen am kommenden Samstag Wartungsarbeiten am Server
|
||||
durch, von 19:00 Uhr bis 19:30 Uhr wird das HUB nicht erreichbar sein. */
|
||||
19
packages/database/prisma/schema/message.prisma
Normal file
19
packages/database/prisma/schema/message.prisma
Normal file
@@ -0,0 +1,19 @@
|
||||
enum GlobalColor {
|
||||
PRIMARY
|
||||
SECONDARY
|
||||
INFO
|
||||
SUCCESS
|
||||
WARNING
|
||||
ERROR
|
||||
}
|
||||
|
||||
model Message {
|
||||
id Int @id @default(autoincrement())
|
||||
color GlobalColor
|
||||
message String
|
||||
showUntil DateTime
|
||||
isMainMsg Boolean
|
||||
active Boolean
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
Reference in New Issue
Block a user