Files
pi-skill/skills/scripts/templates/src/components/review/ReviewList.tsx
2026-05-25 16:41:08 +07:00

123 lines
4.2 KiB
TypeScript

import StarRating from './StarRating';
interface Review {
id: string;
rating: number;
title?: string;
comment: string;
user: { name: string; avatar_url?: string };
created_at: string;
images?: string[];
}
interface ReviewListProps {
reviews: Review[];
productId?: string;
onLoadMore?: () => void;
hasMore?: boolean;
isLoading?: boolean;
}
export default function ReviewList({
reviews,
productId,
onLoadMore,
hasMore = false,
isLoading = false
}: ReviewListProps) {
if (!reviews?.length) {
return (
<div className="text-center py-12">
<div className="w-16 h-16 mx-auto mb-4 bg-gray-100 rounded-full flex items-center justify-center">
<svg className="w-8 h-8 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
</svg>
</div>
<h3 className="font-medium text-gray-900 mb-1"></h3>
<p className="text-gray-500 text-sm"></p>
<a
href={`#write-review${productId ? `?productId=${productId}` : ''}`}
className="mt-4 inline-block text-blue-600 hover:text-blue-700 text-sm font-medium"
>
</a>
</div>
);
}
return (
<div className="space-y-6">
{reviews.map(review => (
<div key={review.id} className="border-b pb-6 last:border-b-0">
<div className="flex items-start justify-between mb-3">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-gray-200 rounded-full flex items-center justify-center overflow-hidden">
{review.user.avatar_url ? (
<img
src={review.user.avatar_url}
alt={review.user.name}
className="w-full h-full object-cover"
/>
) : (
<span className="text-gray-500 font-medium">
{review.user.name.charAt(0).toUpperCase()}
</span>
)}
</div>
<div>
<p className="font-medium text-gray-900">{review.user.name}</p>
<StarRating rating={review.rating} size={14} />
</div>
</div>
<span className="text-sm text-gray-500">
{new Date(review.created_at).toLocaleDateString('th-TH', {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</span>
</div>
{review.title && (
<h4 className="font-medium text-gray-900 mb-1">{review.title}</h4>
)}
<p className="text-gray-600 leading-relaxed">{review.comment}</p>
{review.images && review.images.length > 0 && (
<div className="flex gap-2 mt-4 overflow-x-auto pb-2">
{review.images.map((img, i) => (
<a
key={i}
href={img}
target="_blank"
rel="noopener noreferrer"
className="flex-shrink-0"
>
<img
src={img}
alt={`รูปรีวิว ${i + 1}`}
className="w-20 h-20 object-cover rounded-lg hover:opacity-80 transition-opacity"
/>
</a>
))}
</div>
)}
</div>
))}
{hasMore && (
<div className="text-center pt-4">
<button
onClick={onLoadMore}
disabled={isLoading}
className="px-6 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isLoading ? 'กำลังโหลด...' : 'ดูรีวิวเพิ่มเติม'}
</button>
</div>
)}
</div>
);
}