Files
SweetHome/app/components/ratings/RatingList.js
2026-04-14 14:23:17 +00:00

149 lines
5.0 KiB
JavaScript

'use client';
import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import { Star } from 'lucide-react';
import { getPropertyRatings } from '../../utils/ratings.js';
import toast, { Toaster } from 'react-hot-toast';
const RatingList = ({ propertyId, userId }) => {
const [reviews, setReviews] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchReviews = async () => {
if (!propertyId) {
setLoading(false);
return;
}
try {
setLoading(true);
const data = await getPropertyReviews(propertyId);
setReviews(data || []);
setError(null);
} catch (err) {
console.error('[RatingList] Failed to fetch reviews:', err);
setError('فشل تحميل التقييمات');
setReviews([]);
} finally {
setLoading(false);
}
};
fetchReviews();
}, [propertyId]);
if (loading) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="text-center py-8"
>
<div className="w-10 h-10 border-2 border-gray-200 border-t-gray-500 rounded-full animate-spin mx-auto mb-4" />
<p className="text-gray-500">جاري تحميل التقييمات...</p>
</motion.div>
);
}
if (error) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="text-center py-8"
>
<p className="text-red-500">{error}</p>
</motion.div>
);
}
if (reviews.length === 0) {
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="text-center py-8"
>
<p className="text-gray-500">لا توجد تقييمات حتى الآن. كن أول من يقيم هذا العقار!</p>
</motion.div>
);
}
// Calculate average rating
const averageRating = reviews.reduce((sum, review) => sum + review.rating, 0) / reviews.length;
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className="bg-white rounded-2xl p-6 shadow-sm border border-gray-100"
>
<Toaster position="top-center" reverseOrder={false} />
<div className="space-y-4">
{/* Header with average rating */}
<div className="flex items-center justify-between pb-3 border-b border-gray-100">
<div>
<h2 className="text-xl font-bold text-gray-900">تقييمات المستأجرين</h2>
<p className="text-sm text-gray-500">
{reviews.length} تقييمات
</p>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-1">
{Array.from({ length: 5 }).map((_, index) => (
<Star
key={index}
className={`w-5 h-5 ${index < Math.floor(averageRating) ? 'text-amber-500' : 'text-gray-300'}`}
/>
))}
{averageRating % 1 !== 0 && (
<Star className="w-5 h-5 text-amber-400" />
)}
<span className="font-bold text-gray-900 ml-2">{averageRating.toFixed(1)}</span>
</div>
</div>
</div>
{/* Reviews list */}
<div className="space-y-4">
{reviews.map((review, index) => (
<div key={index} className="border-t border-gray-100 pt-4 first:border-t-0 first:pt-0">
<div className="flex justify-between items-start mb-2">
<div className="flex items-start gap-3">
<div className="w-10 h-10 bg-gray-100 rounded-full flex items-center justify-center flex-shrink-0">
<Star className="w-6 h-6 text-gray-600" />
</div>
<div>
<div className="font-medium text-gray-900">{review.userName || 'مستأجر'}</div>
<div className="flex items-center gap-1 mt-1 text-sm">
{Array.from({ length: 5 }).map((_, starIndex) => (
<Star
key={starIndex}
className={`w-4 h-4 ${starIndex < review.rating ? 'text-amber-500' : 'text-gray-300'}`}
/>
))}
<span className="ml-1 text-xs text-gray-500">({review.rating}/5)</span>
</div>
</div>
</div>
<div className="text-xs text-gray-400">
{review.createdAt ? new Date(review.createdAt).toLocaleDateString('ar-SA') : ''}
</div>
</div>
{review.comment && (
<p className="text-gray-700 text-sm leading-relaxed">{review.comment}</p>
)}
</div>
))}
</div>
</div>
</motion.div>
);
};
export default RatingList;