81 lines
2.5 KiB
TypeScript
81 lines
2.5 KiB
TypeScript
import { useEffect, useState } from 'react'
|
|
import type { Review } from '@/types/nostr'
|
|
import { getReviewsForArticle } from '@/lib/reviews'
|
|
import { getReviewTipsForArticle } from '@/lib/reviewAggregation'
|
|
|
|
interface ArticleReviewsProps {
|
|
articleId: string
|
|
authorPubkey: string
|
|
}
|
|
|
|
export function ArticleReviews({ articleId, authorPubkey }: ArticleReviewsProps) {
|
|
const [reviews, setReviews] = useState<Review[]>([])
|
|
const [tips, setTips] = useState<number>(0)
|
|
const [loading, setLoading] = useState(false)
|
|
const [error, setError] = useState<string | null>(null)
|
|
|
|
useEffect(() => {
|
|
const load = async () => {
|
|
setLoading(true)
|
|
setError(null)
|
|
try {
|
|
const [list, tipsTotal] = await Promise.all([
|
|
getReviewsForArticle(articleId),
|
|
getReviewTipsForArticle({ authorPubkey, articleId }),
|
|
])
|
|
setReviews(list)
|
|
setTips(tipsTotal)
|
|
} catch (e) {
|
|
setError(e instanceof Error ? e.message : 'Erreur lors du chargement des critiques')
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
void load()
|
|
}, [articleId, authorPubkey])
|
|
|
|
return (
|
|
<div className="border rounded-lg p-4 bg-white space-y-3">
|
|
<ArticleReviewsHeader tips={tips} />
|
|
{loading && <p className="text-sm text-gray-600">Chargement des critiques...</p>}
|
|
{error && <p className="text-sm text-red-600">{error}</p>}
|
|
{!loading && !error && reviews.length === 0 && <p className="text-sm text-gray-600">Aucune critique.</p>}
|
|
{!loading && !error && <ArticleReviewsList reviews={reviews} />}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function ArticleReviewsHeader({ tips }: { tips: number }) {
|
|
return (
|
|
<div className="flex items-center justify-between">
|
|
<h3 className="text-lg font-semibold">Critiques</h3>
|
|
<span className="text-sm text-gray-600">Remerciements versés : {tips} sats</span>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
function ArticleReviewsList({ reviews }: { reviews: Review[] }) {
|
|
return (
|
|
<>
|
|
{reviews.map((r) => (
|
|
<div key={r.id} className="border-t pt-2 text-sm">
|
|
<div className="text-gray-800">{r.content}</div>
|
|
<div className="text-xs text-gray-500 flex gap-2">
|
|
<span>Auteur critique : {formatPubkey(r.reviewerPubkey)}</span>
|
|
<span>•</span>
|
|
<span>{formatDate(r.createdAt)}</span>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</>
|
|
)
|
|
}
|
|
|
|
function formatPubkey(pubkey: string): string {
|
|
return `${pubkey.slice(0, 8)}...${pubkey.slice(-8)}`
|
|
}
|
|
|
|
function formatDate(timestamp: number): string {
|
|
return new Date(timestamp * 1000).toLocaleString()
|
|
}
|