├── 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 |
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 |
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 | You need to enable JavaScript to run this app.
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 |
22 |
Back To Home
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 | 
29 | 
30 | 
31 | 
32 | 
33 | 
34 | 
35 | 
36 | 
37 | 
38 | 
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 |
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 && Quantity {' ' + product.quantity} }
31 |
32 | ₹{product?.productId?.price}
33 |
34 |
35 |
36 |
37 |
38 |
39 |
41 | removeFromCart(product)}>
42 |
43 |
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 | } color="primary" onClick={proceedToCheckout}>
50 | Checkout
51 |
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 |
86 | Submit
87 |
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 |
63 | Submit
64 |
65 |
66 |
67 |
68 |
69 |
70 | :
71 |
80 |
81 | Email Sent Successfully
82 |
83 | } variant='contained'>Open Mail
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 |
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 |
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 | } color='primary'>Login
92 | } onClick={handleClose}>Close
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 |
28 |
29 |
30 | Shop It
31 |
32 |
33 |
34 |
35 |
36 |
37 | Home
38 |
39 |
40 | {/*
41 |
42 | Contact Us
43 |
44 | */}
45 |
46 |
47 |
48 |
49 | Cart
50 |
51 |
52 |
53 |
54 |
55 |
56 | Wishlist
57 |
58 |
59 |
60 |
61 | {
62 | setProceed ?
63 | <>
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | handleClickOpen(setOpenAlert)}>
72 | }>
73 | Logout
74 |
75 |
76 | >
77 | :
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | }
86 |
87 |
88 |
89 |
96 |
97 | Do You Want To Logout?
98 |
99 |
100 |
101 | } color='primary' onClick={() => handleLogOut(setProceed, toast, navigate, setOpenAlert)}>Logout
102 | } onClick={() => handleClose(setOpenAlert)}>Close
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 |
37 |
38 |
39 |
44 |
45 |
46 |
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 | } color='primary' onClick={() => handleLogOut(setProceed, toast, navigate, setOpenAlert)}>Logout
89 | } onClick={()=>handleClose(setOpenAlert)}>Close
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 | }>Filters
94 | handleChange(e)}
100 | >
101 | {productFilter.map(prod => (
102 | {prod}
103 | ))}
104 |
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 | } onClick={() => setOpenAlert(true)}>Delete
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 | } color='error' onClick={deleteAccount}>Delete
89 | setOpenAlert(false)} endIcon={ }>Close
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 |
29 | {value === index && (
30 |
31 | {children}
32 |
33 |
34 | )}
35 |
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 |
129 | Sign In
130 |
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 |
136 | Sign In
137 |
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 |
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 | } color='primary'>Login
173 | } onClick={handleClose}>Close
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 |
147 |
148 |
149 |
150 |
151 | {reviews.length >= 1 ?
152 | }>Filters
153 |
160 | {commentFilter.map(prod => (
161 | {prod}
162 | ))}
163 |
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 |
184 | Sign Up
185 |
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 |
setEdit(false)}>
139 | { }
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 |
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 |
192 | Sign Up
193 |
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 | } onClick={handleClickOpen}>Add
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 | }>Cancel
155 | }>Add
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 |
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 | } color='primary' >Add
174 | } onClick={() => handleClose(setOpenAlert)}>Close
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 |
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 |
--------------------------------------------------------------------------------