77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
"use client"
|
|
|
|
import { Card, CardContent, CardHeader } from "@/components/ui/card"
|
|
import { UserAvatar } from "@/components/ui/user-avatar"
|
|
|
|
interface ReviewUser {
|
|
id: number
|
|
username: string
|
|
display_name?: string | null
|
|
avatar_bg_color?: string
|
|
avatar_text?: string | null
|
|
}
|
|
|
|
interface Review {
|
|
id: number
|
|
user_id: number
|
|
blurb?: string | null
|
|
content?: string | null
|
|
score?: number | null
|
|
created_at: string
|
|
user?: ReviewUser | null
|
|
}
|
|
|
|
interface ReviewCardProps {
|
|
review: Review
|
|
}
|
|
|
|
export function ReviewCard({ review }: ReviewCardProps) {
|
|
// Format date in user's locale
|
|
const formattedDate = new Date(review.created_at).toLocaleDateString(undefined, {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: 'numeric',
|
|
minute: '2-digit'
|
|
})
|
|
|
|
const username = review.user?.display_name || review.user?.username || `User ${review.user_id}`
|
|
|
|
return (
|
|
<Card>
|
|
<CardHeader className="pb-2">
|
|
<div className="flex justify-between items-start gap-4">
|
|
<div className="flex items-start gap-3">
|
|
<UserAvatar
|
|
bgColor={review.user?.avatar_bg_color || "#0F4C81"}
|
|
text={review.user?.avatar_text || undefined}
|
|
username={username}
|
|
size="sm"
|
|
/>
|
|
<div className="space-y-1">
|
|
{review.blurb && (
|
|
<h3 className="font-bold text-lg italic">"{review.blurb}"</h3>
|
|
)}
|
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
<span className="font-medium text-foreground">{username}</span>
|
|
<span>•</span>
|
|
<span>{formattedDate}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{review.score !== null && review.score !== undefined && (
|
|
<div className="flex items-center gap-1 bg-primary/10 px-2 py-1 rounded-md">
|
|
<span className="text-lg font-bold text-primary">{review.score.toFixed(1)}</span>
|
|
<span className="text-xs text-muted-foreground">/10</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</CardHeader>
|
|
{review.content && (
|
|
<CardContent>
|
|
<p className="text-sm leading-relaxed whitespace-pre-wrap">{review.content}</p>
|
|
</CardContent>
|
|
)}
|
|
</Card>
|
|
)
|
|
}
|