articles: discussion threads + Related Forum Posts sidebar
ArticleComments component renders under every news + articles detail page. Anonymous visitors see all existing comments and a Sign-in CTA; signed-in members get a composer, threaded replies, and up/down votes. AI personas are tagged with a small AI chip so readers know what they're interacting with — same persona TZ rules from #63 apply. Schema extensions on bb.article_comments: parent_comment_id self-FK for one-level threading, denormalized author fields, vote counters, is_ai_seeded flag, status enum. user_id relaxed to nullable so AI rows can exist without a real user_profile; CHECK constraint enforces 'real user OR is_ai_seeded' so anonymous comments can never sneak through. forum_votes.target_type check expanded to include 'comment' — same polymorphic vote table powers thread/reply/comment votes. New Related Forum Posts sidebar on both /articles/[slug] and /news/[slug]. getRelatedForumThreads() does title-keyword ILIKE OR against forum_threads, ranked by reply_count + recency, with recently- active fallback so the box is never empty. 6 threads per article. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,10 +10,13 @@ import ArticleBody from "@/components/ArticleBody";
|
||||
import StarRating from "@/components/StarRating";
|
||||
import { createClient } from "@/lib/supabase/client";
|
||||
import type { Article } from "@/lib/articles/types";
|
||||
import type { RelatedForumThread } from "@/lib/articles/legacy-source";
|
||||
import ArticleComments from "@/components/ArticleComments";
|
||||
|
||||
interface NewsArticleDetailClientProps {
|
||||
article: Article;
|
||||
relatedArticles: Article[];
|
||||
relatedForumThreads?: RelatedForumThread[];
|
||||
companiesInStory?: React.ReactNode;
|
||||
}
|
||||
|
||||
@@ -30,6 +33,7 @@ function getSessionId(): string {
|
||||
export default function NewsArticleDetailClient({
|
||||
article,
|
||||
relatedArticles,
|
||||
relatedForumThreads = [],
|
||||
companiesInStory,
|
||||
}: NewsArticleDetailClientProps) {
|
||||
const [isSaved, setIsSaved] = useState(false);
|
||||
@@ -514,6 +518,10 @@ export default function NewsArticleDetailClient({
|
||||
Back to News
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Article comments — sign-in gated for posting + voting,
|
||||
public for reading. AI personas participate (tagged). */}
|
||||
<ArticleComments articleSlug={article.slug} />
|
||||
</div>
|
||||
|
||||
{/* Sidebar */}
|
||||
@@ -557,6 +565,42 @@ export default function NewsArticleDetailClient({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Related Forum Posts — same widget as /articles/[slug] */}
|
||||
{relatedForumThreads.length > 0 && (
|
||||
<div className="bg-[#111] border border-[#222] p-5">
|
||||
<h3 className="font-body font-bold text-xs text-[#3b82f6] uppercase tracking-widest mb-4 pb-2 border-b border-[#222]">
|
||||
Related Forum Posts
|
||||
</h3>
|
||||
<ul className="space-y-3.5">
|
||||
{relatedForumThreads.map((t) => (
|
||||
<li key={t.id}>
|
||||
<Link href={`/forum/thread/${t.id}`} className="group block">
|
||||
<p className="font-heading text-[#e0e0e0] text-xs font-bold group-hover:text-[#3b82f6] transition-colors line-clamp-2 leading-snug">
|
||||
{t.title}
|
||||
</p>
|
||||
<p className="flex items-center gap-2 mt-1 text-[10px] text-[#666]">
|
||||
{t.category_name && (
|
||||
<span className="text-[#3b82f6] font-body font-bold uppercase tracking-wider">
|
||||
{t.category_name}
|
||||
</span>
|
||||
)}
|
||||
<span>·</span>
|
||||
<span>{t.reply_count} {t.reply_count === 1 ? "reply" : "replies"}</span>
|
||||
{t.vote_score > 0 && <><span>·</span><span>▲ {t.vote_score}</span></>}
|
||||
</p>
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<Link
|
||||
href="/forum"
|
||||
className="block mt-4 pt-3 border-t border-[#222] text-[11px] text-[#3b82f6] hover:underline font-body font-semibold uppercase tracking-wider"
|
||||
>
|
||||
Browse all forum threads →
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Newsletter Signup */}
|
||||
<div className="bg-[#0d1520] border border-[#1e3a5f] p-5">
|
||||
<h3 className="font-heading text-[#e0e0e0] font-bold mb-2">Stay Updated</h3>
|
||||
|
||||
Reference in New Issue
Block a user