chore: setup project for production
This commit is contained in:
37
components/shopping-cart/emptyCart.jsx
Normal file
37
components/shopping-cart/emptyCart.jsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import { ShoppingBag } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
|
||||
const 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="flex flex-col items-center justify-center py-16 space-y-6">
|
||||
<div className="relative">
|
||||
<div className="w-24 h-24 rounded-full bg-gray-50 flex items-center justify-center">
|
||||
<ShoppingBag size={48} className="text-[#c19a5b]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="text-center space-y-2">
|
||||
<h2 className="text-xl font-medium text-gray-900">Your cart is empty</h2>
|
||||
<p className="text-gray-500">Looks like you haven't added any items to your cart yet</p>
|
||||
</div>
|
||||
|
||||
<Link
|
||||
href='/pages/buy-rudraksha'
|
||||
className="bg-[#c19a5b] hover:bg-[#ab885b] text-white px-8 py-3 font-medium transition-colors"
|
||||
>
|
||||
Continue Shopping
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default EmptyCart;
|
||||
245
components/shopping-cart/shoppingCart.jsx
Normal file
245
components/shopping-cart/shoppingCart.jsx
Normal file
@@ -0,0 +1,245 @@
|
||||
"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 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 handlePaymentSuccess = async (order) => {
|
||||
console.log("Payment SuccessFul", order);
|
||||
const response = await authAxios.post("/orders/payment/", {
|
||||
orderId: order.id,
|
||||
payer_mail: order.payer.email_address,
|
||||
address: order.purchase_units[0].shipping.address,
|
||||
name: order.purchase_units[0].shipping.name.full_name,
|
||||
cartId: cartItems[0].id,
|
||||
});
|
||||
router.push('/accounts/profile/orders')
|
||||
toast.success('You Order Is Successfull!')
|
||||
console.log(response);
|
||||
};
|
||||
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">
|
||||
← CONTINUE SHOPPING
|
||||
</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 ml-96 mr-96">
|
||||
<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>
|
||||
|
||||
<PaymentComponent
|
||||
amount={cartItems[0].total_amount}
|
||||
onSuccess={handlePaymentSuccess}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ShoppingCart;
|
||||
Reference in New Issue
Block a user