diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 0b298baf..ef1b3531 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -26,7 +26,7 @@
"@react-three/fiber": "^8.17.10",
"axios": "^1.7.7",
"bootstrap": "^5.3.3",
- "chart.js": "^4.4.3",
+ "chart.js": "^4.4.6",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
@@ -3570,9 +3570,9 @@
}
},
"node_modules/chart.js": {
- "version": "4.4.4",
- "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.4.tgz",
- "integrity": "sha512-emICKGBABnxhMjUjlYRR12PmOXhJ2eJjEHL2/dZlWjxRAZT1D8xplLFq5M0tMQK8ja+wBS/tuVEJB5C6r7VxJA==",
+ "version": "4.4.6",
+ "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz",
+ "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==",
"dependencies": {
"@kurkle/color": "^0.3.0"
},
diff --git a/frontend/package.json b/frontend/package.json
index 82fba39a..a4d00ba7 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -28,7 +28,7 @@
"@react-three/fiber": "^8.17.10",
"axios": "^1.7.7",
"bootstrap": "^5.3.3",
- "chart.js": "^4.4.3",
+ "chart.js": "^4.4.6",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"date-fns": "^4.1.0",
diff --git a/frontend/src/AgroRentAI/RentProductDetails.jsx b/frontend/src/AgroRentAI/RentProductDetails.jsx
index 5613e994..1dbdf08b 100644
--- a/frontend/src/AgroRentAI/RentProductDetails.jsx
+++ b/frontend/src/AgroRentAI/RentProductDetails.jsx
@@ -3,6 +3,8 @@ import { Star } from 'lucide-react';
import { useParams } from 'react-router-dom';
import { toast, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
+import ProductReview from './components/RatingProductReview';
+
const RentProductDetails = () => {
const [product, setProduct] = useState(null);
@@ -84,7 +86,7 @@ const RentProductDetails = () => {
}
return (
-
+
{/* Heading */}
Product Details
@@ -150,6 +152,7 @@ const RentProductDetails = () => {
+
);
};
diff --git a/frontend/src/AgroRentAI/components/RatingProductReview.jsx b/frontend/src/AgroRentAI/components/RatingProductReview.jsx
new file mode 100644
index 00000000..cc49c759
--- /dev/null
+++ b/frontend/src/AgroRentAI/components/RatingProductReview.jsx
@@ -0,0 +1,252 @@
+import React, { useState } from 'react';
+import { Star } from 'lucide-react';
+import { toast } from 'react-toastify';
+import 'react-toastify/dist/ReactToastify.css';
+import { Bar } from 'react-chartjs-2';
+import { FaThumbsUp, FaThumbsDown } from 'react-icons/fa';
+
+import {
+ Chart as ChartJS,
+ BarElement,
+ CategoryScale,
+ LinearScale,
+ Tooltip,
+ Legend,
+} from 'chart.js';
+
+ChartJS.register(BarElement, CategoryScale, LinearScale, Tooltip, Legend);
+
+const ProductReview = () => {
+ const [newReview, setNewReview] = useState({ rating: 0, title: '', comment: '' });
+ const [averageRating, setAverageRating] = useState(4.0);
+ const [ratingDistribution, setRatingDistribution] = useState([1, 1, 1, 1, 1]);
+ const [helpfulReview, setHelpfulReview] = useState({});
+ const [filterRating, setFilterRating] = useState(0);
+ const [sortOrder, setSortOrder] = useState('newest');
+
+ const [reviews, setReviews] = useState([
+ {
+ _id: '1',
+ rating: 5,
+ title: 'Amazing Product!',
+ comment: 'This product exceeded my expectations. Highly recommend!',
+ date: '2023-10-01',
+ },
+ {
+ _id: '2',
+ rating: 4,
+ title: 'Very Good',
+ comment: 'The product is really good, though it could use a few improvements.',
+ date: '2023-09-15',
+ },
+ {
+ _id: '3',
+ rating: 3,
+ title: 'Average',
+ comment: 'It’s okay, does the job but nothing extraordinary.',
+ date: '2023-08-20',
+ },
+ ]);
+
+ const handleReviewSubmit = () => {
+ if (newReview.rating === 0 || !newReview.comment) {
+ return toast.error("Please provide a rating and a comment.");
+ }
+ const updatedReviews = [...reviews, { ...newReview, _id: Date.now().toString(), date: new Date().toISOString() }];
+ setReviews(updatedReviews);
+ toast.success("Review submitted successfully!");
+ setNewReview({ rating: 0, title: '', comment: '' });
+ };
+
+ // Fetch reviews and rating distribution
+// useEffect(() => {
+ // const fetchReviews = async () => {
+ // try {
+ // const response = await fetch(`${apiUrl}/api/rent-products/${productId}/reviews`);
+ // const data = await response.json();
+ // setReviews(data.reviews);
+ // setAverageRating(data.averageRating);
+ // setRatingDistribution(data.ratingDistribution);
+ // } catch (error) {
+ // console.error('Error fetching reviews:', error);
+ // }
+ // };
+ // fetchReviews();
+// }, [productId, apiUrl]);
+
+ // Handle new review submission
+// const handleReviewSubmit = async () => {
+// if (newReview.rating === 0 || !newReview.comment) {
+// return toast.error("Please provide a rating and a comment.");
+// }
+
+// try {
+// const response = await fetch(`${apiUrl}/api/rent-products/${productId}/reviews`, {
+// method: 'POST',
+// headers: { 'Content-Type': 'application/json' },
+// body: JSON.stringify(newReview),
+// });
+
+// if (response.ok) {
+// toast.success("Review submitted successfully!");
+// setNewReview({ rating: 0, title: '', comment: '' });
+// } else {
+// const errorData = await response.json();
+// toast.error(`Error: ${errorData.message}`);
+// }
+// } catch (error) {
+// toast.error('Failed to submit review');
+// }
+// };
+
+ const markReviewHelpful = (reviewId, isHelpful) => {
+ setHelpfulReview((prevHelpfulReview) => ({
+ ...prevHelpfulReview,
+ [reviewId]: isHelpful,
+ }));
+ };
+
+ // Handle marking reviews as helpful
+// const markReviewHelpful = async (reviewId, isHelpful) => {
+// try {
+// await fetch(`${apiUrl}/api/reviews/${reviewId}/helpful`, {
+// method: 'PATCH',
+// headers: { 'Content-Type': 'application/json' },
+// body: JSON.stringify({ helpful: isHelpful }),
+// });
+// setHelpfulReview({ ...helpfulReview, [reviewId]: isHelpful });
+// } catch (error) {
+// console.error('Error marking review as helpful:', error);
+// }
+// };
+
+
+ // Apply filter and sort to reviews
+ const filteredReviews = reviews
+ .filter((review) => filterRating === 0 || review.rating === filterRating)
+ .sort((a, b) => {
+ if (sortOrder === 'newest') return new Date(b.date) - new Date(a.date);
+ if (sortOrder === 'oldest') return new Date(a.date) - new Date(b.date);
+ if (sortOrder === 'highest') return b.rating - a.rating;
+ if (sortOrder === 'lowest') return a.rating - b.rating;
+ return 0;
+ });
+
+ // Rating distribution graph data
+ const chartData = {
+ labels: ['1 Star', '2 Stars', '3 Stars', '4 Stars', '5 Stars'],
+ datasets: [
+ {
+ label: 'Number of Ratings',
+ data: ratingDistribution,
+ backgroundColor: ['#f87171', '#fbbf24', '#facc15', '#4ade80', '#22c55e'],
+ },
+ ],
+ };
+
+ return (
+
+
Customer Reviews
+
+ {/* Average Rating and Rating Distribution */}
+
+ {averageRating.toFixed(1)}
+
+
+
+
+ {/* Filter and Sort Options */}
+
+ {/* Filter by Rating */}
+
+
+
+
+
+ {/* Sort Options */}
+
+
+
+
+
+
+ {/* Review Form */}
+
+
Submit Your Review
+
+
+ {[1, 2, 3, 4, 5].map((star) => (
+ setNewReview({ ...newReview, rating: star })}
+ />
+ ))}
+
+
setNewReview({ ...newReview, title: e.target.value })}
+ className="mb-4 p-2 border rounded w-full"
+ />
+
+
+ {/* Reviews List */}
+
+ {filteredReviews.map((review) => (
+
+
+
+
{review.rating} / 5
+
{new Date(review.date).toLocaleDateString()}
+
+
{review.title}
+
{review.comment}
+
+
+
+
+
+ ))}
+
+
+ );
+};
+
+export default ProductReview;