Files
rudarksh-frontend/components/shopping-cart/shoppingCart.jsx

293 lines
10 KiB
JavaScript

"use client";
import React, { useContext, useEffect, useState } from "react";
import { Trash2, Plus } from "lucide-react";
import authAxios, { backendUrl } from "@/utils/axios";
import ProductContext from "@/app/contexts/productContext";
import EmptyCart from "./emptyCart";
import { PayPalScriptProvider, PayPalButtons } from "@paypal/react-paypal-js";
import axios from "axios";
import { useRouter } from "next/navigation";
import PaymentComponent from "../payment/paymentComponent";
import { useCurrency } from "@/app/contexts/currencyContext";
import Link from "next/link";
import Image from "next/image";
import toast from "react-hot-toast";
const ShoppingCart = () => {
const [cartItems, setCartItems] = useState(null);
const [error, setError] = useState(null);
const [shippingAddress, setShippingAddress] = useState(""); // New state for address
const router = useRouter();
const { cartFn } = useContext(ProductContext);
const { formatPrice } = useCurrency();
const getCart = async () => {
const response = await authAxios.get("/orders/cart/");
setCartItems(response.data);
};
useEffect(() => {
getCart();
}, []);
const handleQuantityChange = async (variantId, designId, quantityChange) => {
const response = await cartFn(variantId, designId, quantityChange);
console.log(response)
if (response?.status == 200) {
setCartItems((prev) => {
if (!prev) return prev;
const updatedItems = prev[0].items.map((item) => {
if (item.variant.id === variantId && item?.design?.id === designId) {
const updatedQuantity = item.quantity + quantityChange;
const updatedTotalPrice =
(item.variant.price + (item?.design?.design_price || 0)) *
updatedQuantity;
if (updatedQuantity <= 0) {
return null;
}
return {
...item,
quantity: updatedQuantity,
total_price: updatedTotalPrice,
};
}
return item;
});
const filteredItems = updatedItems.filter((item) => item !== null);
return [
{
...prev[0],
items: filteredItems,
total_amount: filteredItems.reduce(
(sum, item) => sum + item.total_price,
0
),
},
];
});
}
};
if (!cartItems) {
return null;
}
if (!cartItems[0]?.items?.length) {
return <EmptyCart />;
}
const handleRazorpayPaymentSuccess = async (response) => {
console.log("Razorpay Payment Successful", response);
try {
const paymentData = {
paymentId: response.razorpay_payment_id,
orderId: response.razorpay_order_id,
signature: response.razorpay_signature,
cartId: cartItems[0].id,
address: response.address,
};
const apiResponse = await authAxios.post("/orders/payment/", paymentData);
router.push("/accounts/profile/orders");
toast.success("Your Order Is Successful!");
console.log(apiResponse);
} catch (error) {
console.error("Error processing Razorpay payment:", error);
toast.error("Payment processing failed. Please try again.");
}
};
const handlePayPalPaymentSuccess = async (order) => {
console.log("PayPal Payment Successful", order);
try {
const paymentData = {
paymentId: order.id,
payerEmail: order.payer.email_address,
cartId: cartItems[0].id,
address: shippingAddress, // Include the shipping address
};
const apiResponse = await authAxios.post("/orders/payment/", paymentData);
router.push("/accounts/profile/orders");
toast.success("Your Order Is Successful!");
console.log(apiResponse);
} catch (error) {
console.error("Error processing PayPal payment:", error);
toast.error("Payment processing failed. Please try again.");
}
};
if (!cartItems) {
return null;
}
if (!cartItems[0]?.items?.length) {
return <EmptyCart />;
}
return (
<div className="w-full bg-white">
<div className="w-full px-4 md:px-8 max-w-[1600px] mx-auto font-['Inter']">
<h1 className="text-center text-2xl font-medium mb-12 tracking-wide">
SHOPPING CART
</h1>
<div className="space-y-6 relative">
<div className="hidden lg:grid lg:grid-cols-[1fr,auto,120px,auto,50px] lg:gap-8 text-sm text-gray-500 mb-4 pr-2">
<div />
<div className="w-[140px] text-right">Price</div>
<div className="text-center">Quantity</div>
<div className="w-[140px] text-right">Total</div>
<div />
</div>
{cartItems[0]?.items?.map((item) => (
<div className="relative" key={item.id}>
<div className="flex flex-col lg:flex-row lg:items-center">
<div className="flex items-start gap-4 mb-4 lg:mb-0 lg:flex-1">
<Image
src={item.variant?.product?.images[0]?.image}
alt="Siddha Mala"
width={80}
height={80}
className="object-cover bg-gray-100"
/>
<div className="space-y-1">
<h3 className="font-medium">
{item.variant.product.product_name}
</h3>
{item.variant.size?.size_name && (
<p className="text-sm text-gray-600">
Size: {item.variant.size.size_name}
</p>
)}
{item?.design?.design_name && (
<p className="text-sm text-gray-600">
Your Design: {item.design.design_name}
</p>
)}
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-[140px,120px,140px,50px] lg:gap-8 items-center">
<span className="text-gray-900 text-right">
{formatPrice(
item.variant.price + (item.design?.design_price || 0)
)}
</span>
<div className="flex items-center bg-gray-50 px-2 justify-center">
{item.quantity > 1 && (
<button
onClick={() =>
handleQuantityChange(
item.variant.id,
item?.design?.id,
-1
)
}
className="px-2 py-2 text-[#c19a5b] hover:text-[#ab885b]"
>
-
</button>
)}
<span className="px-3 py-2">{item.quantity}</span>
<button
onClick={() =>
handleQuantityChange(
item.variant.id,
item?.design?.id,
+1
)
}
className="px-2 py-2 text-[#c19a5b] hover:text-[#ab885b]"
>
+
</button>
</div>
<span className="text-gray-900 text-right">
{formatPrice(item.total_price)}
</span>
<button className="text-[#c19a5b] hover:text-[#ab885b] justify-self-center">
<Trash2
size={18}
onClick={() =>
handleQuantityChange(
item.variant.id,
item.design.id,
-item.quantity
)
}
/>
</button>
</div>
</div>
<div className="h-px w-full bg-gradient-to-r from-transparent via-gray-200 to-transparent my-6" />
</div>
))}
</div>
<div className="flex flex-col sm:flex-row gap-4 sm:gap-8 mt-8">
<button className="text-[#c19a5b] hover:text-[#ab885b] font-medium order-2 sm:order-1">
<Link href="/"> CONTINUE SHOPPING</Link>
</button>
<button className="text-[#c19a5b] hover:text-[#ab885b] sm:ml-auto font-medium order-1 sm:order-2">
CLEAR SHOPPING CART
</button>
</div>
<div className="flex justify-center lg:ml-96 lg:mr-96 mt-10 lg:mt-0">
<div className="space-y-4 w-full max-w-md mx-auto lg:max-w-none">
<div className="flex justify-between">
<span>SUBTOTAL</span>
<span>{formatPrice(cartItems[0].total_amount)}</span>
</div>
<div className="flex justify-between font-medium">
<span>GRAND TOTAL</span>
<span className="text-[#c19a5b]">
{formatPrice(cartItems[0].total_amount)}
</span>
</div>
<label className="flex items-center gap-2">
<input type="checkbox" className="accent-[#c19a5b]" />
<span className="text-sm">
I agree with the{" "}
<Link
href="/policies/terms-of-services"
className="text-blue-600"
>
terms of services
</Link>{" "}
and{" "}
<Link href="/policies/refund-policy" className="text-blue-600">
return And Cancellation policy.
</Link>
</span>
</label>
{/* Payment Component for Razorpay and PayPal */}
<PaymentComponent
amount={cartItems[0].total_amount}
onSuccess={(response) => {
if (response.razorpay_payment_id) {
handleRazorpayPaymentSuccess(response);
} else {
handlePayPalPaymentSuccess(response);
}
}}
/>
</div>
</div>
</div>
</div>
);
};
export default ShoppingCart;