feat: enhance ReviewsSection with rating functionality and update reviews API

This commit is contained in:
2025-06-15 14:21:35 -05:00
parent a71f101b10
commit 5d89f540f3
2 changed files with 55 additions and 11 deletions

View File

@@ -1,6 +1,7 @@
import { useEffect, useState } from "react";
import { fetchReviews, addReview } from "./reviewsApi";
import type { Review } from "./reviewsApi";
import { Star } from "lucide-react";
const ReviewsSection = ({
cardClasses,
@@ -14,6 +15,8 @@ const ReviewsSection = ({
const [reviews, setReviews] = useState<Review[]>([]);
const [name, setName] = useState("");
const [message, setMessage] = useState("");
const [rating, setRating] = useState(5);
const [hoverRating, setHoverRating] = useState(0);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const [success, setSuccess] = useState("");
@@ -28,10 +31,11 @@ const ReviewsSection = ({
setError("");
setSuccess("");
try {
await addReview({ name, message });
await addReview({ name, message, rating });
setSuccess("Review submitted!");
setName("");
setMessage("");
setRating(5);
setReviews(await fetchReviews());
// Close modal immediately after successful submission
setIsModalOpen(false);
@@ -89,11 +93,9 @@ const ReviewsSection = ({
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
<h3 className="text-xl font-bold mb-4 text-transparent bg-gradient-to-r from-cyan-400 to-purple-400 bg-clip-text">
Share Your Review
</h3>
</h3>{" "}
<form onSubmit={handleSubmit} className="flex flex-col gap-4">
<input
className={`p-3 rounded border focus:outline-none ${
@@ -106,6 +108,34 @@ const ReviewsSection = ({
onChange={(e) => setName(e.target.value)}
required
/>
<div className="mb-2">
<label className="block text-sm mb-1">Your Rating</label>
<div className="flex gap-1">
{[1, 2, 3, 4, 5].map((star) => (
<button
key={star}
type="button"
onClick={() => setRating(star)}
onMouseEnter={() => setHoverRating(star)}
onMouseLeave={() => setHoverRating(0)}
className="transition-transform hover:scale-110"
>
<Star
size={24}
fill={
(hoverRating || rating) >= star ? "#38BDF8" : "none"
}
color={
(hoverRating || rating) >= star
? "#38BDF8"
: "#9CA3AF"
}
className="transition-colors duration-200"
/>
</button>
))}
</div>
</div>
<textarea
className={`p-3 rounded border focus:outline-none ${
isDarkMode
@@ -145,7 +175,9 @@ const ReviewsSection = ({
key={review.id}
className={`p-5 rounded-xl border ${cardClasses}`}
>
<div className="flex items-center mb-2">
{" "}
<div className="flex items-center justify-between mb-2">
<div className="flex items-center">
<span className="font-semibold mr-2 text-cyan-400">
{review.name}
</span>
@@ -153,6 +185,17 @@ const ReviewsSection = ({
{review.createdAt?.toDate?.().toLocaleString?.() || ""}
</span>
</div>
<div className="flex">
{Array.from({ length: 5 }, (_, i) => (
<Star
key={i}
size={16}
fill={i < (review.rating || 5) ? "#38BDF8" : "none"}
color={i < (review.rating || 5) ? "#38BDF8" : "#9CA3AF"}
/>
))}
</div>
</div>
<p className={textClasses}>{review.message}</p>
</div>
))}

View File

@@ -5,6 +5,7 @@ export type Review = {
id?: string;
name: string;
message: string;
rating: number;
createdAt?: Timestamp;
};