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
Veröffentlicht am {format(announcement.createdAt, "dd.MM.yyyy HH:mm")} {announcement.editedAt && ` · Aktualisiert am ${format(announcement.editedAt, "dd.MM.yyyy HH:mm")}`}
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 && (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.
)}{job.user.firstName} {job.user.lastName}
{job.user.email}
{job.sentAt && ({format(job.sentAt, "dd.MM.yyyy HH:mm")}
)} {job.lastError && ({job.lastError}
)}Fassung {revision}: {summary.sent} gesendet ·{" "} {summary.skipped} übersprungen · {summary.failed}{" "} fehlgeschlagen
))}Ungesendete E-Mails älterer Fassungen wurden durch die Korrektur ersetzt.