diff --git a/app/api/curator-comments/route.ts b/app/api/curator-comments/route.ts index e64ac4a..18835bb 100644 --- a/app/api/curator-comments/route.ts +++ b/app/api/curator-comments/route.ts @@ -44,6 +44,12 @@ export async function GET(request: NextRequest) { id: true, name: true } + }, + special: { + select: { + id: true, + name: true + } } } } @@ -57,24 +63,68 @@ export async function GET(request: NextRequest) { } }); - // Format the response - const formattedComments = comments.map(recipient => ({ - id: recipient.comment.id, - message: recipient.comment.message, - createdAt: recipient.comment.createdAt, - readAt: recipient.readAt, - puzzle: { - id: recipient.comment.puzzle.id, - date: recipient.comment.puzzle.date, - song: { - title: recipient.comment.puzzle.song.title, - artist: recipient.comment.puzzle.song.artist - }, - genre: recipient.comment.puzzle.genre ? { - id: recipient.comment.puzzle.genre.id, - name: recipient.comment.puzzle.genre.name - } : null + // Format the response with puzzle context + const formattedComments = await Promise.all(comments.map(async (recipient) => { + const puzzle = recipient.comment.puzzle; + + // Calculate puzzle number + let puzzleNumber = 0; + if (puzzle.specialId) { + // Special puzzle + puzzleNumber = await prisma.dailyPuzzle.count({ + where: { + specialId: puzzle.specialId, + date: { + lte: puzzle.date + } + } + }); + } else if (puzzle.genreId) { + // Genre puzzle + puzzleNumber = await prisma.dailyPuzzle.count({ + where: { + genreId: puzzle.genreId, + date: { + lte: puzzle.date + } + } + }); + } else { + // Global puzzle + puzzleNumber = await prisma.dailyPuzzle.count({ + where: { + genreId: null, + specialId: null, + date: { + lte: puzzle.date + } + } + }); } + + return { + id: recipient.comment.id, + message: recipient.comment.message, + createdAt: recipient.comment.createdAt, + readAt: recipient.readAt, + puzzle: { + id: puzzle.id, + date: puzzle.date, + puzzleNumber: puzzleNumber, + song: { + title: puzzle.song.title, + artist: puzzle.song.artist + }, + genre: puzzle.genre ? { + id: puzzle.genre.id, + name: puzzle.genre.name + } : null, + special: puzzle.special ? { + id: puzzle.special.id, + name: puzzle.special.name + } : null + } + }; })); return NextResponse.json(formattedComments); diff --git a/app/curator/CuratorPageClient.tsx b/app/curator/CuratorPageClient.tsx index 34d78f3..5bb3477 100644 --- a/app/curator/CuratorPageClient.tsx +++ b/app/curator/CuratorPageClient.tsx @@ -1,7 +1,7 @@ 'use client'; import { useEffect, useRef, useState } from 'react'; -import { useTranslations } from 'next-intl'; +import { useTranslations, useLocale } from 'next-intl'; interface Genre { id: number; @@ -45,6 +45,7 @@ interface CuratorComment { puzzle: { id: number; date: string; + puzzleNumber: number; song: { title: string; artist: string; @@ -53,6 +54,10 @@ interface CuratorComment { id: number; name: any; } | null; + special: { + id: number; + name: any; + } | null; }; } @@ -77,6 +82,7 @@ function getCuratorUploadHeaders() { export default function CuratorPageClient() { const t = useTranslations('Curator'); + const tNav = useTranslations('Navigation'); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const [isAuthenticated, setIsAuthenticated] = useState(false); @@ -713,28 +719,52 @@ export default function CuratorPageClient() { )} {/* Comments Section */} -
-
-

- {t('commentsTitle')} ({comments.length}) -

- -
+ {(() => { + const unreadCount = comments.filter(c => !c.readAt).length; + const hasUnread = unreadCount > 0; + + return ( +
+
+
+

+ {t('commentsTitle')} ({comments.length}) +

+ {hasUnread && ( + + {unreadCount} {t('newComments')} + + )} +
+ +
{showComments && ( <> @@ -750,8 +780,23 @@ export default function CuratorPageClient() { ? comment.puzzle.genre.name : comment.puzzle.genre.name?.de ?? comment.puzzle.genre.name?.en : null; + const specialName = comment.puzzle.special + ? typeof comment.puzzle.special.name === 'string' + ? comment.puzzle.special.name + : comment.puzzle.special.name?.de ?? comment.puzzle.special.name?.en + : null; const isRead = comment.readAt !== null; + // Determine category label + let categoryLabel = ''; + if (specialName) { + categoryLabel = `★ ${specialName}`; + } else if (genreName) { + categoryLabel = genreName; + } else { + categoryLabel = tNav('global'); + } + return (
- - {t('commentFromPuzzle')} #{comment.puzzle.id} + + Hördle #{comment.puzzle.puzzleNumber} - {genreName && ( - - ({t('commentGenre')}: {genreName}) - - )} + + ({categoryLabel}) +
{new Date(comment.createdAt).toLocaleDateString()} {new Date(comment.createdAt).toLocaleTimeString()}
-
+
{comment.puzzle.song.title} - {comment.puzzle.song.artist}
@@ -832,7 +875,9 @@ export default function CuratorPageClient() { )} )} -
+
+ ); + })()}

{t('uploadSectionTitle')}

diff --git a/messages/de.json b/messages/de.json index 4b987d0..0a5054d 100644 --- a/messages/de.json +++ b/messages/de.json @@ -251,7 +251,8 @@ "unreadComment": "Ungelesen", "archiveComment": "Archivieren", "archiveCommentConfirm": "Möchtest du diesen Kommentar wirklich archivieren?", - "archiveCommentError": "Fehler beim Archivieren des Kommentars." + "archiveCommentError": "Fehler beim Archivieren des Kommentars.", + "newComments": "neu" }, "About": { "title": "Über Hördle & Impressum", diff --git a/messages/en.json b/messages/en.json index 7796b3e..3e91507 100644 --- a/messages/en.json +++ b/messages/en.json @@ -251,7 +251,8 @@ "unreadComment": "Unread", "archiveComment": "Archive", "archiveCommentConfirm": "Do you really want to archive this comment?", - "archiveCommentError": "Error archiving comment." + "archiveCommentError": "Error archiving comment.", + "newComments": "new" }, "About": { "title": "About Hördle & Imprint",