Skip to content

Commit

Permalink
Feat: Add to wishlist and wishlist page
Browse files Browse the repository at this point in the history
  • Loading branch information
Ali-Raza764 committed Jun 1, 2024
1 parent 64211a7 commit 7f56d7f
Show file tree
Hide file tree
Showing 59 changed files with 755 additions and 233 deletions.
Empty file added __tests__/next.config.test.mjs
Empty file.
2 changes: 1 addition & 1 deletion actions/admin/category.actions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use server";
import Category from "@/lib/schemas/Category";
import Category from "@/lib/models/Category";
import checkRole from "@/utils/checkRole";
import dbConnect from "@/utils/dbConnect";

Expand Down
4 changes: 2 additions & 2 deletions actions/admin/featuredproduct.actions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use server";
import FeaturedProduct from "@/lib/schemas/FeaturedProduct";
import Product from "@/lib/schemas/Product";
import FeaturedProduct from "@/lib/models/FeaturedProduct";
import Product from "@/lib/models/Product";
import checkRole from "@/utils/checkRole";
import dbConnect from "@/utils/dbConnect";

Expand Down
2 changes: 1 addition & 1 deletion actions/admin/product.actions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use server";
import Product from "@/lib/schemas/Product";
import Product from "@/lib/models/Product";
import checkRole from "@/utils/checkRole";
import dbConnect from "@/utils/dbConnect";

Expand Down
105 changes: 105 additions & 0 deletions actions/cart.actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
"use server";
import Cart from "@/lib/models/Cart";
import dbConnect from "@/utils/dbConnect";
import { auth, currentUser } from "@clerk/nextjs/server";

dbConnect();

export const addToCart = async (productId) => {
const { userId } = auth();
if (!userId) {
return JSON.parse(
JSON.stringify({
message: "Unauthorized",
status: 401,
})
);
}

// Get the user email from the database using the logged-in user information
const { emailAddresses } = await currentUser();
const email = emailAddresses[0].emailAddress;

const cart = await Cart.findOne({ userEmail: email });

if (cart) {
const productIndex = cart.products.findIndex(p => p.productId.toString() === productId);
if (productIndex > -1) {
cart.products[productIndex].quantity += 1;
} else {
cart.products.push({ productId, quantity: 1 });
}
await cart.save();
return JSON.parse(
JSON.stringify({
message: "Product Added to Cart Successfully",
status: 200,
})
);
}

const newCart = await Cart.create({ userEmail: email, products: [{ productId, quantity: 1 }] });
if (newCart) {
return JSON.parse(
JSON.stringify({
message: "Product Added to Cart Successfully",
status: 200,
})
);
} else {
return JSON.parse(
JSON.stringify({
message: "Failed to add product to cart",
status: 500,
})
);
}
};
export const removeFromCart = async (productId) => {
const { userId } = auth();
if (!userId) {
return JSON.parse(
JSON.stringify({
message: "Unauthorized",
status: 401,
})
);
}

const { emailAddresses } = await currentUser();
const email = emailAddresses[0].emailAddress;

const cart = await Cart.findOne({ userEmail: email });

if (cart) {
const productIndex = cart.products.findIndex(p => p.productId.toString() === productId);
if (productIndex > -1) {
if (cart.products[productIndex].quantity > 1) {
cart.products[productIndex].quantity -= 1;
} else {
cart.products.splice(productIndex, 1);
}
await cart.save();
return JSON.parse(
JSON.stringify({
message: "Product Removed from Cart Successfully",
status: 200,
})
);
} else {
return JSON.parse(
JSON.stringify({
message: "Product Not Found in Cart",
status: 404,
})
);
}
} else {
return JSON.parse(
JSON.stringify({
message: "Cart Not Found",
status: 404,
})
);
}
};
2 changes: 1 addition & 1 deletion actions/user.actions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"use server";
import User from "@/lib/schemas/User";
import User from "@/lib/models/User";
import dbConnect from "@/utils/dbConnect";
import { auth } from "@clerk/nextjs/server";

Expand Down
112 changes: 112 additions & 0 deletions actions/wishlist.actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
"use server";
import WishList from "@/lib/models/WishList";
import dbConnect from "@/utils/dbConnect";
import { auth, currentUser } from "@clerk/nextjs/server";

dbConnect();

export const addToWishList = async (productId) => {
const { userId } = auth();
if (!userId) {
return JSON.parse(
JSON.stringify({
message: "Unauthorized",
status: 401,
})
);
}

const { emailAddresses } = await currentUser();
const email = emailAddresses[0].emailAddress;

const wishlist = await WishList.findOne({ userEmail: email });

if (wishlist) {
const productIndex = wishlist.products.findIndex(
(p) => p.productId.toString() === productId
);
if (productIndex === -1) {
wishlist.products.push({ productId });
await wishlist.save();
return JSON.parse(
JSON.stringify({
message: "Product Added to Wishlist Successfully",
status: 200,
})
);
} else {
return JSON.parse(
JSON.stringify({
message: "Product Already in Wishlist",
status: 400,
})
);
}
}

const newWishList = await WishList.create({
userEmail: email,
products: [{ productId }],
});
if (newWishList) {
return JSON.parse(
JSON.stringify({
message: "Product Added to Wishlist Successfully",
status: 200,
})
);
} else {
return JSON.parse(
JSON.stringify({
message: "Failed to add product to wishlist",
status: 500,
})
);
}
};
export const removeFromWishList = async (productId) => {
const { userId } = auth();
if (!userId) {
return JSON.parse(
JSON.stringify({
message: "Unauthorized",
status: 401,
})
);
}

const { emailAddresses } = await currentUser();
const email = emailAddresses[0].emailAddress;

const wishlist = await WishList.findOne({ userEmail: email });

if (wishlist) {
const productIndex = wishlist.products.findIndex(
(p) => p.productId.toString() === productId
);
if (productIndex > -1) {
wishlist.products.splice(productIndex, 1);
await wishlist.save();
return JSON.parse(
JSON.stringify({
message: "Product Removed from Wishlist Successfully",
status: 200,
})
);
} else {
return JSON.parse(
JSON.stringify({
message: "Product Not Found in Wishlist",
status: 404,
})
);
}
} else {
return JSON.parse(
JSON.stringify({
message: "Wishlist Not Found",
status: 404,
})
);
}
};
8 changes: 1 addition & 7 deletions app/(auth)/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,5 @@ export const metadata = {
};

export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
</body>
</html>
);
return <>{children}</>;
}
10 changes: 4 additions & 6 deletions app/(root)/_components/home/AllProductsCarousel.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ const AllProductsCarousel = ({ products }) => {
{products.map((item) => (
<div className="embla__slide" key={item}>
<ProductItem
key={item._id}
id={item._id}
key={item._id.toString()}
id={item._id.toString()}
name={item.name}
images={item.images}
description={item.description}
excerpt={item.excerpt}
price={item.price}
/>
</div>
Expand All @@ -30,8 +28,8 @@ const AllProductsCarousel = ({ products }) => {
{products.map((item) => (
<div className="embla__slide" key={item}>
<ProductItem
key={item._id}
id={item._id}
key={item._id.toString()}
id={item._id.toString()}
name={item.name}
images={item.images}
description={item.description}
Expand Down
2 changes: 1 addition & 1 deletion app/(root)/_components/home/FeaturedProduct.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const FeaturedProduct = async () => {
{product?.relatedText}
</div>
<Link
href={"/productdetails" + product.productId}
href={"/productdetails" + product.productId.toString()}
className="bg-green-500 text-white px-4 py-2 text-lg w-32 rounded-md"
>
Buy Now
Expand Down
6 changes: 2 additions & 4 deletions app/(root)/_components/home/Sales.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ const Sales = ({ products }) => {
{products.map((item) => (
<div className="embla__slide" key={item}>
<ProductItem
key={item._id}
id={item._id}
key={item._id.toString()}
id={item._id.toString()}
name={item.name}
images={item.images}
description={item.description}
excerpt={item.excerpt}
price={item.price}
/>
</div>
Expand Down
6 changes: 2 additions & 4 deletions app/(root)/allproducts/page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,10 @@ const AllProducts = async ({ searchParams }) => {
{entries.map((item) => {
return (
<ProductItem
key={item._id}
id={item._id}
key={item._id.toString()}
id={item._id.toString()}
name={item.name}
images={item.images}
description={item.description}
excerpt={item.excerpt}
price={item.price}
/>
);
Expand Down
24 changes: 24 additions & 0 deletions app/(root)/cart/CartItem.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// components/reuseable/CartItem.js

import React from "react";
import RemoveFromCartButton from "./RemoveFromCartButton";

const CartItem = ({ id, name, images, description, price, quantity }) => {
return (
<div className="cart-item w-[20rem] border p-4 flex flex-col gap-3">
<img src={images[0]} alt={name} className="w-full h-40 object-cover" />
<h2 className="text-xl font-semibold">{name}</h2>
<p className="w-[15rem] line-clamp-2 text-ellipsis">{description}</p>
<p className="font-bold">Price: ${price}</p>
<p>Quantity: {quantity}</p>
<div className="flex gap-3 mt-3">
<button className="btn bg-blue-500 text-white px-3 py-1 rounded">
Buy Now
</button>
<RemoveFromCartButton id={id} />
</div>
</div>
);
};

export default CartItem;
39 changes: 39 additions & 0 deletions app/(root)/cart/RemoveFromCartButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"use client";
import { removeFromCart } from "@/actions/cart.actions";
import { useRouter } from "next/navigation";
import toast from "react-hot-toast";

const RemoveFromCartButton = ({ id }) => {
const router = useRouter();
const handleRemove = async (id) => {
try {
const res = await removeFromCart(id);
if (res.status === 200) {
console.log(res);
router.refresh();
return res;
} else {
throw new Error("Error when removing from cart");
}
} catch (err) {
console.log(err);
return err;
}
};
return (
<button
className="btn bg-red-500 text-white px-3 py-1 rounded"
onClick={() =>
toast.promise(handleRemove(id), {
loading: "Removing From cart",
success: "Successfully Removed from cart",
error: "Error when Removing From cart",
})
}
>
Remove
</button>
);
};

export default RemoveFromCartButton;
Loading

0 comments on commit 7f56d7f

Please sign in to comment.