├── README.md └── server ├── .gitignore ├── README.md ├── client ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo.png │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt └── src │ ├── App.js │ ├── assets │ ├── admin.png │ ├── full-page.png │ ├── images │ │ ├── Capture.png │ │ ├── banner-1.webp │ │ ├── banner-2.webp │ │ ├── banner-3.webp │ │ ├── camera-1.webp │ │ ├── camera-15webp.webp │ │ ├── camera-2.webp │ │ ├── camera-3.webp │ │ ├── camera-4.webp │ │ ├── camera-5.webp │ │ ├── camera-6.webp │ │ ├── camera-7.webp │ │ ├── camera-8.webp │ │ ├── company-1.webp │ │ ├── company-2.webp │ │ ├── company-3.webp │ │ ├── company-4.webp │ │ ├── company-5.png │ │ ├── company-6.webp │ │ ├── discount-area.webp │ │ ├── home-banner-1.webp │ │ ├── home-banner-2.webp │ │ ├── home-banner-3.webp │ │ ├── home-banner-4.webp │ │ ├── home-banner-5.webp │ │ ├── home-banner-6.webp │ │ ├── logo.png │ │ ├── protected-area.webp │ │ ├── upload-1.png │ │ └── upload.png │ ├── index.js │ └── user.png │ ├── components │ ├── Banner │ │ └── Banner.jsx │ ├── CartSummary │ │ └── CartSummary.jsx │ ├── Chart │ │ └── Chart.jsx │ ├── CompanyArea │ │ └── CompanyArea.jsx │ ├── DiscountArea │ │ └── DiscountArea.jsx │ ├── Footer │ │ └── Footer.jsx │ ├── Header │ │ └── Header.jsx │ ├── HomeBanner │ │ └── HomeBanner.jsx │ ├── Loader │ │ └── Loader.jsx │ ├── Loading │ │ └── Loading.jsx │ ├── MobileMenu │ │ └── MobileMenu.jsx │ ├── NewsLetter │ │ └── NewsLetter.jsx │ ├── ProductRating │ │ └── ProductRating.jsx │ ├── Products │ │ ├── Products.jsx │ │ └── SingleProduct │ │ │ └── SingleProduct.jsx │ ├── ProtectedArea │ │ └── ProtectedArea.jsx │ ├── SectionTitle │ │ └── SectionTitle.jsx │ └── index.js │ ├── fakeData.js │ ├── index.js │ ├── pages │ ├── ActivationEmail │ │ └── ActivationEmail.js │ ├── Cart │ │ └── Cart.jsx │ ├── CartList │ │ └── CartList.jsx │ ├── Checkout │ │ └── Checkout.jsx │ ├── CheckoutPayment │ │ └── CheckoutPayment.jsx │ ├── Contact │ │ └── Contact.jsx │ ├── ForgotPassword │ │ └── ForgotPassword.jsx │ ├── Home │ │ └── Home.jsx │ ├── Login │ │ └── Login.jsx │ ├── Manager │ │ ├── AdminDashboard │ │ │ ├── AddProduct │ │ │ │ └── AddProduct.jsx │ │ │ ├── AdminDashboard.jsx │ │ │ ├── AllProducts │ │ │ │ └── AllProducts.jsx │ │ │ ├── EditUser │ │ │ │ └── EditUser.jsx │ │ │ ├── HomeAdmin │ │ │ │ └── HomeAdmin.jsx │ │ │ ├── OrderList │ │ │ │ └── OrderList.jsx │ │ │ ├── ProcessOrder │ │ │ │ └── ProcessOrder.jsx │ │ │ ├── Sidebar │ │ │ │ └── Sidebar.jsx │ │ │ └── UserList │ │ │ │ ├── UserList.jsx │ │ │ │ └── UserListItem │ │ │ │ └── UserListItem.jsx │ │ └── UserDashboard │ │ │ ├── MyOrders │ │ │ └── Myorders.jsx │ │ │ ├── OrderDetails │ │ │ └── OrderDetails.jsx │ │ │ ├── Profile │ │ │ └── Profile.jsx │ │ │ ├── Sidebar │ │ │ └── Sidebar.jsx │ │ │ └── UserDashboard.jsx │ ├── NotFound │ │ └── NotFound.jsx │ ├── PrivateRoute │ │ └── PrivateRoute.jsx │ ├── ProductDetail │ │ └── ProductDetail.jsx │ ├── Register │ │ └── Register.jsx │ ├── ResetPassword │ │ └── ResetPassword.jsx │ ├── Shop │ │ ├── Shop.jsx │ │ └── SingleItem │ │ │ └── SingleItem.jsx │ └── index.js │ ├── redux │ ├── actions │ │ ├── cartActions.js │ │ ├── orderActions.js │ │ ├── productActions.js │ │ └── userActions.js │ ├── constants │ │ ├── cartConstants.js │ │ ├── orderConstants.js │ │ ├── productConstants.js │ │ └── userConstants.js │ ├── reducers │ │ ├── cartReducer.js │ │ ├── index.js │ │ ├── orderReducer.js │ │ ├── productReducer.js │ │ └── userReducer.js │ └── store.js │ ├── styles │ ├── core │ │ ├── _activation-email.scss │ │ ├── _add-product.scss │ │ ├── _all-products.scss │ │ ├── _banner.scss │ │ ├── _cart.scss │ │ ├── _chart.scss │ │ ├── _checkout-payment.scss │ │ ├── _checkout.scss │ │ ├── _company-area.scss │ │ ├── _contact.scss │ │ ├── _discount-area.scss │ │ ├── _footer.scss │ │ ├── _header.scss │ │ ├── _home-admin.scss │ │ ├── _home-banner.scss │ │ ├── _loader.scss │ │ ├── _mobile-menu.scss │ │ ├── _my-orders.scss │ │ ├── _news-letter.scss │ │ ├── _not-found.scss │ │ ├── _order-details.scss │ │ ├── _process-order.scss │ │ ├── _product-detail.scss │ │ ├── _products.scss │ │ ├── _profile.scss │ │ ├── _protected-area.scss │ │ ├── _register.scss │ │ ├── _reset.scss │ │ ├── _section-title.scss │ │ ├── _sidebar.scss │ │ ├── _user-list-item.scss │ │ ├── core.scss │ │ └── utils │ │ │ ├── _fonts.scss │ │ │ ├── _functions.scss │ │ │ ├── _index.scss │ │ │ ├── _mixins.scss │ │ │ └── _variables.scss │ └── styles.scss │ └── utils │ ├── checkTokenExp.js │ └── validation.js ├── config ├── database.js ├── generateToken.js └── sendMail.js ├── controllers ├── authController.js ├── orderController.js ├── productController.js └── uploadController.js ├── middlewares ├── auth.js ├── authAdmin.js ├── errorHandler.js └── uploadImage.js ├── models ├── orderModels.js ├── productModel.js └── userModels.js ├── package-lock.json ├── package.json ├── routes ├── authRoutes.js ├── orderRoutes.js ├── productRoutes.js ├── uploadRoutes.js └── userRoutes.js ├── server.js └── services └── CustomErrorHandler.js /README.md: -------------------------------------------------------------------------------- 1 | # Mern-camera-website using React + Redux + Sass + Node js + express js + Mongodb, Stripe payment gateway etc. 2 | 3 | - Register, login with validation form and logout. 4 | - Quick login with Google 5 | - For authentication used google OAuth 6 | - Forgot password, reset password and register a new account by Email verification. 7 | - Update user information (name, password and avatar) 8 | - Shopping cart functionality 9 | - Implemented stripe payment gateway 10 | - Implemented user dashboard where user see her profile and he see her orders and what is the status of the individual orders 11 | - Restful apis 12 | - Impelemeted JSON web token for website security and also use refresh token for more secure 13 | - Implemented Admin panel where admin manage all orders, update orders, remove orders, manage all users, update user role, upadate user, add new product, update product, remove product etc 14 | - Admin panel have user User Analytics, sales status etc 15 | - Responsive for all devices like mobile, tablet, laptop, desktop etc 16 | - Used tecnologies: 17 | - Fronted: React js, Reudx, Sass, React-bootstrap, React-router-dom, Framer-motion etc 18 | - Backend: Node js, Express js, Mongodb, JSON web token, cloudinary etc 19 | 20 | # Here is the Demo - (https://mern-camera-shop.herokuapp.com/) 21 | 22 | # Website Interface - 23 | 24 | ![plot](./server/client/src/assets/full-page.png) 25 | 26 | # Admin Dashboard interface - 27 | 28 | ![plot](./server/client/src/assets/admin.png) 29 | 30 | # User Dashboard interface - 31 | 32 | ![plot](./server/client/src/assets/user.png) 33 | -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | /node_modules 3 | .env -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # mern-camera-website 2 | -------------------------------------------------------------------------------- /server/client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ 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* 24 | -------------------------------------------------------------------------------- /server/client/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `npm start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in your browser. 13 | 14 | The page will reload when you make changes.\ 15 | You may also see any lint errors in the console. 16 | 17 | ### `npm test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `npm run build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `npm run eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can't go back!** 35 | 36 | If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own. 39 | 40 | You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `npm run build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /server/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@redux-devtools/extension": "^3.2.2", 7 | "@testing-library/jest-dom": "^5.16.4", 8 | "@testing-library/react": "^12.1.4", 9 | "@testing-library/user-event": "^13.5.0", 10 | "axios": "^0.26.1", 11 | "bootstrap": "^5.1.3", 12 | "framer-motion": "^6.3.0", 13 | "jwt-decode": "^3.1.2", 14 | "react": "^18.0.0", 15 | "react-bootstrap": "^2.2.3", 16 | "react-dom": "^18.0.0", 17 | "react-google-login": "^5.2.2", 18 | "react-icons": "^4.3.1", 19 | "react-redux": "^7.2.8", 20 | "react-router-dom": "^6.3.0", 21 | "react-scripts": "5.0.0", 22 | "react-stripe-checkout": "^2.6.3", 23 | "react-toast-notifications": "^2.5.1", 24 | "recharts": "^2.1.9", 25 | "redux": "^4.1.2", 26 | "redux-thunk": "^2.4.1", 27 | "sass": "^1.50.0", 28 | "web-vitals": "^2.1.4" 29 | }, 30 | "scripts": { 31 | "start": "react-scripts start", 32 | "build": "react-scripts build", 33 | "test": "react-scripts test", 34 | "eject": "react-scripts eject" 35 | }, 36 | "eslintConfig": { 37 | "extends": [ 38 | "react-app", 39 | "react-app/jest" 40 | ] 41 | }, 42 | "browserslist": { 43 | "production": [ 44 | ">0.2%", 45 | "not dead", 46 | "not op_mini all" 47 | ], 48 | "development": [ 49 | "last 1 chrome version", 50 | "last 1 firefox version", 51 | "last 1 safari version" 52 | ] 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /server/client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/public/favicon.ico -------------------------------------------------------------------------------- /server/client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | ICAM - Camera Website 14 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /server/client/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/public/logo.png -------------------------------------------------------------------------------- /server/client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/public/logo192.png -------------------------------------------------------------------------------- /server/client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/public/logo512.png -------------------------------------------------------------------------------- /server/client/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 | -------------------------------------------------------------------------------- /server/client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /server/client/src/App.js: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | import { Routes, Route, Navigate } from "react-router-dom"; 3 | import { Header } from "./components"; 4 | import { 5 | ForgotPassword, 6 | Home, 7 | Login, 8 | Register, 9 | ActivationEmail, 10 | ResetPassword, 11 | NotFound, 12 | PrivateRoute, 13 | UserDashboard, 14 | Profile, 15 | Myorders, 16 | AdminDashboard, 17 | HomeAdmin, 18 | EditUser, 19 | AddProduct, 20 | AllProducts, 21 | Shop, 22 | ProductDetail, 23 | CheckoutPayment, 24 | OrderDetails, 25 | OrderList, 26 | ProcessOrder, 27 | Contact, 28 | } from "./pages"; 29 | import { refreshToken } from "./redux/actions/userActions"; 30 | import { useDispatch } from "react-redux"; 31 | import { ToastProvider } from "react-toast-notifications"; 32 | import { useSelector } from "react-redux"; 33 | import "./styles/styles.scss"; 34 | 35 | function App() { 36 | const dispatch = useDispatch(); 37 | 38 | useEffect(() => { 39 | dispatch(refreshToken()); 40 | }, [dispatch]); 41 | 42 | const user = useSelector((state) => state?.userLogin?.userInfo); 43 | return ( 44 | 45 |
46 | 47 | } /> 48 | : } 51 | /> 52 | } /> 53 | } /> 54 | 55 | : 59 | } 60 | > 61 | 62 | } /> 63 | 67 | 68 | 69 | } 70 | /> 71 | 72 | : 76 | } 77 | /> 78 | 79 | } /> 80 | } /> 81 | 82 | {user?.access_token && user?.user?.role === 0 && ( 83 | 87 | 88 | 89 | } 90 | > 91 | } /> 92 | } /> 93 | } /> 94 | 95 | )} 96 | 97 | {user?.access_token && user?.user?.role === 1 && ( 98 | 102 | 103 | 104 | } 105 | > 106 | } /> 107 | } /> 108 | } /> 109 | } /> 110 | } /> 111 | 112 | } /> 113 | 114 | } /> 115 | } /> 116 | 117 | )} 118 | 119 | } /> 120 | 121 | 122 | ); 123 | } 124 | 125 | export default App; 126 | -------------------------------------------------------------------------------- /server/client/src/assets/admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/admin.png -------------------------------------------------------------------------------- /server/client/src/assets/full-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/full-page.png -------------------------------------------------------------------------------- /server/client/src/assets/images/Capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/Capture.png -------------------------------------------------------------------------------- /server/client/src/assets/images/banner-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/banner-1.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/banner-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/banner-2.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/banner-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/banner-3.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-1.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-15webp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-15webp.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-2.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-3.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-4.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-5.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-6.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-7.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-7.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/camera-8.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/camera-8.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/company-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/company-1.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/company-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/company-2.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/company-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/company-3.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/company-4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/company-4.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/company-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/company-5.png -------------------------------------------------------------------------------- /server/client/src/assets/images/company-6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/company-6.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/discount-area.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/discount-area.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/home-banner-1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/home-banner-1.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/home-banner-2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/home-banner-2.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/home-banner-3.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/home-banner-3.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/home-banner-4.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/home-banner-4.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/home-banner-5.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/home-banner-5.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/home-banner-6.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/home-banner-6.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/logo.png -------------------------------------------------------------------------------- /server/client/src/assets/images/protected-area.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/protected-area.webp -------------------------------------------------------------------------------- /server/client/src/assets/images/upload-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/upload-1.png -------------------------------------------------------------------------------- /server/client/src/assets/images/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/images/upload.png -------------------------------------------------------------------------------- /server/client/src/assets/index.js: -------------------------------------------------------------------------------- 1 | import companyOne from "./images/company-1.webp"; 2 | import companyTwo from "./images/company-2.webp"; 3 | import companyThree from "./images/company-3.webp"; 4 | import companyFour from "./images/company-4.webp"; 5 | import companyFive from "./images/company-5.png"; 6 | import companySix from "./images/company-6.webp"; 7 | import bannerOne from "./images/banner-1.webp"; 8 | import bannerTwo from "./images/banner-2.webp"; 9 | import bannerThree from "./images/banner-3.webp"; 10 | import logo from "./images/logo.png"; 11 | 12 | export { 13 | companyFive, 14 | companyFour, 15 | companyOne, 16 | companyThree, 17 | companyTwo, 18 | companySix, 19 | bannerOne, 20 | bannerThree, 21 | bannerTwo, 22 | logo, 23 | }; 24 | -------------------------------------------------------------------------------- /server/client/src/assets/user.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mdhossin/mern-camera-website/c453ed35ae975a5ddffe714ecc8a369e199a7cef/server/client/src/assets/user.png -------------------------------------------------------------------------------- /server/client/src/components/Banner/Banner.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import { Carousel } from "react-bootstrap"; 3 | import { bannerData } from "../../fakeData"; 4 | 5 | const Banner = () => ( 6 | 7 | {bannerData.map((banner, i) => ( 8 | 9 | First slide 10 | 11 |

{banner.title}

12 |

{banner.desc}

13 | 14 | 15 | 16 | 17 |
18 |
19 | ))} 20 |
21 | ); 22 | 23 | export default Banner; 24 | -------------------------------------------------------------------------------- /server/client/src/components/CartSummary/CartSummary.jsx: -------------------------------------------------------------------------------- 1 | import { Col, Container, Row } from "react-bootstrap"; 2 | 3 | const CartSummary = ({ cartTotal }) => ( 4 |
5 | 6 | 7 | 8 |

SubTotal

9 | 10 | 11 |

${cartTotal}

12 | 13 |
14 |
15 |
16 | ); 17 | 18 | export default CartSummary; 19 | -------------------------------------------------------------------------------- /server/client/src/components/Chart/Chart.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | LineChart, 3 | Line, 4 | XAxis, 5 | CartesianGrid, 6 | Tooltip, 7 | ResponsiveContainer, 8 | } from "recharts"; 9 | 10 | const Chart = ({ title, data, dataKey, grid }) => ( 11 |
12 |

{title}

13 | 14 | 15 | 16 | 17 | 18 | {grid && } 19 | 20 | 21 |
22 | ); 23 | 24 | export default Chart; 25 | -------------------------------------------------------------------------------- /server/client/src/components/CompanyArea/CompanyArea.jsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { compnayData } from "../../fakeData"; 3 | 4 | const CompanyArea = () => ( 5 |
6 | 11 | {compnayData.map((company, i) => ( 12 | 13 | company 14 | 15 | ))} 16 | 17 |
18 | ); 19 | 20 | export default CompanyArea; 21 | -------------------------------------------------------------------------------- /server/client/src/components/DiscountArea/DiscountArea.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import { motion } from "framer-motion"; 3 | 4 | const DiscountArea = () => ( 5 | 6 | 11 |
12 |
13 |

WE'RE AT 71% OF OUR GOAL!

14 |

Discount For All Orders Over $100

15 |
Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
16 | 17 | 18 | 19 |
20 |
21 |
22 | ); 23 | 24 | export default DiscountArea; 25 | -------------------------------------------------------------------------------- /server/client/src/components/HomeBanner/HomeBanner.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import { motion } from "framer-motion"; 3 | 4 | const HomeBanner = () => ( 5 |
6 | 7 | 12 |
13 |
14 |

Smart Protection

15 |

Monitor and control your home anytime, anywhere.

16 | 17 | 18 | 19 |
20 |
21 | 26 |
27 |
28 |

Full Protection

29 |

Featured Security Camera to stay protected

30 | 31 | 32 | 33 |
34 |
35 |
36 |
37 | ); 38 | 39 | export default HomeBanner; 40 | -------------------------------------------------------------------------------- /server/client/src/components/Loader/Loader.jsx: -------------------------------------------------------------------------------- 1 | const Loader = (props) => { 2 | const { inline, backdrop } = props; 3 | 4 | return ( 5 |
10 |
15 |
16 | ); 17 | }; 18 | 19 | Loader.defaultProps = { 20 | inline: false, 21 | backdrop: false, 22 | }; 23 | 24 | export default Loader; 25 | -------------------------------------------------------------------------------- /server/client/src/components/Loading/Loading.jsx: -------------------------------------------------------------------------------- 1 | import { Spinner } from "react-bootstrap"; 2 | 3 | const Loading = () => ( 4 | <> 5 | 6 | 7 | ); 8 | 9 | export default Loading; 10 | -------------------------------------------------------------------------------- /server/client/src/components/MobileMenu/MobileMenu.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import { AiOutlineClose } from "react-icons/ai"; 3 | 4 | const MobileMenu = ({ setMobileOpen }) => ( 5 | <> 6 |
7 | setMobileOpen(false)} 10 | /> 11 |
12 | 13 |
14 |
    15 |
  • 16 | setMobileOpen(false)} 20 | > 21 | Home 22 | 23 |
  • 24 |
  • 25 | setMobileOpen(false)} 29 | > 30 | Shop 31 | 32 |
  • 33 | 34 |
  • 35 | setMobileOpen(false)} 39 | > 40 | Contact 41 | 42 |
  • 43 |
44 | 45 |
46 |
47 | 48 | ); 49 | 50 | export default MobileMenu; 51 | -------------------------------------------------------------------------------- /server/client/src/components/NewsLetter/NewsLetter.jsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | 3 | const NewsLetter = () => ( 4 | 5 | 10 |
11 |

NewsLetter

12 |

13 | Lorem ipsum dolor sit amet, consectetur adipisicing elit. Eos, autem. 14 |

15 |
16 | 17 | 18 |
19 |
20 |
21 |
22 | ); 23 | 24 | export default NewsLetter; 25 | -------------------------------------------------------------------------------- /server/client/src/components/ProductRating/ProductRating.jsx: -------------------------------------------------------------------------------- 1 | import { AiOutlineStar, AiFillStar } from "react-icons/ai"; 2 | const ProductRating = ({ ratingValue }) => { 3 | let rating = []; 4 | 5 | for (let i = 0; i < 5; i++) { 6 | rating.push(); 7 | } 8 | if (ratingValue && ratingValue > 0) { 9 | for (let i = 0; i <= ratingValue - 1; i++) { 10 | rating[i] = ( 11 | 18 | ); 19 | } 20 | } 21 | return <>{rating}; 22 | }; 23 | 24 | export default ProductRating; 25 | -------------------------------------------------------------------------------- /server/client/src/components/Products/Products.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import SectionTitle from "../SectionTitle/SectionTitle"; 3 | import { useSelector, useDispatch } from "react-redux"; 4 | import { getAllProduct } from "../../redux/actions/productActions"; 5 | import Loader from "../Loader/Loader"; 6 | import SingleProduct from "./SingleProduct/SingleProduct"; 7 | 8 | const Products = () => { 9 | const dispatch = useDispatch(); 10 | const productsData = useSelector((state) => state.allProducts); 11 | const { products, loading, error } = productsData; 12 | 13 | useEffect(() => { 14 | dispatch(getAllProduct()); 15 | }, [dispatch]); 16 | return ( 17 |
18 | 19 | 20 |
21 | {loading ? ( 22 | 23 | ) : error ? ( 24 |

25 | {error} 26 |

27 | ) : ( 28 | <> 29 | {products?.map((product) => ( 30 | 31 | ))} 32 | 33 | )} 34 |
35 | {products?.length === 0 && ( 36 |

37 | No product found. 38 |

39 | )} 40 |
41 | ); 42 | }; 43 | 44 | export default Products; 45 | -------------------------------------------------------------------------------- /server/client/src/components/Products/SingleProduct/SingleProduct.jsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { useToasts } from "react-toast-notifications"; 3 | import { FiShoppingCart } from "react-icons/fi"; 4 | import { Link } from "react-router-dom"; 5 | import { useDispatch, useSelector } from "react-redux"; 6 | import { addItemsToCart } from "../../../redux/actions/cartActions"; 7 | import ProductRating from "../../ProductRating/ProductRating"; 8 | 9 | const SingleProduct = ({ product }) => { 10 | const { cartItems } = useSelector((state) => state.cart); 11 | const { addToast } = useToasts(); 12 | const addOrNot = cartItems?.find((item) => item.product === product._id); 13 | const dispatch = useDispatch(); 14 | const addToCartHandler = () => { 15 | dispatch(addItemsToCart(product?._id, 1, addToast)); 16 | }; 17 | return ( 18 | 23 | 24 | 25 | 26 |
27 | 28 |

{product.name}

29 | 30 |
${product.price}
31 | 32 |
33 | {product?.Stock && product?.Stock > 0 ? ( 34 | 42 | ) : ( 43 | 46 | )} 47 |
48 |
49 |
50 | ); 51 | }; 52 | 53 | export default SingleProduct; 54 | -------------------------------------------------------------------------------- /server/client/src/components/ProtectedArea/ProtectedArea.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import { motion } from "framer-motion"; 3 | 4 | const ProtectedArea = () => ( 5 | 6 | 11 |
12 | 13 |
14 |

Protect it now

15 |

Is your business protected?

16 |
Access Gibson to stay protected
17 | 18 | 19 | 20 |
21 |
22 |
23 | ); 24 | 25 | export default ProtectedArea; 26 | -------------------------------------------------------------------------------- /server/client/src/components/SectionTitle/SectionTitle.jsx: -------------------------------------------------------------------------------- 1 | const SectionTitle = ({ title, desc }) => ( 2 |
3 |

{desc}

4 |

{title}

5 |
6 | ); 7 | 8 | export default SectionTitle; 9 | -------------------------------------------------------------------------------- /server/client/src/components/index.js: -------------------------------------------------------------------------------- 1 | import Banner from "./Banner/Banner"; 2 | import Header from "./Header/Header"; 3 | import MobileMenu from "./MobileMenu/MobileMenu"; 4 | import CartSummary from "./CartSummary/CartSummary"; 5 | import CompanyArea from "./CompanyArea/CompanyArea"; 6 | import DiscountArea from "./DiscountArea/DiscountArea"; 7 | import Footer from "./Footer/Footer"; 8 | import HomeBanner from "./HomeBanner/HomeBanner"; 9 | import NewsLetter from "./NewsLetter/NewsLetter"; 10 | import Products from "./Products/Products"; 11 | import ProtectedArea from "./ProtectedArea/ProtectedArea"; 12 | import SectionTitle from "./SectionTitle/SectionTitle"; 13 | import ProductRating from "./ProductRating/ProductRating"; 14 | import Loading from "./Loading/Loading"; 15 | import Loader from "./Loader/Loader"; 16 | 17 | export { 18 | Header, 19 | MobileMenu, 20 | Banner, 21 | CartSummary, 22 | CompanyArea, 23 | DiscountArea, 24 | Footer, 25 | HomeBanner, 26 | NewsLetter, 27 | Products, 28 | ProtectedArea, 29 | SectionTitle, 30 | ProductRating, 31 | Loading, 32 | Loader, 33 | }; 34 | -------------------------------------------------------------------------------- /server/client/src/fakeData.js: -------------------------------------------------------------------------------- 1 | import { 2 | bannerOne, 3 | bannerThree, 4 | bannerTwo, 5 | companyFive, 6 | companyFour, 7 | companyOne, 8 | companyThree, 9 | companyTwo, 10 | } from "./assets"; 11 | 12 | export const bannerData = [ 13 | { 14 | id: 1, 15 | imgPath: bannerOne, 16 | title: "Durable Night Vision Cameras", 17 | desc: "Global Camera Solutions", 18 | }, 19 | { 20 | id: 2, 21 | imgPath: bannerTwo, 22 | title: "One Stop Security Solutions", 23 | desc: "For Your Home and Bussiness Security", 24 | }, 25 | { 26 | id: 3, 27 | imgPath: bannerThree, 28 | title: "Get A CCTV Security Package", 29 | desc: "For Your Home and Bussiness Security", 30 | }, 31 | ]; 32 | 33 | export const productData = [ 34 | { 35 | id: 1, 36 | img: "https://cdn.shopify.com/s/files/1/0040/0323/3892/products/p25_884c8d96-f418-47e0-b886-7140ab07f302_600x.jpg?v=1543492312", 37 | name: "Night Vision HD", 38 | price: 599, 39 | rating: 2, 40 | }, 41 | { 42 | id: 2, 43 | img: "https://cdn.shopify.com/s/files/1/0040/0323/3892/products/p24_d15f04c0-2b14-4f18-8e15-d5c0dea23359_600x.jpg?v=1543492224", 44 | name: "Wireless Bullet HD", 45 | price: 895, 46 | rating: 3, 47 | }, 48 | { 49 | id: 3, 50 | img: "https://cdn.shopify.com/s/files/1/0040/0323/3892/products/p23_808cb461-fbd0-4255-b6f2-130b64555a81_600x.jpg?v=1543492090", 51 | name: "Waterproof Bullet HD", 52 | price: 1199, 53 | rating: 4, 54 | }, 55 | { 56 | id: 4, 57 | img: "https://cdn.shopify.com/s/files/1/0040/0323/3892/products/p6_59b37852-71c3-461e-ac66-1822d36cc4be_600x.jpg?v=1544420375", 58 | name: "Bullet HD Lens", 59 | price: 1299, 60 | rating: 1, 61 | }, 62 | { 63 | id: 5, 64 | img: "https://cdn.shopify.com/s/files/1/0040/0323/3892/products/p21_dc3139bb-bc56-4313-91c9-2f55f9c3a2ac_600x.jpg?v=1543491728", 65 | name: "Wireless HD Camera", 66 | price: 755, 67 | rating: 2, 68 | }, 69 | { 70 | id: 6, 71 | img: "https://cdn.shopify.com/s/files/1/0040/0323/3892/products/p18_975e9c57-5014-4ddc-9889-7bf3f4a22cc8_600x.jpg?v=1543491463", 72 | name: "Surveillance 3D", 73 | price: 855, 74 | rating: 5, 75 | }, 76 | ]; 77 | 78 | export const compnayData = [ 79 | { 80 | id: 1, 81 | img: companyOne, 82 | }, 83 | { 84 | id: 2, 85 | img: companyTwo, 86 | }, 87 | { 88 | id: 3, 89 | img: companyThree, 90 | }, 91 | { 92 | id: 4, 93 | img: companyFour, 94 | }, 95 | { 96 | id: 5, 97 | img: companyFive, 98 | }, 99 | ]; 100 | -------------------------------------------------------------------------------- /server/client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom/client"; 3 | import { BrowserRouter } from "react-router-dom"; 4 | import { Provider } from "react-redux"; 5 | 6 | import App from "./App"; 7 | import store from "./redux/store"; 8 | 9 | const root = ReactDOM.createRoot(document.getElementById("root")); 10 | root.render( 11 | 12 | 13 | 14 | 15 | 16 | ); 17 | -------------------------------------------------------------------------------- /server/client/src/pages/ActivationEmail/ActivationEmail.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import axios from "axios"; 3 | import { Link, useParams } from "react-router-dom"; 4 | import { useToasts } from "react-toast-notifications"; 5 | 6 | const ActivationEmail = () => { 7 | const { activation_token } = useParams(); 8 | const [error, setError] = useState(""); 9 | const [success, setSuccess] = useState(""); 10 | const { addToast } = useToasts(); 11 | useEffect(() => { 12 | if (activation_token) { 13 | const activationEmail = async () => { 14 | try { 15 | const res = await axios.post( 16 | "https://mern-camera-shop.herokuapp.com/api/active", 17 | { 18 | activation_token, 19 | } 20 | ); 21 | setSuccess(res.data.message); 22 | setError(""); 23 | } catch (error) { 24 | setSuccess(""); 25 | error.response && 26 | setError( 27 | error.response.data.message 28 | ? error.response.data.message 29 | : error.message 30 | ); 31 | } 32 | }; 33 | activationEmail(); 34 | } 35 | }, [activation_token, error.response, error.message]); 36 | 37 | useEffect(() => { 38 | if (error) { 39 | addToast(error, { appearance: "error", autoDismiss: true }); 40 | } else if (success) { 41 | addToast(success, { 42 | appearance: "success", 43 | autoDismiss: true, 44 | }); 45 | } 46 | }, [success, error, addToast]); 47 | return ( 48 |
49 |
50 |

{error && error}

51 |

{success && success}

52 | 53 |
54 | 55 | {" "} 56 | 57 | 58 |
59 |
60 |
61 | ); 62 | }; 63 | 64 | export default ActivationEmail; 65 | -------------------------------------------------------------------------------- /server/client/src/pages/Cart/Cart.jsx: -------------------------------------------------------------------------------- 1 | import { AiOutlineClose } from "react-icons/ai"; 2 | import { BiShoppingBag } from "react-icons/bi"; 3 | import { useDispatch, useSelector } from "react-redux"; 4 | import { CartSummary } from "../../components"; 5 | import { 6 | addItemsToCart, 7 | removeItemsFromCart, 8 | } from "../../redux/actions/cartActions"; 9 | import CartList from "../CartList/CartList"; 10 | import CheckOut from "../Checkout/Checkout"; 11 | 12 | const Cart = ({ setCartOpen }) => { 13 | const dispatch = useDispatch(); 14 | const { cartItems } = useSelector((state) => state.cart); 15 | 16 | const cartTotal = cartItems.reduce( 17 | (acc, item) => acc + item.quantity * item.price, 18 | 0 19 | ); 20 | 21 | const qtyChangeHandler = (id, quantity) => { 22 | dispatch(addItemsToCart(id, quantity)); 23 | }; 24 | 25 | const deleteCartItems = (id) => { 26 | dispatch(removeItemsFromCart(id)); 27 | }; 28 | 29 | return ( 30 |
31 |
32 |
33 | Shopping Cart ({cartItems?.length}) 34 |
35 | setCartOpen(false)} 38 | /> 39 |
40 | {cartItems.length > 0 ? ( 41 |
42 | 47 |
48 | ) : ( 49 |
50 | 51 |

Your shopping cart is empty

52 |
53 | )} 54 | {cartItems.length > 0 && ( 55 |
56 | 57 | 58 |
59 | )} 60 |
61 | ); 62 | }; 63 | 64 | export default Cart; 65 | -------------------------------------------------------------------------------- /server/client/src/pages/CartList/CartList.jsx: -------------------------------------------------------------------------------- 1 | import { AiOutlineClose } from "react-icons/ai"; 2 | 3 | const CartList = ({ cartItems, qtyChangeHandler, deleteCartItems }) => ( 4 |
5 | {cartItems?.map((item, index) => ( 6 |
7 | 12 |
13 | 28 | 29 |
30 |
31 | 42 |
43 | ${item.price * item.quantity} 44 |
45 |
46 |
47 |
48 |
49 | ))} 50 |
51 | ); 52 | 53 | export default CartList; 54 | -------------------------------------------------------------------------------- /server/client/src/pages/Checkout/Checkout.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | 3 | const CheckOut = ({ setCartOpen }) => ( 4 |
5 |
6 | 7 | 10 | 11 | 12 | 19 | 20 |
21 |
22 | ); 23 | 24 | export default CheckOut; 25 | -------------------------------------------------------------------------------- /server/client/src/pages/CheckoutPayment/CheckoutPayment.jsx: -------------------------------------------------------------------------------- 1 | import { useDispatch, useSelector } from "react-redux"; 2 | import StripeCheckout from "react-stripe-checkout"; 3 | import { createOrder } from "../../redux/actions/orderActions"; 4 | 5 | const CheckoutPayment = () => { 6 | const dispatch = useDispatch(); 7 | const { cartItems } = useSelector((state) => state.cart); 8 | const { user } = useSelector((state) => state.userLogin?.userInfo); 9 | 10 | const subtotal = cartItems.reduce( 11 | (acc, item) => acc + item.quantity * item.price, 12 | 0 13 | ); 14 | 15 | const shippingCharges = subtotal < 1000 ? 0 : 100; 16 | const tax = subtotal * 0.18; 17 | const totalPrice = Math.round(subtotal + tax + shippingCharges); 18 | 19 | const order = { 20 | orderItems: cartItems, 21 | shippingPrice: shippingCharges, 22 | totalPrice: totalPrice, 23 | }; 24 | 25 | const tokenHandler = (token) => { 26 | order.shippingInfo = token.card; 27 | order.email = token.email; 28 | order.id = token.id; 29 | order.paymentInfo = { 30 | id: token.id, 31 | status: "succeeded", 32 | }; 33 | if (token) { 34 | dispatch(createOrder(order)); 35 | } 36 | }; 37 | 38 | return ( 39 |
40 |
41 |

Payment Info

42 |
43 |

Subtotal:

44 | ${subtotal.toFixed(2)} 45 |
46 |
47 |

Shipping Charges:

48 | ${shippingCharges.toFixed(2)} 49 |
50 |
51 |

Tax :

52 | ${tax.toFixed(2)} 53 |
54 |
55 |
56 |

Total Price :

57 | ${totalPrice.toFixed(2)} 58 |
59 | 60 | 71 | 74 | 75 |
76 |
77 | ); 78 | }; 79 | 80 | export default CheckoutPayment; 81 | -------------------------------------------------------------------------------- /server/client/src/pages/Contact/Contact.jsx: -------------------------------------------------------------------------------- 1 | import { motion } from "framer-motion"; 2 | import { IoCallOutline } from "react-icons/io5"; 3 | import { AiOutlineMail } from "react-icons/ai"; 4 | import { FiSend } from "react-icons/fi"; 5 | import Footer from "../../components/Footer/Footer"; 6 | const Contact = () => ( 7 |
8 |
9 |
10 |

Contact Us

11 |
12 | 13 | 14 | 19 |
20 |
21 | 22 |
23 |

Phone

24 |

010-00001222

25 |

002-00003333

26 |
27 | 28 | 33 |
34 | 35 |
36 |

Email

37 |

icam@gamil.com

38 |

support@gmail.com

39 |
40 | 41 | 46 |
47 | 48 |
49 |

Address

50 |

No: 58 A, East Madison Street,

51 |

Baltimore, MD, USA 4508

52 |
53 |
54 | 55 | 56 |

Contact Form

57 | 62 |
63 |
64 | 70 |
71 |
72 | 78 |
79 |
80 | 86 |
87 |
88 | 93 | 100 | 101 |
102 | 103 |
104 |
105 |
106 |
107 |
108 | 109 |
110 |
111 | ); 112 | 113 | export default Contact; 114 | -------------------------------------------------------------------------------- /server/client/src/pages/ForgotPassword/ForgotPassword.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import axios from "axios"; 3 | import { Link } from "react-router-dom"; 4 | import { useToasts } from "react-toast-notifications"; 5 | import { Spinner } from "react-bootstrap"; 6 | import { isEmail } from "../../utils/validation"; 7 | 8 | const ForgotPassword = () => { 9 | const [data, setData] = useState({ 10 | email: "", 11 | error: "", 12 | success: "", 13 | }); 14 | 15 | const { addToast } = useToasts(); 16 | const { email, error, success } = data; 17 | const [loading, setLoading] = useState(false); 18 | 19 | const handleChangeInput = (e) => { 20 | const { name, value } = e.target; 21 | setData({ ...data, [name]: value, error: "", success: "" }); 22 | }; 23 | 24 | const forgotPassword = async () => { 25 | if (!isEmail(email)) 26 | return setData({ ...data, error: "Invalid emails.", success: "" }); 27 | 28 | try { 29 | setLoading(true); 30 | const res = await axios.post( 31 | "https://mern-camera-shop.herokuapp.com/api/user/forgot_password", 32 | { email } 33 | ); 34 | setLoading(false); 35 | setData({ ...data, error: "", success: res.data.message }); 36 | } catch (error) { 37 | setLoading(false); 38 | error.response.data.message && 39 | setData({ 40 | ...data, 41 | error: 42 | error.response && error.response.data.message 43 | ? error.response.data.message 44 | : error.message, 45 | success: "", 46 | }); 47 | } 48 | }; 49 | 50 | useEffect(() => { 51 | if (error) { 52 | addToast(error, { appearance: "error", autoDismiss: true }); 53 | setData({ 54 | email: "", 55 | error: "", 56 | success: "", 57 | }); 58 | } else if (success) { 59 | addToast(success, { 60 | appearance: "success", 61 | autoDismiss: true, 62 | }); 63 | setData({ 64 | email: "", 65 | error: "", 66 | success: "", 67 | }); 68 | } 69 | }, [error, success, addToast]); 70 | return ( 71 |
72 |
73 |
74 |

Forgot your password?

75 |

76 | We will send you an email to reset your password. 77 |

78 | 79 |
80 |
81 | 84 | 92 |
93 | 94 |
95 | 106 | 107 | 108 | 111 | 112 |
113 | 114 | 117 | 118 |
119 |
120 |
121 |
122 | ); 123 | }; 124 | 125 | export default ForgotPassword; 126 | -------------------------------------------------------------------------------- /server/client/src/pages/Home/Home.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | Banner, 3 | CompanyArea, 4 | DiscountArea, 5 | Footer, 6 | HomeBanner, 7 | NewsLetter, 8 | Products, 9 | ProtectedArea, 10 | } from "../../components"; 11 | 12 | const Home = () => ( 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 |
23 | ); 24 | 25 | export default Home; 26 | -------------------------------------------------------------------------------- /server/client/src/pages/Login/Login.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { Spinner } from "react-bootstrap"; 3 | import { Link, useLocation, useNavigate } from "react-router-dom"; 4 | import { GoogleLogin } from "react-google-login"; 5 | import { AiOutlineEye, AiOutlineEyeInvisible } from "react-icons/ai"; 6 | import { useDispatch, useSelector } from "react-redux"; 7 | import { googleLogin, login } from "../../redux/actions/userActions"; 8 | import { useToasts } from "react-toast-notifications"; 9 | import { USER_LOGIN_RESET } from "../../redux/constants/userConstants"; 10 | const Login = () => { 11 | const navigate = useNavigate(); 12 | let location = useLocation(); 13 | const { addToast } = useToasts(); 14 | const [newUser, setNewUser] = useState({ email: "", password: "" }); 15 | const dispatch = useDispatch(); 16 | const redirect = location.state?.path || "/"; 17 | 18 | const { email, password } = newUser; 19 | 20 | const [typePass, setTypePass] = useState(false); 21 | 22 | const userLogin = useSelector((state) => state?.userLogin); 23 | 24 | const { loading, error, userInfo } = userLogin; 25 | 26 | const handleChangeInput = (e) => { 27 | setNewUser({ ...newUser, [e.target.name]: e.target.value }); 28 | }; 29 | 30 | const handleSubmit = (e) => { 31 | e.preventDefault(); 32 | 33 | dispatch(login(email, password)); 34 | }; 35 | 36 | const responseGoogle = async (response) => { 37 | try { 38 | dispatch(googleLogin(response.tokenId)); 39 | } catch (error) { 40 | alert(error?.message); 41 | } 42 | }; 43 | 44 | useEffect(() => { 45 | if (error) { 46 | dispatch({ type: USER_LOGIN_RESET }); 47 | addToast(error, { appearance: "error", autoDismiss: true }); 48 | } else if (userInfo) { 49 | if (userInfo.message !== undefined) { 50 | addToast(userInfo?.message, { 51 | appearance: "success", 52 | autoDismiss: true, 53 | }); 54 | } 55 | navigate(redirect, { replace: true }); 56 | } 57 | }, [userInfo, error, addToast, navigate, dispatch, redirect]); 58 | 59 | return ( 60 |
61 |
62 |
63 |

Login

64 | 65 |
66 |
67 | 70 | 79 |
80 |
81 | 84 | 93 | setTypePass(!typePass)}> 94 | {typePass ? : } 95 | 96 |
97 | 98 |
99 | Forgot your password? 100 |
101 | 102 | 109 | 110 |
111 | 118 |
119 | 120 |
121 | Don't have an account ? Register 122 |
123 |
124 |
125 |
126 |
127 | ); 128 | }; 129 | 130 | export default Login; 131 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/AdminDashboard/AdminDashboard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Outlet } from "react-router-dom"; 3 | import Sidebar from "./Sidebar/Sidebar"; 4 | 5 | const AdminDashboard = () => ( 6 | <> 7 | 8 |
9 |
10 | {/* used nested route data show here */} 11 | 12 |
13 |
14 | 15 | ); 16 | 17 | export default AdminDashboard; 18 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/AdminDashboard/AllProducts/AllProducts.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import axios from "axios"; 3 | import { Link } from "react-router-dom"; 4 | import { useSelector, useDispatch } from "react-redux"; 5 | import { 6 | getAllProduct, 7 | deleteProduct, 8 | } from "../../../../redux/actions/productActions"; 9 | import { Loader } from "../../../../components"; 10 | 11 | const AllProducts = () => { 12 | const [callback, setCallback] = useState(false); 13 | const dispatch = useDispatch(); 14 | const productsData = useSelector((state) => state.allProducts); 15 | const { products, loading, error } = productsData; 16 | const token = useSelector((state) => state.userLogin?.userInfo?.access_token); 17 | 18 | useEffect(() => { 19 | dispatch(getAllProduct()); 20 | }, [dispatch, callback]); 21 | 22 | const deleteHandler = async (id, public_id) => { 23 | try { 24 | if (window.confirm("are you sure?")) { 25 | const destroyImg = axios.post( 26 | "https://mern-camera-shop.herokuapp.com/api/destroy", 27 | { public_id }, 28 | { 29 | headers: { Authorization: token }, 30 | } 31 | ); 32 | await destroyImg; 33 | dispatch(deleteProduct(token, id)); 34 | setCallback(!callback); 35 | alert("Product Deleted Successfully"); 36 | } 37 | } catch (error) { 38 | alert( 39 | error.response && error.response.data.message 40 | ? error.response.data.message 41 | : error.message 42 | ); 43 | } 44 | }; 45 | return ( 46 |
47 |

All Products

48 | 49 |
50 | {loading ? ( 51 | 52 | ) : error ? ( 53 |

54 | {error} 55 |

56 | ) : ( 57 | <> 58 | {products?.map((product) => ( 59 |
60 | 61 | 62 |
63 |

{product.name}

64 |
65 |
${product.price}
66 |

Stock : {product.Stock}

67 |
68 |

{product.description.slice(0, 30)}...

69 |
70 | 74 | Edit 75 | 76 | 84 |
85 |
86 |
87 | ))} 88 | 89 | )} 90 |
91 | {products?.length === 0 && ( 92 |

93 | No product found. 94 |

95 | )} 96 |
97 | ); 98 | }; 99 | 100 | export default AllProducts; 101 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/AdminDashboard/EditUser/EditUser.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import axios from "axios"; 3 | import { useSelector } from "react-redux"; 4 | import { useNavigate, useParams } from "react-router-dom"; 5 | import { BsFillArrowLeftCircleFill } from "react-icons/bs"; 6 | import { useToasts } from "react-toast-notifications"; 7 | import { Spinner } from "react-bootstrap"; 8 | const EditUser = () => { 9 | const navigate = useNavigate(); 10 | const { id } = useParams(); 11 | const { addToast } = useToasts(); 12 | 13 | const [editUser, setEditUser] = useState([]); 14 | const [checkAdmin, setCheckAdmin] = useState(false); 15 | const [error, setError] = useState(false); 16 | const [success, setSuccess] = useState(false); 17 | const [num, setNum] = useState(0); 18 | const [loading, setLoading] = useState(false); 19 | 20 | const { users } = useSelector((state) => state.userList); 21 | const { userInfo } = useSelector((state) => state.userLogin); 22 | 23 | useEffect(() => { 24 | if (users.length !== 0) { 25 | users.forEach((user) => { 26 | if (user._id === id) { 27 | setEditUser(user); 28 | setCheckAdmin(user.role === 1 ? true : false); 29 | } 30 | }); 31 | } else { 32 | navigate("/dashboard/users"); 33 | } 34 | }, [users, id, navigate]); 35 | 36 | const handleUpdate = async () => { 37 | try { 38 | if (num % 2 !== 0) { 39 | setLoading(true); 40 | const res = await axios.patch( 41 | `https://mern-camera-shop.herokuapp.com/api/admin/update_role/${editUser._id}`, 42 | { 43 | role: checkAdmin ? 1 : 0, 44 | }, 45 | { 46 | headers: { Authorization: userInfo.access_token }, 47 | } 48 | ); 49 | 50 | setError(""); 51 | setSuccess(res.data.message); 52 | setNum(0); 53 | setLoading(false); 54 | } 55 | } catch (err) { 56 | setLoading(false); 57 | setSuccess(""); 58 | err.response && 59 | setError( 60 | error.response && error.response.data.message 61 | ? error.response.data.message 62 | : error.message 63 | ); 64 | } 65 | }; 66 | 67 | const handleCheck = () => { 68 | setSuccess(""); 69 | setError(""); 70 | setCheckAdmin(!checkAdmin); 71 | setNum(num + 1); 72 | }; 73 | 74 | useEffect(() => { 75 | if (error) { 76 | addToast(error, { appearance: "error", autoDismiss: true }); 77 | } else if (success) { 78 | addToast(success, { 79 | appearance: "success", 80 | autoDismiss: true, 81 | }); 82 | navigate("/dashboard/users"); 83 | } 84 | }, [addToast, error, success, navigate]); 85 | 86 | return ( 87 |
88 |
89 | 96 |
97 | 98 |
99 |

Edit User

100 | 101 |
102 | 103 | 109 |
110 | 111 |
112 | 113 | 119 |
120 | 121 |
122 | 128 | 129 |
130 | 131 | 138 |
139 |
140 | ); 141 | }; 142 | 143 | export default EditUser; 144 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/AdminDashboard/HomeAdmin/HomeAdmin.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useMemo, useState } from "react"; 2 | import axios from "axios"; 3 | import { useDispatch, useSelector } from "react-redux"; 4 | import { getAllProduct } from "../../../../redux/actions/productActions"; 5 | import { getAllOrders } from "../../../../redux/actions/orderActions"; 6 | import { userList } from "../../../../redux/actions/userActions"; 7 | import Chart from "../../../../components/Chart/Chart"; 8 | const HomeAdmin = () => { 9 | const dispatch = useDispatch(); 10 | const [userStats, setUserStats] = useState([]); 11 | 12 | const productData = useSelector((state) => state.allProducts); 13 | const { products } = productData; 14 | const { orders } = useSelector((state) => state.allOrders); 15 | 16 | const { access_token } = useSelector((state) => state.userLogin?.userInfo); 17 | 18 | const { users } = useSelector((state) => state.userList); 19 | 20 | useEffect(() => { 21 | dispatch(getAllProduct()); 22 | dispatch(getAllOrders()); 23 | dispatch(userList()); 24 | }, [dispatch]); 25 | 26 | let totalAmount = 0; 27 | orders && 28 | orders.forEach((item) => { 29 | totalAmount += item.totalPrice; 30 | }); 31 | 32 | const MONTHS = useMemo( 33 | () => [ 34 | "Jan", 35 | "Feb", 36 | "Mar", 37 | "Apr", 38 | "May", 39 | "Jun", 40 | "Jul", 41 | "Agu", 42 | "Sep", 43 | "Oct", 44 | "Nov", 45 | "Dec", 46 | ], 47 | [] 48 | ); 49 | 50 | useEffect(() => { 51 | const getStats = async () => { 52 | try { 53 | const config = { 54 | headers: { 55 | "Content-Type": "application/json", 56 | Authorization: access_token, 57 | }, 58 | }; 59 | const res = await axios.get( 60 | "https://mern-camera-shop.herokuapp.com/api/admin/stats", 61 | config 62 | ); 63 | res.data.map((item) => 64 | setUserStats((prev) => [ 65 | ...prev, 66 | { name: MONTHS[item._id - 1], "Active User": item.total }, 67 | ]) 68 | ); 69 | } catch (error) { 70 | console.log(error?.messge); 71 | } 72 | }; 73 | getStats(); 74 | }, [MONTHS, access_token]); 75 | 76 | return ( 77 |
78 |
79 |
80 |
81 |

Total Sales

82 |

${Math.round(totalAmount)}

83 |
84 | 85 |
86 |

All Products

87 |

{products && products?.length}

88 |
89 |
90 |

Total Orders

91 |

{orders && orders?.length}

92 |
93 |
94 |

Active Users

95 |

{users && users?.length}

96 |
97 |
98 | 99 | 105 |
106 |
107 | ); 108 | }; 109 | 110 | export default HomeAdmin; 111 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/AdminDashboard/UserList/UserList.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import { useNavigate } from "react-router-dom"; 4 | import Loading from "../../../../components/Loading/Loading"; 5 | import { userList } from "../../../../redux/actions/userActions"; 6 | import UserListItem from "./UserListItem/UserListItem"; 7 | 8 | const UserList = () => { 9 | const dispatch = useDispatch(); 10 | const navigate = useNavigate(); 11 | const [callback, setCallback] = useState(false); 12 | 13 | const { loading, error, users } = useSelector((state) => state.userList); 14 | const { userInfo } = useSelector((state) => state.userLogin); 15 | 16 | useEffect(() => { 17 | if (userInfo && userInfo?.user.role === 1) { 18 | dispatch(userList()); 19 | } else { 20 | navigate("/"); 21 | } 22 | }, [dispatch, navigate, userInfo, callback]); 23 | return ( 24 | <> 25 |
26 |
27 |
28 |

Users

29 | 30 | {loading ? ( 31 | 32 | ) : error ? ( 33 |

{error}

34 | ) : ( 35 | 40 | )} 41 |
42 |
43 | 44 | ); 45 | }; 46 | 47 | export default UserList; 48 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/UserDashboard/MyOrders/Myorders.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useToasts } from "react-toast-notifications"; 3 | import { useSelector, useDispatch } from "react-redux"; 4 | import { Link } from "react-router-dom"; 5 | import { BiEdit } from "react-icons/bi"; 6 | import { Table } from "react-bootstrap"; 7 | import { clearErrors, myOrders } from "../../../../redux/actions/orderActions"; 8 | import Loader from "../../../../components/Loader/Loader"; 9 | 10 | const MyOrders = () => { 11 | const dispatch = useDispatch(); 12 | const { addToast } = useToasts(); 13 | const { loading, error, orders } = useSelector((state) => state.myOrders); 14 | 15 | useEffect(() => { 16 | if (error) { 17 | addToast(error, { appearance: "error", autoDismiss: true }); 18 | dispatch(clearErrors()); 19 | } 20 | dispatch(myOrders()); 21 | }, [dispatch, error, addToast]); 22 | 23 | return ( 24 |
25 |

My Orders

26 |
27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | {loading ? ( 39 | 40 | 43 | 44 | ) : error ? ( 45 |

{error}

46 | ) : ( 47 | <> 48 | {orders?.map(({ _id, orderStatus, totalPrice, orderItems }) => ( 49 | 50 | 51 | 52 | 53 | 56 | 69 | 70 | ))} 71 | 72 | )} 73 | 74 |
Order IdQuantityPriceStatusActions
41 | 42 |
#{_id}{orderItems?.length}{totalPrice.toFixed(2)} 54 | 55 | 57 | {" "} 58 | 59 | {" "} 60 | 67 | 68 |
75 |
76 |

83 | {orders?.length === 0 && "Your order is empty."} 84 |

85 |
86 | ); 87 | }; 88 | 89 | export default MyOrders; 90 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/UserDashboard/OrderDetails/OrderDetails.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import { useToasts } from "react-toast-notifications"; 3 | import { useSelector, useDispatch } from "react-redux"; 4 | import { Link, useParams } from "react-router-dom"; 5 | import { 6 | clearErrors, 7 | getOrderDetails, 8 | } from "../../../../redux/actions/orderActions"; 9 | import Loader from "../../../../components/Loader/Loader"; 10 | 11 | const OrderDetails = () => { 12 | const { order, error, loading } = useSelector((state) => state.orderDetails); 13 | const dispatch = useDispatch(); 14 | const { orderId } = useParams(); 15 | const { addToast } = useToasts(); 16 | 17 | useEffect(() => { 18 | if (error) { 19 | addToast(error, { appearance: "error", autoDismiss: true }); 20 | dispatch(clearErrors()); 21 | } 22 | dispatch(getOrderDetails(orderId)); 23 | }, [dispatch, error, addToast, orderId]); 24 | return ( 25 | <> 26 | {loading ? ( 27 | 28 | ) : error ? ( 29 |

{error}

30 | ) : ( 31 | <> 32 |
33 |
34 |

35 | Order Id: #{order && order._id} 36 |

37 |
38 |

Shipping Info

39 |
40 |

Name:

41 | {order.user && order.user.name} 42 |
43 | 44 |
45 |

Address:

46 | 47 | {order.shippingInfo && 48 | `${order.shippingInfo.address_line1}, ${order.shippingInfo.address_city}, ${order.shippingInfo.address_zip}, ${order.shippingInfo.address_country}`} 49 | 50 |
51 |
52 |
53 |

Payment

54 |
55 |

63 | {order.paymentInfo && 64 | order.paymentInfo.status === "succeeded" 65 | ? "PAID" 66 | : "NOT PAID"} 67 |

68 |
69 | 70 |
71 |

Amount:

72 | ${order.totalPrice && order.totalPrice} 73 |
74 |
75 | 76 |
77 |

Order Status

78 |
79 |

86 | {order.orderStatus && order.orderStatus} 87 |

88 |
89 |
90 |
91 | 92 |
93 |

Order Items:

94 |
95 | {order.orderItems && 96 | order.orderItems.map((item) => ( 97 |
98 | Product 99 | 100 | {item.name} 101 | {" "} 102 | 103 | {item.quantity} X ${item.price} ={" "} 104 | ${item.price * item.quantity} 105 | 106 |
107 | ))} 108 |
109 |
110 |
111 | 112 | )} 113 | 114 | ); 115 | }; 116 | 117 | export default OrderDetails; 118 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/UserDashboard/Sidebar/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { VscChromeClose } from "react-icons/vsc"; 3 | import { Link, useNavigate } from "react-router-dom"; 4 | import { AiOutlineMenu } from "react-icons/ai"; 5 | import { BiLogOutCircle, BiShoppingBag } from "react-icons/bi"; 6 | import { BsPerson } from "react-icons/bs"; 7 | import { useDispatch, useSelector } from "react-redux"; 8 | import { useToasts } from "react-toast-notifications"; 9 | import { logout } from "../../../../redux/actions/userActions"; 10 | import { USER_LOGOUT_RESET } from "../../../../redux/constants/userConstants"; 11 | 12 | const Sidebar = () => { 13 | const [currentLink, setCurrentLink] = useState(1); 14 | const [navbarState, setNavbarState] = useState(false); 15 | const width = navbarState ? "60%" : "0%"; 16 | const navigate = useNavigate(); 17 | 18 | const dispatch = useDispatch(); 19 | const { addToast } = useToasts(); 20 | 21 | const user = useSelector((state) => state.userLogin); 22 | const { userInfo } = user; 23 | 24 | const logoutUser = useSelector((state) => state.userLogout); 25 | const { userLogout, error } = logoutUser; 26 | 27 | const handleLogout = () => { 28 | if (!userInfo?.access_token) return; 29 | dispatch(logout(userInfo?.access_token)); 30 | }; 31 | 32 | useEffect(() => { 33 | if (error) { 34 | dispatch({ type: USER_LOGOUT_RESET }); 35 | // addToast(error, { appearance: "error", autoDismiss: true }); 36 | } else if (userLogout) { 37 | dispatch({ type: USER_LOGOUT_RESET }); 38 | 39 | // addToast(userLogout?.message, { 40 | // appearance: "success", 41 | // autoDismiss: true, 42 | // }); 43 | 44 | navigate("/"); 45 | } 46 | }, [userLogout, error, addToast, dispatch, navigate]); 47 | 48 | return ( 49 | <> 50 |
51 |
52 |
53 | Dashboard 54 |
55 |
56 | {navbarState ? ( 57 | setNavbarState(false)} /> 58 | ) : ( 59 | { 61 | e.stopPropagation(); 62 | setNavbarState(true); 63 | }} 64 | /> 65 | )} 66 |
67 |
68 |
    69 |
  • setCurrentLink(1)} 72 | > 73 | 74 | 75 | Profile 76 | 77 |
  • 78 |
  • setCurrentLink(2)} 81 | > 82 | 83 | 84 | My Orders 85 | 86 |
  • 87 | 88 |
  • 89 | 90 | Logout 91 |
  • 92 |
93 |
94 |
95 |
96 |
101 |
102 |
    103 |
  • setCurrentLink(1)} 106 | > 107 | setNavbarState(false)}> 108 | 109 | Profile 110 | 111 |
  • 112 |
  • setCurrentLink(2)} 115 | > 116 | setNavbarState(false)} 119 | > 120 | 121 | My Orders 122 | 123 |
  • 124 | 125 |
  • setNavbarState(false), handleLogout)} 128 | > 129 | 130 | Logout 131 |
  • 132 |
133 |
134 |
135 | 136 | ); 137 | }; 138 | 139 | export default Sidebar; 140 | -------------------------------------------------------------------------------- /server/client/src/pages/Manager/UserDashboard/UserDashboard.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Outlet } from "react-router-dom"; 3 | import Sidebar from "./Sidebar/Sidebar"; 4 | 5 | const AdminDashboard = () => ( 6 | <> 7 | 8 |
9 |
10 | {/* used nested route data show here */} 11 | 12 |
13 |
14 | 15 | ); 16 | 17 | export default AdminDashboard; 18 | -------------------------------------------------------------------------------- /server/client/src/pages/NotFound/NotFound.jsx: -------------------------------------------------------------------------------- 1 | const NotFound = () => ( 2 |
3 |

404, Page Not Found!

4 |
5 | ); 6 | 7 | export default NotFound; 8 | -------------------------------------------------------------------------------- /server/client/src/pages/PrivateRoute/PrivateRoute.jsx: -------------------------------------------------------------------------------- 1 | import { useSelector } from "react-redux"; 2 | import { Navigate, useLocation } from "react-router-dom"; 3 | import Loading from "../../components/Loading/Loading"; 4 | 5 | const PrivateRoute = ({ children }) => { 6 | const user = useSelector((state) => state?.userLogin); 7 | const { userInfo, loading } = user; 8 | let location = useLocation(); 9 | if (loading) { 10 | return ; 11 | } 12 | 13 | if (!userInfo?.access_token) { 14 | return ; 15 | } 16 | return children; 17 | }; 18 | 19 | export default PrivateRoute; 20 | -------------------------------------------------------------------------------- /server/client/src/pages/ProductDetail/ProductDetail.jsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { useDispatch, useSelector } from "react-redux"; 3 | import { FiShoppingCart } from "react-icons/fi"; 4 | import { useParams } from "react-router-dom"; 5 | import { useToasts } from "react-toast-notifications"; 6 | import { getProductById } from "../../redux/actions/productActions"; 7 | import { addItemsToCart } from "../../redux/actions/cartActions"; 8 | import { Footer, Loader, ProductRating } from "../../components"; 9 | 10 | const ProductDetail = () => { 11 | const { productId } = useParams(); 12 | const dispatch = useDispatch(); 13 | const { product, loading } = useSelector((state) => state.productById); 14 | 15 | const { cartItems } = useSelector((state) => state.cart); 16 | 17 | const addOrNot = cartItems?.find((item) => item.product === product._id); 18 | 19 | const { addToast } = useToasts(); 20 | 21 | useEffect(() => { 22 | dispatch(getProductById(productId)); 23 | }, [productId, dispatch]); 24 | 25 | const [quantity, setQuantity] = useState(1); 26 | 27 | const addToCartHandler = () => { 28 | dispatch(addItemsToCart(productId, quantity, addToast)); 29 | }; 30 | 31 | return ( 32 | <> 33 |
34 | {loading ? ( 35 | 36 | ) : ( 37 |
38 |
39 | 40 |
41 | 42 |
43 |

{product.name}

44 | 45 |
46 | 47 | ${product.price}.00 48 | 49 |
50 |
51 | ( 52 | {product.ratings}) 53 |
54 | 55 |
56 |

Status: {product.Stock < 0 ? "Out Of Stock" : "In Stock"}

57 |
58 | 59 |
60 | 71 |
72 | {product?.Stock && product?.Stock > 0 ? ( 73 | 81 | ) : ( 82 | 85 | )} 86 |
87 |
88 | 89 |
90 |

{product.description}

91 |
92 |
93 |
94 | )} 95 |
96 |