first commit
This commit is contained in:
353
src/components/navbar/Wishlist.jsx
Normal file
353
src/components/navbar/Wishlist.jsx
Normal file
@@ -0,0 +1,353 @@
|
||||
// import React, { useState } from "react";
|
||||
// import {
|
||||
// useGetWishlistQuery,
|
||||
// useRemoveFromWishlistMutation,
|
||||
// } from "../../features/wishlist/wishlistApi";
|
||||
// import WishlistEmpty from "./WishlistEmpty";
|
||||
// import AddToCart from "../../pages/Cart/AddToCart";
|
||||
// import { useAddToCartMutation } from "../../features/cart/cartAPI";
|
||||
// import { useNavigate } from "react-router-dom";
|
||||
|
||||
// const Wishlist = () => {
|
||||
// const navigate = useNavigate();
|
||||
// const [addToCart] = useAddToCartMutation();
|
||||
// const { data, isLoading, isError } = useGetWishlistQuery();
|
||||
// const [removeFromWishlist] = useRemoveFromWishlistMutation();
|
||||
// const [confirmModal, setConfirmModal] = useState({
|
||||
// show: false,
|
||||
// productId: null,
|
||||
// productName: "",
|
||||
// });
|
||||
|
||||
// const wishlistItems = data?.data?.wishlist || [];
|
||||
|
||||
// // Loading
|
||||
// if (isLoading)
|
||||
// return (
|
||||
// <p className="text-center mt-20 text-xl font-medium text-gray-600">
|
||||
// Loading your wishlist...
|
||||
// </p>
|
||||
// );
|
||||
|
||||
// if (isError) return <WishlistEmpty />;
|
||||
|
||||
// // Empty
|
||||
// if (wishlistItems.length === 0) return <WishlistEmpty />;
|
||||
|
||||
// const handleRemove = async (productId) => {
|
||||
// try {
|
||||
// await removeFromWishlist(productId).unwrap();
|
||||
// setConfirmModal({ show: false, productId: null, productName: "" });
|
||||
// } catch (error) {
|
||||
// console.log("Remove failed", error);
|
||||
// }
|
||||
// };
|
||||
|
||||
// const fallbackImage = "/default-product.png";
|
||||
|
||||
// return (
|
||||
// <div className="max-w-7xl mx-auto px-4 py-12 mt-24 bg-gradient-to-br from-gray-50 to-gray-100">
|
||||
// <h1 className="text-2xl font-extrabold mb-10 text-center text-gray-800 tracking-tight">
|
||||
// My Wishlist
|
||||
// </h1>
|
||||
|
||||
// <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
|
||||
// {wishlistItems.map((item) => {
|
||||
// const image =
|
||||
// item?.product?.images?.gallery?.[0] ||
|
||||
// item?.product?.variants?.[0]?.images?.[0] ||
|
||||
// fallbackImage;
|
||||
|
||||
// return (
|
||||
// <div
|
||||
// key={item.id}
|
||||
// className="bg-white rounded-2xl shadow-md hover:shadow-lg flex flex-col"
|
||||
// >
|
||||
// {/* Product Image */}
|
||||
// <div className="relative h-44 bg-gray-100 overflow-hidden group">
|
||||
// <img
|
||||
// src={image}
|
||||
// onError={(e) => (e.target.src = fallbackImage)}
|
||||
// alt={item?.product?.name || "Product"}
|
||||
// className="object-cover h-full w-full transition-transform duration-500 group-hover:scale-105"
|
||||
// />
|
||||
|
||||
// {/* Remove Button */}
|
||||
// <button
|
||||
// onClick={() =>
|
||||
// setConfirmModal({
|
||||
// show: true,
|
||||
// productId: item.productId,
|
||||
// productName: item?.product?.name || "this product",
|
||||
// })
|
||||
// }
|
||||
// className="absolute top-3 right-3 bg-white shadow p-1.5 rounded-full hover:bg-red-500 hover:text-white transition-all text-sm"
|
||||
// >
|
||||
// ✖
|
||||
// </button>
|
||||
// </div>
|
||||
|
||||
// {/* Product Info */}
|
||||
// <div className="p-4 flex flex-col flex-1">
|
||||
// <h2 className="text-md font-semibold text-gray-800 mb-1 truncate">
|
||||
// {item?.product?.name || "Unknown Product"}
|
||||
// </h2>
|
||||
|
||||
// {/* Price */}
|
||||
// {item?.product?.basePrice && (
|
||||
// <p className="text-lg font-bold text-primary-dark mb-1">
|
||||
// ₹ {item.product.basePrice.toLocaleString()}
|
||||
// </p>
|
||||
// )}
|
||||
|
||||
// {/* Added Date */}
|
||||
// <p className="text-gray-500 text-xs mb-3">
|
||||
// Added on{" "}
|
||||
// <span className="font-medium">
|
||||
// {new Date(item.createdAt).toLocaleDateString()}
|
||||
// </span>
|
||||
// </p>
|
||||
|
||||
// {/* Add To Cart Component */}
|
||||
|
||||
// {/* Buttons */}
|
||||
// <div className="mt-auto flex justify-end w-full">
|
||||
// <button
|
||||
// className="text-primary-default font-semibold text-sm underline hover:text-primary-dark transition-colors"
|
||||
// onClick={async () => {
|
||||
// const token = localStorage.getItem("token");
|
||||
// if (!token) {
|
||||
// alert("Please login first to add product to cart");
|
||||
// navigate("/login");
|
||||
// return;
|
||||
// }
|
||||
// try {
|
||||
// // 1️⃣ Add to Cart API call
|
||||
// await addToCart({
|
||||
// productId: item.productId,
|
||||
// quantity: 1,
|
||||
// }).unwrap();
|
||||
|
||||
// // 2️⃣ Remove from Wishlist API call
|
||||
// await removeFromWishlist(item.productId).unwrap();
|
||||
|
||||
// // 3️⃣ Redirect to Cart page
|
||||
// navigate("/cart");
|
||||
// } catch (err) {
|
||||
// console.log("Error:", err);
|
||||
// }
|
||||
// }}
|
||||
// >
|
||||
// Add To Bag
|
||||
// </button>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// );
|
||||
// })}
|
||||
// </div>
|
||||
|
||||
// {/* Confirmation Modal */}
|
||||
// {confirmModal.show && (
|
||||
// <div className="fixed inset-0 bg-black bg-opacity-40 flex items-center justify-center z-50">
|
||||
// <div className="bg-white rounded-xl shadow-lg p-8 w-96 sm:w-4/5 max-w-md text-center">
|
||||
// <h3 className="text-base font-semibold mb-6">
|
||||
// Are you sure you want to delete <br />
|
||||
// <span className="text-amber-800">
|
||||
// {confirmModal.productName}
|
||||
// </span>{" "}
|
||||
// from your wishlist?
|
||||
// </h3>
|
||||
// <div className="flex justify-center gap-6 mt-6">
|
||||
// <button
|
||||
// onClick={() => handleRemove(confirmModal.productId)}
|
||||
// className="px-6 py-3 bg-primary-default text-white rounded-lg font-semibold hover:bg-primary-dark transition"
|
||||
// >
|
||||
// Yes
|
||||
// </button>
|
||||
// <button
|
||||
// onClick={() =>
|
||||
// setConfirmModal({
|
||||
// show: false,
|
||||
// productId: null,
|
||||
// productName: "",
|
||||
// })
|
||||
// }
|
||||
// className="px-6 py-3 bg-gray-300 text-gray-800 rounded-lg font-semibold hover:bg-gray-400 transition"
|
||||
// >
|
||||
// No
|
||||
// </button>
|
||||
// </div>
|
||||
// </div>
|
||||
// </div>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
// export default Wishlist;
|
||||
|
||||
import React, { useState } from "react";
|
||||
import {
|
||||
useGetWishlistQuery,
|
||||
useRemoveFromWishlistMutation,
|
||||
} from "../../features/wishlist/wishlistApi";
|
||||
import { useAddToCartMutation } from "../../features/cart/cartAPI";
|
||||
import WishlistEmpty from "./WishlistEmpty";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
const Wishlist = () => {
|
||||
const navigate = useNavigate();
|
||||
|
||||
const { data, isLoading, isError } = useGetWishlistQuery();
|
||||
const [addToCart] = useAddToCartMutation();
|
||||
const [removeFromWishlist] = useRemoveFromWishlistMutation();
|
||||
|
||||
const [confirm, setConfirm] = useState(null);
|
||||
|
||||
const wishlist = data?.data?.wishlist || [];
|
||||
const fallbackImage = "/default-product.png";
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="mt-32 text-center text-gray-500 text-lg">
|
||||
Loading wishlist…
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isError || wishlist.length === 0) {
|
||||
return <WishlistEmpty />;
|
||||
}
|
||||
|
||||
const handleAddToCart = async (item) => {
|
||||
const token = localStorage.getItem("token");
|
||||
|
||||
if (!token) {
|
||||
alert("Please login first to add product to cart");
|
||||
navigate("/login");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await addToCart({
|
||||
productId: item.productId,
|
||||
quantity: 1,
|
||||
}).unwrap();
|
||||
|
||||
await removeFromWishlist(item.productId).unwrap();
|
||||
navigate("/cart");
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="max-w-7xl mx-auto px-4 py-12 mt-32 bg-gradient-to-br from-gray-50 to-gray-100">
|
||||
<h1 className="text-2xl font-semibold text-gray-600 mb-10">
|
||||
My Wishlist ({wishlist.length} items)
|
||||
</h1>
|
||||
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
{wishlist.map((item) => {
|
||||
const image =
|
||||
item?.product?.images?.gallery?.[0] ||
|
||||
item?.product?.variants?.[0]?.images?.[0] ||
|
||||
fallbackImage;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className="border border-gray-200 rounded-lg bg-white"
|
||||
>
|
||||
{/* Image */}
|
||||
<div className="relative h-56 bg-gray-50">
|
||||
<img
|
||||
src={image}
|
||||
onError={(e) => (e.target.src = fallbackImage)}
|
||||
alt={item?.product?.name}
|
||||
className="h-full w-full object-contain p-6"
|
||||
/>
|
||||
|
||||
{/* Remove */}
|
||||
<button
|
||||
onClick={() => setConfirm(item)}
|
||||
className="absolute top-3 right-3 text-gray-400
|
||||
hover:text-gray-700 text-sm"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Content */}
|
||||
<div className="px-5 py-4 space-y-2">
|
||||
<p className="text-sm text-gray-500">
|
||||
{item?.product?.category || "Product"}
|
||||
</p>
|
||||
|
||||
<h2 className="text-base font-medium text-gray-900 line-clamp-2">
|
||||
{item?.product?.name}
|
||||
</h2>
|
||||
|
||||
<div className="flex items-center justify-between pt-3">
|
||||
<p className="text-lg font-semibold text-gray-900">
|
||||
₹ {item?.product?.basePrice?.toLocaleString()}
|
||||
</p>
|
||||
|
||||
<button
|
||||
onClick={() => handleAddToCart(item)}
|
||||
className="px-4 py-2 text-sm font-medium
|
||||
border border-gray-900
|
||||
text-gray-900
|
||||
hover:bg-gray-900 hover:text-white
|
||||
transition"
|
||||
>
|
||||
Add to Cart
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Confirm Modal */}
|
||||
{confirm && (
|
||||
<div className="fixed inset-0 bg-black/30 flex items-center justify-center z-50">
|
||||
<div className="bg-white w-96 rounded-lg p-6">
|
||||
<h3 className="text-lg font-medium text-gray-900 mb-4">
|
||||
Remove item?
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 mb-6">
|
||||
Are you sure you want to remove{" "}
|
||||
<span className="font-medium text-gray-900">
|
||||
{confirm.product?.name}
|
||||
</span>{" "}
|
||||
from your wishlist?
|
||||
</p>
|
||||
|
||||
<div className="flex justify-end gap-3">
|
||||
<button
|
||||
onClick={() => setConfirm(null)}
|
||||
className="px-4 py-2 text-sm border border-gray-300"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={async () => {
|
||||
await removeFromWishlist(confirm.productId).unwrap();
|
||||
setConfirm(null);
|
||||
}}
|
||||
className="px-4 py-2 text-sm bg-gray-900 text-white"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Wishlist;
|
||||
Reference in New Issue
Block a user