import Link from "next/link"; import { notFound } from "next/navigation"; import { format } from "date-fns"; import { ArrowLeft, FileText, Mail } from "lucide-react"; import { requireRole } from "@/lib/auth-utils"; import { prisma } from "@/lib/prisma"; import { announcementAudienceLabels } from "@/lib/announcement-access"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@/components/ui/card"; import { EditNewsForm, RetryNewsEmails } from "../edit-news-form"; export const metadata = { title: "Mitteilung bearbeiten · Kita-Planer" }; export default async function EditNewsPage({ params, searchParams, }: { params: Promise<{ id: string }>; searchParams: Promise<{ page?: string }>; }) { const session = await requireRole(["ADMIN"]); const { id } = await params; const announcement = await prisma.announcement.findFirst({ where: { id, kitaId: session.user.kitaId! }, include: { attachments: { select: { id: true, fileName: true, fileUrl: true } }, }, }); if (!announcement) notFound(); const rawPage = Number((await searchParams).page ?? 1); const page = Number.isSafeInteger(rawPage) && rawPage > 0 ? Math.min(rawPage, 100000) : 1; const where = { kitaId: session.user.kitaId!, announcementId: id, revision: announcement.revision, }; const [statuses, emails, older] = await Promise.all([ prisma.announcementEmail.findMany({ where, select: { sentAt: true, skippedAt: true, failed: true }, }), prisma.announcementEmail.findMany({ where, orderBy: [{ createdAt: "asc" }, { id: "asc" }], take: 51, skip: (page - 1) * 50, select: { id: true, sentAt: true, skippedAt: true, failed: true, attempts: true, leaseUntil: true, lastError: true, user: { select: { firstName: true, lastName: true, email: true } }, }, }), prisma.announcementEmail.findMany({ where: { kitaId: session.user.kitaId!, announcementId: id, revision: { lt: announcement.revision }, }, select: { revision: true, sentAt: true, skippedAt: true, failed: true }, }), ]); const history = new Map< number, { sent: number; skipped: number; failed: number } >(); for (const job of older) { const summary = history.get(job.revision) ?? { sent: 0, skipped: 0, failed: 0, }; if (job.sentAt) summary.sent++; else if (job.skippedAt) summary.skipped++; else if (job.failed) summary.failed++; history.set(job.revision, summary); } const backgroundConfigured = (process.env.NOTDIENST_JOB_SECRET?.length ?? 0) >= 32; const sent = statuses.filter((job) => job.sentAt).length; const skipped = statuses.filter((job) => job.skippedAt).length; const failed = statuses.filter( (job) => !job.sentAt && !job.skippedAt && job.failed, ).length; const pending = statuses.length - sent - skipped - failed; return (

SCHWARZES BRETT · BEITRAG

Mitteilung{" "} bearbeiten

Veröffentlicht am {format(announcement.createdAt, "dd.MM.yyyy HH:mm")} {announcement.editedAt && ` · Aktualisiert am ${format(announcement.editedAt, "dd.MM.yyyy HH:mm")}`}

Inhalt korrigieren Empfängergruppe und bestehende Anhänge bleiben bei einer Korrektur erhalten. {announcementAudienceLabels[announcement.audience]} {announcement.attachments.length > 0 && (

Anhänge

{announcement.attachments.map((a) => ( {a.fileName} ))}
)}
E-Mail-Versand Status der aktuellen Fassung. „Gesendet“ bedeutet, dass der Maildienst die Nachricht angenommen hat.
{sent} gesendet {pending} ausstehend {failed} fehlgeschlagen {skipped > 0 && ( {skipped} übersprungen )}
{!backgroundConfigured && (

Automatische Wiederholungen sind noch nicht eingerichtet. Bitte wende dich an die Hosting-Administration; fehlgeschlagene E-Mails kannst du hier selbst erneut versuchen.

)} {!announcement.emailReady && (

Die Anhänge werden noch vorbereitet. Der Versand beginnt erst, wenn alle Dateien gespeichert sind.

)}

Bei eingerichteter Automatik werden fehlgeschlagene Sendungen erneut versucht. Deaktivierte Konten und Personen, die nicht mehr zur Empfängergruppe gehören, werden übersprungen.

{failed > 0 && (
)} {statuses.length === 0 && (

Für diese Fassung sind keine E-Mails vorgemerkt. Bei Beiträgen aus der Zeit vor Einführung dieser Übersicht liegt kein damaliger Versandstatus vor. Über das Formular kannst du die aktuelle Fassung einmalig versenden.

)}
{emails.slice(0, 50).map((job) => (

{job.user.firstName} {job.user.lastName}

{job.sentAt ? "Gesendet" : job.skippedAt ? "Übersprungen" : job.failed ? "Fehlgeschlagen" : job.leaseUntil && job.leaseUntil > new Date() ? "Wird versendet" : "Ausstehend"}

{job.user.email}

{job.sentAt && (

{format(job.sentAt, "dd.MM.yyyy HH:mm")}

)} {job.lastError && (

{job.lastError}

)}
))}
{history.size > 0 && (
Versand früherer Fassungen
{[...history] .sort(([a], [b]) => b - a) .map(([revision, summary]) => (

Fassung {revision}: {summary.sent} gesendet ·{" "} {summary.skipped} übersprungen · {summary.failed}{" "} fehlgeschlagen

))}

Ungesendete E-Mails älterer Fassungen wurden durch die Korrektur ersetzt.

)} {(page > 1 || emails.length > 50) && ( )}
); }