├── src ├── index.css ├── Components │ ├── Carousel │ │ ├── Carousel.css │ │ └── Carousel.jsx │ ├── Checkout │ │ ├── Chekout.module.css │ │ └── CheckoutForm.jsx │ ├── Category_Card │ │ ├── CategoryCard.jsx │ │ └── Category.module.css │ ├── loading │ │ └── Loading.jsx │ ├── CopyRight │ │ └── CopyRight.jsx │ ├── Card │ │ ├── CartCard │ │ │ ├── CartCard.module.css │ │ │ └── CartCard.jsx │ │ ├── Product Card │ │ │ ├── ProductCard.module.css │ │ │ └── ProductCard.jsx │ │ └── Comment Card │ │ │ └── CommentCard.jsx │ ├── Review │ │ ├── Review.css │ │ └── ProductReview.jsx │ └── SearchBar │ │ └── SearchBar.jsx ├── Pages │ ├── WhisList │ │ ├── Wishlist.css │ │ └── Wishlist.jsx │ ├── Update_User │ │ └── Update.module.css │ ├── Detail │ │ └── Productsimilar.css │ ├── Payment │ │ ├── Payment.css │ │ └── PaymentSuccess.jsx │ ├── Cart │ │ ├── Cart.css │ │ ├── OrderSummary.jsx │ │ └── Cart.jsx │ └── Home │ │ └── HomePage.jsx ├── Auth │ ├── Login │ │ ├── login.css │ │ └── Login.jsx │ ├── ForgotPassword │ │ ├── AddNewPassword.jsx │ │ └── ForgotPasswordForm.jsx │ └── Register │ │ └── Register.jsx ├── Admin │ ├── Auth │ │ ├── Login │ │ │ ├── login.css │ │ │ └── AdminLogin.jsx │ │ └── Register │ │ │ └── AdminRegister.jsx │ ├── Pages │ │ ├── AdminHomePage.jsx │ │ └── SingleUserPage.jsx │ └── Components │ │ ├── UserData │ │ ├── UserReviewItem.jsx │ │ ├── UserOrderItem.jsx │ │ ├── UserCartItem.jsx │ │ ├── UserWishlistItem.jsx │ │ └── UserInfoItem.jsx │ │ ├── Widget.jsx │ │ ├── AdminTabs.jsx │ │ ├── Tables │ │ ├── UserTable.jsx │ │ ├── ProductTable.jsx │ │ └── OrderTable.jsx │ │ ├── AddUser.jsx │ │ └── Charts │ │ └── ProductChart.jsx ├── Context │ └── Context.js ├── index.js ├── Navigation │ ├── Mobile.css │ ├── Desktop.css │ ├── DesktopNavigation.jsx │ └── MobileNavigation.jsx ├── Helpers │ └── HomePageBanner.js ├── SingleCategory │ ├── singlecategory.css │ └── SingleCategory.jsx ├── Assets │ └── Images │ │ └── Image.js ├── App.css ├── Constants │ └── Constant.js ├── service-worker.js ├── App.js └── serviceWorkerRegistration.js ├── public ├── robots.txt ├── favicon.ico ├── logo192.png ├── apple-touch-icon.png ├── manifest.json └── index.html ├── .gitignore ├── LICENSE ├── package.json └── README.md /src/index.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Components/Carousel/Carousel.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/Pages/WhisList/Wishlist.css: -------------------------------------------------------------------------------- 1 | .main-card { 2 | background-color: Red; 3 | } -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luckypenny1632333/E-Shopit-Frontend/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luckypenny1632333/E-Shopit-Frontend/HEAD/public/logo192.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luckypenny1632333/E-Shopit-Frontend/HEAD/public/apple-touch-icon.png -------------------------------------------------------------------------------- /src/Pages/Update_User/Update.module.css: -------------------------------------------------------------------------------- 1 | .checkout_form { 2 | width: 950px; 3 | margin-bottom: 20px; 4 | } 5 | 6 | @media screen and (max-width: 960px) { 7 | .checkout_form { 8 | width: 100%; 9 | } 10 | } 11 | 12 | @media (min-width: 768px) and (max-width:1023px) { 13 | .checkout_form { 14 | width: 100%; 15 | } 16 | } -------------------------------------------------------------------------------- /src/Auth/Login/login.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin-top: 100px; 3 | height: 500px; 4 | border: 2px solid black; 5 | } 6 | 7 | .form-box { 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | flex-direction: column; 12 | margin-top: 100px; 13 | border: 2px solid black; 14 | padding: 10px; 15 | gap: 10px; 16 | } -------------------------------------------------------------------------------- /src/Admin/Auth/Login/login.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin-top: 100px; 3 | height: 500px; 4 | border: 2px solid black; 5 | } 6 | 7 | .form-box { 8 | display: flex; 9 | justify-content: center; 10 | align-items: center; 11 | flex-direction: column; 12 | margin-top: 100px; 13 | border: 2px solid black; 14 | padding: 10px; 15 | gap: 10px; 16 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | /.env 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /src/Components/Checkout/Chekout.module.css: -------------------------------------------------------------------------------- 1 | .checkout_form { 2 | width: 950px; 3 | margin-bottom: 20px; 4 | } 5 | 6 | @media screen and (max-width: 960px) { 7 | .checkout_form { 8 | width: 100%; 9 | } 10 | .checkout_form button{ 11 | /* background-color: red; */ 12 | /* width: 150px; */ 13 | } 14 | } 15 | 16 | @media (min-width: 768px) and (max-width:1023px) { 17 | .checkout_form { 18 | width: 100%; 19 | } 20 | } -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ShopIt", 3 | "short_name": "ShopIt", 4 | "theme_color": "#ffffff", 5 | "background_color": "#ffffff", 6 | "display": "standalone", 7 | "scope": "/", 8 | "start_url": "/", 9 | "icons": [ 10 | { 11 | "src": "logo192.png", 12 | "sizes": "192x192", 13 | "type": "image/png", 14 | "purpose": "any maskable" 15 | }, 16 | { 17 | "src": "logo192.png", 18 | "sizes": "192x192", 19 | "type": "image/png" 20 | } 21 | 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/Context/Context.js: -------------------------------------------------------------------------------- 1 | import React, { useState, createContext } from 'react' 2 | export const ContextFunction = createContext() 3 | 4 | const Context = ({ children }) => { 5 | const [cart, setCart] = useState([]) 6 | const [wishlistData, setWishlistData] = useState([]) 7 | 8 | 9 | 10 | 11 | return ( 12 | 13 | {children} 14 | 15 | ) 16 | } 17 | 18 | export default Context -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import './index.css'; 4 | import App from './App'; 5 | import Context from './Context/Context'; 6 | import * as serviceWorkerRegistration from './serviceWorkerRegistration'; 7 | 8 | 9 | const root = ReactDOM.createRoot(document.getElementById('root')); 10 | root.render( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | 18 | serviceWorkerRegistration.register(); 19 | 20 | -------------------------------------------------------------------------------- /src/Navigation/Mobile.css: -------------------------------------------------------------------------------- 1 | .showMobile { 2 | display: none; 3 | } 4 | 5 | @media screen and (max-width: 900px) { 6 | .showMobile { 7 | display: block; 8 | /* border: 2px solid Red; */ 9 | 10 | } 11 | 12 | .links { 13 | display: flex; 14 | flex-direction: column; 15 | justify-content: center; 16 | align-items: center; 17 | padding: 5px; 18 | width: 70px; 19 | } 20 | 21 | } 22 | 23 | @media (min-width: 768px) and (max-width:1023px) { 24 | 25 | } -------------------------------------------------------------------------------- /src/Components/Category_Card/CategoryCard.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styles from './Category.module.css' 3 | import { Link } from 'react-router-dom' 4 | 5 | const CategoryCard = ({ data }) => { 6 | return ( 7 | 8 |
9 | 10 | {data.name} 11 |
12 | 13 | ) 14 | } 15 | 16 | export default CategoryCard -------------------------------------------------------------------------------- /src/Components/loading/Loading.jsx: -------------------------------------------------------------------------------- 1 | import { Skeleton } from '@mui/material' 2 | import { Stack } from '@mui/system' 3 | const Loading = () => { 4 | return ( 5 | 6 | 7 | 8 |
9 | 10 | 11 |
12 |
13 | ) 14 | } 15 | 16 | export default Loading -------------------------------------------------------------------------------- /src/Components/CopyRight/CopyRight.jsx: -------------------------------------------------------------------------------- 1 | import { Typography } from '@mui/material' 2 | import React from 'react' 3 | 4 | const CopyRight = (props) => { 5 | return ( 6 | 7 | 8 | 9 | {' '} 10 | {new Date().getFullYear()} 11 | {/* {'.'} */} 12 | {' © '} 13 | Developed By Saurabh Khatmode 14 | 15 | 16 | ) 17 | } 18 | 19 | export default CopyRight -------------------------------------------------------------------------------- /src/Helpers/HomePageBanner.js: -------------------------------------------------------------------------------- 1 | import { GroupCloth, Shoes, Electronics, FemaleCloth, MaleCloth, Books, Jewelry } from '../Assets/Images/Image'; 2 | const data = [ 3 | { 4 | img: GroupCloth, 5 | name: "Cloths" 6 | }, 7 | { 8 | img: Shoes, 9 | name: "Shoe" 10 | }, 11 | { 12 | img: FemaleCloth, 13 | name: "Cloths" 14 | }, 15 | { 16 | img: Electronics, 17 | name: "Electronics" 18 | }, 19 | { 20 | img: MaleCloth, 21 | name: "Cloths" 22 | }, 23 | { 24 | img: Books, 25 | name: "Book" 26 | }, 27 | { 28 | img: Jewelry, 29 | name: "Jewelry" 30 | }, 31 | ] 32 | export default data -------------------------------------------------------------------------------- /src/SingleCategory/singlecategory.css: -------------------------------------------------------------------------------- 1 | .title { 2 | border-bottom: #1976d2; 3 | padding:50px 70px; 4 | margin-top: 40px; 5 | font-size: 3rem; 6 | } 7 | 8 | .loading { 9 | width: 300px; 10 | height: 350px; 11 | display: flex; 12 | /* justify-content: center; */ 13 | align-items: center; 14 | align-self: start; 15 | border-radius: 4px; 16 | box-shadow: 0px 2px 1px -1px rgb(0 0 0 / 20%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 1px 3px 0px rgb(0 0 0 / 12%); 17 | padding: 10px; 18 | } 19 | 20 | .loading .divider { 21 | display: flex; 22 | justify-content: space-between; 23 | margin-top: 80px; 24 | gap: 10px; 25 | } 26 | 27 | .loading .prod-name { 28 | margin-top: 40px; 29 | } -------------------------------------------------------------------------------- /src/Components/Category_Card/Category.module.css: -------------------------------------------------------------------------------- 1 | .mainCard { 2 | height: 300px; 3 | width: 400px; 4 | display: flex; 5 | position: relative; 6 | cursor: pointer; 7 | } 8 | .mainCard:hover{ 9 | transform: scale(1.05); 10 | transition:ease-in 0.1s; 11 | } 12 | 13 | .mainImg { 14 | height: 100%; 15 | width: 100%; 16 | box-shadow: 0px 8px 13px rgba(0, 0, 0, 0.2); 17 | filter: saturate(0.7) contrast(1) brightness(1); 18 | object-fit: cover; 19 | border-radius: 10px; 20 | } 21 | 22 | .imgTitle { 23 | font-weight: bold; 24 | position: absolute; 25 | /* bottom: ; */ 26 | top: 85%; 27 | color: white; 28 | right: 0; 29 | padding-right: 10px; 30 | font-size: 20px; 31 | 32 | /* right: 0; */ 33 | } 34 | 35 | @media screen and (max-width: 960px) { 36 | .mainCard { 37 | height: 200px; 38 | width: 300px; 39 | } 40 | 41 | .imgTitle { 42 | font-size: 20px; 43 | } 44 | } 45 | 46 | @media (min-width: 768px) and (max-width: 1023px) { 47 | .checkout_form { 48 | width: 100%; 49 | } 50 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Lucky Penny 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Components/Card/CartCard/CartCard.module.css: -------------------------------------------------------------------------------- 1 | .main_cart { 2 | width: 300px; 3 | margin: 30px 10px 40px 10px; 4 | display: flex; 5 | justify-content: center; 6 | align-items: center; 7 | flex-direction: column; 8 | /* padding: 15px; */ 9 | height: 400px; 10 | padding-bottom: 15px; 11 | /* border: 2px solid red; */ 12 | } 13 | 14 | .card_action { 15 | display: flex; 16 | justify-content: center; 17 | align-items: center; 18 | /* border: 2px solid black; */ 19 | flex-direction: column; 20 | } 21 | 22 | .img_box { 23 | height: 200px; 24 | width: 250px; 25 | /* padding: 5px; */ 26 | display: flex; 27 | justify-content: center; 28 | align-items: center; 29 | 30 | } 31 | 32 | .img_box .img { 33 | height: 100%; 34 | width: 100%; 35 | object-fit: contain; 36 | } 37 | 38 | @media screen and (max-width: 960px) { 39 | .main_cart { 40 | width: 250px; 41 | height: 390px; 42 | 43 | } 44 | 45 | .img_box { 46 | padding: 15px 0; 47 | height: 200px; 48 | width: 250px; 49 | margin-top: 15px; 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/Pages/Detail/Productsimilar.css: -------------------------------------------------------------------------------- 1 | .similarProduct::-webkit-scrollbar { 2 | display: none; 3 | } 4 | 5 | .main-content { 6 | display: flex; 7 | justify-content: space-around; 8 | /* align-items: center; */ 9 | /* background-color: red; */ 10 | width: 90%; 11 | flex-wrap: wrap; 12 | } 13 | 14 | .product-image { 15 | width: 400px; 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | } 20 | 21 | .detail-img-box { 22 | height: 300px; 23 | width: 250px; 24 | } 25 | 26 | .detail-img-box .detail-img { 27 | height: 100%; 28 | width: 100%; 29 | object-fit: contain; 30 | /* object-fit: cover; */ 31 | } 32 | 33 | .product-details { 34 | width: 800px; 35 | display: flex; 36 | flex-direction: column; 37 | gap: 1rem; 38 | /* background: red; */ 39 | } 40 | 41 | .chip { 42 | display: flex; 43 | gap: 0.5rem 44 | } 45 | 46 | @media screen and (max-width: 960px) { 47 | .product-details { 48 | width: 100%; 49 | } 50 | } 51 | 52 | @media (min-width: 768px) and (max-width:1023px) { 53 | .product-details { 54 | width: 100%; 55 | } 56 | } -------------------------------------------------------------------------------- /src/Assets/Images/Image.js: -------------------------------------------------------------------------------- 1 | export let payment = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838910/payment_mkel3w.jpg'; 2 | export let profile = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838912/vecteezy_user-avatar-line-style__x94mjc.jpg'; 3 | export let MaleCloth = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838911/Male-Cloth_fyyrzb.jpg'; 4 | export let FemaleCloth = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838912/Cloths_kpwmp2.jpg'; 5 | export let GroupCloth = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838911/Cloth-banner_ylavk9.jpg'; 6 | export let Electronics = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838911/Electronics_lrjvlg.jpg'; 7 | export let Jewelry = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838911/model-jwellery_qlcjog.jpg'; 8 | export let Shoes = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838911/Shoe_e2yc1d.jpg'; 9 | export let Books = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838761/Book_lc6ikb.jpg'; 10 | export let EmptyCart = 'https://res.cloudinary.com/dxguqzge7/image/upload/v1682838909/Cart_bk4xgl.jpg'; 11 | export let customerReview = "https://res.cloudinary.com/dxguqzge7/image/upload/v1682838911/Review_bm6chw.jpg"; -------------------------------------------------------------------------------- /src/Components/Card/Product Card/ProductCard.module.css: -------------------------------------------------------------------------------- 1 | .main_card { 2 | width: 300px; 3 | margin: 30px 10px; 4 | /* margin-bottom: 110px; */ 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | flex-direction: column; 9 | padding: 15px; 10 | height: 400px; 11 | /* border: 2px solid red; */ 12 | /* border: 2px solid blue; */ 13 | } 14 | 15 | .card_action { 16 | display: flex; 17 | justify-content: center; 18 | align-items: center; 19 | /* border: 2px solid red; */ 20 | flex-direction: column; 21 | } 22 | 23 | .cart_box { 24 | height: 250px; 25 | width: 250px; 26 | /* padding: 5px; */ 27 | /* border: 2px solid black; */ 28 | margin: auto; 29 | } 30 | 31 | .cart_img { 32 | height: 100%; 33 | width: 100%; 34 | object-fit: contain; 35 | object-position: center; 36 | } 37 | 38 | @media screen and (max-width: 960px) { 39 | .main_card { 40 | width: 250px; 41 | height: 350px; 42 | padding: 10px; 43 | } 44 | 45 | .cart_box { 46 | height: 200px; 47 | width: 200px; 48 | padding: 15px; 49 | 50 | } 51 | 52 | } 53 | 54 | /* @media (min-width: 768px) and (max-width:1023px) {} */ -------------------------------------------------------------------------------- /src/Components/Carousel/Carousel.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import AliceCarousel from 'react-alice-carousel'; 3 | import BannerData from '../../Helpers/HomePageBanner' 4 | import 'react-alice-carousel/lib/alice-carousel.css'; 5 | import { Link } from 'react-router-dom'; 6 | const Carousel = () => { 7 | const responsive = { 8 | 0: { items: 1 }, 9 | 568: { items: 2 }, 10 | 1024: { items: 3, itemsFit: 'contain' }, 11 | }; 12 | const items = BannerData.map((item) => ( 13 | 14 | 15 |
16 | {item.name} 17 |
18 | 19 | )) 20 | 21 | return ( 22 | 35 | ) 36 | } 37 | 38 | export default Carousel -------------------------------------------------------------------------------- /src/Pages/Payment/Payment.css: -------------------------------------------------------------------------------- 1 | .main-payment-card { 2 | width: 500px; 3 | height: 340px; 4 | margin: 30px 10px 40px 10px; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | /* flex-direction: column; */ 9 | flex-wrap: wrap; 10 | padding: 10px; 11 | 12 | } 13 | 14 | .main-payment-box { 15 | box-shadow: 0px 8px 13px rgba(0, 0, 0, 0.2); 16 | width: 700px; 17 | display: flex; 18 | justify-content: center; 19 | align-items: center; 20 | flex-direction: column; 21 | margin: 20px auto; 22 | border-radius: 10px; 23 | padding: 10px; 24 | gap: 10px; 25 | } 26 | 27 | .payment-img { 28 | height: 100%; 29 | width: 100%; 30 | object-fit: fill; 31 | } 32 | 33 | @media screen and (max-width: 960px) { 34 | .main-payment-card { 35 | width: 350px; 36 | height: 250px; 37 | padding: 0; 38 | } 39 | 40 | .main-payment-box { 41 | width: 90%; 42 | } 43 | 44 | .main-payment-box { 45 | margin-top: 100px; 46 | } 47 | } 48 | 49 | @media (min-width: 768px) and (max-width:1023px) { 50 | .main-payment-box { 51 | margin-top: 130px; 52 | } 53 | 54 | .main-payment-card { 55 | width: 420px; 56 | height: 350px; 57 | } 58 | 59 | .main-payment-box { 60 | width: 70%; 61 | } 62 | } -------------------------------------------------------------------------------- /src/Components/Card/Product Card/ProductCard.jsx: -------------------------------------------------------------------------------- 1 | import { Card, CardActionArea, CardActions, Rating, CardContent, Typography } from '@mui/material'; 2 | import { Box } from '@mui/system'; 3 | import styles from './ProductCard.module.css' 4 | 5 | export default function ProductCard({ prod }) { 6 | return ( 7 | 8 | 9 | 10 | {prod.name} 11 | 12 | 13 | 14 | {prod.name.length > 20 ? prod.name.slice(0, 20) + '...' : prod.name} 15 | 16 | 17 | 18 | 19 | 20 | ₹{prod.price} 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | } -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | Shop It 26 | 27 | 28 | 29 | 30 |
31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@emotion/react": "^11.10.5", 7 | "@emotion/styled": "^11.10.5", 8 | "@mui/material": "^5.11.0", 9 | "@mui/styled-engine-sc": "^5.11.0", 10 | "@testing-library/jest-dom": "^5.16.5", 11 | "@testing-library/react": "^13.4.0", 12 | "@testing-library/user-event": "^13.5.0", 13 | "axios": "^1.2.1", 14 | "react": "^18.2.0", 15 | "react-alice-carousel": "^2.7.0", 16 | "react-countup": "^6.4.2", 17 | "react-dom": "^18.2.0", 18 | "react-icons": "^4.7.1", 19 | "react-router-dom": "^6.5.0", 20 | "react-scripts": "5.0.1", 21 | "react-toastify": "^9.1.1", 22 | "recharts": "^2.5.0", 23 | "styled-components": "^5.3.6", 24 | "web-vitals": "^2.1.4" 25 | }, 26 | "scripts": { 27 | "start": "react-scripts start", 28 | "build": "react-scripts build", 29 | "test": "react-scripts test", 30 | "eject": "react-scripts eject" 31 | }, 32 | "eslintConfig": { 33 | "extends": [ 34 | "react-app", 35 | "react-app/jest" 36 | ] 37 | }, 38 | "browserslist": { 39 | "production": [ 40 | ">0.2%", 41 | "not dead", 42 | "not op_mini all" 43 | ], 44 | "development": [ 45 | "last 1 chrome version", 46 | "last 1 firefox version", 47 | "last 1 safari version" 48 | ] 49 | }, 50 | "devDependencies": { 51 | "style-loader": "^3.3.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Admin/Pages/AdminHomePage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import axios from 'axios' 3 | import { useNavigate } from 'react-router-dom' 4 | import { toast } from 'react-toastify'; 5 | import { Container } from '@mui/material'; 6 | import BasicTabs from '../Components/AdminTabs'; 7 | import CopyRight from '../../Components/CopyRight/CopyRight' 8 | const AdminHomePage = () => { 9 | const [user, setUser] = useState([]); 10 | const [isAdmin, setAdmin] = useState(false); 11 | 12 | useEffect(() => { 13 | getUser(); 14 | }, []) 15 | let navigate = useNavigate() 16 | let authToken = localStorage.getItem("Authorization") 17 | const getUser = async () => { 18 | try { 19 | const { data } = await axios.get(`${process.env.REACT_APP_ADMIN_GET_ALL_USERS}`, { 20 | headers: { 21 | 'Authorization': authToken 22 | } 23 | }) 24 | setUser(data) 25 | setAdmin(true) 26 | } catch (error) { 27 | !isAdmin && navigate('/') 28 | toast.error(error.response.data, { autoClose: 500, theme: "colored" }); 29 | } 30 | } 31 | return ( 32 | <> 33 | {isAdmin && ( 34 | 35 |

Dashboard

36 | 37 |
)} 38 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default AdminHomePage -------------------------------------------------------------------------------- /src/Admin/Components/UserData/UserReviewItem.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { Box, Typography } from '@mui/material' 3 | import { Link } from 'react-router-dom' 4 | import CommentCard from '../../../Components/Card/Comment Card/CommentCard'; 5 | 6 | 7 | const UserReviewItem = ({ commonGetRequest, id }) => { 8 | const [userReview, setUserReview] = useState([]); 9 | 10 | useEffect(() => { 11 | commonGetRequest(process.env.REACT_APP_ADMIN_GET_REVIEW, id, setUserReview); 12 | }, []) 13 | return ( 14 | <> 15 | User Reviews 16 | {userReview.length < 1 && Not reviewed any products} 17 | 18 | 19 | { 20 | userReview.map(review => 21 | 22 | 23 | 26 | Go to that product 27 | 28 | ) 29 | } 30 | 31 | 32 | ) 33 | } 34 | 35 | export default UserReviewItem -------------------------------------------------------------------------------- /src/Pages/Payment/PaymentSuccess.jsx: -------------------------------------------------------------------------------- 1 | import { Link, useSearchParams } from 'react-router-dom' 2 | import { AiOutlineFileDone } from 'react-icons/ai' 3 | import { Box, Button, Typography } from '@mui/material' 4 | import { payment } from '../../Assets/Images/Image' 5 | import './Payment.css' 6 | import CopyRight from '../../Components/CopyRight/CopyRight' 7 | const PaymentSuccess = () => { 8 | const searchParams = useSearchParams()[0] 9 | const referenceNumber = searchParams.get('reference') 10 | return ( 11 | <> 12 |
13 | Payment Successful 14 | Reference Number ={referenceNumber} 15 | Your payment has been successfully submitted. 16 |
oc 17 | We've sent you an email with all of the details of your order.
18 | 19 | 20 |
21 | payment 22 | 23 |
24 |
25 |
26 | 27 | 28 | ) 29 | } 30 | 31 | 32 | export default PaymentSuccess -------------------------------------------------------------------------------- /src/Navigation/Desktop.css: -------------------------------------------------------------------------------- 1 | .nav { 2 | display: flex; 3 | justify-content: space-around; 4 | gap: 220px; 5 | align-items: center; 6 | padding: 10px; 7 | /* margin: 5px; */ 8 | box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1); 9 | position: fixed; 10 | top: 0; 11 | width: 100%; 12 | z-index: 1000; 13 | background: white; 14 | 15 | /* background-color: red; */ 16 | /* border-radius: 10px; */ 17 | } 18 | 19 | nav .logo { 20 | /* background-color: green; */ 21 | width: 100px; 22 | font-weight: 800; 23 | font-size: 25px; 24 | 25 | } 26 | 27 | nav ul { 28 | display: flex; 29 | line-height: 40px; 30 | /* margin-right: 1rem; */ 31 | } 32 | 33 | nav ul li { 34 | list-style-type: none; 35 | } 36 | 37 | nav ul li a { 38 | display: block; 39 | margin: 0 2px; 40 | padding: 8px 18px; 41 | border-radius: 10px; 42 | font-weight: 600; 43 | 44 | } 45 | 46 | .nav-icon-span { 47 | font-size: 20px; 48 | } 49 | 50 | .nav-items { 51 | line-height: 40px; 52 | /* margin-right: 1rem; */ 53 | } 54 | 55 | nav ul .nav-links:after { 56 | content: ""; 57 | display: block; 58 | height: 3px; 59 | width: 0; 60 | background: transparent; 61 | transition: width 0.7s ease, background-color 0.5s ease; 62 | } 63 | 64 | nav ul .nav-links:hover:after { 65 | width: 100%; 66 | background: #1976d2; 67 | } 68 | 69 | .nav-icon:not(:last-child) { 70 | font-size: 29px; 71 | } 72 | 73 | @media screen and (max-width: 900px) { 74 | 75 | 76 | .nav ul { 77 | display: none; 78 | } 79 | 80 | .nav { 81 | display: block; 82 | } 83 | } 84 | 85 | 86 | @media (min-width: 900px) and (max-width:1096px) { 87 | .nav { 88 | gap: 10px; 89 | justify-content: space-around; 90 | } 91 | } -------------------------------------------------------------------------------- /src/Admin/Pages/SingleUserPage.jsx: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import React from 'react' 3 | import UserInfoItem from '../Components/UserData/UserInfoItem'; 4 | import UserCartItem from '../Components/UserData/UserCartItem'; 5 | import UserWishlistItem from '../Components/UserData/UserWishlistItem'; 6 | import UserReviewItem from '../Components/UserData/UserReviewItem'; 7 | import { useParams } from 'react-router-dom'; 8 | import { Container } from '@mui/material'; 9 | import UserOrderItem from '../Components/UserData/UserOrderItem'; 10 | import CopyRight from '../../Components/CopyRight/CopyRight'; 11 | 12 | const SingleUserPage = () => { 13 | const { id } = useParams(); 14 | let authToken = localStorage.getItem("Authorization") 15 | const commonGetRequest = async (url, userId, setData) => { 16 | try { 17 | const { data } = await axios.get(`${url}/${userId}`, { 18 | headers: { 19 | 'Authorization': authToken 20 | } 21 | }); 22 | setData(data) 23 | } catch (error) { 24 | console.log(error); 25 | 26 | } 27 | 28 | } 29 | return ( 30 | <> 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | ) 42 | } 43 | 44 | export default SingleUserPage -------------------------------------------------------------------------------- /src/Admin/Components/UserData/UserOrderItem.jsx: -------------------------------------------------------------------------------- 1 | import { Box, Container, Typography } from '@mui/material'; 2 | import React, { useEffect, useState } from 'react' 3 | import ProductCard from '../../../Components/Card/Product Card/ProductCard'; 4 | import { Link } from 'react-router-dom'; 5 | 6 | const UserOrderItem = ({ commonGetRequest, id }) => { 7 | const [data, setData] = useState([]); 8 | 9 | useEffect(() => { 10 | commonGetRequest(process.env.REACT_APP_ADMIN_GET_ORDER, id, setData); 11 | }, []) 12 | const total = data.reduce((acc, curr) => (acc + curr.totalAmount), 0); 13 | return ( 14 | 15 | User Orders 16 | {data.length === 0 ? 17 | User not order any thing yet 18 | : 19 | <> 20 | Total Amount Spend ₹{total} 21 | 22 | 23 | { 24 | data.map(product => ( 25 | product.productData.map(prod => 26 | 27 | 28 | ) 29 | ) 30 | )} 31 | 32 | 33 | 34 | } 35 | 36 | 37 | ) 38 | } 39 | 40 | export default UserOrderItem -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | /* outline: 3px solid red !important; */ 6 | font-family: 'Poppins', sans-serif; 7 | } 8 | 9 | .main { 10 | display: flex; 11 | justify-content: center; 12 | align-items: center; 13 | flex-direction: column; 14 | } 15 | 16 | 17 | 18 | a { 19 | text-decoration: none; 20 | color: #353535; 21 | 22 | } 23 | 24 | .all-btn { 25 | width: 110px; 26 | /* text-align: center; */ 27 | } 28 | 29 | .active { 30 | 31 | 32 | color: #1976d2; 33 | background-color: transparent; 34 | 35 | 36 | } 37 | 38 | .toastContainerBox { 39 | display: flex; 40 | /* justify-content: center; 41 | align-items: center; */ 42 | width: 300px; 43 | z-index: 1000; 44 | margin:50px auto; 45 | } 46 | 47 | .margin { 48 | margin-top: 120px; 49 | width: 100%; 50 | padding: 0; 51 | } 52 | 53 | @media screen and (max-width: 960px) { 54 | .all-btn { 55 | width: 110px; 56 | display: flex; 57 | justify-content: center; 58 | align-items: center; 59 | } 60 | 61 | .toastContainerBox { 62 | /* max-width: 250px; */ 63 | /* top: 50px; 64 | left: 140px; */ 65 | 66 | } 67 | 68 | .margin { 69 | margin-top: 70px; 70 | } 71 | 72 | 73 | } 74 | 75 | @media (max-width: 768px) { 76 | .recharts-responsive-container { 77 | width: 100%; 78 | } 79 | } 80 | 81 | 82 | @media (min-width: 768px) and (max-width:1023px) {} 83 | 84 | /* .placeholder-animation { 85 | position: relative; 86 | } 87 | 88 | .placeholder-animation::before { 89 | content: attr(placeholder); 90 | position: absolute; 91 | top: 0; 92 | left: 0; 93 | right: 0; 94 | bottom: 0; 95 | display: flex; 96 | justify-content: center; 97 | align-items: center; 98 | animation: slide 2s ease-in-out infinite; 99 | } */ 100 | 101 | @keyframes slide { 102 | 0% { 103 | transform: translateY(0); 104 | } 105 | 106 | 50% { 107 | transform: translateY(-50%); 108 | } 109 | 110 | 100% { 111 | transform: translateY(-100%); 112 | } 113 | } -------------------------------------------------------------------------------- /src/Pages/Cart/Cart.css: -------------------------------------------------------------------------------- 1 | .total-card { 2 | display: flex; 3 | justify-content: space-between; 4 | width: 100%; 5 | margin-top: 90px; 6 | background-color: green; 7 | } 8 | 9 | .total-card { 10 | width: 30%; 11 | background-color: white; 12 | border: 2px solid black; 13 | } 14 | 15 | .card-container { 16 | display: flex; 17 | align-items: center; 18 | flex-wrap: wrap; 19 | } 20 | 21 | .main-card { 22 | width: 500px; 23 | margin: 30px 10px 40px 10px; 24 | display: flex; 25 | justify-content: center; 26 | align-items: center; 27 | /* flex-direction: column; */ 28 | flex-wrap: wrap; 29 | padding: 10px; 30 | height: 540px; 31 | } 32 | 33 | .main-cart-container { 34 | display: flex; 35 | justify-content: center; 36 | align-items: center; 37 | flex-direction: column; 38 | } 39 | 40 | .cart-img-box { 41 | height: 100px; 42 | width: 100px; 43 | border: 2px solid black; 44 | } 45 | 46 | .cart-img-box .cart-img { 47 | height: 100%; 48 | width: 100%; 49 | object-fit: fill; 50 | } 51 | 52 | .cart-img { 53 | width: 200px; 54 | height: 150px; 55 | } 56 | 57 | .total-card { 58 | background-color: red; 59 | height: 100%; 60 | display: flex; 61 | justify-content: center; 62 | align-items: center; 63 | } 64 | 65 | .empty-cart-img { 66 | height: 100%; 67 | width: 100%; 68 | object-fit: contain; 69 | } 70 | 71 | 72 | 73 | 74 | @media screen and (max-width: 960px) { 75 | .main-card { 76 | width: 300px; 77 | height: 350px; 78 | 79 | } 80 | 81 | .total-card { 82 | background-color: green; 83 | } 84 | 85 | .cart-img { 86 | width: 150px; 87 | height: 150px; 88 | object-fit: contain; 89 | } 90 | } 91 | 92 | @media (min-width: 768px) and (max-width: 1023px) { 93 | .total-card { 94 | background-color: blue; 95 | } 96 | 97 | .cart-img { 98 | width: 150px; 99 | height: 150px; 100 | object-fit: contain; 101 | } 102 | } -------------------------------------------------------------------------------- /src/Admin/Components/UserData/UserCartItem.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { Container, Typography } from '@mui/material' 3 | import CartCard from '../../../Components/Card/CartCard/CartCard' 4 | import axios from 'axios'; 5 | import { toast } from 'react-toastify'; 6 | 7 | const UserCartItem = ({ commonGetRequest, id, authToken }) => { 8 | const [userCart, setUserCart] = useState([]); 9 | 10 | 11 | const removeCartItemByAdmin = async (product) => { 12 | try { 13 | const { data } = await axios.delete(`${process.env.REACT_APP_ADMIN_DELETE_CART}/${product._id}`, { 14 | headers: { 15 | 'Authorization': authToken 16 | } 17 | }) 18 | if (data.success === true) { 19 | setUserCart(userCart.filter(c => c.productId._id !== product.productId._id)) 20 | toast.success("Removed From Cart", { autoClose: 500, theme: 'colored' }) 21 | } 22 | else { 23 | toast.error("Something went wrong", { autoClose: 500, theme: 'colored' }) 24 | 25 | } 26 | } catch (error) { 27 | console.log(error); 28 | toast.error(error.response.data.msg, { autoClose: 500, theme: "colored" }); 29 | } 30 | } 31 | useEffect(() => { 32 | commonGetRequest(process.env.REACT_APP_ADMIN_GET_CART, id, setUserCart); 33 | }, []) 34 | return ( 35 | <> 36 | User Cart 37 | {userCart.length < 1 && No items in cart} 38 | 39 | {userCart.map(prod => ( 40 | 41 | ))} 42 | 43 | 44 | 45 | ) 46 | } 47 | 48 | export default UserCartItem -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # E-Shopit-Frontend 2 | 3 | E-Shopit-Frontend is the frontend of an e-commerce web application built with ReactJS ,Material UI, ContextAPI, React-router-dom 4 | 5 | ## Live Link 6 | 7 | You can access the live application at [https://e-shopit.vercel.app/](https://e-shopit.vercel.app/). 8 | 9 | ## Features 10 | 11 | - User authentication and authorization(JWT) 12 | - Admin dashboard for managing products, orders, users and to show statistics 13 | - Payemnt Gateway 14 | - Mail Service 15 | - Forgot Password & Reset Password 16 | - Product listing and search 17 | - Product details and reviews 18 | - Cart management 19 | - Order history 20 | 21 | ## Tech Stack 22 | - MongoDB 23 | - ReactJS 24 | - NodeJS 25 | - ExpressJS 26 | ## Images 27 | 28 | ![Dashboard](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853694/Stat1_asehhd.png) 29 | ![Dashboard](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853694/Stat2_tw25cm.png) 30 | ![Dashboard](https://res.cloudinary.com/dxguqzge7/image/upload/v1682956688/Stat3_rslfzi.png) 31 | ![Orders](https://res.cloudinary.com/dxguqzge7/image/upload/v1682956689/Orders_cyfzkp.png) 32 | ![Users](https://res.cloudinary.com/dxguqzge7/image/upload/v1682956689/Users_nxx1cs.png) 33 | ![HomePage](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853694/Home_bcr44v.png) 34 | ![Products](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853695/Products_vxf8pr.png) 35 | ![Product](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853694/Product_tnba6w.png) 36 | ![Payment](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853693/Payment_xrucd9.png) 37 | ![Cart](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853693/Cart_zpzmwr.png) 38 | ![UserProfile](https://res.cloudinary.com/dxguqzge7/image/upload/v1682853694/User_lyfday.png) 39 | 40 | ## Backend 41 | 42 | The backend of the application is built with NodeJS and ExpressJS and uses a MongoDB database to store the product and user data. The source code for the backend can be found at [https://github.com/luckypenny1632333/E-Shopit-Backend.git](https://github.com/luckypenny1632333/E-Shopit-Backend.git). 43 | 44 | 45 | ## License 46 | 47 | This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for more information. 48 | -------------------------------------------------------------------------------- /src/Constants/Constant.js: -------------------------------------------------------------------------------- 1 | import { Slide } from "@mui/material"; 2 | import axios from "axios"; 3 | import { forwardRef } from "react"; 4 | const getCart = async (setProceed, setCart, authToken) => { 5 | if (setProceed) { 6 | const { data } = await axios.get(`${process.env.REACT_APP_GET_CART}`, 7 | { 8 | headers: { 9 | 'Authorization': authToken 10 | } 11 | }) 12 | setCart(data); 13 | } 14 | } 15 | const getWishList = async (setProceed, setWishlistData, authToken) => { 16 | if (setProceed) { 17 | const { data } = await axios.get(`${process.env.REACT_APP_GET_WISHLIST}`, 18 | { 19 | headers: { 20 | 'Authorization': authToken 21 | } 22 | }) 23 | setWishlistData(data) 24 | } 25 | } 26 | const handleLogOut = (setProceed, toast, navigate, setOpenAlert) => { 27 | if (setProceed) { 28 | localStorage.removeItem('Authorization') 29 | toast.success("Logout Successfully", { autoClose: 500, theme: 'colored' }) 30 | navigate('/') 31 | setOpenAlert(false) 32 | } 33 | else { 34 | toast.error("User is already logged of", { autoClose: 500, theme: 'colored' }) 35 | } 36 | } 37 | 38 | const handleClickOpen = (setOpenAlert) => { 39 | setOpenAlert(true); 40 | }; 41 | 42 | const handleClose = (setOpenAlert) => { 43 | setOpenAlert(false); 44 | }; 45 | const getAllProducts = async (setData) => { 46 | try { 47 | const { data } = await axios.get(process.env.REACT_APP_FETCH_PRODUCT); 48 | setData(data) 49 | 50 | 51 | } catch (error) { 52 | console.log(error); 53 | } 54 | } 55 | 56 | const getSingleProduct = async (setProduct, id, setLoading) => { 57 | 58 | const { data } = await axios.get(`${process.env.REACT_APP_FETCH_PRODUCT}/${id}`) 59 | setProduct(data) 60 | setLoading(false); 61 | 62 | } 63 | 64 | const Transition = forwardRef(function Transition(props, ref) { 65 | return ; 66 | }); 67 | 68 | 69 | 70 | 71 | 72 | export { getCart, getWishList, handleClickOpen, handleClose, handleLogOut, getAllProducts, getSingleProduct, Transition } -------------------------------------------------------------------------------- /src/Components/Review/Review.css: -------------------------------------------------------------------------------- 1 | .form-container { 2 | display: flex; 3 | justify-content: space-between; 4 | align-items: center; 5 | /* gap: 220px; */ 6 | /* flex-wrap: wrap; */ 7 | padding: 50px; 8 | /* background-color: red; */ 9 | } 10 | 11 | .form { 12 | display: flex; 13 | justify-content: center; 14 | align-items: center; 15 | flex-direction: column; 16 | gap: 10px; 17 | width: 400px; 18 | padding: 20px; 19 | } 20 | 21 | .form button { 22 | align-self: flex-start; 23 | margin-left: 30px; 24 | } 25 | 26 | .comment { 27 | width: 300px; 28 | background-color: transparent; 29 | } 30 | 31 | .form-img-box { 32 | height: 550px; 33 | width: 500px; 34 | /* border: 2px solid black; */ 35 | } 36 | 37 | .review-img { 38 | height: 100%; 39 | width: 100%; 40 | /* object-fit: cover; */ 41 | margin-bottom: 20px; 42 | } 43 | 44 | .expression-icon { 45 | font-size: 30px; 46 | display: flex; 47 | justify-content: center; 48 | align-items: center; 49 | } 50 | 51 | .review-box { 52 | display: flex; 53 | flex-direction: column; 54 | justify-content: center; 55 | width: 70%; 56 | margin: 50px auto; 57 | /* border: 2px solid black;/ */ 58 | font-size: 1rem; 59 | } 60 | 61 | @media (min-width: 768px) and (max-width:1023px) { 62 | .review-box { 63 | width: 100%; 64 | /* border: 2px solid black; */ 65 | } 66 | 67 | .form-img-box { 68 | height: 350px; 69 | width: 400px; 70 | } 71 | } 72 | 73 | @media screen and (max-width: 960px) { 74 | .review-box { 75 | width: 100%; 76 | 77 | } 78 | 79 | .form button { 80 | margin-left: 30px; 81 | } 82 | 83 | .form-container { 84 | flex-direction: column-reverse; 85 | } 86 | 87 | .form-img-box { 88 | height: 400px; 89 | width: 350px; 90 | } 91 | 92 | } 93 | 94 | @media (min-width: 900px) and (max-width:1096px) { 95 | .form-container { 96 | flex-direction: row; 97 | } 98 | 99 | 100 | .form-img-box { 101 | height: 350px; 102 | width: 450px; 103 | } 104 | } -------------------------------------------------------------------------------- /src/Admin/Components/UserData/UserWishlistItem.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { Container, Typography } from '@mui/material' 3 | import CartCard from '../../../Components/Card/CartCard/CartCard' 4 | import axios from 'axios' 5 | import { toast } from 'react-toastify' 6 | 7 | const UserWishlistItem = ({ authToken, id, commonGetRequest }) => { 8 | 9 | const [userWishlist, setUserWishlist] = useState([]); 10 | 11 | useEffect(() => { 12 | commonGetRequest(process.env.REACT_APP_ADMIN_GET_WISHLIST, id, setUserWishlist); 13 | }, []) 14 | const removeCartItemByAdmin = async (product) => { 15 | try { 16 | console.log(product._id); 17 | const { data } = await axios.delete(`${process.env.REACT_APP_ADMIN_DELETE_WISHLIST}/${product._id}`, { 18 | headers: { 19 | 'Authorization': authToken 20 | } 21 | }); 22 | if (data.success === true) { 23 | setUserWishlist(userWishlist.filter(c => c.productId._id !== product.productId._id)) 24 | toast.success("Removed From Cart", { autoClose: 500, theme: 'colored' }) 25 | } 26 | else { 27 | toast.error("Something went wrong", { autoClose: 500, theme: 'colored' }) 28 | 29 | } 30 | } catch (error) { 31 | console.log(error); 32 | toast.error(error.response.data.msg, { autoClose: 500, theme: "colored" }); 33 | } 34 | } 35 | return ( 36 | <> 37 | User Wishlist 38 | {userWishlist.length < 1 && No items in wishlist} 39 | 40 | {userWishlist.map(prod => ( 41 | 42 | ))} 43 | 44 | 45 | 46 | ) 47 | } 48 | 49 | export default UserWishlistItem -------------------------------------------------------------------------------- /src/Admin/Components/Widget.jsx: -------------------------------------------------------------------------------- 1 | import { Box, IconButton, Typography, useMediaQuery } from '@mui/material' 2 | import React, { useEffect, useState } from 'react' 3 | import CountUp from 'react-countup'; 4 | 5 | 6 | const Widget = ({ numbers, heading, color, icon }) => { 7 | const isSmallScreen = useMediaQuery('(max-width:600px)'); 8 | const [value, setValue] = useState(0); 9 | const endValue = numbers; 10 | 11 | useEffect(() => { 12 | setValue(endValue); 13 | }, [endValue]); 14 | 15 | const prefix = heading === 'Revenue' ? '₹' : ''; 16 | return ( 17 | 31 | 32 | < Typography variant="h6" sx={{ 33 | color: "white", mb: 1, fontWeight: 'bold', 34 | }}> 35 | {heading} 36 | 37 | 38 | 39 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | {icon} 56 | 57 | 58 | 59 | 60 | ) 61 | } 62 | 63 | export default Widget -------------------------------------------------------------------------------- /src/Pages/Home/HomePage.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import axios from 'axios' 3 | import { Container, Typography } from '@mui/material' 4 | import { Box } from '@mui/system' 5 | import { useContext } from 'react' 6 | import { ContextFunction } from '../../Context/Context' 7 | import CategoryCard from '../../Components/Category_Card/CategoryCard'; 8 | import BannerData from '../../Helpers/HomePageBanner'; 9 | import Carousel from '../../Components/Carousel/Carousel' 10 | import SearchBar from '../../Components/SearchBar/SearchBar' 11 | import CopyRight from '../../Components/CopyRight/CopyRight' 12 | const HomePage = () => { 13 | const { setCart } = useContext(ContextFunction) 14 | let authToken = localStorage.getItem('Authorization') 15 | useEffect(() => { 16 | getCart() 17 | window.scroll(0, 0) 18 | }, []) 19 | const getCart = async () => { 20 | if (authToken !== null) { 21 | const { data } = await axios.get(`${process.env.REACT_APP_GET_CART}`, 22 | { 23 | headers: { 24 | 'Authorization': authToken 25 | } 26 | }) 27 | setCart(data); 28 | } 29 | 30 | } 31 | 32 | 33 | 34 | return ( 35 | <> 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | Categories 44 | 45 | { 46 | BannerData.map(data => ( 47 | 48 | )) 49 | } 50 | 51 | 52 | 53 | 54 | ) 55 | } 56 | 57 | export default HomePage -------------------------------------------------------------------------------- /src/Components/Card/CartCard/CartCard.jsx: -------------------------------------------------------------------------------- 1 | import { Button, Card, CardActionArea, CardActions, CardContent, Rating, Tooltip, Typography } from '@mui/material' 2 | import { Box } from '@mui/system' 3 | import { Link } from 'react-router-dom' 4 | import { AiFillDelete } from 'react-icons/ai' 5 | import styles from './CartCard.module.css' 6 | const CartCard = ({ product, removeFromCart }) => { 7 | 8 | 9 | return ( 10 | 11 | 12 | 13 | 14 | {product?.productId?.name} 15 | 16 | 17 | 18 | {product?.productId?.name.length > 20 ? product?.productId?.name.slice(0, 20) + '...' : product?.productId?.name} 19 | 20 | *': { 26 | m: 1, 27 | }, 28 | }} 29 | > 30 | {product.quantity && } 31 | 32 | ₹{product?.productId?.price} 33 | 34 | 35 | 36 | 37 | 38 | 39 | 41 | 44 | 45 | 46 | 47 | 48 | ) 49 | } 50 | 51 | export default CartCard -------------------------------------------------------------------------------- /src/Pages/Cart/OrderSummary.jsx: -------------------------------------------------------------------------------- 1 | import { Box, Button, Card, CardActions, CardContent, Grid, Typography } from '@mui/material' 2 | import React from 'react' 3 | import { IoBagCheckOutline } from 'react-icons/io5' 4 | 5 | const OrderSummary = ({ proceedToCheckout, total, shippingCoast }) => { 6 | return ( 7 | 13 | 14 | 15 | {" "} 16 | Order Summary 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | SubTotal 25 | 26 | 27 | ₹{total - shippingCoast} 28 | 29 | 30 | 31 | 32 | Shipping 33 | 34 | 35 | ₹{shippingCoast} 36 | 37 | 38 | 39 | 40 | Total 41 | 42 | 43 | ₹{total} 44 | 45 | 46 | 47 |
48 | 49 | 52 | 53 |
54 | ) 55 | } 56 | 57 | export default OrderSummary -------------------------------------------------------------------------------- /src/service-worker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-restricted-globals */ 2 | 3 | // This service worker can be customized! 4 | // See https://developers.google.com/web/tools/workbox/modules 5 | // for the list of available Workbox modules, or add any other 6 | // code you'd like. 7 | // You can also remove this file if you'd prefer not to use a 8 | // service worker, and the Workbox build step will be skipped. 9 | 10 | import { clientsClaim } from 'workbox-core'; 11 | import { ExpirationPlugin } from 'workbox-expiration'; 12 | import { precacheAndRoute, createHandlerBoundToURL } from 'workbox-precaching'; 13 | import { registerRoute } from 'workbox-routing'; 14 | import { StaleWhileRevalidate } from 'workbox-strategies'; 15 | 16 | clientsClaim(); 17 | 18 | // Precache all of the assets generated by your build process. 19 | // Their URLs are injected into the manifest variable below. 20 | // This variable must be present somewhere in your service worker file, 21 | // even if you decide not to use precaching. See https://cra.link/PWA 22 | precacheAndRoute(self.__WB_MANIFEST); 23 | 24 | // Set up App Shell-style routing, so that all navigation requests 25 | // are fulfilled with your index.html shell. Learn more at 26 | // https://developers.google.com/web/fundamentals/architecture/app-shell 27 | const fileExtensionRegexp = new RegExp('/[^/?]+\\.[^/]+$'); 28 | registerRoute( 29 | // Return false to exempt requests from being fulfilled by index.html. 30 | ({ request, url }) => { 31 | // If this isn't a navigation, skip. 32 | if (request.mode !== 'navigate') { 33 | return false; 34 | } // If this is a URL that starts with /_, skip. 35 | 36 | if (url.pathname.startsWith('/_')) { 37 | return false; 38 | } // If this looks like a URL for a resource, because it contains // a file extension, skip. 39 | 40 | if (url.pathname.match(fileExtensionRegexp)) { 41 | return false; 42 | } // Return true to signal that we want to use the handler. 43 | 44 | return true; 45 | }, 46 | createHandlerBoundToURL(process.env.PUBLIC_URL + '/index.html') 47 | ); 48 | 49 | // An example runtime caching route for requests that aren't handled by the 50 | // precache, in this case same-origin .png requests like those from in public/ 51 | registerRoute( 52 | // Add in any other file extensions or routing criteria as needed. 53 | ({ url }) => url.origin === self.location.origin && url.pathname.endsWith('.png'), // Customize this strategy as needed, e.g., by changing to CacheFirst. 54 | new StaleWhileRevalidate({ 55 | cacheName: 'images', 56 | plugins: [ 57 | // Ensure that once this runtime cache reaches a maximum size the 58 | // least-recently used images are removed. 59 | new ExpirationPlugin({ maxEntries: 50 }), 60 | ], 61 | }) 62 | ); 63 | 64 | // This allows the web app to trigger skipWaiting via 65 | // registration.waiting.postMessage({type: 'SKIP_WAITING'}) 66 | self.addEventListener('message', (event) => { 67 | if (event.data && event.data.type === 'SKIP_WAITING') { 68 | self.skipWaiting(); 69 | } 70 | }); 71 | 72 | // Any other custom service worker logic can go here. 73 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import './App.css'; 2 | import { BrowserRouter as Router, Routes, Route } from 'react-router-dom' 3 | import HomePage from './Pages/Home/HomePage'; 4 | import Login from './Auth/Login/Login'; 5 | import Register from './Auth/Register/Register'; 6 | import Cart from './Pages/Cart/Cart'; 7 | import ProductDetail from './Pages/Detail/ProductDetail'; 8 | import SingleCategory from './SingleCategory/SingleCategory'; 9 | import MobileNavigation from './Navigation/MobileNavigation'; 10 | import DesktopNavigation from './Navigation/DesktopNavigation'; 11 | import Wishlist from './Pages/WhisList/Wishlist'; 12 | import PaymentSuccess from './Pages/Payment/PaymentSuccess'; 13 | import { Flip, ToastContainer } from 'react-toastify'; 14 | import 'react-toastify/dist/ReactToastify.css'; 15 | import CheckoutForm from './Components/Checkout/CheckoutForm'; 16 | import UpdateDetails from './Pages/Update_User/UpdateDetails'; 17 | import ForgotPasswordForm from './Auth/ForgotPassword/ForgotPasswordForm'; 18 | import AddNewPassword from './Auth/ForgotPassword/AddNewPassword'; 19 | import AdminLogin from './Admin/Auth/Login/AdminLogin'; 20 | import AdminRegister from './Admin/Auth/Register/AdminRegister'; 21 | import AdminHomePage from './Admin/Pages/AdminHomePage'; 22 | import SingleUserPage from './Admin/Pages/SingleUserPage'; 23 | import SingleProduct from './Admin/Pages/SingleProduct'; 24 | 25 | 26 | 27 | 28 | 29 | function App() { 30 | return ( 31 | <> 32 | 33 | 34 | 35 |
36 | 37 | {/*User Routes */} 38 | } /> 39 | } /> 40 | } /> 41 | } /> 42 | } /> 43 | } /> 44 | } /> 45 | } /> 46 | } /> 47 | } /> 48 | } /> 49 | } /> 50 | 51 | {/* Admin Routes */} 52 | } /> 53 | } /> 54 | } /> 55 | } /> 56 | } /> 57 | 58 |
59 | 60 |
61 | 62 | 63 | 64 | ); 65 | } 66 | export default App; 67 | -------------------------------------------------------------------------------- /src/Auth/ForgotPassword/AddNewPassword.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { useNavigate, useParams } from 'react-router-dom' 3 | import { Avatar, Button, CssBaseline, InputAdornment, TextField, Typography } from '@mui/material' 4 | import { Box, Container } from '@mui/system' 5 | import { MdLockOutline } from 'react-icons/md' 6 | import axios from 'axios' 7 | import { toast } from 'react-toastify' 8 | import CopyRight from '../../Components/CopyRight/CopyRight' 9 | import { RiEyeFill, RiEyeOffFill } from 'react-icons/ri'; 10 | 11 | 12 | const AddNewPassword = () => { 13 | const { id, token } = useParams() 14 | const [password, setPassword] = useState('') 15 | const [showPassword, setShowPassword] = useState(false); 16 | const handleClickShowPassword = () => { 17 | setShowPassword(!showPassword); 18 | }; 19 | let navigate = useNavigate() 20 | const handleSubmit = async (e) => { 21 | e.preventDefault() 22 | try { 23 | 24 | const { data } = await axios.post(`${process.env.REACT_APP_FORGOT_PASSWORD}/${id}/${token}`, { newPassword: password }) 25 | if (data.msg.name == "TokenExpiredError") { 26 | toast.error("Token is expired Please try again", { autoClose: 500, theme: 'colored' }) 27 | navigate('/login') 28 | } 29 | else { 30 | toast.success(data.msg, { autoClose: 500, theme: 'colored' }) 31 | navigate('/login') 32 | } 33 | 34 | } catch (error) { 35 | toast.error(error.response.data.msg, { autoClose: 500, theme: 'colored' }) 36 | } 37 | } 38 | 39 | 40 | 41 | 42 | return ( 43 | 44 | 45 | 53 | 54 | 55 | 56 | 57 | Forgot Password 58 | 59 | 60 | setPassword(e.target.value)} 68 | autoComplete="password" 69 | type={showPassword ? "text" : "password"} 70 | id="password" 71 | InputProps={{ 72 | endAdornment: ( 73 | 74 | {showPassword ? : } 75 | 76 | ) 77 | }} 78 | autoFocus 79 | /> 80 | 88 | 89 | 90 | 91 | 92 | 93 | ) 94 | } 95 | 96 | export default AddNewPassword -------------------------------------------------------------------------------- /src/Auth/ForgotPassword/ForgotPasswordForm.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { Avatar, Button, CssBaseline, TextField, Typography } from '@mui/material' 3 | import { Box, Container } from '@mui/system' 4 | import { MdLockOutline, MdMailOutline } from 'react-icons/md' 5 | import axios from 'axios' 6 | import { toast } from 'react-toastify' 7 | import CopyRight from '../../Components/CopyRight/CopyRight' 8 | 9 | 10 | const ForgotPasswordForm = () => { 11 | const [email, setEmail] = useState('') 12 | const [isSentMail, setIsSentMail] = useState(false); 13 | const handleSubmit = async (e) => { 14 | e.preventDefault() 15 | try { 16 | const sendEmail = await axios.post(`${process.env.REACT_APP_FORGOT_PASSWORD}`, { email: email }) 17 | toast.success(sendEmail.data.msg, { autoClose: 500, theme: 'colored' }) 18 | setIsSentMail(true); 19 | } catch (error) { 20 | toast.error(error.response.data.msg, { autoClose: 500, theme: 'colored' }) 21 | } 22 | 23 | } 24 | 25 | return ( 26 | <> 27 | {!isSentMail ? 28 | 29 | 30 | 38 | 39 | 40 | 41 | 42 | Forgot Password 43 | 44 | 45 | setEmail(e.target.value)} 54 | autoComplete="email" 55 | autoFocus 56 | /> 57 | 65 | 66 | 67 | 68 | 69 | 70 | : 71 | 80 | 81 | Email Sent Successfully 82 | 83 | 84 | 85 | } 86 | 87 | ) 88 | } 89 | 90 | export default ForgotPasswordForm -------------------------------------------------------------------------------- /src/Components/SearchBar/SearchBar.jsx: -------------------------------------------------------------------------------- 1 | import { Container, InputAdornment, TextField, Typography } from "@mui/material"; 2 | import { useEffect, useState } from "react"; 3 | import { AiOutlineSearch } from 'react-icons/ai'; 4 | import Box from '@mui/material/Box'; 5 | import Paper from '@mui/material/Paper'; 6 | import Stack from '@mui/material/Stack'; 7 | import { styled } from '@mui/material/styles'; 8 | import { Link } from "react-router-dom"; 9 | import { getAllProducts } from "../../Constants/Constant"; 10 | const SearchBar = () => { 11 | const [data, setData] = useState([]); 12 | const [filteredData, setFilteredData] = useState([]); 13 | const [searchTerm, setSearchTerm] = useState(''); 14 | 15 | useEffect(() => { 16 | getAllProducts(setData); 17 | }, []) 18 | 19 | const handleSearch = event => { 20 | setSearchTerm(event.target.value); 21 | const newFilteredData = data.filter(item => 22 | (item.name && item.name.toLowerCase().includes(event.target.value.toLowerCase())) || 23 | (item.type && item.type.toLowerCase().includes(event.target.value.toLowerCase())) || 24 | (item.brand && item.brand.toLowerCase().includes(event.target.value.toLowerCase())) || 25 | (item.category && item.category.toLowerCase().includes(event.target.value.toLowerCase())) || 26 | (item.author && item.author.toLowerCase().includes(event.target.value.toLowerCase())) || 27 | (item.description && item.description.toLowerCase().includes(event.target.value.toLowerCase())) || 28 | (item.gender && item.gender.toLowerCase().includes(event.target.value.toLowerCase())) 29 | ); 30 | setFilteredData(newFilteredData); 31 | }; 32 | 33 | 34 | const Item = styled(Paper)(({ theme }) => ({ 35 | backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff', 36 | ...theme.typography.body2, 37 | padding: theme.spacing(1), 38 | textAlign: 'center', 39 | color: theme.palette.text.secondary, 40 | })); 41 | return ( 42 | 43 | 54 | 55 | 56 | ), 57 | }} 58 | /> 59 | { 60 | searchTerm.length > 0 && 61 | 62 | 63 | 64 | {filteredData.length === 0 ? 65 | Product Not Found 66 | : filteredData.map(products => ( 67 | 68 | 69 | {products.name.slice(0, 35)} 70 | {products.name} 71 | 72 | 73 | ))} 74 | 75 | 76 | } 77 | 78 | ) 79 | } 80 | 81 | export default SearchBar -------------------------------------------------------------------------------- /src/Pages/WhisList/Wishlist.jsx: -------------------------------------------------------------------------------- 1 | import { Container } from '@mui/system' 2 | import axios from 'axios' 3 | import CartCard from '../../Components/Card/CartCard/CartCard' 4 | import React, { useContext, useEffect, useState } from 'react' 5 | import { toast } from 'react-toastify' 6 | import { ContextFunction } from '../../Context/Context' 7 | import { useNavigate } from 'react-router-dom' 8 | import { Box, Button, Dialog, DialogActions, DialogContent, Typography } from '@mui/material' 9 | import { AiFillCloseCircle, AiOutlineLogin } from 'react-icons/ai' 10 | import { EmptyCart } from '../../Assets/Images/Image'; 11 | import { Transition } from '../../Constants/Constant' 12 | import CopyRight from '../../Components/CopyRight/CopyRight' 13 | 14 | const Wishlist = () => { 15 | const { wishlistData, setWishlistData } = useContext(ContextFunction) 16 | const [openAlert, setOpenAlert] = useState(false); 17 | 18 | let authToken = localStorage.getItem('Authorization') 19 | let setProceed = authToken ? true : false 20 | let navigate = useNavigate() 21 | useEffect(() => { 22 | getWishList() 23 | }, []) 24 | const getWishList = async () => { 25 | if (setProceed) { 26 | const { data } = await axios.get(`${process.env.REACT_APP_GET_WISHLIST}`, 27 | { 28 | headers: { 29 | 'Authorization': authToken 30 | } 31 | }) 32 | setWishlistData(data) 33 | } 34 | else { 35 | setOpenAlert(true) 36 | } 37 | } 38 | const removeFromWishlist = async (product) => { 39 | if (setProceed) { 40 | try { 41 | const deleteProduct = await axios.delete(`${process.env.REACT_APP_DELETE_WISHLIST}/${product._id}`, { 42 | headers: { 43 | 'Authorization': authToken 44 | } 45 | }) 46 | setWishlistData(wishlistData.filter(c => c.productId._id !== product.productId._id)) 47 | toast.success("Removed From Wishlist", { autoClose: 500, theme: 'colored' }) 48 | } catch (error) { 49 | toast.error(error, { autoClose: 500, theme: 'colored' }) 50 | } 51 | } 52 | } 53 | const handleClose = () => { 54 | setOpenAlert(false); 55 | navigate('/') 56 | }; 57 | const handleToLogin = () => { 58 | navigate('/login') 59 | }; 60 | 61 | return ( 62 | <> 63 | Wishlist 64 | {setProceed && 65 | 66 | wishlistData.length <= 0 ? 67 | ( 68 |
69 | Empty_cart 70 | No products in wishlist 71 |
72 |
) 73 | : ( 74 | {wishlistData.map(product => ( 75 | 76 | ))} 77 | ) 78 | 79 | } 80 | 81 | 87 | 88 | Please Login To Proceed 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | ) 98 | } 99 | 100 | export default Wishlist -------------------------------------------------------------------------------- /src/Navigation/DesktopNavigation.jsx: -------------------------------------------------------------------------------- 1 | import './Desktop.css' 2 | import React, { useContext, useEffect, useState } from 'react' 3 | import { AiOutlineHeart, AiOutlineShoppingCart, AiFillCloseCircle } from 'react-icons/ai' 4 | import { CgProfile } from 'react-icons/cg' 5 | import { FiLogOut } from 'react-icons/fi' 6 | import { Link, NavLink, useNavigate } from 'react-router-dom'; 7 | import { Badge, Button, Dialog, DialogActions, DialogContent, Menu, MenuItem, Slide, Tooltip, Typography } from '@mui/material'; 8 | import { ContextFunction } from '../Context/Context'; 9 | import { toast } from 'react-toastify'; 10 | import { getCart, getWishList, handleLogOut, handleClickOpen, handleClose, Transition } from '../Constants/Constant' 11 | 12 | const DesktopNavigation = () => { 13 | 14 | const { cart, setCart, wishlistData, setWishlistData } = useContext(ContextFunction) 15 | const [openAlert, setOpenAlert] = useState(false); 16 | const navigate = useNavigate() 17 | let authToken = localStorage.getItem('Authorization'); 18 | let setProceed = authToken !== null ? true : false 19 | useEffect(() => { 20 | getCart(setProceed, setCart, authToken) 21 | getWishList(setProceed, setWishlistData, authToken) 22 | }, []) 23 | 24 | 25 | return ( 26 | <> 27 | 89 | 96 | 97 | Do You Want To Logout? 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | ) 108 | } 109 | 110 | export default DesktopNavigation -------------------------------------------------------------------------------- /src/Navigation/MobileNavigation.jsx: -------------------------------------------------------------------------------- 1 | import './Mobile.css' 2 | import Box from '@mui/material/Box'; 3 | import BottomNavigation from '@mui/material/BottomNavigation'; 4 | import { AiOutlineHome, AiOutlineHeart, AiOutlineShoppingCart, AiFillMail, AiFillCloseCircle } from 'react-icons/ai' 5 | import { CgProfile } from 'react-icons/cg' 6 | import { FiLogOut } from 'react-icons/fi' 7 | import React, { useContext, useEffect, useState } from 'react' 8 | import { NavLink, useNavigate } from 'react-router-dom'; 9 | import { Badge, Button, Dialog, DialogActions, DialogContent, Slide, Typography } from '@mui/material'; 10 | import { ContextFunction } from '../Context/Context'; 11 | import { toast } from 'react-toastify'; 12 | import { Transition, getCart, getWishList, handleClickOpen, handleClose, handleLogOut } from '../Constants/Constant'; 13 | 14 | 15 | const MobileNavigation = () => { 16 | const { cart, setCart, wishlistData, setWishlistData } = useContext(ContextFunction) 17 | 18 | const [openAlert, setOpenAlert] = useState(false); 19 | 20 | const navigate = useNavigate() 21 | 22 | let authToken = localStorage.getItem('Authorization') 23 | let setProceed = authToken !== null ? true : false 24 | 25 | useEffect(() => { 26 | getCart(setProceed, setCart, authToken) 27 | getWishList(setProceed, setWishlistData, authToken) 28 | }, []) 29 | 30 | return ( 31 | 32 | 33 | 34 |
35 | 36 |
37 |
38 | 39 |
40 | 41 | 42 | 43 |
44 |
45 | 46 |
47 | 48 | 49 | 50 |
51 |
52 | 53 | 54 | { 55 | setProceed ? 56 | <> 57 | 58 |
59 | 60 | 61 |
62 |
63 |
handleClickOpen(setOpenAlert)}> 64 | 65 | 66 |
67 | 68 | : 69 |
70 | 71 | {/* Login */} 72 |
73 |
74 | } 75 | 76 |
77 | handleClose(setOpenAlert)} 82 | aria-describedby="alert-dialog-slide-description" 83 | > 84 | 85 | Do You Want To Logout? 86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 | ); 94 | } 95 | 96 | 97 | export default MobileNavigation -------------------------------------------------------------------------------- /src/SingleCategory/SingleCategory.jsx: -------------------------------------------------------------------------------- 1 | import './singlecategory.css' 2 | import React, { useState, useEffect } from 'react' 3 | import { Link, useParams } from 'react-router-dom' 4 | import axios from 'axios' 5 | import { Container } from '@mui/system' 6 | import { Box, Button, MenuItem, FormControl, Select } from '@mui/material' 7 | import Loading from '../Components/loading/Loading' 8 | import { BiFilterAlt } from 'react-icons/bi'; 9 | import ProductCard from '../Components/Card/Product Card/ProductCard' 10 | import CopyRight from '../Components/CopyRight/CopyRight' 11 | 12 | 13 | 14 | const SingleCategory = () => { 15 | 16 | const [productData, setProductData] = useState([]) 17 | const [isLoading, setIsLoading] = useState(false) 18 | const [filterOption, setFilterOption] = useState('All') 19 | const [title, setTitle] = useState('All') 20 | const { cat } = useParams() 21 | 22 | useEffect(() => { 23 | getCategoryProduct() 24 | window.scroll(0, 0) 25 | }, []) 26 | 27 | const getCategoryProduct = async () => { 28 | try { 29 | setIsLoading(true) 30 | const { data } = await axios.post(`${process.env.REACT_APP_PRODUCT_TYPE}`, { userType: cat }) 31 | setIsLoading(false) 32 | setProductData(data) 33 | 34 | } catch (error) { 35 | console.log(error); 36 | } 37 | } 38 | 39 | const productFilter = [] 40 | 41 | if (cat === 'book') { 42 | productFilter.push('All', 'Scifi', 'Business', 'Mystery', 'Cookbooks', 'Accessories', 'Price Low To High', 'Price High To Low', 'High Rated', 'Low Rated') 43 | } 44 | else if (cat === 'cloths') { 45 | productFilter.push('All', 'Men', 'Women', 'Price Low To High', 'Price High To Low', 'High Rated', 'Low Rated') 46 | } 47 | else if (cat === 'shoe') { 48 | productFilter.push('All', 'Running', 'Football', 'Formal', 'Casual', 'Price Low To High', 'Price High To Low', 'High Rated', 'Low Rated') 49 | } 50 | else if (cat === 'electronics') { 51 | productFilter.push('All', 'Monitor', 'SSD', 'HDD', 'Price Low To High', 'Price High To Low', 'High Rated', 'Low Rated') 52 | 53 | } 54 | else if (cat === 'jewelry') { 55 | productFilter.push('All') 56 | 57 | } 58 | 59 | const handleChange = (e) => { 60 | setFilterOption(e.target.value.split(" ").join("").toLowerCase()) 61 | setTitle(e.target.value) 62 | } 63 | // pricelowtohigh 64 | // pricehightolow 65 | // highrated 66 | // lowrated 67 | 68 | const getData = async () => { 69 | setIsLoading(true) 70 | const filter = filterOption.toLowerCase() 71 | const { data } = await axios.post(`${process.env.REACT_APP_PRODUCT_TYPE_CATEGORY_}`, { userType: cat, userCategory: filter }) 72 | setProductData(data) 73 | setIsLoading(false) 74 | } 75 | useEffect(() => { 76 | getData() 77 | }, [filterOption]) 78 | 79 | const loading = isLoading ? 80 | ( 81 | 82 | 83 | 84 | 85 | ) 86 | : "" 87 | return ( 88 | <> 89 | 90 | < Box sx={{ minWidth: 140 }}> 91 | 92 | 93 | 94 | 105 | 106 | 107 | 108 | {loading} 109 | 110 | {productData.map(prod => ( 111 | 112 | 113 | 114 | 115 | ))} 116 | 117 | 118 | 119 | 120 | ) 121 | } 122 | 123 | 124 | export default SingleCategory 125 | 126 | // -------------------------------------------------------------------------------- /src/Admin/Components/UserData/UserInfoItem.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { Box, Button, Container, Dialog, DialogActions, DialogContent, DialogContentText, Grid, TextField, Typography } from '@mui/material' 3 | import axios from 'axios'; 4 | import { toast } from 'react-toastify'; 5 | import { AiFillCloseCircle, AiFillDelete } from 'react-icons/ai'; 6 | import { useNavigate } from 'react-router-dom'; 7 | import { Transition } from '../../../Constants/Constant'; 8 | 9 | const UserInfoItem = ({ commonGetRequest, id, authToken }) => { 10 | const [userData, setUserData] = useState([]); 11 | const [openAlert, setOpenAlert] = useState(false); 12 | 13 | let navigate = useNavigate() 14 | useEffect(() => { 15 | commonGetRequest(process.env.REACT_APP_ADMIN_GET_USER, id, setUserData); 16 | window.scroll(0, 0) 17 | 18 | }, []) 19 | 20 | const deleteAccount = async () => { 21 | try { 22 | const deleteUser = await axios.delete(`${process.env.REACT_APP_DELETE_USER_DETAILS}/${userData._id}`, { 23 | headers: { 24 | 'Authorization': authToken 25 | } 26 | }); 27 | toast.success("Account deleted successfully", { autoClose: 500, theme: 'colored' }) 28 | navigate(-1); 29 | 30 | } catch (error) { 31 | toast.error(error.response.data, { autoClose: 500, theme: 'colored' }) 32 | 33 | } 34 | } 35 | 36 | 37 | return ( 38 | 39 | User Details 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | Delete {userData.firstName} {userData.lastName}'s Account? 69 | 70 | 71 | 72 | 73 | 74 | setOpenAlert(false)} 79 | aria-describedby="alert-dialog-slide-description" 80 | > 81 | {/* {"Use Google's location service?"} */} 82 | 83 | 84 | {userData.firstName} {userData.lastName}'s all data will be erased 85 | 86 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 95 | ) 96 | } 97 | 98 | export default UserInfoItem -------------------------------------------------------------------------------- /src/Admin/Components/AdminTabs.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { Tab, Tabs, Typography, Box, useMediaQuery, Grid } from '@mui/material'; 4 | import ProductChart from './Charts/ProductChart'; 5 | import UserTable from './Tables/UserTable'; 6 | import axios from 'axios'; 7 | import ProductTable from './Tables/ProductTable'; 8 | import { VscGraph } from 'react-icons/vsc' 9 | import { CgProfile } from 'react-icons/cg' 10 | import { AiOutlineShoppingCart } from 'react-icons/ai' 11 | import { FaShippingFast } from 'react-icons/fa' 12 | import { TbReportMoney } from 'react-icons/tb' 13 | import OrderTable from './Tables/OrderTable'; 14 | import Widget from './Widget'; 15 | 16 | 17 | function TabPanel(props) { 18 | const { children, value, index, ...other } = props; 19 | 20 | return ( 21 | 36 | ); 37 | } 38 | 39 | TabPanel.propTypes = { 40 | children: PropTypes.node, 41 | index: PropTypes.number.isRequired, 42 | value: PropTypes.number.isRequired, 43 | }; 44 | 45 | function a11yProps(index) { 46 | return { 47 | id: `simple-tab-${index}`, 48 | 'aria-controls': `simple-tabpanel-${index}`, 49 | }; 50 | } 51 | 52 | export default function BasicTabs({ user, setUser, getUser }) { 53 | const [value, setValue] = useState(0); 54 | const [products, setProducts] = useState([]); 55 | const [review, setReview] = useState([]); 56 | const [cart, setCart] = useState([]); 57 | const [wishlist, setWishlist] = useState([]); 58 | const [paymentData, setPaymentData] = useState([]); 59 | 60 | useEffect(() => { 61 | getProductInfo(); 62 | }, []) 63 | const getProductInfo = async () => { 64 | try { 65 | const { data } = await axios.get(process.env.REACT_APP_ADMIN_GET_CHART_DATA) 66 | setProducts(data.product); 67 | setReview(data.review); 68 | setCart(data.cart); 69 | setWishlist(data.wishlist); 70 | setPaymentData(data.payment); 71 | } catch (error) { 72 | console.log(error); 73 | 74 | } 75 | } 76 | 77 | 78 | const handleChange = (event, newValue) => { 79 | setValue(newValue); 80 | }; 81 | 82 | const totalRevenue = paymentData.reduce((acc, curr) => (acc + curr.totalAmount), 0); 83 | const isSmallScreen = useMediaQuery('(max-width:600px)'); 84 | 85 | return ( 86 | 87 | 88 | 89 | } /> 90 | 91 | 92 | } /> 93 | 94 | 95 | } /> 96 | 97 | 98 | } /> 99 | 100 | 101 | 102 | 103 | } /> 104 | } /> 105 | } /> 106 | } /> 107 | 108 | 109 | 110 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | ); 129 | } -------------------------------------------------------------------------------- /src/serviceWorkerRegistration.js: -------------------------------------------------------------------------------- 1 | // This optional code is used to register a service worker. 2 | // register() is not called by default. 3 | 4 | // This lets the app load faster on subsequent visits in production, and gives 5 | // it offline capabilities. However, it also means that developers (and users) 6 | // will only see deployed updates on subsequent visits to a page, after all the 7 | // existing tabs open on the page have been closed, since previously cached 8 | // resources are updated in the background. 9 | 10 | // To learn more about the benefits of this model and instructions on how to 11 | // opt-in, read https://cra.link/PWA 12 | 13 | const isLocalhost = Boolean( 14 | window.location.hostname === 'localhost' || 15 | // [::1] is the IPv6 localhost address. 16 | window.location.hostname === '[::1]' || 17 | // 127.0.0.0/8 are considered localhost for IPv4. 18 | window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) 19 | ); 20 | 21 | export function register(config) { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Let's check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl, config); 38 | 39 | // Add some additional logging to localhost, pointing developers to the 40 | // service worker/PWA documentation. 41 | navigator.serviceWorker.ready.then(() => { 42 | console.log( 43 | 'This web app is being served cache-first by a service ' + 44 | 'worker. To learn more, visit https://cra.link/PWA' 45 | ); 46 | }); 47 | } else { 48 | // Is not localhost. Just register service worker 49 | registerValidSW(swUrl, config); 50 | } 51 | }); 52 | } 53 | } 54 | 55 | function registerValidSW(swUrl, config) { 56 | navigator.serviceWorker 57 | .register(swUrl) 58 | .then((registration) => { 59 | registration.onupdatefound = () => { 60 | const installingWorker = registration.installing; 61 | if (installingWorker == null) { 62 | return; 63 | } 64 | installingWorker.onstatechange = () => { 65 | if (installingWorker.state === 'installed') { 66 | if (navigator.serviceWorker.controller) { 67 | // At this point, the updated precached content has been fetched, 68 | // but the previous service worker will still serve the older 69 | // content until all client tabs are closed. 70 | console.log( 71 | 'New content is available and will be used when all ' + 72 | 'tabs for this page are closed. See https://cra.link/PWA.' 73 | ); 74 | 75 | // Execute callback 76 | if (config && config.onUpdate) { 77 | config.onUpdate(registration); 78 | } 79 | } else { 80 | // At this point, everything has been precached. 81 | // It's the perfect time to display a 82 | // "Content is cached for offline use." message. 83 | console.log('Content is cached for offline use.'); 84 | 85 | // Execute callback 86 | if (config && config.onSuccess) { 87 | config.onSuccess(registration); 88 | } 89 | } 90 | } 91 | }; 92 | }; 93 | }) 94 | .catch((error) => { 95 | console.error('Error during service worker registration:', error); 96 | }); 97 | } 98 | 99 | function checkValidServiceWorker(swUrl, config) { 100 | // Check if the service worker can be found. If it can't reload the page. 101 | fetch(swUrl, { 102 | headers: { 'Service-Worker': 'script' }, 103 | }) 104 | .then((response) => { 105 | // Ensure service worker exists, and that we really are getting a JS file. 106 | const contentType = response.headers.get('content-type'); 107 | if ( 108 | response.status === 404 || 109 | (contentType != null && contentType.indexOf('javascript') === -1) 110 | ) { 111 | // No service worker found. Probably a different app. Reload the page. 112 | navigator.serviceWorker.ready.then((registration) => { 113 | registration.unregister().then(() => { 114 | window.location.reload(); 115 | }); 116 | }); 117 | } else { 118 | // Service worker found. Proceed as normal. 119 | registerValidSW(swUrl, config); 120 | } 121 | }) 122 | .catch(() => { 123 | console.log('No internet connection found. App is running in offline mode.'); 124 | }); 125 | } 126 | 127 | export function unregister() { 128 | if ('serviceWorker' in navigator) { 129 | navigator.serviceWorker.ready 130 | .then((registration) => { 131 | registration.unregister(); 132 | }) 133 | .catch((error) => { 134 | console.error(error.message); 135 | }); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Auth/Login/Login.jsx: -------------------------------------------------------------------------------- 1 | import './login.css' 2 | import { Avatar, Button, Checkbox, CssBaseline, FormControlLabel, Grid, InputAdornment, TextField, Typography } from '@mui/material' 3 | import { Box, Container } from '@mui/system' 4 | import React, { useEffect } from 'react' 5 | import { useState } from 'react' 6 | import axios from 'axios' 7 | import { Link, useNavigate } from 'react-router-dom' 8 | import { toast } from 'react-toastify' 9 | import { MdLockOutline } from 'react-icons/md' 10 | import { RiEyeFill, RiEyeOffFill } from 'react-icons/ri'; 11 | 12 | import CopyRight from '../../Components/CopyRight/CopyRight' 13 | 14 | 15 | 16 | const Login = () => { 17 | const [credentials, setCredentials] = useState({ email: "", password: "" }) 18 | const [showPassword, setShowPassword] = useState(false); 19 | const handleClickShowPassword = () => { 20 | setShowPassword(!showPassword); 21 | }; 22 | const navigate = useNavigate() 23 | 24 | const handleOnChange = (e) => { 25 | setCredentials({ ...credentials, [e.target.name]: e.target.value }) 26 | } 27 | useEffect(() => { 28 | let auth = localStorage.getItem('Authorization'); 29 | if (auth) { 30 | navigate("/") 31 | } 32 | }, []) 33 | const handleSubmit = async (e) => { 34 | e.preventDefault() 35 | let emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 36 | try { 37 | if (!credentials.email && !credentials.password) { 38 | toast.error("All fields are required", { autoClose: 500, theme: 'colored' }) 39 | } 40 | else if (!emailRegex.test(credentials.email)) { 41 | toast.error("Please enter a valid email", { autoClose: 500, theme: 'colored' }) 42 | } 43 | else if (credentials.password.length < 5) { 44 | toast.error("Please enter valid password", { autoClose: 500, theme: 'colored' }) 45 | } 46 | else if (credentials.email && credentials.password) { 47 | const sendAuth = await axios.post(`${process.env.REACT_APP_LOGIN}`, { email: credentials.email, password: credentials.password }) 48 | const receive = await sendAuth.data 49 | if (receive.success === true) { 50 | toast.success("Login Successfully", { autoClose: 500, theme: 'colored' }) 51 | localStorage.setItem('Authorization', receive.authToken) 52 | navigate('/') 53 | } 54 | else{ 55 | toast.error("Something went wrong, Please try again", { autoClose: 500, theme: 'colored' }) 56 | navigate('/') 57 | } 58 | } 59 | } 60 | catch (error) { 61 | error.response.data.error.length === 1 ? 62 | toast.error(error.response.data.error[0].msg, { autoClose: 500, theme: 'colored' }) 63 | : toast.error(error.response.data.error, { autoClose: 500, theme: 'colored' }) 64 | } 65 | 66 | } 67 | 68 | 69 | return ( 70 | 71 | 72 | 80 | 81 | 82 | 83 | 84 | Sign in 85 | 86 | 87 | 99 | 112 | {showPassword ? : } 113 | 114 | ) 115 | }} 116 | autoComplete="current-password" 117 | 118 | /> 119 | } 121 | label="Remember me" 122 | /> 123 | 131 | 132 | 133 | 134 | Forgot password? 135 | 136 | 137 | 138 | 139 | Don't have an account? Sign Up 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | ) 148 | } 149 | 150 | export default Login -------------------------------------------------------------------------------- /src/Admin/Auth/Login/AdminLogin.jsx: -------------------------------------------------------------------------------- 1 | import './login.css' 2 | import { Avatar, Button, Checkbox, CssBaseline, FormControlLabel, Grid, InputAdornment, TextField, Typography } from '@mui/material' 3 | import { Box, Container } from '@mui/system' 4 | import React, { useEffect } from 'react' 5 | import { useState } from 'react' 6 | import axios from 'axios' 7 | import { Link, useNavigate } from 'react-router-dom' 8 | import { toast } from 'react-toastify' 9 | import { MdLockOutline } from 'react-icons/md' 10 | import { RiEyeFill, RiEyeOffFill } from 'react-icons/ri'; 11 | import CopyRight from '../../../Components/CopyRight/CopyRight' 12 | 13 | const AdminLogin = () => { 14 | 15 | const [credentials, setCredentials] = useState({ email: "", password: "", key: "" }) 16 | const [showPassword, setShowPassword] = useState(false); 17 | const handleClickShowPassword = () => { 18 | setShowPassword(!showPassword); 19 | }; 20 | 21 | const navigate = useNavigate() 22 | const handleOnChange = (e) => { 23 | setCredentials({ ...credentials, [e.target.name]: e.target.value }) 24 | } 25 | useEffect(() => { 26 | let auth = localStorage.getItem('Authorization'); 27 | if (auth) { 28 | navigate("/") 29 | } 30 | }, []) 31 | const handleSubmit = async (e) => { 32 | e.preventDefault() 33 | let emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 34 | try { 35 | if (!credentials.email && !credentials.password) { 36 | toast.error("All fields are required", { autoClose: 500, theme: 'colored' }) 37 | } 38 | else if (!emailRegex.test(credentials.email)) { 39 | toast.error("Please enter a valid email", { autoClose: 500, theme: 'colored' }) 40 | } 41 | else if (credentials.password.length < 5) { 42 | toast.error("Please enter valid password", { autoClose: 500, theme: 'colored' }) 43 | } 44 | else if (credentials.email && credentials.password) { 45 | const sendAuth = await axios.post(process.env.REACT_APP_ADMIN_LOGIN, 46 | { 47 | email: credentials.email, 48 | password: credentials.password, 49 | key: credentials.key 50 | }) 51 | const receive = await sendAuth.data 52 | if (receive.success === true) { 53 | toast.success("Login Successfully", { autoClose: 500, theme: 'colored' }) 54 | localStorage.setItem('Authorization', receive.authToken) 55 | navigate('/admin/home') 56 | } else { 57 | toast.error("Invalid Credentials", { autoClose: 500, theme: 'colored' }) 58 | } 59 | } 60 | } 61 | catch (error) { 62 | toast.error("Invalid Credentials", { autoClose: 500, theme: 'colored' }) 63 | } 64 | 65 | } 66 | 67 | 68 | return ( 69 | 70 | 71 | 79 | 80 | 81 | 82 | 83 | Sign in 84 | 85 | 86 | 97 | 110 | {showPassword ? : } 111 | 112 | ) 113 | }} 114 | 115 | /> 116 | 126 | } 128 | label="Remember me" 129 | /> 130 | 138 | 139 | 140 | 141 | Forgot password? 142 | 143 | 144 | 145 | 146 | Don't have an account? Sign Up 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | ) 155 | } 156 | 157 | export default AdminLogin -------------------------------------------------------------------------------- /src/Admin/Components/Tables/UserTable.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import { 3 | Table, 4 | TableBody, 5 | TableCell, 6 | TableContainer, 7 | TableHead, 8 | TableRow, 9 | Paper, 10 | Container, 11 | InputAdornment, 12 | TextField, 13 | 14 | } 15 | from '@mui/material' 16 | import { Link } from 'react-router-dom'; 17 | import { AiOutlineSearch } from 'react-icons/ai'; 18 | import AddUser from '../AddUser'; 19 | const UserTable = ({ user, getUser }) => { 20 | const columns = [ 21 | { 22 | id: 'name', 23 | label: 'Name', 24 | minWidth: 100, 25 | align: 'center', 26 | }, 27 | { 28 | id: 'phone', 29 | label: 'Phone Number', 30 | align: 'center', 31 | minWidth: 100 32 | }, 33 | { 34 | id: 'email', 35 | label: 'Email', 36 | minWidth: 70, 37 | align: 'center', 38 | 39 | }, 40 | { 41 | id: 'date', 42 | label: 'Created On', 43 | minWidth: 100, 44 | align: 'center', 45 | 46 | }, 47 | ]; 48 | 49 | const [searchQuery, setSearchQuery] = useState(""); 50 | const handleSearchInputChange = (event) => { 51 | setSearchQuery(event.target.value); 52 | }; 53 | const sortedUser = user.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); 54 | 55 | const filteredUsers = sortedUser.filter((user) => { 56 | const firstName = user.firstName.toLowerCase(); 57 | const lastName = user.lastName.toLowerCase(); 58 | const fullName = user.firstName.toLowerCase() + user.lastName.toLowerCase(); 59 | const phoneNumber = user.phoneNumber.toString(); 60 | const email = user.email.toLowerCase(); 61 | const queries = searchQuery.toLowerCase().split(" "); 62 | 63 | return queries.every((query) => firstName.includes(query) || lastName.includes(query) || fullName.includes(query) || phoneNumber.includes(query) || email.includes(query)); 64 | }); 65 | 66 | return ( 67 | <> 68 | 69 | 70 | 80 | 81 | 82 | ), 83 | }} 84 | /> 85 | 86 | 87 | 89 | 90 | 91 | 92 | 93 | {columns.map((column) => ( 94 | 99 | {column.label} 100 | 101 | ))} 102 | 103 | 104 | 105 | 106 | {filteredUsers.length === 0 ? ( 107 | 108 | 109 |
110 |

User not found.

111 |
112 |
113 |
114 | ) : (filteredUsers.map((info) => ( 115 | 119 | 120 | 121 | {info.firstName + " " + info.lastName} 122 | 123 | 124 | 125 | 126 | {info.phoneNumber} 127 | 128 | 129 | 130 | 131 | {info.email} 132 | 133 | 134 | 135 | 136 | { 137 | new Date(info.createdAt).toLocaleDateString('en-us', { 138 | weekday: "long", year: "numeric", month: "short", day: "numeric" 139 | } 140 | ) 141 | } 142 | {" "} 143 | {new Date(info.createdAt).toLocaleTimeString('en-US')} 144 | 145 | 146 | 147 | )) 148 | ) 149 | } 150 |
151 |
152 |
153 |
154 | 155 | 156 | ) 157 | } 158 | 159 | export default UserTable -------------------------------------------------------------------------------- /src/Pages/Cart/Cart.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from 'react' 2 | import { ContextFunction } from '../../Context/Context'; 3 | import { 4 | Button, 5 | Typography, 6 | Dialog, 7 | DialogActions, 8 | DialogContent, 9 | Container, 10 | CssBaseline, 11 | Box, 12 | } from '@mui/material' 13 | import axios from 'axios' 14 | import { Link, useNavigate } from 'react-router-dom' 15 | import { toast } from 'react-toastify' 16 | import { AiFillCloseCircle, AiOutlineLogin } from 'react-icons/ai' 17 | import CartCard from '../../Components/Card/CartCard/CartCard'; 18 | import ProductCard from '../../Components/Card/Product Card/ProductCard'; 19 | import './Cart.css' 20 | import OrderSummary from './OrderSummary'; 21 | import { EmptyCart } from '../../Assets/Images/Image'; 22 | import { Transition } from '../../Constants/Constant'; 23 | import CopyRight from '../../Components/CopyRight/CopyRight'; 24 | 25 | 26 | 27 | const Cart = () => { 28 | const { cart, setCart } = useContext(ContextFunction) 29 | const [total, setTotal] = useState(0) 30 | const [openAlert, setOpenAlert] = useState(false); 31 | const [previousOrder, setPreviousOrder] = useState([]); 32 | let shippingCoast = 100 33 | 34 | 35 | const navigate = useNavigate() 36 | let authToken = localStorage.getItem('Authorization') 37 | let setProceed = authToken ? true : false 38 | 39 | 40 | useEffect(() => { 41 | if (setProceed) { 42 | getCart() 43 | getPreviousOrder() 44 | } 45 | else { 46 | setOpenAlert(true) 47 | } 48 | window.scroll(0, 0) 49 | 50 | }, []) 51 | 52 | useEffect(() => { 53 | if (setProceed) { 54 | setTotal(cart.reduce((acc, curr) => (acc + ((curr.productId?.price * curr.quantity) + shippingCoast)), 0)) 55 | } 56 | 57 | }, [cart]) 58 | 59 | const getCart = async () => { 60 | if (setProceed) { 61 | const { data } = await axios.get(`${process.env.REACT_APP_GET_CART}`, 62 | { 63 | headers: { 64 | 'Authorization': authToken 65 | } 66 | }) 67 | setCart(data); 68 | } 69 | 70 | } 71 | const handleClose = () => { 72 | setOpenAlert(false); 73 | navigate('/') 74 | }; 75 | const handleToLogin = () => { 76 | navigate('/login') 77 | }; 78 | const getPreviousOrder = async () => { 79 | const { data } = await axios.get(`${process.env.REACT_APP_GET_PREVIOUS_ORDER}`, 80 | { 81 | headers: { 82 | 'Authorization': authToken 83 | } 84 | }) 85 | setPreviousOrder(data) 86 | } 87 | 88 | const removeFromCart = async (product) => { 89 | if (setProceed) { 90 | try { 91 | const response = await axios.delete(`${process.env.REACT_APP_DELETE_CART}/${product._id}`, { 92 | headers: { 93 | 'Authorization': authToken 94 | } 95 | }) 96 | toast.success("Removed From Cart", { autoClose: 500, theme: 'colored' }) 97 | setCart(cart.filter(c => c.productId._id !== product.productId._id)) 98 | } catch (error) { 99 | toast.error("Something went wrong", { autoClose: 500, theme: 'colored' }) 100 | 101 | } 102 | } 103 | } 104 | const proceedToCheckout = async () => { 105 | if (cart.length <= 0) { 106 | toast.error("Please add items in cart to proceed", { autoClose: 500, theme: 'colored' }) 107 | } 108 | else { 109 | sessionStorage.setItem('totalAmount', total) 110 | navigate('/checkout') 111 | } 112 | } 113 | 114 | return ( 115 | <> 116 | 117 | 118 | 119 | Cart 120 | { 121 | setProceed && 122 | cart.length <= 0 && 123 | 124 |
125 | Empty_cart 126 | Your Cart is Empty 127 |
128 |
129 | 130 | } 131 | 132 | 133 | { 134 | cart.length > 0 && 135 | cart.map(product => 136 | 137 | 138 | )} 139 | 140 | 141 | { 142 | cart.length > 0 && 143 | 144 | 145 | 146 | } 147 | 148 | 149 |
150 | {setProceed && previousOrder.length > 0 && Previous Orders} 151 | 152 | { 153 | previousOrder.map(product => ( 154 | product.productData.map(prod => 155 | 156 | 157 | ) 158 | ) 159 | )} 160 | 161 | 168 | 169 | Please Login To Proceed 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | ) 179 | } 180 | 181 | export default Cart -------------------------------------------------------------------------------- /src/Components/Review/ProductReview.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import axios from 'axios'; 3 | import Rating from '@mui/material/Rating'; 4 | import { 5 | MdSentimentSatisfiedAlt, 6 | MdSentimentDissatisfied, 7 | MdSentimentVeryDissatisfied, 8 | MdSentimentNeutral, 9 | MdSentimentVerySatisfied, 10 | MdStarRate, 11 | MdOutlineSentimentVeryDissatisfied, 12 | MdSend, 13 | MdOutlineFilterAlt 14 | } from 'react-icons/md' 15 | import Box from '@mui/material/Box'; 16 | import { Button, MenuItem, Select, TextField, Tooltip, Typography } from '@mui/material'; 17 | import { toast } from 'react-toastify'; 18 | import './Review.css' 19 | import CommentCard from '../Card/Comment Card/CommentCard'; 20 | import { customerReview } from '../../Assets/Images/Image'; 21 | 22 | 23 | 24 | const labels = { 25 | 0: , 26 | 0.5: , 27 | 1: , 28 | 1.5: , 29 | 2: , 30 | 2.5: , 31 | 3: , 32 | 3.5: , 33 | 4: , 34 | 4.5: , 35 | 5: , 36 | }; 37 | 38 | 39 | function getLabelText(value) { 40 | return `${value} Star${value !== 1 ? 's' : ''}, ${labels[value]}`; 41 | } 42 | const ProductReview = ({ authToken, setProceed, setOpenAlert, id }) => { 43 | const [value, setValue] = useState(0); 44 | const [hover, setHover] = useState(''); 45 | const [reviews, setReviews] = useState([]) 46 | const [comment, setComment] = useState('') 47 | const [filterOption, setFilterOption] = useState('All') 48 | const [title, setTitle] = useState('All') 49 | 50 | const commentFilter = ["All", "Most Recent", "Old", "Positive First", "Negative First"] 51 | const handleChange = (e) => { 52 | setFilterOption(e.target.value.split(" ").join("").toLowerCase()) 53 | setTitle(e.target.value) 54 | fetchReviews() 55 | } 56 | const fetchReviews = async () => { 57 | const filter = filterOption.toLowerCase() 58 | const { data } = await axios.post(`${process.env.REACT_APP_GET_REVIEW}/${id}`, { filterType: filter }) 59 | setReviews(data) 60 | } 61 | useEffect(() => { 62 | fetchReviews() 63 | }, [title, id]) 64 | 65 | const handleSubmitReview = async (e) => { 66 | e.preventDefault() 67 | if (!comment && !value) { 68 | toast.error("Please Fill the all Fields", { theme: "colored", autoClose: 500, }) 69 | } 70 | else if (comment.length <= 4) { 71 | toast.error("Please add more than 4 characters", { theme: "colored", autoClose: 500, }) 72 | } 73 | else if (value <= 0) { 74 | toast.error("Please add rating", { theme: "colored", autoClose: 500, }) 75 | } 76 | else if (comment.length >= 4 && value > 0) { 77 | try { 78 | if (setProceed) { 79 | const { data } = await axios.post(`${process.env.REACT_APP_ADD_REVIEW}`, { id: id, comment: comment, rating: value }, { 80 | headers: { 81 | 'Authorization': authToken 82 | } 83 | }) 84 | toast.success(data.msg, { theme: "colored", autoClose: 500, }) 85 | fetchReviews() 86 | } 87 | else { 88 | setOpenAlert(true) 89 | } 90 | setComment('') 91 | setValue(null) 92 | } 93 | catch (error) { 94 | toast.error(error.response.data.msg, { theme: "colored", autoClose: 600, }) 95 | setComment('') 96 | setValue('') 97 | } 98 | } 99 | } 100 | return ( 101 | <> 102 |
103 |
104 | 112 | { 119 | setValue(newValue); 120 | }} 121 | onChangeActive={(event, newHover) => { 122 | setHover(newHover); 123 | }} 124 | emptyIcon={} 125 | /> 126 | {value !== null && ( 127 | {labels[hover !== -1 ? hover : value]} 128 | )} 129 | 130 | { 133 | setComment(e.target.value) 134 | }} 135 | label="Add Review" 136 | placeholder="What did you like or dislike?" 137 | multiline 138 | className='comment' 139 | variant="outlined" 140 | /> 141 | 142 | 143 | 144 | 145 | 146 | 147 |
148 | Customer Review 149 |
150 |
151 | {reviews.length >= 1 ? 152 | 153 | 164 | 165 | 166 | : 167 | No reviews have been submitted for this product yet. Be the first to add a review! 168 | } 169 | 170 | { 171 | reviews.map(review => 172 | 173 | ) 174 | } 175 | 176 | 177 | 178 | ) 179 | } 180 | 181 | export default ProductReview 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /src/Auth/Register/Register.jsx: -------------------------------------------------------------------------------- 1 | import '../Login/login.css' 2 | import React, { useEffect, useState } from 'react' 3 | import axios from 'axios' 4 | import { Link, useNavigate } from 'react-router-dom' 5 | import { Avatar, Button, Checkbox, CssBaseline, FormControlLabel, Grid, InputAdornment, TextField, Typography } from '@mui/material' 6 | import { MdLockOutline } from 'react-icons/md' 7 | import { Box, Container } from '@mui/system' 8 | import { toast } from 'react-toastify' 9 | import CopyRight from '../../Components/CopyRight/CopyRight' 10 | import { RiEyeFill, RiEyeOffFill } from 'react-icons/ri'; 11 | 12 | 13 | 14 | const Register = () => { 15 | 16 | const [credentials, setCredentials] = useState({ firstName: "", lastName: '', email: "", phoneNumber: '', password: "" }) 17 | const [showPassword, setShowPassword] = useState(false); 18 | const handleClickShowPassword = () => { 19 | setShowPassword(!showPassword); 20 | }; 21 | const navigate = useNavigate() 22 | const handleOnChange = (e) => { 23 | setCredentials({ ...credentials, [e.target.name]: e.target.value }) 24 | } 25 | useEffect(() => { 26 | let auth = localStorage.getItem('Authorization'); 27 | if (auth) { 28 | navigate("/") 29 | } 30 | }, []) 31 | const handleSubmit = async (e) => { 32 | e.preventDefault() 33 | let phoneRegex = /^(?:(?:\+|0{0,2})91(\s*[\-]\s*)?|[0]?)?[789]\d{9}$/gm; 34 | let emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 35 | try { 36 | if (!credentials.email && !credentials.firstName && !credentials.password && !credentials.phoneNumber && !credentials.lastName) { 37 | toast.error("All fields are required", { autoClose: 500, theme: 'colored' }) 38 | } 39 | else if (credentials.firstName.length < 1 || credentials.lastName.length < 1) { 40 | toast.error("Please enter valid name", { autoClose: 500, theme: 'colored' }) 41 | } 42 | else if (emailRegex.test(credentials.email)===false) { 43 | toast.error("Please enter valid email", { autoClose: 500, theme: 'colored' }) 44 | } 45 | else if (phoneRegex.test(credentials.phoneNumber)===false) { 46 | toast.error("Please enter a valid phone number", { autoClose: 500, theme: 'colored' }) 47 | console.log(1); 48 | } 49 | else if (credentials.password.length < 5) { 50 | toast.error("Please enter password with more than 5 characters", { autoClose: 500, theme: 'colored' }) 51 | } 52 | else if (credentials.email && credentials.firstName && credentials.lastName && credentials.phoneNumber && credentials.password) { 53 | const sendAuth = await axios.post(`${process.env.REACT_APP_REGISTER}`, 54 | { 55 | firstName: credentials.firstName, 56 | lastName: credentials.lastName, 57 | email: credentials.email, 58 | phoneNumber: credentials.phoneNumber, 59 | password: credentials.password, 60 | }) 61 | const receive = await sendAuth.data 62 | if (receive.success === true) { 63 | toast.success("Registered Successfully", { autoClose: 500, theme: 'colored' }) 64 | localStorage.setItem('Authorization', receive.authToken) 65 | navigate('/') 66 | console.log(receive); 67 | } 68 | else { 69 | toast.error("Something went wrong, Please try again", { autoClose: 500, theme: 'colored' }) 70 | navigate('/') 71 | } 72 | } 73 | } catch (error) { 74 | toast.error(error.response.data.error[0].msg, { autoClose: 500, theme: 'colored' }) 75 | 76 | } 77 | 78 | } 79 | 80 | 81 | return ( 82 | <> 83 | 84 | 85 | 93 | 94 | 95 | 96 | 97 | Sign up 98 | 99 | 100 | 101 | 102 | 113 | 114 | 115 | 125 | 126 | 127 | 138 | 139 | 140 | 150 | 151 | 152 | 162 | {showPassword ? : } 163 | 164 | ) 165 | }} 166 | value={credentials.password} 167 | onChange={handleOnChange} 168 | autoComplete="new-password" 169 | /> 170 | 171 | 172 | } 174 | label="I want to receive inspiration, marketing promotions and updates via email." 175 | /> 176 | 177 | 178 | 186 | 187 | 188 | Already have an account? 189 | 190 | Sign in 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | ) 200 | } 201 | 202 | export default Register -------------------------------------------------------------------------------- /src/Components/Card/Comment Card/CommentCard.jsx: -------------------------------------------------------------------------------- 1 | import { Avatar, Box, Button, Grid, Rating, SpeedDial, SpeedDialAction, SpeedDialIcon, TextField } from '@mui/material' 2 | import axios from 'axios'; 3 | import { useEffect, useState } from 'react'; 4 | import { AiFillEdit, AiFillDelete, AiOutlineSend } from 'react-icons/ai' 5 | import { GiCancel } from 'react-icons/gi' 6 | import { toast } from 'react-toastify'; 7 | const CommentCard = ({ userReview, setReviews, reviews, fetchReviews }) => { 8 | let date = new Date(userReview.createdAt).toLocaleDateString('en-us', { weekday: "long", year: "numeric", month: "short", day: "numeric" }) 9 | let time = new Date(userReview.createdAt).toLocaleTimeString('en-US') 10 | const [authUser, setAuthUser] = useState() 11 | const [editComment, setEditComment] = useState(userReview.comment) 12 | const [edit, setEdit] = useState(false) 13 | const [isAdmin, setIsAdmin] = useState(false) 14 | const [value, setValue] = useState(userReview.rating); 15 | let authToken = localStorage.getItem('Authorization') 16 | useEffect(() => { 17 | authToken && getUser() 18 | }, []) 19 | const getUser = async () => { 20 | const { data } = await axios.get(`${process.env.REACT_APP_GET_USER_DETAILS}`, { 21 | headers: { 22 | 'Authorization': authToken 23 | } 24 | }) 25 | setAuthUser(data._id); 26 | if (data.isAdmin === true) { 27 | setIsAdmin(true) 28 | } 29 | } 30 | const handleDeleteComment = async () => { 31 | try { 32 | const { data } = await axios.delete(`${process.env.REACT_APP_DELETE_REVIEW}/${userReview._id}`, { 33 | headers: { 34 | 'Authorization': authToken 35 | } 36 | }) 37 | toast.success(data.msg, { autoClose: 500, theme: 'colored' }) 38 | setReviews(reviews.filter(r => r._id !== userReview._id)) 39 | } catch (error) { 40 | toast.success(error, { autoClose: 500, theme: 'colored' }) 41 | } 42 | 43 | } 44 | const deleteCommentByAdmin = async () => { 45 | if (isAdmin) { 46 | try { 47 | const { data } = await axios.delete(`${process.env.REACT_APP_ADMIN_DELETE_REVIEW}/${userReview._id}`, 48 | { 49 | headers: { 50 | 'Authorization': authToken 51 | } 52 | }) 53 | toast.success(data.msg, { autoClose: 500, theme: 'colored' }) 54 | setReviews(reviews.filter(r => r._id !== userReview._id)) 55 | } catch (error) { 56 | console.log(error); 57 | toast.success(error.response.data, { autoClose: 500, theme: 'colored' }) 58 | } 59 | } else { 60 | toast.success("Access denied", { autoClose: 500, theme: 'colored' }) 61 | } 62 | } 63 | const sendEditResponse = async () => { 64 | if (!editComment && !value) { 65 | toast.error("Please Fill the all Fields", { autoClose: 500, }) 66 | } 67 | else if (editComment.length <= 4) { 68 | toast.error("Please add more than 4 characters", { autoClose: 500, }) 69 | } 70 | else if (value <= 0) { 71 | toast.error("Please add rating", { autoClose: 500, }) 72 | } 73 | else if (editComment.length >= 4 && value > 0) { 74 | try { 75 | if (authToken) { 76 | const response = await axios.put(`${process.env.REACT_APP_EDIT_REVIEW}`, 77 | { id: userReview._id, comment: editComment, rating: value }, 78 | { 79 | headers: { 80 | 'Authorization': authToken 81 | } 82 | }) 83 | toast.success(response.data.msg, { autoClose: 500, }) 84 | fetchReviews() 85 | setEdit(false) 86 | } 87 | } 88 | catch (error) { 89 | toast.error("Something went wrong", { autoClose: 600, }) 90 | } 91 | } 92 | } 93 | return ( 94 | 95 | 97 | 98 | 99 | 100 | 101 |

{userReview?.user?.firstName + ' ' + userReview?.user?.lastName}

102 |

103 | {!edit && } 104 | {edit && 105 | { 110 | setValue(newValue); 111 | }} 112 | />} 113 |

114 |

115 | {!edit && userReview.comment} 116 |

117 |

118 | {edit && { 121 | setEditComment(e.target.value) 122 | }} 123 | label="Edit Review" 124 | multiline 125 | className='comment' 126 | variant="standard" 127 | sx={{ width: '90%', }} 128 | /> 129 | 130 | 131 | } 132 |

133 | 134 | {edit &&
137 | 138 | 140 |
141 | } 142 | 143 |

144 | {date} {time} 145 |

146 | 147 | {(authUser === userReview?.user?._id || isAdmin) && 148 | 149 | } 153 | > 154 | {/* {actions.map((action) => ( */} 155 | } 157 | tooltipTitle={"Edit"} 158 | onClick={() => setEdit(true)} 159 | /> 160 | } 162 | tooltipTitle={"Delete"} 163 | onClick={isAdmin ? deleteCommentByAdmin : handleDeleteComment} 164 | /> 165 | 166 | 167 | 168 | } 169 |
170 |
171 | 172 | 173 | ) 174 | } 175 | 176 | export default CommentCard -------------------------------------------------------------------------------- /src/Admin/Components/Tables/ProductTable.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import { AiOutlineSearch } from 'react-icons/ai'; 3 | import { 4 | Table, 5 | TableBody, 6 | TableCell, 7 | TableContainer, 8 | TableHead, 9 | TableRow, 10 | Paper, 11 | Container, 12 | InputAdornment, 13 | TextField, 14 | } 15 | from '@mui/material' 16 | import { Link } from 'react-router-dom'; 17 | import AddProduct from '../AddProduct'; 18 | const ProductTable = ({ data, getProductInfo }) => { 19 | const [filteredData, setFilteredData] = useState([]); 20 | const [searchTerm, setSearchTerm] = useState(''); 21 | const columns = [ 22 | { 23 | id: 'name', 24 | label: 'Name', 25 | minWidth: 170, 26 | align: 'center', 27 | }, 28 | { 29 | id: 'image', 30 | label: 'Image', 31 | minWidth: 100, 32 | align: 'center', 33 | }, 34 | { 35 | id: 'type', 36 | label: 'Product Type', 37 | align: 'center', 38 | minWidth: 100 39 | }, 40 | { 41 | id: 'price', 42 | label: 'Price', 43 | minWidth: 100, 44 | align: 'center', 45 | 46 | }, 47 | { 48 | id: 'rating', 49 | label: 'Rating', 50 | minWidth: 100, 51 | align: 'center', 52 | 53 | }, 54 | ]; 55 | const filterData = () => { 56 | if (searchTerm === '') { 57 | return data; 58 | } 59 | return data.filter( 60 | (item) => 61 | (item.name && 62 | item.name.toLowerCase().includes(searchTerm.toLowerCase())) || 63 | (item.type && 64 | item.type.toLowerCase().includes(searchTerm.toLowerCase())) || 65 | (item.price && 66 | item.price.toString().toLowerCase().includes(searchTerm.toLowerCase())) || 67 | (item.rating && 68 | item.rating.toString().toLowerCase().includes(searchTerm.toLowerCase())) || 69 | (item.brand && 70 | item.brand.toLowerCase().includes(searchTerm.toLowerCase())) || 71 | (item.category && 72 | item.category.toLowerCase().includes(searchTerm.toLowerCase())) || 73 | (item.author && 74 | item.author.toLowerCase().includes(searchTerm.toLowerCase())) || 75 | (item.description && 76 | item.description.toLowerCase().includes(searchTerm.toLowerCase())) || 77 | (item.gender && 78 | item.gender.toLowerCase().includes(searchTerm.toLowerCase())) 79 | ); 80 | }; 81 | 82 | const handleSearch = (event) => { 83 | const value = event.target.value; 84 | setSearchTerm(value); 85 | const newFilteredData = filterData(); 86 | setFilteredData(newFilteredData); 87 | }; 88 | 89 | useEffect(() => { 90 | setFilteredData(filterData()); 91 | }, [data, searchTerm]); 92 | 93 | 94 | return ( 95 | <> 96 | 97 | 107 | 108 | 109 | ), 110 | }} 111 | /> 112 | 113 | 114 | 120 | 121 | 122 | 123 | 124 | {columns.map((column) => ( 125 | 130 | {column.label} 131 | 132 | ))} 133 | 134 | 135 | 136 | 137 | {filteredData.length === 0 ? ( 138 | 139 | 140 |
141 |

Product not found.

142 |
143 |
144 |
145 | ) : ( 146 | 147 | filteredData.map((prod) => ( 148 | 152 | 153 | 154 | {prod.name.slice(0, 20)} 155 | 156 | 157 | 158 | 159 | {prod.name} 160 | 161 | 162 | 163 | 164 | 165 | {prod.type} 166 | 167 | 168 | 169 | 170 | ₹{prod.price} 171 | 172 | 173 | 174 | 175 | {prod.rating} 176 | 177 | 178 | 179 | )) 180 | ) 181 | } 182 |
183 |
184 |
185 |
186 | 187 | ) 188 | } 189 | 190 | export default ProductTable -------------------------------------------------------------------------------- /src/Admin/Auth/Register/AdminRegister.jsx: -------------------------------------------------------------------------------- 1 | import '../Login/login.css' 2 | import React, { useEffect, useState } from 'react' 3 | import axios from 'axios' 4 | import { Link, useNavigate } from 'react-router-dom' 5 | import { Avatar, Button, Checkbox, CssBaseline, FormControlLabel, Grid, InputAdornment, TextField, Typography } from '@mui/material' 6 | import { MdLockOutline } from 'react-icons/md' 7 | import { Box, Container } from '@mui/system' 8 | import { toast } from 'react-toastify' 9 | import { RiEyeFill, RiEyeOffFill } from 'react-icons/ri'; 10 | 11 | import CopyRight from '../../../Components/CopyRight/CopyRight' 12 | 13 | const AdminRegister = () => { 14 | const [credentials, setCredentials] = useState({ firstName: "", lastName: '', email: "", phoneNumber: '', password: "", key: "" }) 15 | const [showPassword, setShowPassword] = useState(false); 16 | 17 | const handleClickShowPassword = () => { 18 | setShowPassword(!showPassword); 19 | }; 20 | 21 | const navigate = useNavigate(); 22 | 23 | const handleOnChange = (e) => { 24 | setCredentials({ ...credentials, [e.target.name]: e.target.value }) 25 | } 26 | 27 | useEffect(() => { 28 | let auth = localStorage.getItem('Authorization'); 29 | if (auth) { 30 | navigate("/") 31 | } 32 | }, []) 33 | 34 | const handleSubmit = async (e) => { 35 | e.preventDefault() 36 | let phoneRegex = /^(?:(?:\+|0{0,2})91(\s*[\-]\s*)?|[0]?)?[789]\d{9}$/gm; 37 | let emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 38 | try { 39 | if (!credentials.email && !credentials.firstName && !credentials.password && !credentials.phoneNumber && !credentials.lastName) { 40 | toast.error("All fields are required", { autoClose: 500, theme: 'colored' }) 41 | } 42 | else if (credentials.firstName.length <= 3 || credentials.lastName.length <= 3) { 43 | toast.error("Please enter name with more than 3 characters", { autoClose: 500, theme: 'colored' }) 44 | } 45 | else if (!emailRegex.test(credentials.email)) { 46 | toast.error("Please enter valid email", { autoClose: 500, theme: 'colored' }) 47 | } 48 | else if (!phoneRegex.test(credentials.phoneNumber)) { 49 | toast.error("Please enter a valid phone number", { autoClose: 500, theme: 'colored' }) 50 | } 51 | else if (credentials.password.length < 5) { 52 | toast.error("Please enter password with more than 5 characters", { autoClose: 500, theme: 'colored' }) 53 | } 54 | else if (credentials.email && credentials.firstName && credentials.lastName && credentials.phoneNumber && credentials.password) { 55 | const sendAuth = await axios.post(process.env.REACT_APP_ADMIN_REGISTER, 56 | { 57 | firstName: credentials.firstName, 58 | lastName: credentials.lastName, 59 | email: credentials.email, 60 | phoneNumber: credentials.phoneNumber, 61 | password: credentials.password, 62 | key: credentials.key 63 | }) 64 | const receive = await sendAuth.data 65 | if (receive.success === true) { 66 | toast.success("Registered Successfully", { autoClose: 500, theme: 'colored' }) 67 | localStorage.setItem('Authorization', receive.authToken) 68 | navigate('/admin/home') 69 | } 70 | else { 71 | toast.error("Invalid Credentials", { autoClose: 500, theme: 'colored' }) 72 | } 73 | } 74 | } catch (error) { 75 | toast.error("Invalid Credentials", { autoClose: 500, theme: 'colored' }) 76 | } 77 | } 78 | 79 | return ( 80 | <> 81 | 82 | 83 | 91 | 92 | 93 | 94 | 95 | Sign up 96 | 97 | 98 | 99 | 100 | 111 | 112 | 113 | 123 | 124 | 125 | 135 | 136 | 137 | 147 | 148 | 149 | 160 | {showPassword ? : } 161 | 162 | ) 163 | }} 164 | autoComplete="new-password" 165 | /> 166 | 167 | 168 | 178 | 179 | 180 | } 182 | label="I want to receive inspiration, marketing promotions and updates via email." 183 | /> 184 | 185 | 186 | 194 | 195 | 196 | Already have an account? 197 | 198 | Sign in 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | ) 208 | } 209 | 210 | export default AdminRegister -------------------------------------------------------------------------------- /src/Admin/Components/AddUser.jsx: -------------------------------------------------------------------------------- 1 | import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Divider, Grid, TextField, Typography } from '@mui/material'; 2 | import axios from 'axios'; 3 | import React, { useState } from 'react' 4 | import { MdOutlineCancel, MdPersonAddAlt1 } from 'react-icons/md'; 5 | import { toast } from 'react-toastify'; 6 | import { Transition } from '../../Constants/Constant'; 7 | 8 | 9 | const AddUser = ({ getUser }) => { 10 | const [open, setOpen] = useState(false); 11 | const [credentials, setCredentials] = useState({ firstName: "", lastName: '', email: "", phoneNumber: '', password: "" }) 12 | const handleOnChange = (e) => { 13 | setCredentials({ ...credentials, [e.target.name]: e.target.value }) 14 | } 15 | const handleClickOpen = () => { 16 | setOpen(true); 17 | }; 18 | 19 | const handleClose = () => { 20 | setOpen(false); 21 | }; 22 | const handleSubmit = async (e) => { 23 | e.preventDefault() 24 | let phoneRegex = /^(?:(?:\+|0{0,2})91(\s*[\-]\s*)?|[0]?)?[789]\d{9}$/gm; 25 | let emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 26 | try { 27 | if (!credentials.email && !credentials.firstName && !credentials.password && !credentials.phoneNumber && !credentials.lastName) { 28 | toast.error("Please Fill the all Fields", { autoClose: 500, theme: 'colored' }) 29 | } 30 | else if (credentials.firstName.length <= 3 || credentials.lastName.length <= 3) { 31 | toast.error("Please enter name with more than 3 characters", { autoClose: 500, theme: 'colored' }) 32 | } 33 | else if (!emailRegex.test(credentials.email)) { 34 | toast.error("Please enter valid email", { autoClose: 500, theme: 'colored' }) 35 | } 36 | else if (!phoneRegex.test(credentials.phoneNumber)) { 37 | toast.error("Please enter a valid phone number", { autoClose: 500, theme: 'colored' }) 38 | } 39 | else if (credentials.password.length < 5) { 40 | toast.error("Please enter password with more than 5 characters", { autoClose: 500, theme: 'colored' }) 41 | } 42 | else if (credentials.email && credentials.firstName && credentials.lastName && credentials.phoneNumber && credentials.password) { 43 | const sendAuth = await axios.post(`${process.env.REACT_APP_REGISTER}`, 44 | { 45 | firstName: credentials.firstName, 46 | lastName: credentials.lastName, 47 | email: credentials.email, 48 | phoneNumber: credentials.phoneNumber, 49 | password: credentials.password, 50 | }) 51 | const receive = await sendAuth.data 52 | setOpen(false); 53 | if (receive.success === true) { 54 | getUser() 55 | toast.success("Registered Successfully", { autoClose: 500, theme: 'colored' }) 56 | setCredentials({ 57 | firstName: "", 58 | lastName: '', 59 | email: "", 60 | phoneNumber: '', 61 | password: "" 62 | }) 63 | } 64 | else { 65 | toast.error("Some thing went wrong", { autoClose: 500, theme: 'colored' }) 66 | } 67 | } 68 | } catch (error) { 69 | toast.error(error.response.data.error, { autoClose: 500, theme: 'colored' }) 70 | } 71 | 72 | } 73 | return ( 74 | <> 75 | 76 | Add new user 77 | 78 | 79 | 80 | 81 | 86 | Add new user 87 | 88 | 89 | 90 | 91 | 102 | 103 | 104 | 114 | 115 | 116 | 126 | 127 | 128 | 138 | 139 | 140 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | ) 162 | } 163 | 164 | export default AddUser -------------------------------------------------------------------------------- /src/Components/Checkout/CheckoutForm.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from 'react' 2 | import { Button, Container, Dialog, DialogActions, DialogContent, Grid, TextField, Typography } from '@mui/material' 3 | import styles from './Chekout.module.css' 4 | import { BsFillCartCheckFill } from 'react-icons/bs' 5 | import { MdUpdate } from 'react-icons/md' 6 | import axios from 'axios' 7 | import { ContextFunction } from '../../Context/Context' 8 | import { Link, useNavigate } from 'react-router-dom' 9 | import { profile } from '../../Assets/Images/Image' 10 | import { toast } from 'react-toastify' 11 | import CopyRight from '../CopyRight/CopyRight' 12 | import { Transition, handleClose } from '../../Constants/Constant' 13 | import { AiFillCloseCircle, AiOutlineSave } from 'react-icons/ai' 14 | 15 | const CheckoutForm = () => { 16 | const { cart } = useContext(ContextFunction) 17 | const [userData, setUserData] = useState([]) 18 | const [openAlert, setOpenAlert] = useState(false); 19 | 20 | let authToken = localStorage.getItem('Authorization') 21 | let setProceed = authToken ? true : false 22 | let navigate = useNavigate() 23 | let totalAmount = sessionStorage.getItem('totalAmount') 24 | 25 | useEffect(() => { 26 | if (setProceed) { 27 | getUserData() 28 | 29 | } 30 | else { 31 | navigate('/') 32 | } 33 | 34 | }, []) 35 | 36 | const [userDetails, setUserDetails] = useState({ 37 | firstName: '', 38 | lastName: '', 39 | phoneNumber: '', 40 | userEmail: '', 41 | address: '', 42 | zipCode: '', 43 | city: '', 44 | userState: '', 45 | 46 | }) 47 | const getUserData = async () => { 48 | try { 49 | const { data } = await axios.get(`${process.env.REACT_APP_GET_USER_DETAILS}`, { 50 | headers: { 51 | 'Authorization': authToken 52 | } 53 | }) 54 | setUserData(data); 55 | if (!data.address || !data.city || !data.zipCode || !data.userState) { 56 | setOpenAlert(true); 57 | console.log(1); 58 | } 59 | userDetails.firstName = data.firstName 60 | userDetails.lastName = data.lastName 61 | userDetails.userEmail = data.email 62 | userDetails.phoneNumber = data.phoneNumber 63 | userDetails.address = data.address 64 | userDetails.zipCode = data.zipCode 65 | userDetails.city = data.city 66 | userDetails.userState = data.userState 67 | } catch (error) { 68 | console.log(error); 69 | } 70 | 71 | } 72 | 73 | const checkOutHandler = async (e) => { 74 | e.preventDefault() 75 | 76 | if (!userDetails.firstName || !userDetails.lastName || !userDetails.userEmail || !userDetails.phoneNumber || !userDetails.address || !userDetails.zipCode || !userDetails.city || !userDetails.userState) { 77 | toast.error("Please fill all fields", { autoClose: 500, theme: "colored" }) 78 | } 79 | else { 80 | try { 81 | const { data: { key } } = await axios.get(`${process.env.REACT_APP_GET_KEY}`) 82 | const { data } = await axios.post(`${process.env.REACT_APP_GET_CHECKOUT}`, { 83 | amount: totalAmount, 84 | productDetails: JSON.stringify(cart), 85 | userId: userData._id, 86 | userDetails: JSON.stringify(userDetails), 87 | }) 88 | 89 | const options = { 90 | key: key, 91 | amount: totalAmount, 92 | currency: "INR", 93 | name: userData.firstName + ' ' + userData.lastName, 94 | description: "Payment", 95 | image: profile, 96 | order_id: data.order.id, 97 | callback_url: process.env.REACT_APP_GET_PAYMENTVERIFICATION, 98 | prefill: { 99 | name: userData.firstName + ' ' + userData.lastName, 100 | email: userData.email, 101 | contact: userData.phoneNumber 102 | }, 103 | notes: { 104 | "address": `${userData.address} ${userData.city} ${userData.zipCode} ${userData.userState}` 105 | }, 106 | theme: { 107 | "color": "#1976d2" 108 | }, 109 | 110 | }; 111 | const razor = new window.Razorpay(options); 112 | razor.open(); 113 | } catch (error) { 114 | console.log(error); 115 | } 116 | } 117 | } 118 | 119 | const handleOnchange = (e) => { 120 | setUserDetails({ ...userDetails, [e.target.name]: e.target.value }) 121 | } 122 | 123 | 124 | 125 | return ( 126 | <> 127 | 128 | Checkout 129 |
130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 |
161 | 162 | handleClose(setOpenAlert)} 167 | aria-describedby="alert-dialog-slide-description" 168 | > 169 | 170 | Add permanent address then you don't have to add again. 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 |
179 | 180 | 181 | 182 | ) 183 | } 184 | 185 | export default CheckoutForm -------------------------------------------------------------------------------- /src/Admin/Components/Tables/OrderTable.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { 3 | Table, 4 | TableBody, 5 | TableCell, 6 | TableContainer, 7 | TableHead, 8 | TableRow, 9 | Paper, 10 | IconButton, 11 | Collapse, 12 | Typography, 13 | } from '@mui/material'; 14 | import { MdKeyboardArrowDown } from 'react-icons/md' 15 | import { Link } from 'react-router-dom'; 16 | 17 | const OrderTable = ({ orders }) => { 18 | const [openOrderId, setOpenOrderId] = useState(""); 19 | const sortedOrders = orders.sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt)); 20 | return ( 21 | <> 22 | 28 | 29 | 30 | 31 | 32 | 33 | User Name 34 | Email 35 | Phone Number 36 | Total Amount 37 | Order Created Date 38 | 39 | 40 | 41 | {sortedOrders.map((order) => ( 42 | 43 | 44 | 45 | setOpenOrderId(openOrderId === order._id ? "" : order._id)} 49 | 50 | > 51 | {} 52 | 53 | 54 | 55 | 56 | 57 | {`${order.userData.firstName} ${order.userData.lastName}`} 58 | 59 | 60 | 61 | {order.userData.userEmail} 62 | 63 | {order.userData.phoneNumber} 64 | 65 | {order.totalAmount} 66 | { 67 | new Date(order.createdAt).toLocaleDateString('en-us', { 68 | weekday: "long", year: "numeric", month: "short", day: "numeric" 69 | } 70 | ) 71 | } 72 | {" "} 73 | {new Date(order.createdAt).toLocaleTimeString('en-US')} 74 | 75 | 76 | 77 | 78 |
79 | 80 | {`Address: ${order.userData.address}`} 81 | {`Zip Code: ${order.userData.zipCode}`} 82 | {`City: ${order.userData.city}`} 83 | {`State: ${order.userData.userState}`} 84 |
85 | 86 | 87 | Product Name 88 | Image 89 | Price 90 | Quantity 91 | Rating 92 | 93 | 94 | 95 | {order.productData.map(product => ( 96 | 97 | 98 | 99 | {product.productId.name} 100 | 101 | 102 | 103 | 104 | {product.productId.name} 105 | 106 | 107 | 108 | 109 | {product.productId.price} 110 | 111 | 112 | 113 | 114 | {product.quantity} 115 | 116 | 117 | 118 | 119 | {product.productId.rating} 120 | 121 | 122 | 123 | 124 | ))} 125 | 126 |
127 | 128 | 129 | 130 | 131 | 132 | ))} 133 | 134 | 135 |
136 |
137 | 138 | 139 | ); 140 | }; 141 | 142 | export default OrderTable; 143 | -------------------------------------------------------------------------------- /src/Admin/Components/Charts/ProductChart.jsx: -------------------------------------------------------------------------------- 1 | import { Container } from "@mui/material"; 2 | import { 3 | BarChart, 4 | Bar, 5 | XAxis, 6 | YAxis, 7 | Tooltip, 8 | Legend, 9 | CartesianGrid, 10 | ResponsiveContainer, 11 | PieChart, 12 | Pie, 13 | Cell, 14 | Area, 15 | AreaChart, 16 | } from "recharts"; 17 | const RADIAN = Math.PI / 175; 18 | const renderCustomizedLabel = ({ 19 | cx, 20 | cy, 21 | midAngle, 22 | innerRadius, 23 | outerRadius, 24 | percent, 25 | index, 26 | }) => { 27 | const radius = innerRadius + (outerRadius - innerRadius) * 0.5; 28 | const x = cx + radius * Math.cos(-midAngle * RADIAN); 29 | const y = cy + radius * Math.sin(-midAngle * RADIAN); 30 | 31 | return ( 32 | cx ? "start" : "end"} 37 | dominantBaseline="central" 38 | > 39 | {`${(percent * 100).toFixed(0)}%`} 40 | 41 | ); 42 | }; 43 | const ProductChart = ({ products, review, cart, wishlist, paymentData }) => { 44 | const productData = [ 45 | { 46 | name: "Cloths", 47 | Quantity: products.filter((prod) => prod.type === "cloths").length, 48 | }, 49 | { 50 | name: "Shoes", 51 | Quantity: products.filter((prod) => prod.type === "shoe").length, 52 | }, 53 | { 54 | name: "Electronics", 55 | Quantity: products.filter((prod) => prod.type === "electronics").length, 56 | }, 57 | { 58 | name: "Books", 59 | Quantity: products.filter((prod) => prod.type === "book").length, 60 | }, 61 | { 62 | name: "Jewelry", 63 | Quantity: products.filter((prod) => prod.type === "jewelry").length, 64 | }, 65 | ]; 66 | 67 | const reviewData = [ 68 | { 69 | name: "One ⭐", 70 | Reviews: review.filter((prod) => Math.round(prod.rating) === 1).length, 71 | }, 72 | { 73 | name: "Two ⭐", 74 | Reviews: review.filter((prod) => Math.round(prod.rating) === 2).length, 75 | }, 76 | { 77 | name: "Three ⭐", 78 | Reviews: review.filter((prod) => Math.round(prod.rating) === 3).length, 79 | }, 80 | { 81 | name: "Four ⭐", 82 | Reviews: review.filter((prod) => Math.round(prod.rating) === 4).length, 83 | }, 84 | { 85 | name: "Five ⭐", 86 | Reviews: review.filter((prod) => Math.round(prod.rating) === 5).length, 87 | }, 88 | ]; 89 | 90 | const cartData = [ 91 | { 92 | name: "Cloths", 93 | "Quantity in cart": cart.filter( 94 | (prod) => prod.productId.type === "cloths" 95 | ).length, 96 | }, 97 | { 98 | name: "Shoes", 99 | "Quantity in cart": cart.filter((prod) => prod.productId.type === "shoe") 100 | .length, 101 | }, 102 | { 103 | name: "Electronics", 104 | "Quantity in cart": cart.filter( 105 | (prod) => prod.productId.type === "electronics" 106 | ).length, 107 | }, 108 | { 109 | name: "Books", 110 | "Quantity in cart": cart.filter((prod) => prod.productId.type === "book") 111 | .length, 112 | }, 113 | { 114 | name: "Jewelry", 115 | "Quantity in cart": cart.filter( 116 | (prod) => prod.productId.type === "jewelry" 117 | ).length, 118 | }, 119 | ]; 120 | 121 | const wishlistData = [ 122 | { 123 | name: "Cloths", 124 | "Quantity in wishlist": wishlist.filter( 125 | (prod) => prod.productId.type === "cloths" 126 | ).length, 127 | }, 128 | { 129 | name: "Shoes", 130 | "Quantity in wishlist": wishlist.filter( 131 | (prod) => prod.productId.type === "shoe" 132 | ).length, 133 | }, 134 | { 135 | name: "Electronics", 136 | "Quantity in wishlist": wishlist.filter( 137 | (prod) => prod.productId.type === "electronics" 138 | ).length, 139 | }, 140 | { 141 | name: "Books", 142 | "Quantity in wishlist": wishlist.filter( 143 | (prod) => prod.productId.type === "book" 144 | ).length, 145 | }, 146 | { 147 | name: "Jewelry", 148 | "Quantity in wishlist": wishlist.filter( 149 | (prod) => prod.productId.type === "jewelry" 150 | ).length, 151 | }, 152 | ]; 153 | 154 | const groupedData = paymentData 155 | .sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt)) 156 | .reduce((acc, item) => { 157 | const month = item.createdAt.substr(0, 7); 158 | const index = acc.findIndex((el) => el.month === month); 159 | if (index !== -1) { 160 | acc[index].totalAmount += item.totalAmount; 161 | } else { 162 | acc.push({ month: month, totalAmount: item.totalAmount }); 163 | } 164 | return acc; 165 | }, []); 166 | 167 | const formatXAxis = (tickItem) => { 168 | return new Date(tickItem).toLocaleString("default", { month: "short" }); 169 | }; 170 | 171 | const COLORS = ["#0088FE", "#00C49F", "#FFBB28", "#FF8042", "#8884d8"]; 172 | 173 | return ( 174 | <> 175 | 176 |

177 | Payment 178 |

179 |
180 | 181 | 190 | 191 | 192 | 193 | 194 | 195 | 203 | 204 | 205 |
206 |

207 | Products 208 |

209 |
210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 |
221 |

222 | Users Cart 223 |

224 |
233 |

Shoes

234 |

235 |

Cloths

236 |

237 |

Books

238 |

239 |

Electronics

240 |

241 |

Jewelry

242 |

243 |
244 |
245 | 246 | 247 | 248 | 258 | 259 | {cartData.map((entry, index) => ( 260 | 264 | ))} 265 | 266 | 267 | 268 |
269 |

276 | Users Wishlist 277 |

278 |
279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 |
290 |

291 | Reviews 292 |

293 |
294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 |
305 |
306 | 307 | ); 308 | }; 309 | 310 | export default ProductChart; 311 | --------------------------------------------------------------------------------