This commit is contained in:
Your Name committed 2026-06-07 17:17:01 +07:00
1 parent d325cd8763
commit c6bf2f70ac
45 files changed
+5195 -338

No files matched your search

+55 -1
View File
@@ -21,6 +21,8 @@ export default function ProductReviews({ productId }: { productId: number }) {
const [rating, setRating] = useState(5)
const [comment, setComment] = useState('')
const [submitting, setSubmitting] = useState(false)
const [filterRating, setFilterRating] = useState<number | null>(null)
const [visibleCount, setVisibleCount] = useState(3)
const fetchReviews = () => {
fetch(`${API_BASE}/reviews/product/${productId}`)
@@ -68,6 +70,12 @@ export default function ProductReviews({ productId }: { productId: number }) {
? (reviews.reduce((acc, r) => acc + r.rating, 0) / reviews.length).toFixed(1)
: '0.0'
const filteredReviews = filterRating
? reviews.filter(r => r.rating === filterRating)
: reviews
const visibleReviews = filteredReviews.slice(0, visibleCount)
return (
<div className="pt-16 border-t border-spa-stone/10 space-y-12">
<div className="flex flex-col md:flex-row gap-12 items-start">
@@ -118,12 +126,47 @@ export default function ProductReviews({ productId }: { productId: number }) {
)}
<div className="space-y-6">
{/* Filter Bar */}
{reviews.length > 0 && !loading && (
<div className="flex gap-2 overflow-x-auto pb-2" style={{ scrollbarWidth: 'none', msOverflowStyle: 'none' }}>
<button
onClick={() => { setFilterRating(null); setVisibleCount(3); }}
className={`flex-shrink-0 px-4 py-1.5 rounded-full text-xs font-bold transition-all border ${
filterRating === null
? 'bg-spa-stone text-white border-spa-stone'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-stone/50'
}`}
>
All ({reviews.length})
</button>
{[5, 4, 3, 2, 1].map(star => {
const count = reviews.filter(r => r.rating === star).length;
if (count === 0) return null;
return (
<button
key={`filter-${star}`}
onClick={() => { setFilterRating(star); setVisibleCount(3); }}
className={`flex-shrink-0 flex items-center gap-1 px-4 py-1.5 rounded-full text-xs font-bold transition-all border ${
filterRating === star
? 'bg-spa-stone text-white border-spa-stone'
: 'bg-white text-spa-stone border-spa-stone/20 hover:border-spa-stone/50'
}`}
>
{star} <Star className={`w-3 h-3 ${filterRating === star ? 'fill-white text-white' : 'fill-orange-400 text-orange-400'}`} /> ({count})
</button>
);
})}
</div>
)}
{loading ? (
<p className="text-spa-stone animate-pulse text-sm">Loading reviews...</p>
) : reviews.length === 0 ? (
<p className="text-spa-stone/60 text-sm italic">No reviews yet. Be the first to share your thoughts!</p>
) : visibleReviews.length === 0 ? (
<p className="text-spa-stone/60 text-sm italic">No reviews found for this rating.</p>
) : (
reviews.map(review => (
visibleReviews.map(review => (
<div key={review.id} className="border-b border-spa-stone/10 pb-6 last:border-0">
<div className="flex items-center gap-3 mb-2">
{review.customer?.pictureUrl ? (
@@ -147,6 +190,17 @@ export default function ProductReviews({ productId }: { productId: number }) {
</div>
))
)}
{visibleCount < filteredReviews.length && (
<div className="text-center pt-4">
<button
onClick={() => setVisibleCount(prev => prev + 5)}
className="px-6 py-2.5 border border-spa-stone/20 text-spa-stone text-xs font-bold tracking-widest uppercase rounded-full hover:border-spa-stone hover:text-pop-black transition-all bg-white"
>
Show More Reviews
</button>
</div>
)}
</div>
</div>
</div>