diff --git a/src/pages/UserCartPaymentSuccess.tsx b/src/pages/UserCartPaymentSuccess.tsx new file mode 100644 index 00000000..1ac0c846 --- /dev/null +++ b/src/pages/UserCartPaymentSuccess.tsx @@ -0,0 +1,44 @@ +/* eslint-disable */ +import React, { useEffect, useState } from 'react'; +import { Meta } from '../components/Meta'; +import { useAppDispatch, useAppSelector } from '../store/store'; +import { PuffLoader, PulseLoader } from 'react-spinners'; +import { toast } from 'react-toastify'; +import { checkout, getUserCarts } from '../store/features/carts/cartSlice'; +import { + FaCheckSquare, + FaMinus, + FaPlus, + FaEdit, + FaTrash, + FaGift, + FaShippingFast, +} from 'react-icons/fa'; +import { useNavigate } from 'react-router-dom'; +import Product from '../components/product/Product'; +import { Box, LinearProgress } from '@mui/material'; +import { useLocation } from 'react-router-dom'; + +const UserCartPaymentSuccess: React.FC = () => { + const dispatch = useAppDispatch(); + const [isLoading, setIsLoading] = useState(true); + const [currentEndpoint, setCurrentEndpoint] = useState(''); + const navigate = useNavigate(); + const location = useLocation(); + + useEffect(() => { + toast.success('Cart payment success'); + navigate('/shopping-cart'); + }, [location.search, navigate]); + + return ( + <> + +
+ +
+ + ); +}; + +export default UserCartPaymentSuccess; diff --git a/src/pages/UserLogin.tsx b/src/pages/UserLogin.tsx index b708838a..f0c9979c 100644 --- a/src/pages/UserLogin.tsx +++ b/src/pages/UserLogin.tsx @@ -1,24 +1,24 @@ /* eslint-disable */ -import React, { useEffect, useRef, useState } from "react"; -import { FcGoogle } from "react-icons/fc"; -import { BiSolidShow } from "react-icons/bi"; -import { BiSolidHide } from "react-icons/bi"; -import { useAppDispatch, useAppSelector } from "../store/store"; -import { loginUser } from "../store/features/auth/authSlice"; -import { toast } from "react-toastify"; -import { useFormik } from "formik"; -import * as Yup from "yup"; -import { Link, useNavigate } from "react-router-dom"; -import { PulseLoader } from "react-spinners"; -import { addProductToWishlist } from "../store/features/wishlist/wishlistSlice"; -import authService from "../store/features/auth/authService"; +import React, { useEffect, useRef, useState } from 'react'; +import { FcGoogle } from 'react-icons/fc'; +import { BiSolidShow } from 'react-icons/bi'; +import { BiSolidHide } from 'react-icons/bi'; +import { useAppDispatch, useAppSelector } from '../store/store'; +import { loginUser } from '../store/features/auth/authSlice'; +import { toast } from 'react-toastify'; +import { useFormik } from 'formik'; +import * as Yup from 'yup'; +import { Link, useNavigate } from 'react-router-dom'; +import { PulseLoader } from 'react-spinners'; +import { addProductToWishlist } from '../store/features/wishlist/wishlistSlice'; +import authService from '../store/features/auth/authService'; import { joinRoom } from '../utils/socket/socket'; const LoginSchema = Yup.object().shape({ email: Yup.string() - .email("Email must be valid") - .required("Email is required"), - password: Yup.string().required("Password is required"), + .email('Email must be valid') + .required('Email is required'), + password: Yup.string().required('Password is required'), }); function UserLogin() { @@ -39,35 +39,39 @@ function UserLogin() { const formik = useFormik({ initialValues: { - email: "", - password: "", + email: '', + password: '', }, validationSchema: LoginSchema, onSubmit: async (values) => { + const { email } = values; + localStorage.setItem('loggedEmail', email); const action = await dispatch(loginUser(values)); if (loginUser.fulfilled.match(action)) { - const pendingWishlistProduct = localStorage.getItem("pendingWishlistProduct"); + const pendingWishlistProduct = localStorage.getItem( + 'pendingWishlistProduct' + ); if (pendingWishlistProduct) { await dispatch(addProductToWishlist(pendingWishlistProduct)); - localStorage.removeItem("pendingWishlistProduct"); + localStorage.removeItem('pendingWishlistProduct'); } } - } + }, }); useEffect(() => { - const token = localStorage.getItem("token"); + const token = localStorage.getItem('token'); if (token) { - navigate("/home"); + navigate('/home'); } }, [navigate]); useEffect( function () { if (isSuccess && token && isAuthenticated) { - localStorage.setItem("token", token); + localStorage.setItem('token', token); toast.success(message); - navigate("/home"); + navigate('/home'); formik.resetForm(); joinRoom(token); } @@ -121,7 +125,7 @@ function UserLogin() {
) ) : ( - "" + '' )}

@@ -161,11 +165,11 @@ function UserLogin() { ) : null} @@ -186,4 +190,4 @@ function UserLogin() { ); } -export default UserLogin; \ No newline at end of file +export default UserLogin; diff --git a/src/pages/UserViewCart.tsx b/src/pages/UserViewCart.tsx index 37da0a45..d49826c1 100644 --- a/src/pages/UserViewCart.tsx +++ b/src/pages/UserViewCart.tsx @@ -1,10 +1,21 @@ /* eslint-disable */ -import React, { useEffect, useState } from "react"; -import { Meta } from "../components/Meta"; -import { useAppDispatch, useAppSelector } from "../store/store"; -import { PuffLoader, PulseLoader } from "react-spinners"; -import { toast } from "react-toastify"; -import { checkout, getUserCarts , clearCarts,createCart,clearCart,clearCartProduct} from "../store/features/carts/cartSlice"; +import React, { useEffect, useState } from 'react'; +import { Meta } from '../components/Meta'; +import { useAppDispatch, useAppSelector } from '../store/store'; +import { PuffLoader, PulseLoader } from 'react-spinners'; +import { toast } from 'react-toastify'; +import { + checkout, + getUserCarts, + clearCarts, + createCart, + clearCart, + clearCartProduct, + createProductStripe, + createSessionStripe, + updateCartStatus, + userSaveOrder, +} from '../store/features/carts/cartSlice'; import { FaCheckSquare, FaMinus, @@ -13,19 +24,20 @@ import { FaTrash, FaGift, FaShippingFast, -} from "react-icons/fa"; -import { GiBroom } from "react-icons/gi"; -import { useNavigate } from "react-router-dom"; -import Dialog from "@mui/material/Dialog"; -import DialogActions from "@mui/material/DialogActions"; -import DialogContent from "@mui/material/DialogContent"; -import DialogContentText from "@mui/material/DialogContentText"; -import DialogTitle from "@mui/material/DialogTitle"; -import Product from "../components/product/Product"; -import { Box, LinearProgress } from "@mui/material"; -import Button from "@mui/material/Button"; +} from 'react-icons/fa'; +import { GiBroom } from 'react-icons/gi'; +import { useNavigate } from 'react-router-dom'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; +import Product from '../components/product/Product'; +import { Box, LinearProgress } from '@mui/material'; +import Button from '@mui/material/Button'; import Dispatch from 'react'; - +import { fetchUserProfile } from '../store/features/user/userSlice'; +import { useLocation } from 'react-router-dom'; const UserViewCart: React.FC = () => { const dispatch = useAppDispatch(); @@ -34,49 +46,181 @@ const UserViewCart: React.FC = () => { const [cartData, setCartData] = useState(null); const [cartResponseData, setCartResponseData] = useState(null); const [isLoggedOut, setIsLoggedOut] = useState(false); - const [checkoutData, setcheckoutData] = useState(null); + const [checkoutData, setCheckoutData] = useState(null); const [isCheckoutSuccess, setCheckoutSuccess] = useState(null); const [isPreloader, setIsPreloader] = useState(false); const [discount, setDiscount] = useState(0); const [totalProductPrice, setTotalProductPrice] = useState(0); - const [arrayOfProduct, setarrayOfProduct] = useState(null); + const [arrayOfProduct, setArrayOfProduct] = useState(null); const [quantities, setQuantities] = useState<{ [key: string]: number }>({}); - const [open,setOpen] = useState(false) - + const [open, setOpen] = useState(false); + const [cartToPay, setCartToPay] = useState(null); + const [amountToPay, setAmountToPay] = useState(null); + const [stripePrice, setStripePrice] = useState(''); + const [currentEndpoint, setCurrentEndpoint] = useState(''); const navigate = useNavigate(); + const location = useLocation(); const cartState = useAppSelector((state) => state.cart); - - useEffect(() => { - const fetchCarts = async () => { - try { - setIsLoading(true); - const response = await dispatch(getUserCarts()); - const response1 = await dispatch(getUserCarts()).unwrap(); - if (response.payload === "Not authorized") { - setIsLoggedOut(true); - toast.error("Please login first"); - navigate("/login"); - } - setCartResponseData(response1.data); - setIsLoading(false); - } catch (error: any) { - if (error === "Not authorized") { - setIsLoggedOut(true); - toast.error("Please login first"); - navigate("/login"); - } - console.error("Error fetching carts:", error); - setIsLoading(false); - setIsError(true); - toast.error(error.message); - } - }; fetchCarts(); + checkPayFailOrSuccess(); }, [dispatch]); + const fetchCarts = async () => { + try { + setIsLoading(true); + const response = await dispatch(getUserCarts()); + const response1 = await dispatch(getUserCarts()).unwrap(); + if (response.payload === 'Not authorized') { + setIsLoggedOut(true); + toast.error('Please login first'); + navigate('/login'); + } + setCartResponseData(response1.data); + setIsLoading(false); + } catch (error: any) { + if (error === 'Not authorized') { + setIsLoggedOut(true); + toast.error('Please login first'); + navigate('/login'); + } + console.error('Error fetching carts:', error); + setIsLoading(false); + setIsError(true); + toast.error(error.message); + } + }; + const handleCartCheckOut = async ( + cartId: string, + index: number, + productsArr: Array<{ + name: string; + description: string; + image: string; + price: string; + shopId: string; + }> + ) => { + setIsPreloader(true); + try { + const response = await dispatch(checkout(cartId)); + if (!response.payload) { + throw new Error( + 'Checkout failed, Check your internet connection or tryagainlater' + ); + } + localStorage.setItem('cartToPay', cartId); + + localStorage.setItem('productsToSave', JSON.stringify(productsArr)); + const totalCartAmount = response.payload.data.totalAmount; + const array = cartResponseData.carts[index]; + + setArrayOfProduct(array); + setCheckoutData(totalCartAmount); + + const totalProductPrice = array.products.reduce( + (acc, product) => acc + parseFloat(product.price), + 0 + ); + setTotalProductPrice(totalProductPrice); + + const names = productsArr.map((product) => product.name).join(', '); + const descriptions = productsArr + .map((product) => product.description) + .join(', '); + const image1 = productsArr[0]?.image; + const image2 = productsArr[1]?.image; + const shopidToSave: any = productsArr[0]?.shopId; + localStorage.setItem('shopIdToSave', shopidToSave); + + const unit_amount = Math.round(totalCartAmount * 100); + + setAmountToPay(unit_amount); + const stripeProduct = await dispatch( + createProductStripe({ + name: names, + description: descriptions, + image1, + image2, + unit_amount: unit_amount, + }) + ); + localStorage.setItem( + 'stripePrice', + stripeProduct.payload.data.product.default_price + ); + + setCheckoutSuccess(true); + + toast.success('Checkout is done Successfully'); + } catch (error) { + console.error('Checkout failed', error); + toast.error('Checkout failed'); + } finally { + setIsPreloader(false); + } + }; + + const handlePayCart = async () => { + try { + setIsPreloader(true); + const profile: any = await dispatch(fetchUserProfile()); + const data = { + successUrl: 'https://e-commerce-ninja-fn-staging.netlify.app/shopping-cart?success', + cancelUrl: 'https://e-commerce-ninja-fn-staging.netlify.app/shopping-cart?cancel', + customerEmail: profile.payload.email, + price: localStorage.getItem('stripePrice'), + }; + const response = await dispatch(createSessionStripe(data)); + const url = response.payload.data.session.url; + window.location.href = url; + } catch (error) { + console.error('Checkout failed', error); + toast.error('Payment initialization failed, try again later'); + } finally { + setIsPreloader(false); + } + }; + + const checkPayFailOrSuccess = async () => { + const params = window.location.search.slice(1); + if (params === 'success') { + setIsPreloader(true); + const cartId = localStorage.getItem('cartToPay'); + const products = localStorage.getItem('productsToSave'); + const shopId = localStorage.getItem('shopIdToSave'); + if (!cartId || !products || !shopId) { + navigate('/shopping-cart'); + toast.error('Unkonwn error occured saving order'); + return; + } + const data = { + cartId: cartId, + status: 'Paid', + }; + const cartStatus = await dispatch(updateCartStatus(data)); + const order = await dispatch( + userSaveOrder({ + cartId: cartId, + paymentMethodId: 'Stripe', + products: products, + shopId: shopId, + }) + ); + toast.success('Cart Payment successful'); + localStorage.removeItem('cartToPay'); + localStorage.removeItem('productsToSave'); + localStorage.removeItem('shopIdToSave'); + navigate('/shopping-cart'); + setIsPreloader(false); + } else if (params === 'cancel') { + toast.error('Payment cancelled successfully'); + navigate('/shopping-cart'); + setIsPreloader(false); + } + }; if (isLoading) { return ( @@ -89,7 +233,7 @@ const UserViewCart: React.FC = () => { if (isError) { return (

-

Failed to load cart products. Please try again later.

+

No cart found.

); } @@ -109,31 +253,17 @@ const UserViewCart: React.FC = () => { ); } - const handleCartCheckOut = async (cartId, index) => { - setIsPreloader(true); - const response = await dispatch(checkout(cartId)); - const array = cartResponseData?.carts[index]; - setarrayOfProduct(array); - setcheckoutData(response.payload.data.totalAmount); - const totalProductPrice = array.products.reduce( - (acc, product) => acc + parseFloat(product.price) * (product.quantity || 1), - 0 - ); - setTotalProductPrice(totalProductPrice); - setCheckoutSuccess(true); - setIsPreloader(false); - toast.success("Checkout is done Successfully"); - }; - - const handleAddProductToCart = async (productId: string, quantity:number) => { + const handleAddProductToCart = async ( + productId: string, + quantity: number + ) => { try { - if (quantity < 1) return; + if (quantity < 1) return; const response = await dispatch( createCart({ productId, quantity }) ).unwrap(); if (response.data) { - setQuantities((prevQuantities) => ({ ...prevQuantities, [productId]: quantity, @@ -145,12 +275,12 @@ const UserViewCart: React.FC = () => { toast.error(response.message); } } catch (error: any) { - if (error === "Not authorized") { - localStorage.setItem("pendingCartProduct", productId); - toast.error("Please login first"); - navigate("/login"); + if (error === 'Not authorized') { + localStorage.setItem('pendingCartProduct', productId); + toast.error('Please login first'); + navigate('/login'); } else { - toast.error("Something went wrong. Please try again later."); + toast.error('Something went wrong. Please try again later.'); } } finally { setIsLoading(false); @@ -159,94 +289,97 @@ const UserViewCart: React.FC = () => { const incrementQuantity = (productId: string) => { const currentQuantity = quantities[productId] || 1; - handleAddProductToCart(productId,currentQuantity+1) + handleAddProductToCart(productId, currentQuantity + 1); }; const decrementQuantity = (productId: string) => { const currentQuantity = quantities[productId] || 1; if (currentQuantity > 1) { - handleAddProductToCart(productId,currentQuantity-1) - + handleAddProductToCart(productId, currentQuantity - 1); } }; const handleClearCart = async () => { + setIsPreloader(true); + await dispatch(clearCarts()).unwrap(); + setIsPreloader(false); + await fetchCarts(); + toast.success('Cart cleared successfully'); + navigate('/shopping-cart'); + handleClose(); + }; + + const handleClearSingleCart = async (cartId) => { try { - await dispatch(clearCarts()).unwrap(); - const response1 = await dispatch(getUserCarts()).unwrap(); + setIsPreloader(true); + await dispatch(clearCart(cartId)); + const response1 = await dispatch(getUserCarts()).unwrap(); + setCheckoutSuccess(false); setCartResponseData(response1.data); - - toast.success("Cart cleared successfully"); - setCartResponseData({ ...cartResponseData, carts: [] }); - setTotalProductPrice(0); + const remainingCarts = cartResponseData.carts.filter( + (cart) => cart.cartId !== cartId + ); + setCartResponseData({ ...cartResponseData, carts: remainingCarts }); + setIsPreloader(false); + toast.success('Cart cleared successfully'); } catch (error) { - console.error("Error clearing cart:", error); - toast.error("Failed to clear the cart"); + console.error('Error clearing cart:', error); + toast.error('Failed to clear the cart'); + } finally { + setIsPreloader(false); } }; - const handleClearSingleCart = async (cartId) => { - + const handleClearCartProduct = async ( + cartId, + productId, + cartProductsList + ) => { try { - await dispatch(clearCart(cartId)); - const response1 = await dispatch(getUserCarts()).unwrap(); - setCheckoutSuccess(false); - setCartResponseData(response1.data); - const remainingCarts = cartResponseData.carts.filter((cart)=>cart.cartId !== cartId) - setCartResponseData({...cartResponseData,carts:remainingCarts}); - - - toast.success("Cart cleared successfully"); + setIsPreloader(true); + if (cartProductsList.length <= 1) { + await handleClearSingleCart(cartId); + return; + } + const response = await dispatch(clearCartProduct({ cartId, productId })); + const response1 = await dispatch(getUserCarts()).unwrap(); + setCartResponseData(response1.data); + toast.success('product cleared successfully'); } catch (error) { - console.error("Error clearing cart:", error); - toast.error("Failed to clear the cart"); - } -}; - -const handleClearCartProduct = async(cartId,productId,cartProductsList)=>{ - try { - if(cartProductsList.length <=1) { - await handleClearSingleCart(cartId); - return; + toast.error('Failed to clear the product '); + throw error; + } finally { + setIsPreloader(false); } - const response = await dispatch(clearCartProduct({cartId,productId})) - const response1 = await dispatch(getUserCarts()).unwrap(); - setCartResponseData(response1.data); - toast.success("product cleared successfully"); - } catch (error) { - toast.error("Failed to clear the product "); - throw error - } -} + }; -let cartProductsList=null; -const handleClose = () => { - - setOpen(false); -}; + let cartProductsList = null; + const handleClose = () => { + setOpen(false); + }; return ( <> {isPreloader && ( -
- - - -
- )} -
- -
+
+ + + +
+ )} +
+ +
{cartResponseData?.carts?.map((cart: any, index) => ( @@ -254,13 +387,26 @@ const handleClose = () => {

Shopping Cart

- + {cart.status === 'Paid' ? ( + + ) : ( + + )} - handleClearSingleCart(cart.cartId)}/> + handleClearSingleCart(cart.cartId)} + />
{cart.products.map((product: any) => { @@ -281,25 +427,42 @@ const handleClose = () => { {product.discount}
${product.price}
-
-
- - - + {cart.status !== 'Paid' && ( +
+
+ + + +
+
+ +
-
- -
-
+ )}
@@ -344,64 +507,66 @@ const handleClose = () => { ))}
Total Discount:
-
${(totalProductPrice - checkoutData).toFixed(2)}
+
+ ${(totalProductPrice - checkoutData).toFixed(2)} +
Total amount:
${checkoutData.toFixed(2)}
- + ) : null} - - - {"Delete all Carts"} - - - - Are you sure you want to delete all Carts ? - - - - - - - + + + {'Delete all Carts'} + + + + Are you sure you want to delete all Carts ? + + + + + + + diff --git a/src/router.tsx b/src/router.tsx index 1f6f4479..fff2737b 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -11,23 +11,24 @@ import { ResendEmail } from './components/ResendEmail'; import GoogleCallback from './components/GoogleCallback'; import SendResetPasswordLink from './pages/SendResetPasswordLink'; import ResetPassword from './pages/ResetPassword'; -import { ProtectedRoute } from "./utils/protectRoute/ProtectedRoute"; +import { ProtectedRoute } from './utils/protectRoute/ProtectedRoute'; import ViewProduct from './pages/ViewProduct'; import UserLogin from './pages/UserLogin'; import SellerLogin from './pages/SellerLogin'; import AdminLogin from './pages/admin/Login'; import UserViewCart from './pages/UserViewCart'; -import Search from "./pages/Search"; -import SellerViewProduct from "./pages/seller/SellerViewProduct"; -import SellerCollection from "./pages/seller/SellerCollection"; -import { SellerLayout } from "./components/layout/SellerLayout"; -import SellerDashboard from "./pages/seller/SellerDashboard"; -import { AdminDashboard } from "./pages/admin/Dashboard"; -import { OverViewDashboard } from "./pages/admin/OverView"; -import Users from "./pages/admin/Users"; +import Search from './pages/Search'; +import SellerViewProduct from './pages/seller/SellerViewProduct'; +import SellerCollection from './pages/seller/SellerCollection'; +import { SellerLayout } from './components/layout/SellerLayout'; +import SellerDashboard from './pages/seller/SellerDashboard'; +import { AdminDashboard } from './pages/admin/Dashboard'; +import { OverViewDashboard } from './pages/admin/OverView'; +import Users from './pages/admin/Users'; import Logout from './components/layout/Logout'; import UserProfile from './pages/UserEditProfile'; import ProductsPage from './pages/Products'; +import UserCartPaymentSuccess from './pages/UserCartPaymentSuccess'; const AppRouter: React.FC = () => { return (
@@ -40,10 +41,19 @@ const AppRouter: React.FC = () => { } /> } /> } /> - } /> - } /> + } + /> + } + /> } /> - } /> + } + /> } /> } /> } /> @@ -51,6 +61,15 @@ const AppRouter: React.FC = () => { }/> } /> } /> + } /> + } /> + } /> + + }> + } /> + } /> + } /> + } /> }> } /> @@ -60,7 +79,14 @@ const AppRouter: React.FC = () => { } /> - }> + + + + } + > } /> } /> diff --git a/src/store/features/carts/cartService.tsx b/src/store/features/carts/cartService.tsx index fca91b95..913abf99 100644 --- a/src/store/features/carts/cartService.tsx +++ b/src/store/features/carts/cartService.tsx @@ -1,25 +1,25 @@ /* eslint-disable */ -import { axiosInstance } from "../../../utils/axios/axiosInstance"; +import { axiosInstance } from '../../../utils/axios/axiosInstance'; const createCart = async (productId: string, quantity: number) => { try { - const response = await axiosInstance.post("/api/cart/create-update-cart", { + const response = await axiosInstance.post('/api/cart/create-update-cart', { productId, quantity, }); return response.data; } catch (error) { - console.error("Error creating cart", error); + console.error('Error creating cart', error); throw error; } }; const getUserCarts = async () => { try { - const response = await axiosInstance.get("/api/cart/buyer-get-carts"); + const response = await axiosInstance.get('/api/cart/buyer-get-carts'); return response.data; } catch (error) { - console.error("Error getting user carts", error); + console.error('Error getting user carts', error); throw error; } }; @@ -30,39 +30,141 @@ const productCheckout = async (cartId: string) => { return response.data; }; const clearCart = async (cartId: string) => { -try { - const response = await axiosInstance.delete(`api/cart/buyer-clear-cart/${cartId}`); - return response.data; -} catch (error) { - throw error -} -} + try { + const response = await axiosInstance.delete( + `api/cart/buyer-clear-cart/${cartId}` + ); + return response.data; + } catch (error) { + throw error; + } +}; const clearCartProduct = async (cartId: string, productId: string) => { - try { - const response = await axiosInstance.delete(`api/cart/buyer-clear-cart-product/${cartId}/${productId}`); - return response.data; - } catch (error) { - throw error - } -} -const clearCarts = async () => { try { - const response = await axiosInstance.delete("/api/cart/buyer-clear-carts"); - return response + const response = await axiosInstance.delete( + `api/cart/buyer-clear-cart-product/${cartId}/${productId}` + ); + return response.data; + } catch (error) { + throw error; } - catch (error) { - console.error("Error clear carts", error); +}; +const clearCarts = async () => { + try { + const response = await axiosInstance.delete('/api/cart/buyer-clear-carts'); + console.log('MRR', response); + return response; + } catch (error) { + console.error('Error clear carts', error); throw error; } -} +}; + +const createStripeProduct = async (data) => { + const response = await axiosInstance.post('/api/cart/create-stripe-product', { + planInfo: { + active: true, + name: data.name, + 'images[0]': data.image1, + 'images[1]': data.image2, + url: 'https://e-commerce-ninja-fn-staging.netlify.app', + description: data.description, + default_price_data: { + unit_amount: data.unit_amount, + currency: 'usd', + }, + }, + }); + + return response.data; +}; +const createStripeSession = async (data) => { + const customer_email = data.email; + console.log('Cuatomer email', customer_email); + const response = await axiosInstance.post( + '/api/cart/checkout-stripe-session', + // { + // sessionInfo: { + // success_url: data.successUrl, + // cancel_url: data.cancelUrl, + // customer_email: data.customerEmail, + // mode: 'payment', + // ui_mode: 'hosted', + // payment_method_types: ['card'], + // line_items: [ + // { + // quantity: 1, + // price: data.price, + // }, + // ], + // }, + // sessionInfo: { + // success_url: + // 'http://localhost:3000/api-gateway/stripe/checkout-payment-succeeded', + // cancel_url: + // 'http://localhost:3000/api-gateway/stripe/checkout-payment-cancelled', + // customer_email: 'k.joshua800@gmail.com', + // mode: 'payment', + // ui_mode: 'hosted', + // payment_method_types: ['card'], + // line_items: [ + // { + // quantity: 1, + // price: 'price_1PjIQRP2sfrKqqIOWUYjolbZ', + // }, + // ], + // }, + // } + { + sessionInfo: { + success_url: data.successUrl, + cancel_url: data.cancelUrl, + customer_email: data.customerEmail, + mode: 'payment', + ui_mode: 'hosted', + payment_method_types: ['card'], + line_items: [ + { + quantity: 1, + price: data.price, + }, + ], + }, + } + ); + return response.data; +}; + +const updateCartStatus = async (data) => { + const response = await axiosInstance.put('/api/cart/update-cart-status', { + cartId: data.cartId, + status: data.status, + }); + return response.data; +}; + +const saveOrder = async (data) => { + const response = await axiosInstance.post('/api/cart/user-create-order', { + cartId: data.cartId, + paymentMethodId: data.paymentMethodId, + products: data.products, + status: 'pending', + shopId: data.shopId, + }); + return response.data; +}; const cartService = { createCart, getUserCarts, productCheckout, clearCarts, clearCart, - clearCartProduct + clearCartProduct, + createStripeProduct, + createStripeSession, + updateCartStatus, + saveOrder, }; export default cartService; diff --git a/src/store/features/carts/cartSlice.tsx b/src/store/features/carts/cartSlice.tsx index 91672243..03149494 100644 --- a/src/store/features/carts/cartSlice.tsx +++ b/src/store/features/carts/cartSlice.tsx @@ -1,15 +1,15 @@ /* eslint-disable */ -import { createSlice, createAsyncThunk, PayloadAction } from "@reduxjs/toolkit"; -import cartService from "./cartService"; -import { getErrorMessage } from "../../../utils/axios/axiosInstance"; -import { iCartInitialResource } from "../../../utils/types/store"; +import { createSlice, createAsyncThunk, PayloadAction } from '@reduxjs/toolkit'; +import cartService from './cartService'; +import { getErrorMessage } from '../../../utils/axios/axiosInstance'; +import { iCartInitialResource } from '../../../utils/types/store'; const initialState: iCartInitialResource = { carts: [], isLoading: false, isError: false, isSuccess: false, - message: "", + message: '', isLoggedOut: false, cartCounter: 0, cartTotalMoney: 0, @@ -22,7 +22,7 @@ interface CreateCartParams { } export const createCart = createAsyncThunk( - "cart/create-cart", + 'cart/create-cart', async ({ productId, quantity }: CreateCartParams, thunkAPI) => { try { const cart = await cartService.createCart(productId, quantity); @@ -46,7 +46,7 @@ const calculateTotalPrice = (carts: any[]) => { }; export const getUserCarts = createAsyncThunk( - "cart/userGetCarts", + 'cart/userGetCarts', async (_, thunkAPI) => { try { const carts = await cartService.getUserCarts(); @@ -58,7 +58,7 @@ export const getUserCarts = createAsyncThunk( ); export const checkout = createAsyncThunk( - "cart/buyer-cart-checkout", + 'cart/buyer-cart-checkout', async (cartId: string, thunkApi) => { try { const response = await cartService.productCheckout(cartId); @@ -70,12 +70,12 @@ export const checkout = createAsyncThunk( ); export const clearCart = createAsyncThunk( - "cart/buyer-clear-cart", + 'cart/buyer-clear-cart', async (cartId: string, thunkApi) => { try { const response = await cartService.clearCart(cartId); - await cartService.getUserCarts() - + await cartService.getUserCarts(); + return response; } catch (error) { return thunkApi.rejectWithValue(getErrorMessage(error)); @@ -84,8 +84,11 @@ export const clearCart = createAsyncThunk( ); export const clearCartProduct = createAsyncThunk( - "cart/buyer-clear-cart-product", - async ({ cartId, productId }: { cartId: string; productId: string }, thunkApi) => { + 'cart/buyer-clear-cart-product', + async ( + { cartId, productId }: { cartId: string; productId: string }, + thunkApi + ) => { try { const response = await cartService.clearCartProduct(cartId, productId); return response; @@ -96,7 +99,7 @@ export const clearCartProduct = createAsyncThunk( ); export const clearCarts = createAsyncThunk( - "cart/userClearCarts", + 'cart/userClearCarts', async (_, thunkAPI) => { try { const response = await cartService.clearCarts(); @@ -107,8 +110,52 @@ export const clearCarts = createAsyncThunk( } ); +export const createProductStripe = createAsyncThunk( + 'cart/createCartProduct', + async (data: any, thunkApi) => { + try { + const response = await cartService.createStripeProduct(data); + return response; + } catch (error) { + return thunkApi.rejectWithValue(getErrorMessage(error)); + } + } +); + +export const createSessionStripe = createAsyncThunk( + 'cart/createSessionStripe', + async (data: any, thunkApi) => { + try { + const response = await cartService.createStripeSession(data); + return response; + } catch (error) { + return thunkApi.rejectWithValue(getErrorMessage(error)); + } + } +); +export const updateCartStatus = createAsyncThunk( + 'cart/updateCartStatus', + async (data: any, thunkApi) => { + try { + const response = await await cartService.updateCartStatus(data); + return response; + } catch (error) { + return thunkApi.rejectWithValue(getErrorMessage(error)); + } + } +); + +export const userSaveOrder = createAsyncThunk('cart/saveOrder', async(data:any,thunkApi)=> { + try { + const response = await cartService.saveOrder(data); + return response; + } catch (error) { + return thunkApi.rejectWithValue(getErrorMessage(error)); + } +}) + const cartSlice = createSlice({ - name: "cart", + name: 'cart', initialState, reducers: { addCart: (state, action) => { @@ -117,7 +164,10 @@ const cartSlice = createSlice({ usergetCarts: (state, action: PayloadAction) => { state.carts.push(action.payload); }, - updateCartProductQuantity: (state, action: PayloadAction<{ productId: string; quantity: number }>) => { + updateCartProductQuantity: ( + state, + action: PayloadAction<{ productId: string; quantity: number }> + ) => { const { productId, quantity } = action.payload; state.carts.forEach((cart) => { cart.products.forEach((product: any) => { @@ -136,26 +186,26 @@ const cartSlice = createSlice({ state.isLoading = true; state.isError = false; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(createCart.fulfilled, (state, action) => { state.isLoading = false; state.isError = false; state.isSuccess = true; state.carts.push(action.payload); - state.message = "Cart created successfully"; + state.message = 'Cart created successfully'; }) .addCase(createCart.rejected, (state, action) => { state.isLoading = false; state.isError = true; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(getUserCarts.pending, (state) => { state.isLoading = true; state.isError = false; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(getUserCarts.fulfilled, (state, action) => { state.isLoading = false; @@ -179,77 +229,76 @@ const cartSlice = createSlice({ }); state.cartProductslist = cartsProductsList; - state.message = ""; + state.message = ''; }) .addCase(getUserCarts.rejected, (state, action) => { state.isLoading = false; state.isError = true; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(checkout.pending, (state) => { state.isLoading = true; state.isError = false; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(checkout.fulfilled, (state, action) => { state.isLoading = false; state.isError = false; state.isSuccess = true; state.carts.push(action.payload); - state.message = ""; + state.message = ''; }) .addCase(checkout.rejected, (state, action) => { state.isLoading = false; state.isError = true; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(clearCart.pending, (state) => { state.isLoading = true; state.isError = false; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(clearCart.fulfilled, (state, action) => { state.isLoading = false; state.isError = false; state.isSuccess = true; - state.message = action.payload.message; }) .addCase(clearCart.rejected, (state, action) => { state.isLoading = false; state.isError = true; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(clearCartProduct.pending, (state) => { state.isLoading = true; state.isError = false; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(clearCartProduct.fulfilled, (state, action) => { state.isLoading = false; state.isError = false; state.isSuccess = true; state.carts.push(action.payload); - state.message = ""; + state.message = ''; }) .addCase(clearCartProduct.rejected, (state, action) => { state.isLoading = false; state.isError = true; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(clearCarts.pending, (state) => { state.isLoading = true; state.isError = false; state.isSuccess = false; - state.message = ""; + state.message = ''; }) .addCase(clearCarts.fulfilled, (state, action: PayloadAction) => { state.isLoading = false; @@ -269,5 +318,6 @@ const cartSlice = createSlice({ }, }); -export const { addCart, usergetCarts, updateCartProductQuantity } = cartSlice.actions; +export const { addCart, usergetCarts, updateCartProductQuantity } = + cartSlice.actions; export default cartSlice.reducer;