Files
eCommerce-website/src/components/recentlyViewed/RecentlyViewed.jsx

266 lines
8.8 KiB
JavaScript

// import React from "react";
// import { useSelector } from "react-redux";
// import { Link } from "react-router-dom";
// import { selectRecentProducts } from "../../features/recentlyViewed/recentlyViewedApi";
// const RecentlyViewedCard = ({ product }) => {
// const image = product.image || "/placeholder-product.png";
// const price = product.price || 0;
// return (
// <Link
// to={product.url || "#"}
// className="group block rounded-2xl overflow-hidden bg-white
// border border-gray-100
// transition-all duration-500
// hover:-translate-y-1 hover:shadow-xl"
// >
// {/* Image */}
// <div className="relative aspect-[3/4] overflow-hidden">
// <img
// src={image}
// alt={product.name}
// className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-105"
// />
// {/* Soft gradient */}
// <div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent" />
// {/* "Viewed" badge */}
// <div className="absolute top-3 left-3 bg-primary-dark backdrop-blur
// text-white text-xs font-semibold
// px-3 py-1 rounded-full shadow-sm">
// Viewed
// </div>
// </div>
// {/* Content */}
// <div className="p-4">
// <h3 className="text-gray-900 text-base font-medium leading-snug line-clamp-2">
// {product.name || "Product Name"}
// </h3>
// <div className="mt-2 flex items-center gap-2">
// <span className="text-lg font-semibold text-gray-900">₹{price}</span>
// </div>
// <div className="mt-3 h-[2px] w-0 bg-primary-dark transition-all duration-500 group-hover:w-10" />
// </div>
// </Link>
// );
// };
// const RecentlyViewed = ({ limit = 6 }) => {
// const allProducts = useSelector(selectRecentProducts);
// const recentProducts = allProducts.slice(0, limit);
// if (recentProducts.length === 0) return null;
// return (
// <section className="bg-[#A95F5F] mt-12 px-5 md:px-20 p-24">
// <div className="max-w-7xl mx-auto px-6">
// {/* Heading */}
// <div className="text-center mb-14">
// <h2 className="text-3xl sm:text-4xl font-bold text-gray-900">
// Recently Viewed Products
// </h2>
// <p className="text-gray-100 mt-2 text-lg">
// Continue shopping from where you left off
// </p>
// </div>
// {/* Product Grid */}
// <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-8">
// {recentProducts.map((product) => (
// <RecentlyViewedCard key={product.id} product={product} />
// ))}
// </div>
// </div>
// </section>
// );
// };
// export default RecentlyViewed;
import React from "react";
import { useSelector } from "react-redux";
import { Link } from "react-router-dom";
import { Heart } from "lucide-react";
import { selectRecentProducts } from "../../features/recentlyViewed/recentlyViewedApi";
import {
useAddToWishlistMutation,
useRemoveFromWishlistMutation,
useGetWishlistQuery,
} from "../../features/wishlist/wishlistApi";
const RecentlyViewedCard = ({ product, wishlistIds, handleWishlist }) => {
const discount =
product.comparePrice && product.comparePrice > product.price
? Math.round(
((product.comparePrice - product.price) / product.comparePrice) * 100,
)
: 0;
const offersCount = Math.floor(Math.random() * 3) + 1; // mock offers
return (
<Link
to={product.url || "#"}
className="group bg-white rounded-2xl overflow-hidden hover:shadow-xl transition-shadow duration-300 border border-gray-200"
>
{/* Image */}
<div className="relative bg-gray-50 overflow-hidden aspect-[3/4]">
<img
src={product.image || "/placeholder-product.png"}
alt={product.name}
className="w-full h-full object-cover object-top group-hover:scale-105 transition-transform duration-500"
loading="lazy"
/>
{/* Viewed Badge */}
<div className="absolute top-3 left-3 bg-primary-dark text-white text-xs font-semibold px-3 py-1.5 rounded shadow-sm">
Viewed
</div>
{/* Offers Badge */}
{offersCount > 0 && (
<div className="absolute bottom-3 left-3 bg-gray-800/90 backdrop-blur-sm text-white text-xs font-semibold px-3 py-1.5 rounded">
{offersCount} OFFER{offersCount > 1 ? "S" : ""} FOR YOU
</div>
)}
{/* Wishlist */}
<div className="absolute top-3 right-3 flex flex-col gap-2">
<button
onClick={(e) => handleWishlist(e, product.id)}
className="w-9 h-9 bg-white rounded-full flex items-center justify-center shadow-md hover:shadow-lg transition-shadow"
title="Add to Wishlist"
>
<Heart
size={16}
className={
wishlistIds.includes(product.id)
? "text-red-500 fill-red-500"
: "text-gray-700"
}
/>
</button>
</div>
</div>
{/* Product Info */}
<div className="p-4">
{/* Brand/Category */}
<p className="text-xs text-gray-500 uppercase tracking-wide mb-1">
{product.brand || "Brand"}
</p>
{/* Product Name */}
<h3 className="text-lg font-medium text-primary-dark line-clamp-2 min-h-[2.5rem]">
{product.name || "Product Name"}
</h3>
{/* Price */}
<div className="flex items-center gap-2 mb-1 mt-1">
<span className="text-lg font-bold text-gray-900">
{product.price?.toLocaleString() || "0"}
</span>
{product.comparePrice && (
<span className="text-sm text-gray-400 line-through">
{product.comparePrice.toLocaleString()}
</span>
)}
{discount > 0 && (
<p className="text-xs font-semibold text-orange-600">
{discount}% OFF
</p>
)}
</div>
{/* Color Variants */}
{product.variants?.length > 0 && (
<div className="flex items-center gap-1.5 mt-2">
{product.variants.slice(0, 5).map((variant, idx) => {
const colorValue = variant.color?.toLowerCase() || "#e5e7eb";
return (
<div
key={variant._id || idx}
className="w-5 h-5 rounded-full border-2 border-gray-700 hover:border-gray-500 transition-colors cursor-pointer"
style={{ backgroundColor: colorValue }}
title={variant.color}
/>
);
})}
{product.variants.length > 5 && (
<span className="text-xs text-gray-500 ml-1">
+{product.variants.length - 5}
</span>
)}
</div>
)}
</div>
</Link>
);
};
const RecentlyViewed = ({ limit = 6 }) => {
const allProducts = useSelector(selectRecentProducts);
const recentProducts = allProducts.slice(0, limit);
const { data: wishlistData } = useGetWishlistQuery();
const [addToWishlist] = useAddToWishlistMutation();
const [removeFromWishlist] = useRemoveFromWishlistMutation();
const wishlistIds =
wishlistData?.data?.wishlist?.map(
(item) => item.product?._id || item.productId,
) ||
wishlistData?.data?.products?.map((item) => item._id) ||
[];
const handleWishlist = async (e, productId) => {
e.preventDefault();
e.stopPropagation();
try {
if (wishlistIds.includes(productId)) {
await removeFromWishlist(productId).unwrap();
} else {
await addToWishlist(productId).unwrap();
}
} catch (error) {
console.error("Wishlist error:", error);
}
};
if (recentProducts.length === 0) return null;
return (
<section className="bg-[#A95F5F] mt-12 px-5 md:px-20 py-12">
<div className="max-w-7xl mx-auto px-6">
{/* Heading */}
<div className="text-center mb-14">
<h2 className="text-3xl sm:text-4xl font-bold text-gray-900">
Recently Viewed Products
</h2>
<p className="text-gray-100 mt-2 text-lg">
Continue shopping from where you left off
</p>
</div>
{/* Product Grid */}
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-6 lg:gap-8">
{recentProducts.map((product) => (
<RecentlyViewedCard
key={product.id}
product={product}
wishlistIds={wishlistIds}
handleWishlist={handleWishlist}
/>
))}
</div>
</div>
</section>
);
};
export default RecentlyViewed;