Overview
The CommentSection component provides a complete commenting system for articles. It includes comment posting, display, and wallet authentication integration.
Component Interface
interface CommentSectionProps {
articleId: string
}
Props
The unique identifier of the article to display comments for. Used to fetch and post comments.
Usage
Basic Implementation
import CommentSection from './components/CommentSection'
function ArticleDetail({ article }) {
return (
<div>
<h1>{article.title}</h1>
<div>{article.content}</div>
<CommentSection articleId={article.id} />
</div>
)
}
In Article Page
export default function ArticlePage() {
const { id } = useParams()
const { data: article } = useArticle(id)
return (
<article>
{/* Article content */}
<CommentSection articleId={id} />
</article>
)
}
Features
Displays total comment count in the section header:
<h3>
Comments
<span>{comments?.length || 0}</span>
</h3>
Wallet Authentication
Requires wallet connection to post comments:
const account = useCurrentAccount()
{!account ? (
<ConnectModal trigger={<button>GET STARTED</button>} />
) : (
<form onSubmit={handleSubmit}>
{/* Comment form */}
</form>
)}
Users must connect a wallet to post comments. The ConnectModal from @mysten/dapp-kit handles authentication.
Character Limit
Comments are limited to 280 characters:
<textarea
maxLength={280}
value={commentText}
onChange={(e) => setCommentText(e.target.value)}
/>
<span>
{commentText.length}/280
</span>
Character count changes color when approaching limit (>250 characters).
<form onSubmit={handleSubmit}>
<textarea
value={commentText}
onChange={(e) => setCommentText(e.target.value)}
placeholder="What are your thoughts on this story?"
maxLength={280}
/>
<div>
<span>{commentText.length}/280</span>
<button
type="submit"
disabled={!commentText.trim() || isPending}
>
{isPending ? 'POSTING...' : 'POST COMMENT'}
</button>
</div>
</form>
Submit Handler
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
if (!commentText.trim()) return
postComment({ blobId: articleId, text: commentText }, {
onSuccess: () => {
setCommentText('')
},
onError: (err) => {
console.error("Failed to post comment:", err)
alert("Failed to post comment. See console for details.")
}
})
}
Validation
- Button disabled when textarea is empty or whitespace-only
- Button disabled during submission (
isPending)
- Form cleared on successful submission
Loading State
{isLoading ? (
<div className="spinner"></div>
) : (
// Comments list
)}
Empty State
{comments && comments.length > 0 ? (
// Render comments
) : (
<p>No comments yet. Be the first to share your thoughts!</p>
)}
Each comment displays:
<div className="comment-item">
<div>
<span>{comment.author.slice(0, 6)}...{comment.author.slice(-4)}</span>
<span>{new Date(comment.timestamp).toLocaleDateString()}</span>
</div>
<p>{comment.text}</p>
</div>
Comment Data:
- Shortened wallet address (first 6 and last 4 characters)
- Formatted timestamp
- Full comment text
interface Comment {
id: string
blob_id: string
author: string
preview_text: string
content_blob_id: string | null
comment_type: 'text' | 'text_long' | 'media'
timestamp: number
tips_received: number
text: string // Loaded from Walrus
}
Data Fetching
Custom Hooks
const { data: comments, isLoading } = useArticleComments(articleId)
const { mutate: postComment, isPending } = usePostComment()
Fetches all comments for a specific article.function useArticleComments(articleId: string): {
data: Comment[] | undefined
isLoading: boolean
}
Mutation hook for posting new comments.function usePostComment(): {
mutate: (params: { blobId: string; text: string }) => void
isPending: boolean
}
Layout Structure
┌──────────────────────────────────────────┐
│ Comments [5] │
├──────────────────────────────────────────┤
│ │
│ [Comment Form or Connect Wallet Prompt] │
│ │
├──────────────────────────────────────────┤
│ ┌──────────────────────────────────────┐ │
│ │ 0x1234...5678 Jan 15, 2025 │ │
│ │ This is a great article! │ │
│ └──────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────┐ │
│ │ 0xabcd...ef01 Jan 14, 2025 │ │
│ │ Thanks for sharing! │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────┘
Styling
Section Styles
style={{
marginTop: '4rem',
// Section container
}}
- 2rem font size
- Uppercase text
- 4px bottom border
- Comment count badge with background
- Card brutalist styling
- Background:
var(--bg-card)
- Centered content for unauthenticated state
Textarea Styles
style={{
width: '100%',
minHeight: '100px',
padding: '1rem',
background: 'var(--bg-deep)',
border: '2px solid var(--border-color)',
color: 'var(--text-main)',
fontSize: '1rem',
resize: 'vertical',
fontFamily: 'var(--font-mono)'
}}
style={{
padding: '1.5rem',
border: '2px solid var(--border-color)',
background: 'var(--bg-deep)',
boxShadow: '4px 4px 0 var(--border-color)'
}}
Dependencies
import { useState } from 'react'
import { useCurrentAccount, ConnectModal } from '@mysten/dapp-kit'
import { useArticleComments, usePostComment } from '../hooks/useComments'
Required Hooks
useCurrentAccount: Get connected wallet account
useArticleComments: Fetch article comments
usePostComment: Submit new comments
Required Components
ConnectModal: Wallet connection modal from @mysten/dapp-kit
Wallet Integration
Account Detection
const account = useCurrentAccount()
if (!account) {
// Show connect wallet prompt
} else {
// Show comment form
}
Connect Modal State
const [open, setOpen] = useState(false)
<ConnectModal
trigger={<button>GET STARTED</button>}
open={open}
onOpenChange={setOpen}
/>
Error Handling
Post Errors
onError: (err) => {
console.error("Failed to post comment:", err)
alert("Failed to post comment. See console for details.")
}
Error handling currently uses browser alerts. Consider implementing a toast notification system for better UX.
if (!commentText.trim()) return
Prevents submission of empty or whitespace-only comments.
State Management
Local State
const [commentText, setCommentText] = useState('')
const [open, setOpen] = useState(false)
State Reset
Comment text is cleared after successful submission:
onSuccess: () => {
setCommentText('')
}
Best Practices
Always check for wallet connection before showing comment forms.
// Good: Check authentication state
{account ? <CommentForm /> : <ConnectPrompt />}
// Bad: Show form without checking
<CommentForm />
Trim whitespace before validation to prevent empty comments.
// Good: Trim and validate
if (!commentText.trim()) return
// Bad: Check raw value
if (!commentText) return
Future Enhancements
Potential features for comment system:
- Comment editing and deletion
- Nested replies/threading
- Comment tipping functionality
- Rich text formatting
- Media attachments
- Comment reactions
- Spam filtering
- Moderation tools