├── Procfile ├── .DS_Store ├── frontend ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── profile.png │ ├── manifest.json │ └── index.html ├── src │ ├── Assets │ │ ├── bg.jpg │ │ ├── background.jpg │ │ ├── icons │ │ │ ├── bag.png │ │ │ ├── home.png │ │ │ ├── user.png │ │ │ ├── logout.png │ │ │ ├── search.png │ │ │ ├── homeActive.png │ │ │ ├── userActive.png │ │ │ ├── logoutActive.png │ │ │ ├── searchActive.png │ │ │ ├── shopping-cart.png │ │ │ ├── shopping-bagActive.png │ │ │ └── shopping-cartActive.png │ │ ├── slider-2.png │ │ └── background2.jpg │ ├── constans │ │ ├── FavouriteConstans.js │ │ ├── CartConstans.js │ │ ├── OrderConstans.js │ │ ├── ProductConstans.js │ │ └── userContans.js │ ├── more │ │ ├── Rules.css │ │ ├── Metadata.js │ │ ├── UserOption.css │ │ ├── Loader.js │ │ ├── BottomTabs.css │ │ ├── Support.css │ │ ├── Notfound.jsx │ │ ├── CommingSoon.jsx │ │ ├── CommingSoon.css │ │ ├── Rules.jsx │ │ ├── Loading.css │ │ └── BottomTab.jsx │ ├── component │ │ ├── Home │ │ │ ├── Header.css │ │ │ └── Home.css │ │ ├── cart │ │ │ ├── ConfirmOrder.css │ │ │ ├── Success.jsx │ │ │ ├── CartItemCard.js │ │ │ ├── orderSuccess.css │ │ │ ├── CartItemCard.css │ │ │ ├── CheckoutSteps.jsx │ │ │ ├── FavouriteItemsCard.jsx │ │ │ ├── payment.css │ │ │ ├── FavouriteItemsCard.css │ │ │ ├── Favourites.jsx │ │ │ ├── Shipping.css │ │ │ ├── ConfirmOrder.jsx │ │ │ ├── Cart.css │ │ │ ├── Cart.jsx │ │ │ ├── Favourite.css │ │ │ ├── Shipping.jsx │ │ │ ├── CheckoutSteps.css │ │ │ └── Payment.jsx │ │ ├── user │ │ │ ├── Profile.css │ │ │ ├── myOrders.css │ │ │ ├── orderDetails.css │ │ │ ├── Profile.jsx │ │ │ ├── ResetPassword.css │ │ │ ├── ForgotPassword.css │ │ │ ├── UpdatePassword.css │ │ │ ├── ForgotPassword.jsx │ │ │ ├── MyOrder.jsx │ │ │ ├── ResetPassword.jsx │ │ │ ├── UpdatePassword.jsx │ │ │ ├── MyOrderDetails.jsx │ │ │ └── EditProfile.jsx │ │ ├── Admin │ │ │ ├── Sidebar.css │ │ │ ├── UpdateOrder.css │ │ │ ├── AllProducts.css │ │ │ ├── productReviews.css │ │ │ ├── Sidebar.js │ │ │ ├── dashboard.css │ │ │ ├── Dashboard.jsx │ │ │ ├── newProduct.css │ │ │ ├── AllProducts.jsx │ │ │ ├── AllUsers.jsx │ │ │ ├── AllOrder.jsx │ │ │ └── UpdateUser.jsx │ │ └── Products │ │ │ ├── Product.css │ │ │ ├── Search.css │ │ │ ├── ProductCard.jsx │ │ │ ├── Search.jsx │ │ │ ├── ReviewCard.jsx │ │ │ ├── Productdetails.css │ │ │ └── ProductCard.css │ ├── index.css │ ├── index.js │ ├── reportWebVitals.js │ ├── route │ │ └── ProtectedRoute.js │ ├── actions │ │ ├── FavouriteAction.js │ │ ├── CartAction.js │ │ └── OrderAction.js │ ├── reducers │ │ ├── CartReducer.js │ │ ├── FavouriteReducer.js │ │ └── OrderReducer.js │ └── store.js ├── .gitignore ├── package.json └── README.md ├── backend ├── middleware │ ├── catchAsyncErrors.js │ ├── auth.js │ └── error.js ├── utils │ ├── ErrorHandler.js │ ├── jwtToken.js │ ├── sendMail.js │ └── Features.js ├── db │ └── Database.js ├── routes │ ├── PaymentRoute.js │ ├── OrderRoute.js │ ├── ProductRoute.js │ └── UserRoute.js ├── controller │ ├── PaymentController.js │ └── OrderController.js ├── config │ └── .env ├── server.js ├── app.js └── models │ ├── OrderModel.js │ ├── ProductModel.js │ └── UserModel.js ├── .gitIgnore └── package.json /Procfile: -------------------------------------------------------------------------------- 1 | web: node backend/server.js -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/.DS_Store -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /frontend/src/Assets/bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/bg.jpg -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/public/logo192.png -------------------------------------------------------------------------------- /frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/public/logo512.png -------------------------------------------------------------------------------- /frontend/public/profile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/public/profile.png -------------------------------------------------------------------------------- /frontend/src/Assets/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/background.jpg -------------------------------------------------------------------------------- /frontend/src/Assets/icons/bag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/bag.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/home.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/user.png -------------------------------------------------------------------------------- /frontend/src/Assets/slider-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/slider-2.png -------------------------------------------------------------------------------- /frontend/src/Assets/background2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/background2.jpg -------------------------------------------------------------------------------- /frontend/src/Assets/icons/logout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/logout.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/search.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/homeActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/homeActive.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/userActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/userActive.png -------------------------------------------------------------------------------- /backend/middleware/catchAsyncErrors.js: -------------------------------------------------------------------------------- 1 | module.exports = (theFunc) => (req, res, next) => { 2 | Promise.resolve(theFunc(req, res, next)).catch(next); 3 | }; 4 | -------------------------------------------------------------------------------- /frontend/src/Assets/icons/logoutActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/logoutActive.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/searchActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/searchActive.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/shopping-cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/shopping-cart.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/shopping-bagActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/shopping-bagActive.png -------------------------------------------------------------------------------- /frontend/src/Assets/icons/shopping-cartActive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Nitish8800/Full_Stack_Ecommerce_Project/HEAD/frontend/src/Assets/icons/shopping-cartActive.png -------------------------------------------------------------------------------- /frontend/src/constans/FavouriteConstans.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_FAVOURITE = "ADD_TO_FAVOURITE"; 2 | 3 | export const REMOVE_FROM_FAVOURITE = "REMOVE_FROM_FAVOURITE"; 4 | 5 | -------------------------------------------------------------------------------- /frontend/src/constans/CartConstans.js: -------------------------------------------------------------------------------- 1 | export const ADD_TO_CART = "ADD_TO_CART"; 2 | 3 | export const REMOVE_CART_ITEM = "REMOVE_CART_ITEM"; 4 | 5 | export const SAVE_SHIPPING_INFO = "SAVE_SHIPPING_INFO"; -------------------------------------------------------------------------------- /frontend/src/more/Rules.css: -------------------------------------------------------------------------------- 1 | ul.rules > li{ 2 | font-family: sans-serif; 3 | padding: 10px 0; 4 | list-style: none; 5 | line-height: 1.3; 6 | font-weight: 500; 7 | font-size: 1.2rem; 8 | } -------------------------------------------------------------------------------- /frontend/src/more/Metadata.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import Helmet from "react-helmet"; 3 | 4 | const MetaData = ({title}) => { 5 | return ( 6 | 7 | {title} 8 | 9 | ) 10 | } 11 | 12 | export default MetaData 13 | -------------------------------------------------------------------------------- /backend/utils/ErrorHandler.js: -------------------------------------------------------------------------------- 1 | class ErrorHandler extends Error{ 2 | constructor(message,statusCode){ 3 | super(message); 4 | this.statusCode = statusCode 5 | 6 | Error.captureStackTrace(this,this.constructor); 7 | } 8 | 9 | } 10 | module.exports = ErrorHandler -------------------------------------------------------------------------------- /frontend/src/more/UserOption.css: -------------------------------------------------------------------------------- 1 | .speedDialIcon{ 2 | width: 56px; 3 | height: 56px; 4 | border-radius: 100%; 5 | object-fit: cover; 6 | } 7 | .speedDial{ 8 | position: fixed; 9 | right: 1vmax; 10 | top: 13vmax; 11 | } 12 | .speedDial.active{ 13 | top: 5vmax; 14 | } 15 | -------------------------------------------------------------------------------- /frontend/src/component/Home/Header.css: -------------------------------------------------------------------------------- 1 | .inputBox > span{ 2 | font-family: "Roboto"; 3 | animation: sliding 14s linear infinite; 4 | display: block; 5 | } 6 | @keyframes sliding{ 7 | 0%{ 8 | transform: translateX(-70%); 9 | } 10 | 100%{ 11 | transform: translateX(130%); 12 | } 13 | } -------------------------------------------------------------------------------- /frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* -------------------------------------------------------------------------------- /frontend/src/more/Loader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import "./Loading.css"; 3 | 4 | const Loading = () => { 5 | return ( 6 |
7 | 8 | 11 |
12 | ) 13 | } 14 | 15 | export default Loading 16 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | import {Provider} from "react-redux"; 7 | import store from './store'; 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | 16 | reportWebVitals(); 17 | -------------------------------------------------------------------------------- /frontend/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /backend/db/Database.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const connectDatabase = () => { 4 | mongoose.set("strictQuery", false); 5 | mongoose 6 | .connect(process.env.DB_URL, { 7 | useNewUrlParser: true, 8 | useUnifiedTopology: true, 9 | }) 10 | .then((data) => { 11 | console.log(`mongodb is connected with server: ${data.connection.host}`); 12 | }); 13 | }; 14 | 15 | module.exports = connectDatabase; 16 | -------------------------------------------------------------------------------- /frontend/src/more/BottomTabs.css: -------------------------------------------------------------------------------- 1 | 2 | .bottomOption{ 3 | position: fixed; 4 | z-index: 10000; 5 | width: 100%; 6 | height: 60px; 7 | bottom: 0; 8 | display: flex; 9 | align-items: center; 10 | justify-content: space-around; 11 | box-shadow: 0 2px 5px rgb(0 0 0 / 65%); 12 | background-color: #fff; 13 | left: 0; 14 | } 15 | .icon{ 16 | display: flex; 17 | } -------------------------------------------------------------------------------- /.gitIgnore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | /frontend/node_modules 4 | /frontend/.pnp 5 | /frontend/.pnp.js 6 | 7 | # testing 8 | /frontend/coverage 9 | 10 | # production 11 | /frontend/build 12 | 13 | # misc 14 | /frontend/.DS_Store 15 | /frontend/.env.local 16 | /frontend/.env.development.local 17 | /frontend/.env.test.local 18 | /frontend/.env.production.local 19 | /backend/config/.env 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /backend/routes/PaymentRoute.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { 3 | Payment, 4 | sendStripeApiKey, 5 | } = require("../controller/PaymentController"); 6 | const router = express.Router(); 7 | const { isAuthenticatedUser } = require("../middleware/auth"); 8 | 9 | router.route("/payment/process").post(isAuthenticatedUser, Payment); 10 | 11 | router.route("/stripeapikey").get(isAuthenticatedUser, sendStripeApiKey); 12 | 13 | module.exports = router; 14 | -------------------------------------------------------------------------------- /frontend/src/component/cart/ConfirmOrder.css: -------------------------------------------------------------------------------- 1 | .shippingBtn { 2 | 3 | background-color: #37b67a; 4 | color: white; 5 | font: 300 1vmax "Roboto"; 6 | width: 100%; 7 | padding: 1vmax; 8 | cursor: pointer; 9 | transition: all 0.6s; 10 | margin: 2vmax; 11 | border: 1px solid black; 12 | border-radius: 5px; 13 | 14 | } 15 | 16 | .shippingBtn:hover { 17 | background-color: rgb(161, 238, 167); 18 | color: #141615; 19 | } 20 | -------------------------------------------------------------------------------- /backend/utils/jwtToken.js: -------------------------------------------------------------------------------- 1 | // create token and saving that in cookies 2 | const sendToken = (user, statusCode, res) => { 3 | const token = user.getJwtToken(); 4 | 5 | // Options for cookies 6 | const options = { 7 | expires: new Date( 8 | Date.now() + process.env.COOKIE_EXPIRE + 24 * 60 * 60 * 1000 9 | ), 10 | httpOnly: true, 11 | }; 12 | 13 | res.status(statusCode).cookie("token", token, options).json({ 14 | success: true, 15 | user, 16 | token, 17 | }); 18 | }; 19 | 20 | 21 | module.exports = sendToken; 22 | -------------------------------------------------------------------------------- /frontend/src/component/cart/Success.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import CheckCircleIcon from "@material-ui/icons/CheckCircle"; 3 | import "./orderSuccess.css"; 4 | import { Typography } from "@material-ui/core"; 5 | import { Link } from "react-router-dom"; 6 | 7 | const Success = () => { 8 | return ( 9 |
10 | 11 | 12 | Your Order has been Placed successfully 13 | View Orders 14 |
15 | ); 16 | }; 17 | 18 | export default Success; -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /frontend/src/more/Support.css: -------------------------------------------------------------------------------- 1 | .support{ 2 | background-image: url(https://image.freepik.com/free-vector/flat-customer-support-illustration_23-2148899114.jpg); 3 | background-position: left; 4 | background-repeat: no-repeat; 5 | background-size: 30%; 6 | } 7 | .animation{ 8 | width:35px; 9 | height: 35px; 10 | border-radius: 50%; 11 | background-color: pink; 12 | position: fixed; 13 | top: 10%; 14 | right: 10%; 15 | border: none; 16 | animation: zoom 3s linear infinite; 17 | } 18 | @keyframes zoom { 19 | 0%,100%{ 20 | transform: scale(1.5); 21 | } 22 | 50%{ 23 | transform: scale(.7); 24 | } 25 | } -------------------------------------------------------------------------------- /backend/utils/sendMail.js: -------------------------------------------------------------------------------- 1 | const nodeMailer = require("nodemailer"); 2 | 3 | const sendMail = async (options) => { 4 | const transporter = nodeMailer.createTransport({ 5 | host: process.env.SMPT_HOST, 6 | port: process.env.SMPT_PORT, 7 | service: process.env.SMPT_SERVICE, 8 | secure: true, 9 | auth: { 10 | user: process.env.SMPT_MAIL, 11 | pass: process.env.SMPT_PASSWORD, 12 | }, 13 | }); 14 | 15 | const mailOptions = { 16 | from: process.env.SMPT_MAIL, 17 | to: options.email, 18 | subject: options.subject, 19 | text: options.message, 20 | }; 21 | 22 | await transporter.sendMail(mailOptions); 23 | }; 24 | 25 | 26 | module.exports = sendMail; 27 | -------------------------------------------------------------------------------- /backend/controller/PaymentController.js: -------------------------------------------------------------------------------- 1 | const catchAsyncErrors = require("../middleware/catchAsyncErrors"); 2 | 3 | const stripe = require("stripe")(process.env.STRIPE_SECRET_KEY); 4 | 5 | exports.Payment = catchAsyncErrors(async (req, res, next) => { 6 | const myPayment = await stripe.paymentIntents.create({ 7 | amount: req.body.amount, 8 | currency: "INR", 9 | metadata: { 10 | company: "MERN", 11 | }, 12 | }); 13 | 14 | res 15 | .status(200) 16 | .json({ success: true, client_secret: myPayment.client_secret }); 17 | }); 18 | 19 | exports.sendStripeApiKey = catchAsyncErrors(async (req, res, next) => { 20 | res.status(200).json({ stripeApiKey: process.env.STRIPE_API_KEY }); 21 | }); 22 | -------------------------------------------------------------------------------- /frontend/src/more/Notfound.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | 4 | const Notfound = () => { 5 | return ( 6 |
7 |
17 |

404 Not Found anything in this url

18 | Go Back to Home 26 |
27 |
28 | ) 29 | } 30 | 31 | export default Notfound -------------------------------------------------------------------------------- /frontend/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 15 | 16 | 17 | 18 | 19 | React App 20 | 21 | 22 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /backend/config/.env: -------------------------------------------------------------------------------- 1 | PORT = 4000 2 | 3 | DB_URL = mongodb+srv://niku8800:8800@cluster0.poi9y5j.mongodb.net/test 4 | 5 | JWT_SECRET_KEY = 544543543%%^%^$^$$$^^:GUFUR%4565345ty65488r 6 | 7 | JWT_EXPIRES = 600d 8 | 9 | COOKIE_EXPIRE = 5 10 | 11 | SMPT_SERVICE = gmail 12 | 13 | SMPT_HOST = nitishfea120784@gmail.com 14 | 15 | SMPT_PORT = 465 16 | 17 | SMPT_PASSWORD = ffobbxhlabvtfspy 18 | 19 | SMPT_MAIL = nitishfea120784@gmail.com 20 | 21 | CLOUDINARY_NAME = nestecommerce 22 | 23 | CLOUDINARY_API_KEY = 287343356731762 24 | 25 | CLOUDINARY_API_SECRET = WpHI8T5CnouxGOL4gqrWjbC2Lac 26 | 27 | STRIPE_SECRET_KEY = sk_test_51KqhTiSCOY1feElHaE4xHCOMDz8mhU4YeUHhDKpC0GCSKKOckkOaeAPAdHgMk9nNVnCpaER7yIPBAMy5aj43TwD800bvT5p8Fk 28 | 29 | STRIPE_API_KEY = pk_test_51KqhTiSCOY1feElHD5wFbmgVj1ibYhNCzVejAXs45y6pxzdMEvOwbv1CdGszDixmmCVPQkeTTOfWz10RHNQ71gKc00Y4fb5uBt 30 | -------------------------------------------------------------------------------- /frontend/src/component/cart/CartItemCard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import DeleteIcon from "@mui/icons-material/Delete"; 4 | import Button from "@mui/material/Button"; 5 | import "./CartItemCard.css"; 6 | 7 | const CartItemCard = ({ item, deleteCartItems }) => { 8 | return ( 9 |
10 | ssa 11 |
12 | {item.name} 13 | {`Price: $ ${item.price}`} 14 | 23 |
24 |
25 | ); 26 | }; 27 | 28 | export default CartItemCard; 29 | -------------------------------------------------------------------------------- /backend/middleware/auth.js: -------------------------------------------------------------------------------- 1 | const ErrorHandler = require("../utils/ErrorHandler"); 2 | const catchAsyncErrors = require("./catchAsyncErrors"); 3 | const jwt = require("jsonwebtoken"); 4 | const User = require("../models/UserModel"); 5 | 6 | exports.isAuthenticatedUser = catchAsyncErrors(async (req, res, next) => { 7 | const { token } = req.cookies; 8 | 9 | if (!token) { 10 | return next(new ErrorHandler("Please Login for access this resource", 401)); 11 | } 12 | 13 | const decodedData = jwt.verify(token, process.env.JWT_SECRET_KEY); 14 | 15 | req.user = await User.findById(decodedData.id); 16 | 17 | next(); 18 | }); 19 | 20 | // Admin Roles 21 | exports.authorizeRoles = (...roles) => { 22 | return (req, res, next) => { 23 | if (!roles.includes(req.user.role)) { 24 | return next( 25 | new ErrorHandler(`${req.user.role} can not access this resources`) 26 | ); 27 | } 28 | next(); 29 | }; 30 | }; 31 | -------------------------------------------------------------------------------- /frontend/src/component/user/Profile.css: -------------------------------------------------------------------------------- 1 | .profileContainer { 2 | width: 100%; 3 | display: flex; 4 | align-items: center; 5 | justify-content: center; 6 | padding: 1vmax 0px; 7 | } 8 | 9 | img.profile__img { 10 | border-radius: 100%; 11 | height: 150px; 12 | width: 150px; 13 | object-fit: cover; 14 | border: 4px solid #2f6ddf; 15 | } 16 | .edit__profile{ 17 | color: #0a8ef7; 18 | font-family: "Poppins"; 19 | width: 100%; 20 | text-align: end; 21 | padding: .5vmax 0px; 22 | } 23 | .information { 24 | display: flex; 25 | flex-direction: column; 26 | align-items: center; 27 | justify-content: center; 28 | } 29 | .info { 30 | display: flex; 31 | padding: 5px 0px; 32 | } 33 | .change__info { 34 | display: flex; 35 | flex-direction: column; 36 | padding: 2vmax 0; 37 | } 38 | a.settings { 39 | color: #1c6068; 40 | font-family: 'Poppins'; 41 | font-weight: 600; 42 | } -------------------------------------------------------------------------------- /backend/routes/OrderRoute.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { 3 | createOrder, 4 | getSingleOrder, 5 | getAllOrders, 6 | getAdminAllOrders, 7 | updateAdminOrder, 8 | deleteOrder, 9 | } = require("../controller/OrderController"); 10 | const { isAuthenticatedUser, authorizeRoles } = require("../middleware/auth"); 11 | const router = express.Router(); 12 | 13 | router.route("/order/new").post(isAuthenticatedUser, createOrder); 14 | 15 | router.route("/order/:id").get(isAuthenticatedUser, getSingleOrder); 16 | 17 | router.route("/orders/me").get(isAuthenticatedUser, getAllOrders); 18 | 19 | router 20 | .route("/admin/orders") 21 | .get(isAuthenticatedUser, authorizeRoles("admin"), getAdminAllOrders); 22 | 23 | router 24 | .route("/admin/order/:id") 25 | .put(isAuthenticatedUser, authorizeRoles("admin"), updateAdminOrder) 26 | .delete(isAuthenticatedUser, authorizeRoles("admin"), deleteOrder); 27 | 28 | module.exports = router; 29 | -------------------------------------------------------------------------------- /frontend/src/component/Admin/Sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | background-color: rgb(255, 255, 255); 3 | position: sticky; 4 | top: 0; 5 | left: 0; 6 | display: flex; 7 | flex-direction: column; 8 | overflow: hidden; 9 | height: 100vh; 10 | } 11 | 12 | .sidebar > a:first-child { 13 | padding: 0; 14 | } 15 | .sidebar > a > img { 16 | width: 100%; 17 | transition: all 0.5s; 18 | padding: 1vmax 0; 19 | } 20 | 21 | .sidebar a { 22 | text-decoration: none; 23 | color: rgba(0, 0, 0, 0.493); 24 | font: 200 1rem "Roboto"; 25 | padding: 1.8rem 1.2rem; 26 | transition: all 0.5s; 27 | } 28 | .sidebar a > P { 29 | display: flex; 30 | align-items: center; 31 | } 32 | .sidebar a > p > svg { 33 | margin-right: 0.5rem; 34 | } 35 | 36 | .MuiTypography-root { 37 | background-color: #fff !important; 38 | } 39 | .MuiTypography-root.MuiTreeItem-label.MuiTypography-body1 { 40 | color: #999; 41 | } -------------------------------------------------------------------------------- /frontend/src/route/ProtectedRoute.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useSelector } from 'react-redux' 3 | import { Redirect,Route } from 'react-router-dom'; 4 | 5 | const ProtectedRoute = ({isAdmin, component: Component, ...rest}) => { 6 | 7 | const {loading, isAuthenticated, user} = useSelector((state) => state.user); 8 | 9 | return ( 10 | <> 11 | {loading === false && ( 12 | { 16 | if(isAuthenticated === false){ 17 | return 18 | } 19 | if(isAdmin === true && user.role !=="admin"){ 20 | return 21 | } 22 | return 23 | } 24 | } 25 | /> 26 | )} 27 | 28 | ) 29 | } 30 | 31 | export default ProtectedRoute 32 | -------------------------------------------------------------------------------- /frontend/src/more/CommingSoon.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { useSelector } from 'react-redux'; 3 | import "./CommingSoon.css"; 4 | import BottomTab from './BottomTab'; 5 | import Loading from './Loader'; 6 | import MetaData from './Metadata'; 7 | 8 | const CommingSoon = () => { 9 | 10 | const {loading} = useSelector( 11 | (state) => state.cart 12 | ); 13 | 14 | return ( 15 | <> 16 | {loading ? () : ( 17 | <> 18 | 19 |
20 |
21 | CommingSoon.... 22 |
23 |
24 | 25 |
26 |
27 |
28 |
29 | 30 | 31 | )} 32 | 33 | ) 34 | } 35 | 36 | export default CommingSoon 37 | -------------------------------------------------------------------------------- /frontend/src/component/cart/orderSuccess.css: -------------------------------------------------------------------------------- 1 | .orderSuccess { 2 | margin: auto; 3 | text-align: center; 4 | padding: 10vmax; 5 | height: 50vh; 6 | display: flex; 7 | flex-direction: column; 8 | justify-content: center; 9 | align-items: center; 10 | } 11 | .orderSuccess > svg { 12 | font-size: 7vmax; 13 | color: #3BB77E; 14 | } 15 | .orderSuccess > p { 16 | font-size: 2vmax; 17 | } 18 | .orderSuccess > a { 19 | background-color: #3BB77E; 20 | color: white; 21 | border: none; 22 | padding: 1vmax 3vmax; 23 | cursor: pointer; 24 | font: 400 1vmax "Roboto"; 25 | text-decoration: none; 26 | margin: 2vmax; 27 | } 28 | 29 | @media screen and (max-width: 600px) { 30 | .orderSuccess > a { 31 | padding: 3vw 6vw; 32 | font: 400 4vw "Roboto"; 33 | margin: 2vmax; 34 | } 35 | 36 | .orderSuccess > svg { 37 | font-size: 20vw; 38 | } 39 | .orderSuccess > p { 40 | margin: 2vmax; 41 | font-size: 5vw; 42 | } 43 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "full_stack-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": " backend/server.js", 6 | "engines": { 7 | "node": "17.9.0" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "start": "node backend/server.js", 12 | "dev": "nodemon backend/server.js", 13 | "heroku-postbuild": "NPM_CONFIG_PRODUCTION=false && npm install --prefix frontend && npm run build --prefix frontend" 14 | }, 15 | "author": "Nitish Kumar", 16 | "license": "ISC", 17 | "dependencies": { 18 | "@material-ui/core": "^4.12.3", 19 | "bcryptjs": "^2.4.3", 20 | "body-parser": "^1.19.1", 21 | "cloudinary": "^1.29.0", 22 | "cookie-parser": "^1.4.6", 23 | "dotenv": "^16.0.0", 24 | "express": "^4.17.2", 25 | "express-fileupload": "^1.3.1", 26 | "jsonwebtoken": "^9.0.0", 27 | "mongoose": "^6.1.4", 28 | "nodemailer": "^6.7.2", 29 | "nodemon": "^2.0.15", 30 | "npm": "^8.7.0", 31 | "stripe": "^8.215.0", 32 | "validator": "^13.7.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /frontend/src/component/Admin/UpdateOrder.css: -------------------------------------------------------------------------------- 1 | .updateOrderForm { 2 | margin: 5vmax 0; 3 | padding: 3vmax; 4 | background-color: white; 5 | } 6 | 7 | .updateOrderForm > div { 8 | display: flex; 9 | width: 100%; 10 | align-items: center; 11 | } 12 | .updateOrderForm > div > select { 13 | padding: 1vmax 4vmax; 14 | margin: 2rem 0; 15 | width: 100%; 16 | box-sizing: border-box; 17 | border: 1px solid rgba(0, 0, 0, 0.267); 18 | border-radius: 4px; 19 | font: 300 0.9vmax cursive; 20 | outline: none; 21 | } 22 | 23 | .updateOrderForm > div > svg { 24 | position: absolute; 25 | transform: translateX(1vmax); 26 | font-size: 1.6vmax; 27 | color: rgba(0, 0, 0, 0.623); 28 | } 29 | 30 | @media screen and (max-width: 600px) { 31 | .updateOrderForm { 32 | padding: 5vmax; 33 | } 34 | 35 | .updateOrderForm > div > select { 36 | padding: 2.5vmax 5vmax; 37 | font: 300 1.7vmax cursive; 38 | } 39 | 40 | .updateOrderForm > div > svg { 41 | font-size: 2.8vmax; 42 | } 43 | } -------------------------------------------------------------------------------- /frontend/src/component/Products/Product.css: -------------------------------------------------------------------------------- 1 | .pagination{ 2 | display: flex; 3 | align-items: center; 4 | padding: 0; 5 | } 6 | .page-item{ 7 | background-color: #fff; 8 | list-style: none; 9 | border: 1px solid rgba(0,0,0,0.178); 10 | padding: 1vmax 1.5vmax; 11 | transition: all 0.3s; 12 | cursor: pointer; 13 | } 14 | .page-item:first-child{ 15 | border-radius: 5px 0 0 5px; 16 | } 17 | .page-item:last-child{ 18 | border-top-right-radius: 5px; 19 | border-bottom-right-radius: 5px; 20 | 21 | } 22 | .page-link{ 23 | font: 300 0.7vmax "Roboto"; 24 | color: rgb(80,80,80); 25 | transition: all 0.3s; 26 | } 27 | .page-item:hover{ 28 | background-color: rgb(230,230,230); 29 | } 30 | .page-item:hover .page-link{ 31 | color: rgb(37, 37, 37); 32 | } 33 | .pageItemActive{ 34 | background-color: #197EF3; 35 | } 36 | .pageLinkActive{ 37 | color: white; 38 | } 39 | .category-link{ 40 | list-style: none; 41 | font-family: Roboto; 42 | cursor: pointer; 43 | border-top: 1px solid #999; 44 | padding: 10px 10px; 45 | } 46 | -------------------------------------------------------------------------------- /backend/utils/Features.js: -------------------------------------------------------------------------------- 1 | class Features { 2 | constructor(query, queryStr) { 3 | this.query = query; 4 | this.queryStr = queryStr; 5 | } 6 | 7 | // Search the Product 8 | search() { 9 | const keyword = this.queryStr.keyword 10 | ? { 11 | name: { 12 | $regex: this.queryStr.keyword, 13 | $options: "i", 14 | }, 15 | } 16 | : {}; 17 | this.query = this.query.find({ ...keyword }); 18 | return this; 19 | } 20 | 21 | // Filter the product by Category 22 | filter() { 23 | const queryCopy = { ...this.queryStr }; 24 | 25 | // Removing some field for category 26 | const removeFields = ["keyword", "page", "limit"]; 27 | 28 | removeFields.forEach((key) => delete queryCopy[key]); 29 | 30 | this.query = this.query.find(queryCopy); 31 | return this; 32 | } 33 | 34 | // Pagination 35 | pagination(resultPerPage) { 36 | const currentPage = Number(this.queryStr.page) || 1; 37 | const skip = resultPerPage * (currentPage - 1); 38 | 39 | this.query = this.query.limit(resultPerPage).skip(skip); 40 | 41 | return this; 42 | } 43 | } 44 | 45 | module.exports = Features; 46 | -------------------------------------------------------------------------------- /frontend/src/actions/FavouriteAction.js: -------------------------------------------------------------------------------- 1 | import { ADD_TO_FAVOURITE, ADD_TO_FAVOURITE_OFFER, REMOVE_FROM_FAVOURITE, REMOVE_FROM_FAVOURITE_OFFER} 2 | from "../constans/FavouriteConstans"; 3 | import axios from "axios"; 4 | 5 | // Add to favourites 6 | export const addFavouriteItemsToCart = (id,quantity) => async (dispatch, getState) =>{ 7 | const {data} = await axios.get(`/api/v2/product/${id}`); 8 | 9 | dispatch({ 10 | type: ADD_TO_FAVOURITE, 11 | payload: { 12 | product: data.product._id, 13 | name: data.product.name, 14 | price: data.product.price, 15 | image: data.product.images[0].url, 16 | stock: data.product.Stock, 17 | quantity, 18 | } 19 | }) 20 | 21 | localStorage.setItem("favouriteItems", JSON.stringify(getState().favourite.favouriteItems)); 22 | } 23 | 24 | // Delete from favourites 25 | export const deleteFavouriteItemsToCart = (id) => async (dispatch, getState) => { 26 | dispatch({ 27 | type: REMOVE_FROM_FAVOURITE, 28 | payload: id, 29 | }); 30 | 31 | localStorage.setItem("favouriteItems", JSON.stringify(getState().favourite.favouriteItems)); 32 | }; 33 | -------------------------------------------------------------------------------- /backend/routes/ProductRoute.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { 3 | getAllProducts, 4 | createProduct, 5 | updateProduct, 6 | deleteProduct, 7 | getSingleProduct, 8 | createProductReview, 9 | getSingleProductReviews, 10 | deleteReview, 11 | } = require("../controller/ProductController"); 12 | const { isAuthenticatedUser, authorizeRoles } = require("../middleware/auth"); 13 | const router = express.Router(); 14 | 15 | router.route("/products").get(getAllProducts); 16 | 17 | router 18 | .route("/admin/products") 19 | .get(isAuthenticatedUser, authorizeRoles("admin"), getAllProducts); 20 | 21 | router 22 | .route("/product/new") 23 | .post(isAuthenticatedUser, authorizeRoles("admin"), createProduct); 24 | 25 | router 26 | .route("/product/:id") 27 | .put(isAuthenticatedUser, authorizeRoles("admin"), updateProduct) 28 | .delete(isAuthenticatedUser, authorizeRoles("admin"), deleteProduct) 29 | .get(getSingleProduct); 30 | 31 | router.route("/product/review").post(isAuthenticatedUser, createProductReview); 32 | 33 | router 34 | .route("/reviews") 35 | .get(getSingleProductReviews) 36 | .delete(isAuthenticatedUser, authorizeRoles("admin"), deleteReview); 37 | 38 | module.exports = router; 39 | -------------------------------------------------------------------------------- /backend/middleware/error.js: -------------------------------------------------------------------------------- 1 | const ErrorHandler = require("../utils/ErrorHandler"); 2 | 3 | module.exports = (err,req,res,next) =>{ 4 | err.statusCode = err.statusCode || 500 5 | err.message = err.message || "Interval server error" 6 | 7 | // wrong mongodb id error 8 | if(err.name === "CastError"){ 9 | const message = `Resources not found with this id..Invalid ${err.path}`; 10 | err = new ErrorHandler(message, 400) 11 | 12 | } 13 | 14 | 15 | // Duplicate key error 16 | if (err.code === 11000) { 17 | const message = `Duplicate ${Object.keys(err.keyValue)} Entered`; 18 | err = new ErrorHandler(message, 400); 19 | } 20 | 21 | // Wrong Jwt error 22 | if (err.name === "JsonWebTokenError") { 23 | const message = `Your url is invalid please try again`; 24 | err = new ErrorHandler(message, 400); 25 | } 26 | 27 | //Jwt expired error 28 | if (err.name === "TokenExpiredError") { 29 | const message = `Your url is expired please try again`; 30 | err = new ErrorHandler(message, 400); 31 | } 32 | 33 | res.status(err.statusCode).json({ 34 | success: false, 35 | message: err.message 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /frontend/src/component/Products/Search.css: -------------------------------------------------------------------------------- 1 | .searchBox { 2 | width: 100vw; 3 | height: 100vh; 4 | max-width: 100%; 5 | display: flex; 6 | justify-content: center; 7 | align-items: center; 8 | background-color: rgb(231, 231, 231); 9 | position: fixed; 10 | top: 0%; 11 | left: 0; 12 | } 13 | 14 | .searchBox > input[type="text"] { 15 | box-shadow: 0 0 5px rgba(0, 0, 0, 0.274); 16 | background-color: white; 17 | color: rgba(0, 0, 0, 0.637); 18 | padding: 1vmax 2vmax; 19 | width: 50%; 20 | outline: none; 21 | border: 2px solid #197EF3; 22 | border-radius: 8px; 23 | font: 300 1.1vmax cursive; 24 | box-sizing: border-box; 25 | height: 8%; 26 | } 27 | @media screen and (max-width: 600px) { 28 | .searchBox > input[type="text"] { 29 | width: 100%; 30 | font: 300 4vw cursive; 31 | height: 10%; 32 | } 33 | 34 | .searchBox > input[type="submit"] { 35 | height: 10%; 36 | width: 30%; 37 | font: 300 4vw "Roboto"; 38 | } 39 | } 40 | @media screen and (max-width: 600px) { 41 | .searchBox > input[type="text"]{ 42 | margin: 0 5%; 43 | } 44 | svg.bi.bi-search.pointer{ 45 | right: 9%!important; 46 | } 47 | } -------------------------------------------------------------------------------- /backend/server.js: -------------------------------------------------------------------------------- 1 | const app = require("./app"); 2 | // const dotenv = require("dotenv"); 3 | const connectDatabase = require("./db/Database.js"); 4 | const cloudinary = require("cloudinary"); 5 | 6 | // Handling uncaught Exception 7 | process.on("uncaughtException", (err) => { 8 | console.log(`Error: ${err.message}`); 9 | console.log(`Shutting down the server for Handling uncaught Exception`); 10 | }); 11 | 12 | // config 13 | if (process.env.NODE_ENV !== "PRODUCTION") { 14 | require("dotenv").config({ 15 | path: "backend/config/.env", 16 | }); 17 | } 18 | 19 | // Connect Database 20 | connectDatabase(); 21 | 22 | cloudinary.config({ 23 | cloud_name: process.env.CLOUDINARY_NAME, 24 | api_key: process.env.CLOUDINARY_API_KEY, 25 | api_secret: process.env.CLOUDINARY_API_SECRET, 26 | }); 27 | 28 | // create server 29 | const server = app.listen(process.env.PORT, () => { 30 | console.log(`Server is running on http://localhost: ${process.env.PORT}`); 31 | }); 32 | 33 | // Unhandled promise rejection 34 | process.on("unhandledRejection", (err) => { 35 | console.log(`Shutting down server for ${err.message}`); 36 | console.log(`Shutting down the server due to Unhandled promise rejection`); 37 | server.close(() => { 38 | process.exit(1); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /frontend/src/constans/OrderConstans.js: -------------------------------------------------------------------------------- 1 | export const CREATE_ORDER_REQUEST = "CREATE_ORDER_REQUEST"; 2 | export const CREATE_ORDER_SUCCESS = "CREATE_ORDER_SUCCESS"; 3 | export const CREATE_ORDER_FAIL = "CREATE_ORDER_FAIL"; 4 | 5 | export const MY_ORDERS_REQUEST = "MY_ORDERS_REQUEST"; 6 | export const MY_ORDERS_SUCCESS = "MY_ORDERS_SUCCESS"; 7 | export const MY_ORDERS_FAIL = "MY_ORDERS_FAIL"; 8 | 9 | export const ALL_ORDERS_REQUEST = "ALL_ORDERS_REQUEST"; 10 | export const ALL_ORDERS_SUCCESS = "ALL_ORDERS_SUCCESS"; 11 | export const ALL_ORDERS_FAIL = "ALL_ORDERS_FAIL"; 12 | 13 | export const UPDATE_ORDER_REQUEST = "UPDATE_ORDER_REQUEST"; 14 | export const UPDATE_ORDER_SUCCESS = "UPDATE_ORDER_SUCCESS"; 15 | export const UPDATE_ORDER_RESET = "UPDATE_ORDER_RESET"; 16 | export const UPDATE_ORDER_FAIL = "UPDATE_ORDER_FAIL"; 17 | 18 | export const DELETE_ORDER_REQUEST = "DELETE_ORDER_REQUEST"; 19 | export const DELETE_ORDER_SUCCESS = "DELETE_ORDER_SUCCESS"; 20 | export const DELETE_ORDER_RESET = "DELETE_ORDER_RESET"; 21 | export const DELETE_ORDER_FAIL = "DELETE_ORDER_FAIL"; 22 | 23 | export const ORDER_DETAILS_REQUEST = "ORDER_DETAILS_REQUEST"; 24 | export const ORDER_DETAILS_SUCCESS = "ORDER_DETAILS_SUCCESS"; 25 | export const ORDER_DETAILS_FAIL = "ORDER_DETAILS_FAIL"; 26 | 27 | export const CLEAR_ERRORS = "CLEAR_ERRORS"; -------------------------------------------------------------------------------- /frontend/src/reducers/CartReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_TO_CART, 3 | REMOVE_CART_ITEM, 4 | SAVE_SHIPPING_INFO, 5 | } from "../constans/CartConstans"; 6 | 7 | export const cartReducer = ( 8 | state = { cartItems: [], shippingInfo: {} }, 9 | action 10 | ) => { 11 | switch (action.type) { 12 | case ADD_TO_CART: 13 | const item = action.payload; 14 | 15 | const isItemExist = state.cartItems.find( 16 | (i) => i.product === item.product 17 | ); 18 | 19 | if (isItemExist) { 20 | return { 21 | ...state, 22 | cartItems: state.cartItems.map((i) => 23 | i.product === isItemExist.product ? item : i 24 | ), 25 | }; 26 | } else { 27 | return { 28 | ...state, 29 | cartItems: [...state.cartItems, item], 30 | }; 31 | } 32 | 33 | case REMOVE_CART_ITEM: 34 | return { 35 | ...state, 36 | cartItems: state.cartItems.filter((i) => i.product !== action.payload), 37 | }; 38 | 39 | case SAVE_SHIPPING_INFO: 40 | return { 41 | ...state, 42 | shippingInfo: action.payload, 43 | }; 44 | 45 | default: 46 | return state; 47 | 48 | } 49 | }; 50 | 51 | -------------------------------------------------------------------------------- /frontend/src/reducers/FavouriteReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_TO_FAVOURITE, 3 | REMOVE_FROM_FAVOURITE, 4 | } from "../constans/FavouriteConstans"; 5 | 6 | export const favouriteReducer = ( 7 | state = {favouriteItems: []}, 8 | action 9 | ) => { 10 | switch (action.type){ 11 | case ADD_TO_FAVOURITE: 12 | const item = action.payload; 13 | 14 | const isItemExist = state.favouriteItems.find( 15 | (i) => i.product === item.product 16 | ); 17 | 18 | if (isItemExist) { 19 | return { 20 | ...state, 21 | favouriteItems: state.favouriteItems.map((i) => 22 | i.product === isItemExist.product ? item : i 23 | ), 24 | }; 25 | } else { 26 | return { 27 | ...state, 28 | favouriteItems: [...state.favouriteItems, item], 29 | }; 30 | } 31 | 32 | case REMOVE_FROM_FAVOURITE: 33 | return{ 34 | ...state, 35 | favouriteItems: state.favouriteItems.filter((i) => i.product !== action.payload), 36 | }; 37 | 38 | default: 39 | return state; 40 | } 41 | }; 42 | 43 | -------------------------------------------------------------------------------- /frontend/src/more/CommingSoon.css: -------------------------------------------------------------------------------- 1 | .bg{ 2 | background-color: #252839; 3 | width: 100%; 4 | height: 100vh; 5 | display: flex; 6 | align-items: center; 7 | justify-content: center; 8 | } 9 | .bg span{ 10 | font-size: 10vh; 11 | color: #252839; 12 | position: relative; 13 | letter-spacing: 5px; 14 | -webkit-text-stroke: 0.3vw #383d52; 15 | text-transform: uppercase; 16 | padding: 0px 10px; 17 | } 18 | .bg span::before{ 19 | content: attr(dataText); 20 | position: absolute; 21 | top: 0; 22 | letter-spacing: 5px; 23 | left: 0; 24 | width: 0%; 25 | height: 100%; 26 | color: #01fe87; 27 | -webkit-text-stroke: 0vw #383d52; 28 | padding: 0px 10px; 29 | overflow: hidden; 30 | animation: animate 6s linear infinite; 31 | } 32 | @keyframes animate { 33 | 0%,10%,100%{ 34 | width: 0%; 35 | } 36 | 70%,90%{ 37 | width: 100%; 38 | } 39 | } 40 | .circle{ 41 | width:35px; 42 | height: 35px; 43 | border-radius: 50%; 44 | background-color: yellow; 45 | position: fixed; 46 | top: 10%; 47 | right: 10%; 48 | border: none; 49 | animation: zoom 3s linear infinite; 50 | } 51 | @keyframes zoom { 52 | 0%,100%{ 53 | transform: scale(1.5); 54 | } 55 | 50%{ 56 | transform: scale(.7); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /backend/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const app = express(); 3 | const ErrorHandler = require("./middleware/error"); 4 | const cookieParser = require("cookie-parser"); 5 | const fileUpload = require("express-fileupload"); 6 | const path = require("path"); 7 | 8 | app.use(express.json()); 9 | app.use(cookieParser()); 10 | app.use(express.json({ limit: "50mb" })); 11 | app.use(express.urlencoded({ limit: "50mb", extended: true })); 12 | app.use(fileUpload()); 13 | 14 | // config 15 | if (process.env.NODE_ENV !== "PRODUCTION") { 16 | require("dotenv").config({ 17 | path: "backend/config/.env", 18 | }); 19 | } 20 | 21 | // Route imports 22 | const product = require("./routes/ProductRoute"); 23 | const user = require("./routes/UserRoute"); 24 | const order = require("./routes/OrderRoute"); 25 | const payment = require("./routes/PaymentRoute"); 26 | 27 | app.use("/api/v2", product); 28 | 29 | app.use("/api/v2", user); 30 | 31 | app.use("/api/v2", order); 32 | 33 | app.use("/api/v2", payment); 34 | 35 | app.use(express.static(path.join(__dirname, "../frontend/build"))); 36 | app.get("/", (req, res) => { 37 | res.send("Hello World"); 38 | }); 39 | 40 | app.get("*", (req, res) => { 41 | res.sendFile(path.resolve(__dirname, "../frontend/build/index.html")); 42 | }); 43 | 44 | // it's for errorHandeling 45 | app.use(ErrorHandler); 46 | 47 | module.exports = app; 48 | -------------------------------------------------------------------------------- /frontend/src/actions/CartAction.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_TO_CART, 3 | REMOVE_CART_ITEM, 4 | SAVE_SHIPPING_INFO, 5 | } from "../constans/CartConstans"; 6 | import axios from "axios"; 7 | 8 | // Add to Cart ---Product 9 | export const addItemsToCart = (id, quantity) => async (dispatch, getState) => { 10 | const { data } = await axios.get(`/api/v2/product/${id}`); 11 | 12 | dispatch({ 13 | type: ADD_TO_CART, 14 | payload: { 15 | product: data.product._id, 16 | name: data.product.name, 17 | price: data.product.price, 18 | image: data.product.images[0].url, 19 | stock: data.product.Stock, 20 | quantity, 21 | }, 22 | }); 23 | 24 | localStorage.setItem("cartItems", JSON.stringify(getState().cart.cartItems)); 25 | }; 26 | 27 | // REMOVE FROM CART ---Product 28 | export const removeItemsFromCart = (id) => async (dispatch, getState) => { 29 | dispatch({ 30 | type: REMOVE_CART_ITEM, 31 | payload: id, 32 | }); 33 | 34 | localStorage.setItem("cartItems", JSON.stringify(getState().cart.cartItems)); 35 | }; 36 | 37 | 38 | // SAVE SHIPPING INFO 39 | export const saveShippingInfo = (data) => async (dispatch) => { 40 | dispatch({ 41 | type: SAVE_SHIPPING_INFO, 42 | payload: data, 43 | }); 44 | 45 | localStorage.setItem("shippingInfo", JSON.stringify(data)); 46 | }; -------------------------------------------------------------------------------- /backend/routes/UserRoute.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const { 3 | createUser, 4 | loginUser, 5 | logoutUser, 6 | forgotPassword, 7 | resetPassword, 8 | userDetails, 9 | updatePassword, 10 | updateProfile, 11 | getAllUsers, 12 | getSingleUser, 13 | updateUserRole, 14 | deleteUser, 15 | } = require("../controller/UserController"); 16 | const { isAuthenticatedUser, authorizeRoles } = require("../middleware/auth"); 17 | const router = express.Router(); 18 | 19 | router.route("/registration").post(createUser); 20 | 21 | router.route("/login").post(loginUser); 22 | 23 | 24 | router.route("/logout").get(logoutUser); 25 | 26 | router.route("/password/forgot").post(forgotPassword); 27 | 28 | router.route("/password/reset/:token").put(resetPassword); 29 | 30 | router.route("/me/update").put(isAuthenticatedUser, updatePassword); 31 | 32 | router.route("/me/update/info").put(isAuthenticatedUser, updateProfile); 33 | 34 | router.route("/me").get(isAuthenticatedUser, userDetails); 35 | 36 | router 37 | .route("/admin/users") 38 | .get(isAuthenticatedUser, authorizeRoles("admin"), getAllUsers); 39 | 40 | router 41 | .route("/admin/user/:id") 42 | .get(isAuthenticatedUser, authorizeRoles("admin"), getSingleUser) 43 | .put(isAuthenticatedUser, authorizeRoles("admin"), updateUserRole) 44 | .delete(isAuthenticatedUser, authorizeRoles("admin"), deleteUser); 45 | 46 | module.exports = router; 47 | -------------------------------------------------------------------------------- /frontend/src/component/Admin/AllProducts.css: -------------------------------------------------------------------------------- 1 | .productListContainer { 2 | width: 94%; 3 | box-sizing: border-box; 4 | background-color: rgb(255, 255, 255); 5 | border-left: 1px solid rgba(0, 0, 0, 0.158); 6 | display: flex; 7 | flex-direction: column; 8 | height: 100vh; 9 | 10 | } 11 | .MuiDataGrid-columnHeader{ 12 | background: #3BB77E; 13 | } 14 | 15 | #productListHeading { 16 | font: 400 2rem "Roboto"; 17 | padding: 0.5vmax; 18 | box-sizing: border-box; 19 | color: rgba(0, 0, 0, 0.637); 20 | transition: all 0.5s; 21 | margin: 1.5rem; 22 | text-align: center; 23 | } 24 | 25 | .productListTable { 26 | background-color: white; 27 | border: none !important; 28 | } 29 | 30 | .productListTable div { 31 | font: 300 1vmax "Roboto"; 32 | color: rgba(0, 0, 0, 0.678); 33 | border: none !important; 34 | } 35 | 36 | .productListTable a, 37 | .productListTable button { 38 | color: rgba(0, 0, 0, 0.527); 39 | transition: all 0.5s; 40 | } 41 | 42 | .productListTable a:hover { 43 | color: tomato; 44 | } 45 | 46 | .productListTable button:hover { 47 | color: rgb(236, 30, 30); 48 | } 49 | 50 | .MuiDataGrid-columnHeader div { 51 | color: rgb(255, 255, 255); 52 | } 53 | 54 | @media screen and (max-width: 600px) { 55 | .productListTable div { 56 | font: 300 4vw "Roboto"; 57 | } 58 | } -------------------------------------------------------------------------------- /frontend/src/component/cart/CartItemCard.css: -------------------------------------------------------------------------------- 1 | .CartItemCard { 2 | display: flex; 3 | padding: 1vmax; 4 | height: 8vmax; 5 | align-items: flex-start; 6 | box-sizing: border-box; 7 | } 8 | .CartItemCard > img { 9 | width: 5vmax; 10 | } 11 | 12 | .CartItemCard > div { 13 | display: flex; 14 | margin: 0.3vmax 1vmax; 15 | flex-direction: column; 16 | } 17 | 18 | .CartItemCard > div > a { 19 | font: 300 0.9vmax cursive; 20 | color: rgba(24, 24, 24, 0.815); 21 | text-decoration: none; 22 | } 23 | 24 | .CartItemCard > div > span { 25 | font: 300 0.9vmax "Roboto"; 26 | color: rgba(24, 24, 24, 0.815); 27 | } 28 | 29 | .CartItemCard > div > Button { 30 | width:140px; 31 | border-radius:5px; 32 | color: red; 33 | padding: 7px; 34 | border: 1px solid black; 35 | margin-top: 2px; 36 | } 37 | 38 | .CartItemCard > div > Button:hover { 39 | background-color: red; 40 | color: white; 41 | } 42 | 43 | @media screen and (max-width: 600px) { 44 | .CartItemCard { 45 | padding: 3vmax; 46 | height: 25vmax; 47 | } 48 | .CartItemCard > img { 49 | width: 10vmax; 50 | } 51 | 52 | .CartItemCard > div { 53 | margin: 1vmax 2vmax; 54 | } 55 | 56 | .CartItemCard > div > a { 57 | font: 300 2vmax cursive; 58 | } 59 | 60 | .CartItemCard > div > span { 61 | font: 300 1.9vmax "Roboto"; 62 | } 63 | 64 | .CartItemCard > div > p { 65 | font: 100 1.8vmax "Roboto"; 66 | } 67 | } -------------------------------------------------------------------------------- /frontend/src/component/Products/ProductCard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import { Rating } from "@material-ui/lab"; 4 | import "./ProductCard.css"; 5 | const ProductCard = ({ product }) => { 6 | const options = { 7 | value: product.ratings, 8 | readOnly: true, 9 | precision: 0.5, 10 | }; 11 | 12 | return ( 13 | <> 14 | 15 | {product.name} 20 |

{product.name}

21 |
22 | 23 | ({product.numOfReviews} Reviews) 24 |
25 |
31 |
32 |

41 | {product.offerPrice > 0 ? `${product.offerPrice}%` : ""} 42 |

43 | {`$${product.price}.00`} 44 |
45 |
46 | 47 | 48 | ); 49 | }; 50 | 51 | export default ProductCard; 52 | -------------------------------------------------------------------------------- /frontend/src/component/Products/Search.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, Fragment } from "react"; 2 | import BottomTab from "../../more/BottomTab"; 3 | import MetaData from "../../more/Metadata"; 4 | import "./Search.css"; 5 | 6 | const Search = ({ history }) => { 7 | const [keyword, setKeyword] = useState(""); 8 | 9 | const searchSubmitHandler = (e) => { 10 | e.preventDefault(); 11 | if (keyword.trim()) { 12 | history.push(`/products/${keyword}`); 13 | } else { 14 | history.push("/products"); 15 | } 16 | }; 17 | 18 | return ( 19 | 20 | 21 |
22 | setKeyword(e.target.value)} 26 | /> 27 | 40 | 41 | 42 |
43 | 44 |
45 | ); 46 | }; 47 | 48 | export default Search; 49 | -------------------------------------------------------------------------------- /frontend/src/component/Products/ReviewCard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { useSelector } from "react-redux"; 3 | import { Rating } from "@material-ui/lab"; 4 | import Loading from "../../more/Loader"; 5 | 6 | const ReviewCard = ({ review }) => { 7 | // eslint-disable-next-line 8 | 9 | const { loading } = useSelector((state) => state.productDetails); 10 | 11 | const options = { 12 | value: review.rating, 13 | readOnly: true, 14 | precision: 0.5, 15 | color: "#3BB77E", 16 | }; 17 | 18 | return ( 19 | <> 20 | {loading ? ( 21 | 22 | ) : ( 23 | <> 24 |
31 |

38 | {review.name} 39 |

40 |

41 | {String(review.time).substr(0, 10)} 42 |

43 |
44 |
45 |

46 | {review.comment} 47 |

48 | 49 |
50 | 51 | )} 52 | 53 | ); 54 | }; 55 | 56 | export default ReviewCard; 57 | -------------------------------------------------------------------------------- /frontend/src/component/Admin/productReviews.css: -------------------------------------------------------------------------------- 1 | .productReviewsContainer { 2 | width: 100%; 3 | box-sizing: border-box; 4 | background-color: rgb(255, 255, 255); 5 | border-left: 1px solid rgba(0, 0, 0, 0.158); 6 | height: 100vh; 7 | } 8 | 9 | .productReviewsForm { 10 | width: 20rem; 11 | display: flex; 12 | flex-direction: column; 13 | align-items: center; 14 | margin: auto; 15 | padding: 3vmax; 16 | background-color: white; 17 | } 18 | 19 | .productReviewsFormHeading { 20 | color: rgba(0, 0, 0, 0.733); 21 | font: 300 2rem "Roboto"; 22 | text-align: center; 23 | } 24 | 25 | .productReviewsForm > div { 26 | display: flex; 27 | width: 100%; 28 | align-items: center; 29 | margin: 2rem; 30 | } 31 | .productReviewsForm > div > input { 32 | padding: 1vmax 4vmax; 33 | padding-right: 1vmax; 34 | width: 100%; 35 | box-sizing: border-box; 36 | border: 1px solid rgba(0, 0, 0, 0.267); 37 | border-radius: 4px; 38 | font: 300 0.9vmax cursive; 39 | outline: none; 40 | } 41 | 42 | .productReviewsForm > div > svg { 43 | position: absolute; 44 | transform: translateX(1vmax); 45 | font-size: 1.6vmax; 46 | color: rgba(0, 0, 0, 0.623); 47 | } 48 | 49 | @media screen and (max-width: 600px) { 50 | .productReviewsContainer { 51 | border-left: none; 52 | border-top: 1px solid rgba(0, 0, 0, 0.158); 53 | } 54 | .productReviewsForm > div > input { 55 | padding: 2.5vmax 5vmax; 56 | font: 300 1.7vmax cursive; 57 | } 58 | 59 | .productReviewsForm > div > svg { 60 | font-size: 2.8vmax; 61 | } 62 | } -------------------------------------------------------------------------------- /frontend/src/component/cart/CheckoutSteps.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Typography, Stepper, StepLabel, Step } from "@material-ui/core"; 3 | import LocalShippingIcon from "@material-ui/icons/LocalShipping"; 4 | import LibraryAddCheckIcon from "@material-ui/icons/LibraryAddCheck"; 5 | import AccountBalanceIcon from "@material-ui/icons/AccountBalance"; 6 | import "./CheckoutSteps.css"; 7 | import BottomTab from "../../more/BottomTab"; 8 | 9 | const CheckoutSteps = ({ activeStep }) => { 10 | const steps = [ 11 | { 12 | label: Shipping Details, 13 | icon: , 14 | }, 15 | { 16 | label: Confirm Order, 17 | icon: , 18 | }, 19 | { 20 | label: Payment, 21 | icon: , 22 | }, 23 | ]; 24 | 25 | const stepStyles = { 26 | boxSizing: "border-box", 27 | }; 28 | 29 | return ( 30 | <> 31 | 32 | {steps.map((item, index) => ( 33 | = index ? true : false} 37 | > 38 | = index ? "#3BB77E" : "rgba(0, 0, 0, 0.649)", 41 | }} 42 | icon={item.icon} 43 | > 44 | {item.label} 45 | 46 | 47 | ))} 48 | 49 | 50 | 51 | ); 52 | }; 53 | 54 | export default CheckoutSteps; -------------------------------------------------------------------------------- /frontend/src/more/Rules.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import "./Rules.css"; 3 | import Header from '../component/Home/Header'; 4 | import BottomTab from './BottomTab'; 5 | import MetaData from './Metadata'; 6 | import Footer from '../Footer'; 7 | 8 | const Rules = () => { 9 | return ( 10 | <> 11 | 12 |
13 |
19 |
    20 | Some Rules: 26 |
  • 1. You can easily return your product..But you have to give us the delivery charge...
  • 27 |
  • 2. You have to give delivery charge first for cash on Delivery..In Los Angeles City you have to give 70tk and outside jashore charge will be 120 tk
  • 28 |
  • 3. You can not buy the outofstock products...
  • 29 |
  • 4. You can buy any products from us...we are trying to our best for give the best quality of products...
  • 30 |
  • 5. You can find more new features in our buiseness in very soon...Our developers team always work for your good services...
  • 31 |
  • 6. At last thanks for visit our website...Have a good day !
  • 32 |
33 |
34 |