feat: add checkout page with order submission and payment handling
This commit is contained in:
parent
3d8be45a96
commit
436c5a2624
@ -22,7 +22,6 @@ const Checkout = () => {
|
|||||||
let ship = searchParams.get('ship')
|
let ship = searchParams.get('ship')
|
||||||
|
|
||||||
const { cartState, clearCart } = useCart();
|
const { cartState, clearCart } = useCart();
|
||||||
const [cart, setCart] = useState<any[]>([])
|
|
||||||
const [totalCart, setTotalCart] = useState<number>(0)
|
const [totalCart, setTotalCart] = useState<number>(0)
|
||||||
const [activePayment, setActivePayment] = useState<string>('credit-card')
|
const [activePayment, setActivePayment] = useState<string>('credit-card')
|
||||||
const [selectedCountry, setSelectedCountry] = useState<string>('')
|
const [selectedCountry, setSelectedCountry] = useState<string>('')
|
||||||
@ -42,41 +41,24 @@ const Checkout = () => {
|
|||||||
note: ''
|
note: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
// Fetch cart data from API
|
// ✅ Use cartState.cartArray as the source of truth for BOTH guest and logged-in users
|
||||||
useEffect(() => {
|
const cart = cartState.cartArray;
|
||||||
getCartData()
|
console.log("📦 Checkout - Cart from CartContext:", cart);
|
||||||
}, [])
|
|
||||||
|
|
||||||
// Calculate total whenever cart changes
|
// Calculate total whenever cart changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cart && cart.length > 0) {
|
if (cart && cart.length > 0) {
|
||||||
const total = cart.reduce((acc: number, item: any) => acc + (item.price * item.quantity), 0)
|
const total = cart.reduce((acc: number, item: any) => {
|
||||||
setTotalCart(total)
|
const price = item.price || 0;
|
||||||
|
const quantity = item.quantity || item.quantityPurchase || 1;
|
||||||
|
return acc + (price * quantity);
|
||||||
|
}, 0);
|
||||||
|
setTotalCart(total);
|
||||||
|
} else {
|
||||||
|
setTotalCart(0);
|
||||||
}
|
}
|
||||||
}, [cart])
|
}, [cart])
|
||||||
|
|
||||||
const getCartData = async () => {
|
|
||||||
const token = localStorage.getItem("token")
|
|
||||||
if (!token) {
|
|
||||||
console.error("❌ No token found in localStorage");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await axios.get(`${BaseURL}/cart`, {
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${token}`,
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
withCredentials: true
|
|
||||||
})
|
|
||||||
console.log("Cart response ✅:", res.data);
|
|
||||||
setCart(res?.data?.cart?.items || [])
|
|
||||||
} catch (error) {
|
|
||||||
console.error("❌ Error fetching cart:", error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleCountryChange = (countryName: string) => {
|
const handleCountryChange = (countryName: string) => {
|
||||||
setSelectedCountry(countryName)
|
setSelectedCountry(countryName)
|
||||||
const country = locationData.countries.find(c => c.name === countryName)
|
const country = locationData.countries.find(c => c.name === countryName)
|
||||||
@ -146,7 +128,6 @@ const Checkout = () => {
|
|||||||
// Clear cart immediately after successful order
|
// Clear cart immediately after successful order
|
||||||
console.log("💳 Cash on Delivery order successful - clearing cart");
|
console.log("💳 Cash on Delivery order successful - clearing cart");
|
||||||
clearCart()
|
clearCart()
|
||||||
setCart([])
|
|
||||||
router.push(`/order-success?orderId=${response.data.data._id}&orderNumber=${response.data.data.orderNumber}`)
|
router.push(`/order-success?orderId=${response.data.data._id}&orderNumber=${response.data.data.orderNumber}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +172,6 @@ const Checkout = () => {
|
|||||||
// Clear cart immediately after successful order
|
// Clear cart immediately after successful order
|
||||||
console.log("💳 Credit Card/Stripe order successful - clearing cart");
|
console.log("💳 Credit Card/Stripe order successful - clearing cart");
|
||||||
clearCart()
|
clearCart()
|
||||||
setCart([])
|
|
||||||
router.push(`/order-success?orderId=${orderId}&orderNumber=${response.data.data.orderNumber}`)
|
router.push(`/order-success?orderId=${orderId}&orderNumber=${response.data.data.orderNumber}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,11 +396,20 @@ const Checkout = () => {
|
|||||||
{cart.length < 1 ? (
|
{cart.length < 1 ? (
|
||||||
<p className='text-button pt-3'>No product in cart</p>
|
<p className='text-button pt-3'>No product in cart</p>
|
||||||
) : (
|
) : (
|
||||||
cart.map((item, index) => (
|
cart.map((item: any, index: number) => {
|
||||||
|
// Handle both API format (item.product.name) and CartContext format (item.name)
|
||||||
|
const itemName = item.product?.name || item.name;
|
||||||
|
const itemImage = item.product?.thumbImage?.[0] || item.thumbImage?.[0] || item.images?.[0];
|
||||||
|
const itemSize = item.size || item.selectedSize || item.sizes?.[0];
|
||||||
|
const itemColor = item.color || item.selectedColor || item.variation?.[0]?.color;
|
||||||
|
const itemQuantity = item.quantity || item.quantityPurchase || 1;
|
||||||
|
const itemPrice = item.price;
|
||||||
|
|
||||||
|
return (
|
||||||
<div key={index} className="item flex items-center justify-between w-full pb-5 border-b border-line gap-6 mt-5">
|
<div key={index} className="item flex items-center justify-between w-full pb-5 border-b border-line gap-6 mt-5">
|
||||||
<div className="bg-img w-[100px] aspect-square flex-shrink-0 rounded-lg overflow-hidden">
|
<div className="bg-img w-[100px] aspect-square flex-shrink-0 rounded-lg overflow-hidden">
|
||||||
<Image
|
<Image
|
||||||
src={item.product.thumbImage[0]}
|
src={itemImage}
|
||||||
width={500}
|
width={500}
|
||||||
height={500}
|
height={500}
|
||||||
alt='img'
|
alt='img'
|
||||||
@ -429,23 +418,24 @@ const Checkout = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between w-full">
|
<div className="flex items-center justify-between w-full">
|
||||||
<div>
|
<div>
|
||||||
<div className="name text-title">{item.product.name}</div>
|
<div className="name text-title">{itemName}</div>
|
||||||
<div className="caption1 text-secondary mt-2">
|
<div className="caption1 text-secondary mt-2">
|
||||||
<span className='size capitalize'>{item.size}</span>
|
<span className='size capitalize'>{itemSize}</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span className='color capitalize'>{item.color}</span>
|
<span className='color capitalize'>{itemColor}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-title">
|
<div className="text-title">
|
||||||
<span className='quantity'>{item.quantity}</span>
|
<span className='quantity'>{itemQuantity}</span>
|
||||||
<span className='px-1'>x</span>
|
<span className='px-1'>x</span>
|
||||||
<span>
|
<span>
|
||||||
${item.price}.00
|
${itemPrice}.00
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))
|
);
|
||||||
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="discount-block py-5 flex justify-between border-b border-line">
|
<div className="discount-block py-5 flex justify-between border-b border-line">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user