diff --git a/components/comments/admin-comment-inbox.tsx b/components/comments/admin-comment-inbox.tsx index d8424dc..3e10358 100644 --- a/components/comments/admin-comment-inbox.tsx +++ b/components/comments/admin-comment-inbox.tsx @@ -1,6 +1,7 @@ "use client"; import { useEffect, useState } from "react"; +import Link from "next/link"; import { RefreshCwIcon } from "lucide-react"; import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; @@ -9,8 +10,7 @@ import { Field, FieldGroup, FieldLabel } from "@/components/ui/field"; import { FuzzyCombobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList } from "@/components/ui/combobox"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Empty, EmptyHeader, EmptyTitle, EmptyDescription } from "@/components/ui/empty"; -import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"; -import type { CommentPage } from "@/lib/comments/types"; +import type { CommentItem, CommentPage } from "@/lib/comments/types"; import { characterRarityGradientClass } from "@/lib/catalog/rarity"; import { cn } from "@/lib/utils"; import { useMarkCommentsRead } from "./admin-unread-comments"; @@ -21,7 +21,6 @@ import { useCommentFeed } from "./use-comment-feed"; type TargetOption = { value: string; label: string; image: string | null; rarity: number | null; characterKey: string | null }; export function AdminCommentInbox({ initial, targets, initialTarget, initialComment }: { initial: CommentPage; targets: TargetOption[]; initialTarget?: string; initialComment?: string }) { - const [notificationOpen, setNotificationOpen] = useState(Boolean(initialComment)); const [target, setTarget] = useState(targets.find((item) => item.value === initialTarget) ?? null); const [status, setStatus] = useState("all"); const [answered, setAnswered] = useState("all"); @@ -31,11 +30,17 @@ export function AdminCommentInbox({ initial, targets, initialTarget, initialComm useCommentEvents({ admin: true }, () => feed.refresh({ silent: true, forceRevision: true })); const markRead = useMarkCommentsRead(); useEffect(() => { void markRead(target?.value ?? "all"); }, [markRead, target, feed.revision]); + const groups = new Map(); + for (const item of feed.page.items) { + const comments = groups.get(item.target) ?? []; + comments.push(item); + groups.set(item.target, comments); + } return
- {initialComment && initialTarget && - การสนทนาความคิดเห็นจากการแจ้งเตือนและคำตอบกลับ - {notificationOpen && feed.refresh({ silent: true })} />} - } + {initialComment && initialTarget &&
+

การสนทนาจากการแจ้งเตือน

+ feed.refresh({ silent: true })} /> +
} ไกด์หรือรอบ Stygian item.label} itemToStringValue={(item) => item.value} @@ -53,7 +58,16 @@ export function AdminCommentInbox({ initial, targets, initialTarget, initialComm {feed.error && {feed.error}} - {feed.page.items.map((item) => feed.refresh({ silent: true, forceRevision: true })} revision={feed.revision} />)} + {Array.from(groups, ([targetKey, items]) =>
+ + {items[0].targetImage && <> + {/* eslint-disable-next-line @next/next/no-img-element */} + {`ภาพ + } +

{items[0].targetName}

+ + {items.map((item) => feed.refresh({ silent: true, forceRevision: true })} revision={feed.revision} />)} +
)} {!feed.page.items.length && !feed.busy && !feed.error && ไม่พบความคิดเห็นที่ตรงกันความคิดเห็นจากทุกไกด์และทุกรอบ Stygian จะแสดงที่นี่} {feed.busy && } {feed.page.nextCursor && } diff --git a/components/comments/comment-card.tsx b/components/comments/comment-card.tsx index 09c43a5..7fb66ed 100644 --- a/components/comments/comment-card.tsx +++ b/components/comments/comment-card.tsx @@ -2,7 +2,6 @@ import { useRouter } from "next/navigation"; -import Link from "next/link"; import { useCallback, useEffect, useRef, useState, useSyncExternalStore } from "react"; import { ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, EllipsisVerticalIcon, HeartIcon, ThumbsDownIcon, ThumbsUpIcon } from "lucide-react"; import { toast } from "sonner"; @@ -122,7 +121,6 @@ export function CommentCard({ item, viewer, onChange, revision = 0, inbox = fals }) { const router = useRouter(); const fullWidthMobile = inbox || moderationDetails; - const isMobileInbox = () => inbox && window.matchMedia("(max-width: 639px)").matches; const [mode, setMode] = useState<"reply" | "edit" | null>(null); const [expanded, setExpanded] = useState(defaultExpanded); const [hasOpenedReplies, setHasOpenedReplies] = useState(defaultExpanded); @@ -134,7 +132,6 @@ export function CommentCard({ item, viewer, onChange, revision = 0, inbox = fals const [history, setHistory] = useState(false); const [deleting, setDeleting] = useState(false); const [pending, setPending] = useState(false); - const [thread, setThread] = useState(false); const [reactionOverride, setReactionOverride] = useState<{ reaction: number; likes: number; hearted: boolean } | null>(null); const optimistic = reactionOverride ?? { reaction: item.reaction, likes: item.likes, hearted: item.hearted }; const reactionQueue = useRef>(Promise.resolve()); @@ -204,20 +201,11 @@ export function CommentCard({ item, viewer, onChange, revision = 0, inbox = fals } function compose(next: "reply" | "edit") { if (!viewer) return router.push(commentSignInHref()); - if (next === "reply" && isMobileInbox()) { setThread(true); return; } setMode(next); } const canReadHistory = (!item.deleted && !item.hidden) || Boolean(viewer?.admin); - return
{ - if (isMobileInbox() && event.currentTarget.contains(event.target as Node) && !(event.target as Element).closest("a, button, input, textarea, [role='button']")) setThread(true); - }} id={`comment-${item.id}`} tabIndex={highlighted ? -1 : undefined} className={cn("flex scroll-mt-36 flex-col gap-2 py-2", inbox && "border-b pb-5", highlighted && "rounded-lg bg-accent ring-2 ring-ring", expanded && !item.rootId && "relative before:absolute before:bottom-8 before:left-5 before:top-12 before:border-l before:border-border", fullWidthMobile && "max-sm:before:hidden")}> - {inbox && - {item.targetImage && <> - {/* eslint-disable-next-line @next/next/no-img-element */} - {`ภาพ - } - {item.target.startsWith("stygian:") && {item.targetName}} - } + return
+
{item.authorName.slice(0, 2)}
@@ -249,11 +237,11 @@ export function CommentCard({ item, viewer, onChange, revision = 0, inbox = fals {viewer?.admin ? : optimistic.hearted && !item.deleted && !item.hidden && ผู้ดูแลถูกใจ} - {inbox && } +
{mode && setMode(null)} onSaved={() => { setMode(null); expandReplies(true); onChange(); }} />} - {replies && !item.rootId && (item.replyCount > 0 || expanded) && { if (isMobileInbox()) setThread(true); else expandReplies(value.includes("replies")); }}> + {replies && !item.rootId && (item.replyCount > 0 || expanded) && expandReplies(value.includes("replies"))}> {`การตอบกลับ ${item.replyCount.toLocaleString("th-TH")} รายการ`} {hasOpenedReplies &&
@@ -271,10 +259,7 @@ export function CommentCard({ item, viewer, onChange, revision = 0, inbox = fals ลบความคิดเห็นนี้?ความคิดเห็นนี้ คำตอบกลับทุกระดับ ประวัติการแก้ไข และรูปภาพจะถูกลบอย่างถาวร ไม่สามารถกู้คืนได้
- - การสนทนาความคิดเห็นต้นทางและคำตอบกลับ เรียงจากเก่าไปใหม่ - {thread && } - +
; }