diff --git a/package-lock.json b/package-lock.json
index 3af8300c..353016a8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"@mui/material": "^5.16.4",
"@reduxjs/toolkit": "^2.2.5",
"antd": "^5.19.2",
+ "aos": "^2.3.4",
"axios": "^1.7.2",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
@@ -58,6 +59,7 @@
"@testing-library/dom": "^10.2.0",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
+ "@types/aos": "^3.0.7",
"@types/fork-ts-checker-webpack-plugin": "^0.4.5",
"@types/jest": "^29.5.12",
"@types/mini-css-extract-plugin": "^2.5.1",
@@ -7491,6 +7493,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@types/aos": {
+ "version": "3.0.7",
+ "resolved": "https://registry.npmjs.org/@types/aos/-/aos-3.0.7.tgz",
+ "integrity": "sha512-sEhyFqvKauUJZDbvAB3Pggynrq6g+2PS4XB3tmUr+mDL1gfDJnwslUC4QQ7/l8UD+LWpr3RxZVR/rHoZrLqZVg==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/aria-query": {
"version": "5.0.4",
"dev": true,
@@ -8801,6 +8810,17 @@
"node": ">= 8"
}
},
+ "node_modules/aos": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/aos/-/aos-2.3.4.tgz",
+ "integrity": "sha512-zh/ahtR2yME4I51z8IttIt4lC1Nw0ktsFtmeDzID1m9naJnWXhCoARaCgNOGXb5CLy3zm+wqmRAEgMYB5E2HUw==",
+ "license": "MIT",
+ "dependencies": {
+ "classlist-polyfill": "^1.0.3",
+ "lodash.debounce": "^4.0.6",
+ "lodash.throttle": "^4.0.1"
+ }
+ },
"node_modules/app-root-dir": {
"version": "1.0.2",
"dev": true,
@@ -10666,6 +10686,12 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/classlist-polyfill": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz",
+ "integrity": "sha512-GzIjNdcEtH4ieA2S8NmrSxv7DfEV5fmixQeyTmqmRmRJPGpRBaSnA2a0VrCjyT8iW8JjEdMbKzDotAJf+ajgaQ==",
+ "license": "Unlicense"
+ },
"node_modules/classnames": {
"version": "2.5.1",
"license": "MIT"
@@ -19843,7 +19869,6 @@
},
"node_modules/lodash.debounce": {
"version": "4.0.8",
- "dev": true,
"license": "MIT"
},
"node_modules/lodash.memoize": {
@@ -19857,6 +19882,12 @@
"license": "MIT",
"peer": true
},
+ "node_modules/lodash.throttle": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==",
+ "license": "MIT"
+ },
"node_modules/log-driver": {
"version": "1.2.7",
"dev": true,
diff --git a/package.json b/package.json
index ba875b81..89ddb57f 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"@mui/material": "^5.16.4",
"@reduxjs/toolkit": "^2.2.5",
"antd": "^5.19.2",
+ "aos": "^2.3.4",
"axios": "^1.7.2",
"cors": "^2.8.5",
"dotenv": "^16.4.5",
@@ -60,6 +61,7 @@
"@testing-library/dom": "^10.2.0",
"@testing-library/jest-dom": "^6.4.6",
"@testing-library/react": "^16.0.0",
+ "@types/aos": "^3.0.7",
"@types/fork-ts-checker-webpack-plugin": "^0.4.5",
"@types/jest": "^29.5.12",
"@types/mini-css-extract-plugin": "^2.5.1",
diff --git a/public/assets/images/23172.jpg b/public/assets/images/23172.jpg
new file mode 100644
index 00000000..0f100dda
Binary files /dev/null and b/public/assets/images/23172.jpg differ
diff --git a/public/assets/images/add-cart-buy-now-online-commerce-graphic-concept.jpg b/public/assets/images/add-cart-buy-now-online-commerce-graphic-concept.jpg
new file mode 100644
index 00000000..dd9f5cb3
Binary files /dev/null and b/public/assets/images/add-cart-buy-now-online-commerce-graphic-concept.jpg differ
diff --git a/public/assets/images/cropped-image-woman-inputting-card-information-key-phone-laptop-while-shopping-online.jpg b/public/assets/images/cropped-image-woman-inputting-card-information-key-phone-laptop-while-shopping-online.jpg
new file mode 100644
index 00000000..e79ff491
Binary files /dev/null and b/public/assets/images/cropped-image-woman-inputting-card-information-key-phone-laptop-while-shopping-online.jpg differ
diff --git a/public/assets/images/cyber-monday-shopping-sales.jpg b/public/assets/images/cyber-monday-shopping-sales.jpg
new file mode 100644
index 00000000..f4e761e8
Binary files /dev/null and b/public/assets/images/cyber-monday-shopping-sales.jpg differ
diff --git a/public/assets/images/happy-man-with-handbags-dancing-after-shopping-spree.jpg b/public/assets/images/happy-man-with-handbags-dancing-after-shopping-spree.jpg
new file mode 100644
index 00000000..0961433d
Binary files /dev/null and b/public/assets/images/happy-man-with-handbags-dancing-after-shopping-spree.jpg differ
diff --git a/public/assets/images/laptop-shopping-bags-online-shopping-concept.jpg b/public/assets/images/laptop-shopping-bags-online-shopping-concept.jpg
new file mode 100644
index 00000000..e419aed7
Binary files /dev/null and b/public/assets/images/laptop-shopping-bags-online-shopping-concept.jpg differ
diff --git a/public/assets/images/shopping-cart-gift-boxes.jpg b/public/assets/images/shopping-cart-gift-boxes.jpg
new file mode 100644
index 00000000..6ebaab30
Binary files /dev/null and b/public/assets/images/shopping-cart-gift-boxes.jpg differ
diff --git a/public/assets/images/still-life-say-no-fast-fashion.jpg b/public/assets/images/still-life-say-no-fast-fashion.jpg
new file mode 100644
index 00000000..886e5c6e
Binary files /dev/null and b/public/assets/images/still-life-say-no-fast-fashion.jpg differ
diff --git a/public/assets/shoe1.jpeg b/public/assets/shoe1.jpeg
deleted file mode 100644
index aa06ea37..00000000
Binary files a/public/assets/shoe1.jpeg and /dev/null differ
diff --git a/public/assets/shoe2.jpeg b/public/assets/shoe2.jpeg
deleted file mode 100644
index 45f67048..00000000
Binary files a/public/assets/shoe2.jpeg and /dev/null differ
diff --git a/public/assets/shoe3.jpeg b/public/assets/shoe3.jpeg
deleted file mode 100644
index aac735c5..00000000
Binary files a/public/assets/shoe3.jpeg and /dev/null differ
diff --git a/public/assets/shoe4.jpeg b/public/assets/shoe4.jpeg
deleted file mode 100644
index 2e6ea55a..00000000
Binary files a/public/assets/shoe4.jpeg and /dev/null differ
diff --git a/src/App.scss b/src/App.scss
index 55c86793..be22122e 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -1,5 +1,6 @@
@import './assets/styles/Colors.scss';
@import './assets/styles/style.scss';
+@import './assets/styles/toastify.scss';
@import './assets/styles/Sample.scss';
@import './assets/styles/signup.scss';
@import './assets/styles/Login.scss';
diff --git a/src/assets/styles/Colors.scss b/src/assets/styles/Colors.scss
index 6a8af75a..be501a2e 100644
--- a/src/assets/styles/Colors.scss
+++ b/src/assets/styles/Colors.scss
@@ -26,9 +26,24 @@ $text-family: 'Averia Serif Libre';
$white-color: #FFFFFF;
$border-color: #D9D9D9;
$red-color:red;
+$grayColor:gray;
$primary-color-half: rgb(248,244,244);
$red-color:red;
$menu-hover: #FE975B;
$green-color: rgb(3, 216, 3);
$green-middle-color: rgba(3, 216, 3, 0.3);
$red-middle-color: rgba(216, 8, 3, 0.3);
+
+
+$toastify-color-light: #fff;
+$toastify-color-dark: #121212;
+$toastify-color-info: #3498db;
+$toastify-color-success: orange;
+$toastify-color-warning: #f1c40f;
+$toastify-color-error: #e74c3c;
+
+
+$toastify-icon-color-info: var($toastify-color-info);
+$toastify-icon-color-success: var($toastify-color-success);
+$toastify-icon-color-warning: var($toastify-color-warning);
+$toastify-icon-color-error: var($toastify-color-error);
\ No newline at end of file
diff --git a/src/assets/styles/LandingPage.scss b/src/assets/styles/LandingPage.scss
index a9b41e22..aea5f480 100644
--- a/src/assets/styles/LandingPage.scss
+++ b/src/assets/styles/LandingPage.scss
@@ -1,6 +1,7 @@
.landing-container {
padding: 3rem 2rem 4rem 5rem;
background-color: $container-color;
+
.loader {
display: flex;
justify-content: center;
@@ -8,6 +9,44 @@
height: 100vh;
}
+ .load-more {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-top: 2rem;
+ padding: 1rem 2rem;
+ cursor: pointer;
+
+ button {
+ background-color: $primary-color;
+ color: $white-color;
+ border: none;
+ padding: 0.8rem 1rem;
+ border-radius: 0.5rem;
+ cursor: pointer;
+ }
+
+ button:hover {
+ background-color: $primary-color-dark;
+ padding: 0.8rem 2rem;
+ transition: all 0.5s ease-in-out;
+ animation: bounce 1s infinite;
+
+ }
+
+ @keyframes bounce {
+
+ 0%,
+ 100% {
+ transform: translateY(0);
+ }
+
+ 50% {
+ transform: translateY(-10px);
+ }
+ }
+ }
+
.error-message {
display: flex;
justify-content: center;
@@ -51,7 +90,8 @@
label {
width: 15rem;
}
- .span{
+
+ .span {
width: 20rem;
}
}
diff --git a/src/assets/styles/Sample.scss b/src/assets/styles/Sample.scss
index 581bc697..a7b7152f 100644
--- a/src/assets/styles/Sample.scss
+++ b/src/assets/styles/Sample.scss
@@ -1,31 +1,31 @@
.sampleImages1 {
display: flex;
- width: 100%;
+ width: 100vw;
color: $white;
background-color: $white;
- z-index: -1;
gap: 1rem;
- height: 30rem;
+ height: 40rem;
.sample1, .sample3 {
flex: 1;
display: flex;
flex-direction: column;
- width: 30%;
+ width: 20%;
z-index: 100;
+ height: 40rem;
gap: 1rem;
}
.sample2 {
- flex: 1;
- background-size: cover;
- background-position: center;
- background-repeat: no-repeat;
- width: 30%;
- z-index: 100;
+ width: 40%;
display: flex;
position: relative;
+ img{
+ width: 100%;
+ height: 100%;
+ object-fit: fill;
+ }
.arrow {
position: absolute;
top: 50%;
@@ -73,13 +73,13 @@
align-items: center;
position: relative;
z-index: 100;
+ height: 40rem;
img{
width: 100%;
- height: 14.5rem;
- object-fit: cover;
+ height: 100%;
}
p {
- font-size: 1.4rem;
+ font-size: 1.8rem;
}
button {
@@ -103,6 +103,7 @@
flex-direction: column;
align-items: flex-start;
left: 3rem;
+ gap: 1rem;
}
button {
@@ -118,6 +119,8 @@
align-items: flex-start;
position: absolute;
left: 3rem;
+ gap: 1rem;
+
}
button {
@@ -136,6 +139,8 @@
align-items: flex-end;
position: absolute;
right: 3rem;
+ gap: 1rem;
+
}
button {
@@ -144,7 +149,6 @@
}
.accessories {
- // background-image: url('../../public/assets/right-bottom.png');
.text-container {
display: flex;
@@ -152,8 +156,10 @@
align-items: flex-end;
position: absolute;
right: 3rem;
+ gap: 1rem;
+
p {
- padding-right: 1.5rem;
+ padding-right: .1rem;
}
button {
diff --git a/src/assets/styles/ViewCart.scss b/src/assets/styles/ViewCart.scss
index 86d7670c..35402ef0 100644
--- a/src/assets/styles/ViewCart.scss
+++ b/src/assets/styles/ViewCart.scss
@@ -42,6 +42,7 @@ FaCheckSquare {
border: 1px solid $border-color;
border-radius: 10px;
margin-bottom: 10px;
+ margin-left: 1rem;
.title {
display: flex;
diff --git a/src/assets/styles/toastify.scss b/src/assets/styles/toastify.scss
new file mode 100644
index 00000000..3fa58320
--- /dev/null
+++ b/src/assets/styles/toastify.scss
@@ -0,0 +1,44 @@
+.Toastify__toast-container {
+ z-index: 100;
+ width: 380px;
+ font-size: 1.5rem;
+ font-weight: 500;
+ .Toastify__toast--success {
+ font-size: medium;
+ text-align: center;
+ color: $white;
+ background: $toastify-color-success;
+ }
+ .Toastify__toast--info {
+ color: $white-color;
+ text-align: center;
+ background: $toastify-color-info;
+ }
+ .Toastify__toast--warning {
+ text-align: center;
+ color: yellow;
+ background: gray;
+ }
+ .Toastify__toast--error {
+ color: rgb(178, 3, 3);
+ text-align: center;
+ background:$toastify-color-error;
+ }
+ .Toastify__progress-bar--info {
+ background: blue;
+ }
+ .Toastify__progress-bar--success {
+ background: $primary-color-light;
+ }
+ .Toastify__progress-bar--warning {
+ background: var(--toastify-color-progress-warning);
+ }
+ .Toastify__progress-bar--error {
+ background: $red-color;
+ }
+ .Toastify__toast-icon{
+ svg{
+ fill: white;
+ }
+ }
+ }
\ No newline at end of file
diff --git a/src/components/layout/Sample.tsx b/src/components/layout/Sample.tsx
index bd757f27..2975a3e6 100644
--- a/src/components/layout/Sample.tsx
+++ b/src/components/layout/Sample.tsx
@@ -12,8 +12,12 @@ import leftBottom from "../../../public/assets/images/left-bottom.png";
import rightBottom from "../../../public/assets/images/right-bottom.png";
const images = [
'/assets/middle.png',
- '/assets/shoe2.jpeg',
- '/assets/shoe3.jpeg'
+ '/assets/images/1293.jpg',
+ '/assets/images/add-cart-buy-now-online-commerce-graphic-concept.jpg',
+ '/assets/images/cropped-image-woman-inputting-card-information-key-phone-laptop-while-shopping-online.jpg',
+ '/assets/images/cyber-monday-shopping-sales.jpg',
+ '/assets/images/happy-man-with-handbags-dancing-after-shopping-spree.jpg',
+ '/assets/images/laptop-shopping-bags-online-shopping-concept.jpg',
];
const Sample: React.FC = () => {
@@ -69,7 +73,8 @@ const Sample: React.FC = () => {
-
+
+
diff --git a/src/components/product/Product.tsx b/src/components/product/Product.tsx
index 02f9bc88..d24de3b0 100644
--- a/src/components/product/Product.tsx
+++ b/src/components/product/Product.tsx
@@ -7,6 +7,7 @@ import { useAppDispatch, useAppSelector } from '../../store/store';
import { createCart, getUserCarts } from "../../store/features/carts/cartSlice";
import { addProductToWishlist, removeProductFromWishlist, fetchWishlistProducts } from '../../store/features/wishlist/wishlistSlice';
import { toast } from "react-toastify";
+import aos from "aos"
interface ProductProps {
id: string;
@@ -36,6 +37,9 @@ const Product: React.FC
= ({
const isProductInWishlist = wishlist.some((item: any) => item.id === id);
const [isInWishlist, setIsInWishlist] = useState(isProductInWishlist);
+ useEffect(()=>{
+ aos.init({ once: true });
+ },[]);
useEffect(() => {
setIsInWishlist(isProductInWishlist);
}, [isProductInWishlist]);
@@ -142,7 +146,7 @@ const Product: React.FC = ({
return (
-
+
{
const { products, isError, isSuccess, isLoading, message } = useAppSelector(
(state: any) => state.products
);
+ const [visibleProducts, setVisibleProducts] = useState
(20);
useEffect(() => {
dispatch(fetchProducts());
}, [dispatch]);
@@ -60,6 +61,10 @@ const LandingPage: React.FC = () => {
checkProductToCartPending();
}, []);
+ const handleLoadMore = () => {
+ setVisibleProducts((prevVisibleProducts) => prevVisibleProducts + 20);
+ };
+
return (
<>
@@ -81,7 +86,9 @@ const LandingPage: React.FC = () => {
{isSuccess &&
Array.isArray(products) &&
- products?.map((product: any) => (
+ products
+ .slice(0,visibleProducts)
+ .map((product: any) => (
{
/>
))}
+ {visibleProducts < products.length && (
+
+
)}
)}
diff --git a/src/pages/Products.tsx b/src/pages/Products.tsx
index a22ec25d..39aa692d 100644
--- a/src/pages/Products.tsx
+++ b/src/pages/Products.tsx
@@ -21,6 +21,8 @@ const ProductsPage: React.FC = () => {
const [maxPrice, setMaxPrice] = useState(0);
const [minPrice, setMinPrice] = useState(0);
+ const [visibleProducts, setVisibleProducts] = useState
(20);
+
useEffect(() => {
dispatch(fetchProducts());
}, [dispatch]);
@@ -81,6 +83,10 @@ const ProductsPage: React.FC = () => {
return price >= priceRange[0] && price <= priceRange[1];
});
+ const handleLoadMore = () => {
+ setVisibleProducts((prevVisibleProducts) => prevVisibleProducts + 20);
+ };
+
return (
<>
@@ -116,7 +122,9 @@ const ProductsPage: React.FC = () => {
{isSuccess &&
Array.isArray(filteredProducts) &&
- filteredProducts.map((product: any) => (
+ filteredProducts
+ .slice(0,visibleProducts)
+ .map((product: any) => (
{
/>
))}
+ {visibleProducts < products.length && (
+
+
)}
)}
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 c9a52fb4..ff423333 100644
--- a/src/pages/UserViewCart.tsx
+++ b/src/pages/UserViewCart.tsx
@@ -11,6 +11,10 @@ import {
createCart,
clearCart,
clearCartProduct,
+ createProductStripe,
+ createSessionStripe,
+ updateCartStatus,
+ userSaveOrder,
} from "../store/features/carts/cartSlice";
import {
FaCheckSquare,
@@ -32,6 +36,8 @@ 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();
@@ -40,46 +46,184 @@ 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 [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 try again later"
+ );
+ }
+ 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,
+ })
+ );
+ console.log(stripeProduct);
+ 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("Unknown error occurred 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 (
@@ -92,7 +236,7 @@ const UserViewCart: React.FC = () => {
if (isError) {
return (
-
Failed to load cart products. Please try again later.
+
No cart found.
);
}
@@ -112,23 +256,6 @@ 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
@@ -175,22 +302,18 @@ const UserViewCart: React.FC = () => {
}
};
const handleClearCart = async () => {
- try {
- await dispatch(clearCarts()).unwrap();
- const response1 = await dispatch(getUserCarts()).unwrap();
- setCartResponseData(response1.data);
-
- toast.success("Cart cleared successfully");
- setCartResponseData({ ...cartResponseData, carts: [] });
- setTotalProductPrice(0);
- } catch (error) {
- console.error("Error clearing cart:", error);
- toast.error("Failed to clear the cart");
- }
+ setIsPreloader(true);
+ await dispatch(clearCarts()).unwrap();
+ setIsPreloader(false);
+ await fetchCarts();
+ toast.success("Cart cleared successfully");
+ navigate("/shopping-cart");
+ handleClose();
};
const handleClearSingleCart = async (cartId) => {
try {
+ setIsPreloader(true);
await dispatch(clearCart(cartId));
const response1 = await dispatch(getUserCarts()).unwrap();
setCheckoutSuccess(false);
@@ -199,11 +322,13 @@ const UserViewCart: React.FC = () => {
(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");
+ } finally {
+ setIsPreloader(false);
}
};
@@ -213,6 +338,7 @@ const UserViewCart: React.FC = () => {
cartProductsList
) => {
try {
+ setIsPreloader(true);
if (cartProductsList.length <= 1) {
await handleClearSingleCart(cartId);
return;
@@ -224,6 +350,8 @@ const UserViewCart: React.FC = () => {
} catch (error) {
toast.error("Failed to clear the product ");
throw error;
+ } finally {
+ setIsPreloader(false);
}
};
@@ -249,61 +377,71 @@ const UserViewCart: React.FC = () => {
)}
+
-
-
-
- {cartResponseData?.carts?.length > 0 &&
- cartResponseData.carts.map((cart: any, index) => (
-
-
-
-
Shopping Cart
+
+
+
+ {cartResponseData?.carts?.map((cart: any, index) => (
+
+
+
+
Shopping Cart
+ {cart.status === "Paid" ? (
+
+ ) : (
+ )}
- handleClearSingleCart(cart.cartId)}
- />
-
-
- {cart.products.map((product: any) => {
- return (
-
-
-
-
-
-
-
-
-
navigate(`/product/${product.id}`)}
- >
- {product.name}
-
-
-
-
- {product.discount}
-
-
${product.price}
-
+
handleClearSingleCart(cart.cartId)}
+ />
+
+
+ {cart.products.map((product: any) => {
+ return (
+
+
+
+
+
+
+
+
+
navigate(`/product/${product.id}`)}
+ >
+ {product.name}
+
+
+
+
+ {product.discount}
+
+
${product.price}
+
{product.description}
+
+ {cart.status !== "Paid" && (
-
+ )}
- );
- })}
-
+
+ );
+ })}
- ))}
+
+ ))}
@@ -395,7 +534,7 @@ const UserViewCart: React.FC = () => {
Total amount:
${checkoutData.toFixed(2)}
-
+
) : null}