Portatour Reviews 🆓

<div className="reviews-list"> reviews.map(review => ( <div key=review.id className="review-card"> <div className="reviewer-info"> <img src=review.user.avatar alt=review.user.name /> <strong>review.user.name</strong> review.is_verified_purchase && <span className="verified">✓ Verified Tour</span> </div> <StarRating rating=review.rating readonly /> <h3>review.title</h3> <p>review.comment</p> review.images?.length > 0 && ( <div className="review-images"> review.images.map(img => <img key=img src=img />) </div> ) <button onClick=() => markHelpful(review.id)>👍 Helpful (review.helpful_count)</button> </div> )) </div>

protected $casts = [ 'images' => 'array', 'replies' => 'array', 'is_verified_purchase' => 'boolean', 'is_approved' => 'boolean', ]; portatour reviews

return ( <div className="portatour-reviews"> <div className="reviews-header"> <h2>Customer Reviews</h2> <div className="rating-summary"> <span className="average">stats?.average_rating.toFixed(1)</span> <StarRating rating=stats?.average_rating /> <span>(stats?.total_reviews reviews)</span> </div> </div> &lt;div className="reviews-list"&gt; reviews

</script> ✅ Verified purchase only (via booking ID) ✅ Star rating (1–5) + title + comment ✅ Image upload (max 5) ✅ Helpful button ✅ Admin approval workflow ✅ Average rating & breakdown ✅ Sort by newest / highest rated ✅ SEO structured data div key=review.id className="review-card"&gt

useEffect(() => fetch( /api/tours/$tourId/reviews ) .then(res => res.json()) .then(data => setStats(data.stats); setReviews(data.reviews.data); ); , [tourId]);