Skip to content

Commit 1ebd808

Browse files
authored
Merge pull request #2335 from SadafKausar2025/productdetail
Added borders to product detail page
2 parents 70afccd + 42c1d74 commit 1ebd808

File tree

2 files changed

+82
-81
lines changed

2 files changed

+82
-81
lines changed

src/User/components/Popular_Categories/ProductGrid.jsx

-8
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,6 @@ function ProductCard({ product }) {
120120
onAddToCart(product);
121121
}}
122122
disabled={cartItems.find((item) => item.id === product.id)}>
123-
{/* <lord-icon
124-
style={{
125-
height: "20px",
126-
width: "20px",
127-
}}
128-
src="https://cdn.lordicon.com/pbrgppbb.json"
129-
trigger="hover"
130-
colors="primary:#ffffff"></lord-icon> */}
131123
{cartItems.find((item) => item.id === product.id)
132124
? "Added"
133125
: "Add to Cart"}

src/User/components/Products/ProductDetails.jsx

+82-73
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const ProductImage = ({ thumbnail, images }) => (
2222
<img
2323
src={thumbnail}
2424
alt="Product Image"
25-
className={`${sharedClasses.roundedLg} ${sharedClasses.mb4} w-full h-auto max-h-[50vh] object-contain`}
25+
className={`${sharedClasses.roundedLg} ${sharedClasses.mb4} w-full h-auto max-h-[50vh] object-contain bg-gray-100 border-2 border-green-700 hover:cursor-pointer`}
2626
/>
2727
<div
2828
className={`${sharedClasses.flexSpaceX2} ${sharedClasses.mb4} justify-center`}>
@@ -31,16 +31,14 @@ const ProductImage = ({ thumbnail, images }) => (
3131
key={i}
3232
src={i}
3333
alt={`Thumbnail ${i}`}
34-
className="w-1/4 h-auto rounded-lg object-cover"
34+
className="w-1/4 h-auto rounded-lg object-cover bg-gray-100 border-2 border-green-700 hover:cursor-pointer "
3535
/>
3636
))}
3737
</div>
3838
</div>
3939
);
4040

4141
const ProductDetails = ({ product }) => {
42-
43-
4442
return (
4543
<div className="w-full lg:w-1/2 lg:pl-6">
4644
<h2 className="text-2xl font-bold mb-2 sm:text-2xl md:text-3xl md:mb-8 text-black">
@@ -50,7 +48,9 @@ const ProductDetails = ({ product }) => {
5048
{product?.description}
5149
</p>
5250
<p className="text-xl font-semibold mb-2">
53-
{product?.newPrice} <span className="line-through text-zinc-500">{product?.price}</span> ({product?.discountPercentage}% OFF)
51+
{product?.newPrice}{" "}
52+
<span className="line-through text-zinc-500">{product?.price}</span> (
53+
{product?.discountPercentage}% OFF)
5454
</p>
5555
<p className="text-zinc-500 dark:white mb-4">Inclusive of taxes</p>
5656
<ColorOptions />
@@ -60,7 +60,7 @@ const ProductDetails = ({ product }) => {
6060
<ProductInfo product={product} />
6161
<ProductRatings product={product} />
6262
</div>
63-
)
63+
);
6464
};
6565

6666
const ColorOptions = () => (
@@ -114,7 +114,7 @@ const ActionButtons = ({ product }) => {
114114
const dispatch = useDispatch();
115115
const cartItems = useSelector((state) => state.cart.items);
116116
const wishlistItems = useSelector((state) => state.wishlist.items);
117-
const navigate = useNavigate()
117+
const navigate = useNavigate();
118118

119119
const onAddToCart = () => {
120120
const quantity = 1;
@@ -130,93 +130,97 @@ const ActionButtons = ({ product }) => {
130130

131131
return (
132132
<div className={`${sharedClasses.mb4} space-y-2`}>
133-
{
134-
cartItems.find((item) => item.id === product?.id) ? (
135-
<button
136-
className={`${sharedClasses.buttonGreen} w-full hover:bg-[#3d9970ff] transition-colors disabled:opacity-45 disabled:pointer-events-none`}
137-
onClick={() => navigate("/cart")}
138-
aria-label="Buy now"
139-
>
140-
Buy now
141-
</button>
142-
) :
143-
(
144-
<button
145-
className={`${sharedClasses.buttonGreen} w-full hover:bg-[#3d9970ff] transition-colors disabled:opacity-45 disabled:pointer-events-none`}
146-
onClick={onAddToCart}
147-
>
148-
Add to cart
149-
</button>
150-
)
151-
}
133+
{cartItems.find((item) => item.id === product?.id) ? (
134+
<button
135+
className={`${sharedClasses.buttonGreen} w-full hover:bg-[#3d9970ff] transition-colors disabled:opacity-45 disabled:pointer-events-none`}
136+
onClick={() => navigate("/cart")}
137+
aria-label="Buy now">
138+
Buy now
139+
</button>
140+
) : (
141+
<button
142+
className={`${sharedClasses.buttonGreen} w-full hover:bg-[#3d9970ff] transition-colors disabled:opacity-45 disabled:pointer-events-none`}
143+
onClick={onAddToCart}>
144+
Add to cart
145+
</button>
146+
)}
152147
<button
153148
className="w-full px-4 py-2 bg-zinc-200 dark:bg-zinc-700 text-zinc-700 dark:text-zinc-300 rounded-lg hover:bg-zinc-800 transition-colors disabled:opacity-45 disabled:pointer-events-none"
154149
disabled={wishlistItems.find((item) => item.id === product?.id)}
155-
onClick={onAddToWishlist}
156-
>
150+
onClick={onAddToWishlist}>
157151
{wishlistItems.find((item) => item.id === product?.id)
158152
? "Item added to wishlist"
159153
: "Add to wishlist"}
160154
</button>
161155
</div>
162-
)
156+
);
163157
};
164158

165159
const ProductInfo = ({ product }) => (
166160
<div className={sharedClasses.mb4}>
167161
<h3 className="text-lg font-semibold mb-2">Product Details</h3>
168162
{product?.category && <p>Category: {product.category}</p>}
169-
{product?.availabilityStatus && <p>Availability Status: {product.availabilityStatus}</p>}
163+
{product?.availabilityStatus && (
164+
<p>Availability Status: {product.availabilityStatus}</p>
165+
)}
170166
{product?.brand && <p>Brand: {product.brand}</p>}
171167
{product?.returnPolicy && <p>Return Policy: {product.returnPolicy}</p>}
172-
{product?.warrantyInformation && <p>Warranty Information: {product.warrantyInformation}</p>}
173-
{product?.shippingInformation && <p>Shipping Information: {product.shippingInformation}</p>}
168+
{product?.warrantyInformation && (
169+
<p>Warranty Information: {product.warrantyInformation}</p>
170+
)}
171+
{product?.shippingInformation && (
172+
<p>Shipping Information: {product.shippingInformation}</p>
173+
)}
174174
</div>
175175
);
176176

177177
const ProductRatings = ({ product }) => {
178-
179178
const calculatePercentages = () => {
180179
const totalReviews = product?.reviews.length || 0;
181180

182-
const counts = product?.reviews?.reduce((acc, review) => {
183-
if (review.rating === 5) acc.excellent++;
184-
else if (review.rating === 4) acc.veryGood++;
185-
else if (review.rating === 3 || review.rating === 2) acc.good++;
186-
else if (review.rating === 1 || review.rating === 0) acc.low++;
187-
return acc;
188-
}, { excellent: 0, veryGood: 0, good: 0, low: 0 });
189-
181+
const counts = product?.reviews?.reduce(
182+
(acc, review) => {
183+
if (review.rating === 5) acc.excellent++;
184+
else if (review.rating === 4) acc.veryGood++;
185+
else if (review.rating === 3 || review.rating === 2) acc.good++;
186+
else if (review.rating === 1 || review.rating === 0) acc.low++;
187+
return acc;
188+
},
189+
{ excellent: 0, veryGood: 0, good: 0, low: 0 }
190+
);
190191

191192
return [
192193
{ label: "Excellent", width: (counts?.excellent / totalReviews) * 100 },
193194
{ label: "Very Good", width: (counts?.veryGood / totalReviews) * 100 },
194195
{ label: "Good", width: (counts?.good / totalReviews) * 100 },
195-
{ label: "Low", width: (counts?.low / totalReviews) * 100 }
196+
{ label: "Low", width: (counts?.low / totalReviews) * 100 },
196197
];
197198
};
198199

199-
200200
return (
201201
<div className={sharedClasses.mb4}>
202202
<h3 className="text-lg font-semibold mb-2">Product Ratings & Reviews</h3>
203203
<div className="flex items-center mb-2">
204204
<span className="text-2xl font-bold">{product?.rating}</span>
205205
<span className="text-yellow-500 ml-2"></span>
206206
</div>
207-
<p className={`${sharedClasses.textGray} mb-2`}>Total reviews {product?.reviews.length}</p>
207+
<p className={`${sharedClasses.textGray} mb-2`}>
208+
Total reviews {product?.reviews.length}
209+
</p>
208210
{calculatePercentages().map((rating, index) => (
209211
<RatingBar key={index} {...rating} />
210212
))}
211213
</div>
212-
)
214+
);
213215
};
214216

215217
const RatingBar = ({ label, width }) => (
216218
<div className="flex items-center mb-1">
217219
<span className={`flex-1 ${sharedClasses.textGray}`}>{label}</span>
218220
<div className="w-4/5 relative bg-green-300 rounded-lg">
219-
<div style={{ width: `${width}%` }} className={`bg-green-700 h-2 rounded-lg`}></div>
221+
<div
222+
style={{ width: `${width}%` }}
223+
className={`bg-green-700 h-2 rounded-lg`}></div>
220224
</div>
221225
</div>
222226
);
@@ -225,28 +229,24 @@ const CustomerFeedback = ({ reviews }) => (
225229
<div className="mt-8 px-4 ">
226230
<h3 className="text-lg font-semibold mb-2">Customer Feedback</h3>
227231
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-4">
228-
{
229-
reviews?.map((review, index) => {
230-
return (
231-
<div key={index} className="p-4 bg-[#798280ff] rounded-lg text-white">
232-
<div className="flex items-center mb-2">
233-
<img
234-
src={avatar}
235-
alt="User Avatar"
236-
className={`w-12 h-12 ${sharedClasses.roundedFull} mr-2`}
237-
/>
238-
<div>
239-
<p className="font-semibold">{review?.reviewerName}</p>
240-
<p className="text-sm text-white">{review?.reviewerEmail}</p>
241-
</div>
232+
{reviews?.map((review, index) => {
233+
return (
234+
<div key={index} className="p-4 bg-[#798280ff] rounded-lg text-white">
235+
<div className="flex items-center mb-2">
236+
<img
237+
src={avatar}
238+
alt="User Avatar"
239+
className={`w-12 h-12 ${sharedClasses.roundedFull} mr-2`}
240+
/>
241+
<div>
242+
<p className="font-semibold">{review?.reviewerName}</p>
243+
<p className="text-sm text-white">{review?.reviewerEmail}</p>
242244
</div>
243-
<p className="mb-2 text-white">
244-
{review?.comment}
245-
</p>
246245
</div>
247-
)
248-
})
249-
}
246+
<p className="mb-2 text-white">{review?.comment}</p>
247+
</div>
248+
);
249+
})}
250250
</div>
251251
</div>
252252
);
@@ -256,15 +256,21 @@ const ProductPage = () => {
256256
const [product, setProduct] = useState(null);
257257

258258
function getNewPrice(discountPercent, actualPrice) {
259-
return ((100 - discountPercent) * actualPrice / 100).toFixed(2)
259+
return (((100 - discountPercent) * actualPrice) / 100).toFixed(2);
260260
}
261261

262262
const fetchProduct = async () => {
263263
try {
264-
const response = await axios.get(`https://dummyjson.com/products/${productId}`);
264+
const response = await axios.get(
265+
`https://dummyjson.com/products/${productId}`
266+
);
265267
const requiredProduct = response.data;
266-
requiredProduct.newPrice = getNewPrice(requiredProduct.discountPercentage, requiredProduct.price)
267-
requiredProduct.image = requiredProduct.images[0] || requiredProduct.thumbnail
268+
requiredProduct.newPrice = getNewPrice(
269+
requiredProduct.discountPercentage,
270+
requiredProduct.price
271+
);
272+
requiredProduct.image =
273+
requiredProduct.images[0] || requiredProduct.thumbnail;
268274
setProduct(requiredProduct);
269275
} catch (error) {
270276
console.error("Axios error:", error);
@@ -275,20 +281,23 @@ const ProductPage = () => {
275281
if (productId) {
276282
fetchProduct();
277283
}
278-
}, [productId])
284+
}, [productId]);
279285

280286
return (
281287
<div className="bg-[#fff0e3ff] min-h-screen">
282288
<div className="max-w-7xl mx-auto bg-[#fff0e3ff] rounded-lg p-4 sm:p-6">
283289
<div className="flex flex-col lg:flex-row mt-24">
284-
<ProductImage thumbnail={product?.thumbnail} images={product?.images} />
290+
<ProductImage
291+
thumbnail={product?.thumbnail}
292+
images={product?.images}
293+
/>
285294
<ProductDetails product={product} />
286295
</div>
287296
<CustomerFeedback reviews={product?.reviews} />
288297
<Similarproducts category={product?.category} />
289298
</div>
290299
</div>
291-
)
300+
);
292301
};
293302

294303
export default ProductPage;

0 commit comments

Comments
 (0)