├── MERN Project ├── admin │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── index.html │ ├── src │ │ ├── App.css │ │ ├── App.js │ │ ├── components │ │ │ ├── chart │ │ │ │ ├── Chart.jsx │ │ │ │ └── chart.css │ │ │ ├── featuredInfo │ │ │ │ ├── FeaturedInfo.jsx │ │ │ │ └── featuredInfo.css │ │ │ ├── sidebar │ │ │ │ ├── Sidebar.jsx │ │ │ │ └── sidebar.css │ │ │ ├── topbar │ │ │ │ ├── Topbar.jsx │ │ │ │ └── topbar.css │ │ │ ├── widgetLg │ │ │ │ ├── WidgetLg.jsx │ │ │ │ └── widgetLg.css │ │ │ └── widgetSm │ │ │ │ ├── WidgetSm.jsx │ │ │ │ └── widgetSm.css │ │ ├── dummyData.js │ │ ├── firebase.js │ │ ├── index.js │ │ ├── pages │ │ │ ├── home │ │ │ │ ├── Home.jsx │ │ │ │ └── home.css │ │ │ ├── login │ │ │ │ └── Login.jsx │ │ │ ├── newProduct │ │ │ │ ├── NewProduct.jsx │ │ │ │ └── newProduct.css │ │ │ ├── newUser │ │ │ │ ├── NewUser.jsx │ │ │ │ └── newUser.css │ │ │ ├── product │ │ │ │ ├── Product.jsx │ │ │ │ └── product.css │ │ │ ├── productList │ │ │ │ ├── ProductList.jsx │ │ │ │ └── productList.css │ │ │ ├── user │ │ │ │ ├── User.jsx │ │ │ │ └── user.css │ │ │ └── userList │ │ │ │ ├── UserList.jsx │ │ │ │ └── userList.css │ │ ├── redux │ │ │ ├── apiCalls.js │ │ │ ├── productRedux.js │ │ │ ├── store.js │ │ │ └── userRedux.js │ │ └── requestMethods.js │ └── yarn.lock ├── api │ ├── .gitignore │ ├── index.js │ ├── models │ │ ├── Cart.js │ │ ├── Order.js │ │ ├── Product.js │ │ └── User.js │ ├── package-lock.json │ ├── package.json │ ├── routes │ │ ├── auth.js │ │ ├── cart.js │ │ ├── order.js │ │ ├── product.js │ │ ├── stripe.js │ │ ├── user.js │ │ └── verifyToken.js │ └── yarn.lock └── client │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ └── index.html │ ├── src │ ├── App.jsx │ ├── components │ │ ├── Announcement.jsx │ │ ├── Categories.jsx │ │ ├── CategoryItem.jsx │ │ ├── Footer.jsx │ │ ├── Navbar.jsx │ │ ├── Newsletter.jsx │ │ ├── Product.jsx │ │ ├── Products.jsx │ │ └── Slider.jsx │ ├── data.js │ ├── index.js │ ├── pages │ │ ├── Cart.jsx │ │ ├── Home.jsx │ │ ├── Login.jsx │ │ ├── Product.jsx │ │ ├── ProductList.jsx │ │ ├── Register.jsx │ │ └── Success.jsx │ ├── redux │ │ ├── apiCalls.js │ │ ├── cartRedux.js │ │ ├── store.js │ │ └── userRedux.js │ ├── requestMethods.js │ └── responsive.js │ └── yarn.lock ├── README.md ├── React Quiz ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public │ └── index.html ├── src │ ├── App.css │ ├── App.jsx │ ├── assets │ │ └── bg.jpg │ ├── components │ │ ├── Start.jsx │ │ ├── Timer.jsx │ │ └── Trivia.jsx │ ├── index.js │ └── sounds │ │ ├── correct.mp3 │ │ ├── play.mp3 │ │ ├── wait.mp3 │ │ └── wrong.mp3 └── yarn.lock ├── _config.yml └── mern-blog-app ├── api ├── .gitignore ├── index.js ├── models │ ├── Category.js │ ├── Post.js │ └── User.js ├── package.json ├── routes │ ├── auth.js │ ├── categories.js │ ├── posts.js │ └── users.js └── yarn.lock └── client ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── public └── index.html ├── src ├── App.js ├── components │ ├── header │ │ ├── Header.jsx │ │ └── header.css │ ├── post │ │ ├── Post.jsx │ │ └── post.css │ ├── posts │ │ ├── Posts.jsx │ │ └── posts.css │ ├── sidebar │ │ ├── Sidebar.jsx │ │ └── sidebar.css │ ├── singlePost │ │ ├── SinglePost.jsx │ │ └── singlePost.css │ └── topbar │ │ ├── TopBar.jsx │ │ └── topbar.css ├── context │ ├── Actions.js │ ├── Context.js │ └── Reducer.js ├── index.js └── pages │ ├── home │ ├── Home.jsx │ └── home.css │ ├── login │ ├── Login.jsx │ └── login.css │ ├── register │ ├── Register.jsx │ └── register.css │ ├── settings │ ├── Settings.jsx │ └── settings.css │ ├── single │ ├── Single.jsx │ └── single.css │ └── write │ ├── Write.jsx │ └── write.css └── yarn.lock /MERN Project/admin/.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 | -------------------------------------------------------------------------------- /MERN Project/admin/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 | ### `yarn start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn 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 | ### `yarn 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 | ### `yarn 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 | ### `yarn 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 | -------------------------------------------------------------------------------- /MERN Project/admin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lamaadmin", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.11.4", 7 | "@material-ui/data-grid": "^4.0.0-alpha.29", 8 | "@material-ui/icons": "^4.11.2", 9 | "@reduxjs/toolkit": "^1.6.1", 10 | "@testing-library/jest-dom": "^5.11.4", 11 | "@testing-library/react": "^11.1.0", 12 | "@testing-library/user-event": "^12.1.10", 13 | "axios": "^0.21.4", 14 | "firebase": "^9.1.0", 15 | "react": "^17.0.2", 16 | "react-dom": "^17.0.2", 17 | "react-redux": "^7.2.5", 18 | "react-router-dom": "^5.2.0", 19 | "react-scripts": "4.0.3", 20 | "recharts": "^2.0.9", 21 | "redux-persist": "^6.0.0", 22 | "timeago.js": "^4.0.2", 23 | "web-vitals": "^1.0.1" 24 | }, 25 | "scripts": { 26 | "start": "react-scripts start", 27 | "build": "react-scripts build", 28 | "test": "react-scripts test", 29 | "eject": "react-scripts eject" 30 | }, 31 | "eslintConfig": { 32 | "extends": [ 33 | "react-app", 34 | "react-app/jest" 35 | ] 36 | }, 37 | "browserslist": { 38 | "production": [ 39 | ">0.2%", 40 | "not dead", 41 | "not op_mini all" 42 | ], 43 | "development": [ 44 | "last 1 chrome version", 45 | "last 1 firefox version", 46 | "last 1 safari version" 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /MERN Project/admin/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 18 | React Admin App 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /MERN Project/admin/src/App.css: -------------------------------------------------------------------------------- 1 | .container{ 2 | display: flex; 3 | margin-top: 10px; 4 | } 5 | 6 | 7 | .link{ 8 | text-decoration: none; 9 | color: inherit; 10 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/App.js: -------------------------------------------------------------------------------- 1 | import Sidebar from "./components/sidebar/Sidebar"; 2 | import Topbar from "./components/topbar/Topbar"; 3 | import "./App.css"; 4 | import Home from "./pages/home/Home"; 5 | import { 6 | BrowserRouter as Router, 7 | Switch, 8 | Route, 9 | Redirect, 10 | } from "react-router-dom"; 11 | import UserList from "./pages/userList/UserList"; 12 | import User from "./pages/user/User"; 13 | import NewUser from "./pages/newUser/NewUser"; 14 | import ProductList from "./pages/productList/ProductList"; 15 | import Product from "./pages/product/Product"; 16 | import NewProduct from "./pages/newProduct/NewProduct"; 17 | import Login from "./pages/login/Login"; 18 | import { useSelector } from "react-redux"; 19 | 20 | function App() { 21 | const admin = useSelector((state) => state.user.currentUser.isAdmin); 22 | return ( 23 | 24 | 25 | 26 | 27 | 28 | {admin && ( 29 | <> 30 | 31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | )} 57 |
58 |
59 | ); 60 | } 61 | 62 | export default App; 63 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/chart/Chart.jsx: -------------------------------------------------------------------------------- 1 | import "./chart.css"; 2 | import { 3 | LineChart, 4 | Line, 5 | XAxis, 6 | CartesianGrid, 7 | Tooltip, 8 | ResponsiveContainer, 9 | } from "recharts"; 10 | 11 | export default function Chart({ title, data, dataKey, grid }) { 12 | 13 | return ( 14 |
15 |

{title}

16 | 17 | 18 | 19 | 20 | 21 | {grid && } 22 | 23 | 24 |
25 | ); 26 | } 27 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/chart/chart.css: -------------------------------------------------------------------------------- 1 | .chart { 2 | margin: 20px; 3 | padding: 20px; 4 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 5 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 6 | } 7 | 8 | .chartTitle { 9 | margin-bottom: 20px; 10 | } 11 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/featuredInfo/FeaturedInfo.jsx: -------------------------------------------------------------------------------- 1 | import "./featuredInfo.css"; 2 | import { ArrowDownward, ArrowUpward } from "@material-ui/icons"; 3 | import { useEffect, useState } from "react"; 4 | import { userRequest } from "../../requestMethods"; 5 | 6 | export default function FeaturedInfo() { 7 | const [income, setIncome] = useState([]); 8 | const [perc, setPerc] = useState(0); 9 | 10 | useEffect(() => { 11 | const getIncome = async () => { 12 | try { 13 | const res = await userRequest.get("orders/income"); 14 | setIncome(res.data); 15 | setPerc((res.data[1].total * 100) / res.data[0].total - 100); 16 | } catch {} 17 | }; 18 | getIncome(); 19 | }, []); 20 | 21 | return ( 22 |
23 |
24 | Revanue 25 |
26 | ${income[1]?.total} 27 | 28 | %{Math.floor(perc)}{" "} 29 | {perc < 0 ? ( 30 | 31 | ) : ( 32 | 33 | )} 34 | 35 |
36 | Compared to last month 37 |
38 |
39 | Sales 40 |
41 | $4,415 42 | 43 | -1.4 44 | 45 |
46 | Compared to last month 47 |
48 |
49 | Cost 50 |
51 | $2,225 52 | 53 | +2.4 54 | 55 |
56 | Compared to last month 57 |
58 |
59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/featuredInfo/featuredInfo.css: -------------------------------------------------------------------------------- 1 | .featured { 2 | width: 100%; 3 | display: flex; 4 | justify-content: space-between; 5 | } 6 | 7 | .featuredItem { 8 | flex: 1; 9 | margin: 0px 20px; 10 | padding: 30px; 11 | border-radius: 10px; 12 | cursor: pointer; 13 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 14 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 15 | } 16 | 17 | .featuredTitle{ 18 | font-size: 20px; 19 | } 20 | 21 | .featuredMoneyContainer{ 22 | margin: 10px 0px; 23 | display: flex; 24 | align-items: center; 25 | } 26 | 27 | .featuredMoney{ 28 | font-size: 30px; 29 | font-weight: 600; 30 | } 31 | 32 | .featuredMoneyRate{ 33 | display: flex; 34 | align-items: center; 35 | margin-left: 20px; 36 | } 37 | 38 | .featuredIcon{ 39 | font-size: 14px; 40 | margin-left: 5px; 41 | color: green; 42 | } 43 | 44 | .featuredIcon.negative{ 45 | color: red; 46 | } 47 | 48 | .featuredSub{ 49 | font-size: 15px; 50 | color: gray; 51 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/components/sidebar/Sidebar.jsx: -------------------------------------------------------------------------------- 1 | import "./sidebar.css"; 2 | import { 3 | LineStyle, 4 | Timeline, 5 | TrendingUp, 6 | PermIdentity, 7 | Storefront, 8 | AttachMoney, 9 | BarChart, 10 | MailOutline, 11 | DynamicFeed, 12 | ChatBubbleOutline, 13 | WorkOutline, 14 | Report, 15 | } from "@material-ui/icons"; 16 | import { Link } from "react-router-dom"; 17 | 18 | export default function Sidebar() { 19 | return ( 20 |
21 |
22 |
23 |

Dashboard

24 |
    25 | 26 |
  • 27 | 28 | Home 29 |
  • 30 | 31 |
  • 32 | 33 | Analytics 34 |
  • 35 |
  • 36 | 37 | Sales 38 |
  • 39 |
40 |
41 |
42 |

Quick Menu

43 |
    44 | 45 |
  • 46 | 47 | Users 48 |
  • 49 | 50 | 51 |
  • 52 | 53 | Products 54 |
  • 55 | 56 |
  • 57 | 58 | Transactions 59 |
  • 60 |
  • 61 | 62 | Reports 63 |
  • 64 |
65 |
66 |
67 |

Notifications

68 |
    69 |
  • 70 | 71 | Mail 72 |
  • 73 |
  • 74 | 75 | Feedback 76 |
  • 77 |
  • 78 | 79 | Messages 80 |
  • 81 |
82 |
83 |
84 |

Staff

85 |
    86 |
  • 87 | 88 | Manage 89 |
  • 90 |
  • 91 | 92 | Analytics 93 |
  • 94 |
  • 95 | 96 | Reports 97 |
  • 98 |
99 |
100 |
101 |
102 | ); 103 | } 104 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/sidebar/sidebar.css: -------------------------------------------------------------------------------- 1 | .sidebar { 2 | flex: 1; 3 | height: calc(100vh - 50px); 4 | background-color: rgb(251, 251, 255); 5 | position: sticky; 6 | top: 50px; 7 | } 8 | 9 | .sidebarWrapper { 10 | padding: 20px; 11 | color: #555; 12 | } 13 | 14 | .sidebarMenu { 15 | margin-bottom: 10px; 16 | } 17 | 18 | .sidebarTitle { 19 | font-size: 13px; 20 | color: rgb(187, 186, 186); 21 | } 22 | 23 | .sidebarList { 24 | list-style: none; 25 | padding: 5px; 26 | } 27 | 28 | .sidebarListItem { 29 | padding: 5px; 30 | cursor: pointer; 31 | display: flex; 32 | align-items: center; 33 | border-radius: 10px; 34 | } 35 | 36 | .sidebarListItem.active, 37 | .sidebarListItem:hover { 38 | background-color: rgb(240, 240, 255); 39 | } 40 | 41 | .sidebarIcon{ 42 | margin-right: 5px; 43 | font-size: 20px !important; 44 | } 45 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/topbar/Topbar.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./topbar.css"; 3 | import { NotificationsNone, Language, Settings } from "@material-ui/icons"; 4 | 5 | export default function Topbar() { 6 | return ( 7 |
8 |
9 |
10 | lamaadmin 11 |
12 |
13 |
14 | 15 | 2 16 |
17 |
18 | 19 | 2 20 |
21 |
22 | 23 |
24 | 25 |
26 |
27 |
28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/topbar/topbar.css: -------------------------------------------------------------------------------- 1 | .topbar { 2 | width: 100%; 3 | height: 50px; 4 | background-color: white; 5 | position: sticky; 6 | top: 0; 7 | z-index: 999; 8 | } 9 | 10 | .topbarWrapper { 11 | height: 100%; 12 | padding: 0px 20px; 13 | display: flex; 14 | align-items: center; 15 | justify-content: space-between; 16 | } 17 | 18 | .logo { 19 | font-weight: bold; 20 | font-size: 30px; 21 | color: darkblue; 22 | cursor: pointer; 23 | } 24 | 25 | .topRight{ 26 | display: flex; 27 | align-items: center; 28 | } 29 | 30 | .topbarIconContainer { 31 | position: relative; 32 | cursor: pointer; 33 | margin-right: 10px; 34 | color: #555; 35 | } 36 | 37 | .topIconBadge{ 38 | width: 15px; 39 | height: 15px; 40 | position: absolute; 41 | top: -5px; 42 | right: 0px; 43 | background-color: red; 44 | color: white; 45 | border-radius: 50%; 46 | display: flex; 47 | align-items: center; 48 | justify-content: center; 49 | font-size: 10px; 50 | } 51 | 52 | .topAvatar{ 53 | width: 40px; 54 | height: 40px; 55 | border-radius: 50%; 56 | cursor: pointer; 57 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/components/widgetLg/WidgetLg.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import { userRequest } from "../../requestMethods"; 3 | import "./widgetLg.css"; 4 | import {format} from "timeago.js" 5 | 6 | export default function WidgetLg() { 7 | const [orders, setOrders] = useState([]); 8 | 9 | useEffect(() => { 10 | const getOrders = async () => { 11 | try { 12 | const res = await userRequest.get("orders"); 13 | setOrders(res.data); 14 | } catch {} 15 | }; 16 | getOrders(); 17 | }, []); 18 | const Button = ({ type }) => { 19 | return ; 20 | }; 21 | return ( 22 |
23 |

Latest transactions

24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | {orders.map((order) => ( 32 | 33 | 36 | 37 | 38 | 41 | 42 | ))} 43 |
CustomerDateAmountStatus
34 | {order.userId} 35 | {format(order.createdAt)}${order.amount} 39 |
44 |
45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/widgetLg/widgetLg.css: -------------------------------------------------------------------------------- 1 | .widgetLg { 2 | flex: 2; 3 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 4 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 5 | padding: 20px; 6 | } 7 | 8 | .widgetLgTitle { 9 | font-size: 22px; 10 | font-weight: 600; 11 | } 12 | 13 | .widgetLgTable{ 14 | width: 100%; 15 | border-spacing: 20px; 16 | } 17 | 18 | .widgetLgTh{ 19 | text-align: left; 20 | } 21 | 22 | .widgetLgUser{ 23 | display: flex; 24 | align-items: center; 25 | font-weight: 600; 26 | } 27 | 28 | .widgetLgImg { 29 | width: 40px; 30 | height: 40px; 31 | border-radius: 50%; 32 | object-fit: cover; 33 | margin-right: 10px; 34 | } 35 | 36 | .widgetLgDate,.widgetLgAmount{ 37 | font-weight: 300; 38 | } 39 | 40 | .widgetLgButton { 41 | padding: 5px 7px; 42 | border: none; 43 | border-radius: 10px; 44 | } 45 | 46 | .widgetLgButton.approved{ 47 | background-color: #e5faf2; 48 | color: #3bb077; 49 | } 50 | .widgetLgButton.declined{ 51 | background-color: #fff0f1; 52 | color: #d95087; 53 | 54 | } 55 | .widgetLgButton.pending{ 56 | background-color: #ebf1fe; 57 | color: #2a7ade; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/widgetSm/WidgetSm.jsx: -------------------------------------------------------------------------------- 1 | import "./widgetSm.css"; 2 | import { Visibility } from "@material-ui/icons"; 3 | import { useEffect, useState } from "react"; 4 | import { userRequest } from "../../requestMethods"; 5 | 6 | export default function WidgetSm() { 7 | const [users, setUsers] = useState([]); 8 | 9 | useEffect(() => { 10 | const getUsers = async () => { 11 | try { 12 | const res = await userRequest.get("users/?new=true"); 13 | setUsers(res.data); 14 | } catch {} 15 | }; 16 | getUsers(); 17 | }, []); 18 | 19 | return ( 20 |
21 | New Join Members 22 | 43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /MERN Project/admin/src/components/widgetSm/widgetSm.css: -------------------------------------------------------------------------------- 1 | .widgetSm{ 2 | flex: 1; 3 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 4 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 5 | padding: 20px; 6 | margin-right: 20px; 7 | } 8 | 9 | .widgetSmTitle{ 10 | font-size: 22px; 11 | font-weight: 600; 12 | } 13 | 14 | .widgetSmImg{ 15 | width: 40px; 16 | height: 40px; 17 | border-radius: 50%; 18 | object-fit: cover; 19 | } 20 | 21 | .widgetSmList{ 22 | margin: 0; 23 | padding: 0; 24 | list-style: none; 25 | } 26 | 27 | .widgetSmListItem{ 28 | display: flex; 29 | align-items: center; 30 | justify-content: space-between; 31 | margin: 20px 0px; 32 | } 33 | 34 | .widgetSmUser{ 35 | display: flex; 36 | flex-direction: column; 37 | } 38 | 39 | .widgetSmUsername{ 40 | font-weight: 600; 41 | } 42 | 43 | .widgetSmUserTitle{ 44 | font-weight: 300; 45 | } 46 | 47 | .widgetSmButton{ 48 | display: flex; 49 | align-items: center; 50 | border: none; 51 | border-radius: 10px; 52 | padding: 7px 10px; 53 | background-color: #eeeef7; 54 | color: #555; 55 | cursor: pointer; 56 | } 57 | 58 | .widgetSmIcon{ 59 | font-size: 16px !important; 60 | margin-right: 5px; 61 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/dummyData.js: -------------------------------------------------------------------------------- 1 | export const userData = [ 2 | { 3 | name: "Jan", 4 | "Active User": 4000, 5 | }, 6 | { 7 | name: "Feb", 8 | "Active User": 3000, 9 | }, 10 | { 11 | name: "Mar", 12 | "Active User": 5000, 13 | }, 14 | { 15 | name: "Apr", 16 | "Active User": 4000, 17 | }, 18 | { 19 | name: "May", 20 | "Active User": 3000, 21 | }, 22 | { 23 | name: "Jun", 24 | "Active User": 2000, 25 | }, 26 | { 27 | name: "Jul", 28 | "Active User": 4000, 29 | }, 30 | { 31 | name: "Agu", 32 | "Active User": 3000, 33 | }, 34 | { 35 | name: "Sep", 36 | "Active User": 4000, 37 | }, 38 | { 39 | name: "Oct", 40 | "Active User": 1000, 41 | }, 42 | { 43 | name: "Nov", 44 | "Active User": 4000, 45 | }, 46 | { 47 | name: "Dec", 48 | "Active User": 3000, 49 | }, 50 | ]; 51 | 52 | export const productData = [ 53 | { 54 | name: "Jan", 55 | "Sales": 4000, 56 | }, 57 | { 58 | name: "Feb", 59 | "Sales": 3000, 60 | }, 61 | { 62 | name: "Mar", 63 | "Sales": 5000, 64 | }, 65 | ]; 66 | 67 | export const userRows = [ 68 | { 69 | id: 1, 70 | username: "Jon Snow", 71 | avatar: 72 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 73 | email: "jon@gmail.com", 74 | status: "active", 75 | transaction: "$120.00", 76 | }, 77 | { 78 | id: 2, 79 | username: "Jon Snow", 80 | avatar: 81 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 82 | email: "jon@gmail.com", 83 | status: "active", 84 | transaction: "$120.00", 85 | }, 86 | { 87 | id: 3, 88 | username: "Jon Snow", 89 | avatar: 90 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 91 | email: "jon@gmail.com", 92 | status: "active", 93 | transaction: "$120.00", 94 | }, 95 | { 96 | id: 4, 97 | username: "Jon Snow", 98 | avatar: 99 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 100 | email: "jon@gmail.com", 101 | status: "active", 102 | transaction: "$120.00", 103 | }, 104 | { 105 | id: 5, 106 | username: "Jon Snow", 107 | avatar: 108 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 109 | email: "jon@gmail.com", 110 | status: "active", 111 | transaction: "$120.00", 112 | }, 113 | { 114 | id: 6, 115 | username: "Jon Snow", 116 | avatar: 117 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 118 | email: "jon@gmail.com", 119 | status: "active", 120 | transaction: "$120.00", 121 | }, 122 | { 123 | id: 7, 124 | username: "Jon Snow", 125 | avatar: 126 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 127 | email: "jon@gmail.com", 128 | status: "active", 129 | transaction: "$120.00", 130 | }, 131 | { 132 | id: 8, 133 | username: "Jon Snow", 134 | avatar: 135 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 136 | email: "jon@gmail.com", 137 | status: "active", 138 | transaction: "$120.00", 139 | }, 140 | { 141 | id: 9, 142 | username: "Jon Snow", 143 | avatar: 144 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 145 | email: "jon@gmail.com", 146 | status: "active", 147 | transaction: "$120.00", 148 | }, 149 | { 150 | id: 10, 151 | username: "Jon Snow", 152 | avatar: 153 | "https://images.pexels.com/photos/1152994/pexels-photo-1152994.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 154 | email: "jon@gmail.com", 155 | status: "active", 156 | transaction: "$120.00", 157 | }, 158 | ]; 159 | 160 | export const productRows = [ 161 | { 162 | id: 1, 163 | name: "Apple Airpods", 164 | img: 165 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 166 | stock: 123, 167 | status: "active", 168 | price: "$120.00", 169 | }, 170 | { 171 | id: 2, 172 | name: "Apple Airpods", 173 | img: 174 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 175 | stock: 123, 176 | status: "active", 177 | price: "$120.00", 178 | }, 179 | { 180 | id: 3, 181 | name: "Apple Airpods", 182 | img: 183 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 184 | stock: 123, 185 | status: "active", 186 | price: "$120.00", 187 | }, 188 | { 189 | id: 4, 190 | name: "Apple Airpods", 191 | img: 192 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 193 | stock: 123, 194 | status: "active", 195 | price: "$120.00", 196 | }, 197 | { 198 | id: 5, 199 | name: "Apple Airpods", 200 | img: 201 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 202 | stock: 123, 203 | status: "active", 204 | price: "$120.00", 205 | }, 206 | { 207 | id: 6, 208 | name: "Apple Airpods", 209 | img: 210 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 211 | stock: 123, 212 | status: "active", 213 | price: "$120.00", 214 | }, 215 | { 216 | id: 7, 217 | name: "Apple Airpods", 218 | img: 219 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 220 | stock: 123, 221 | status: "active", 222 | price: "$120.00", 223 | }, 224 | { 225 | id: 8, 226 | name: "Apple Airpods", 227 | img: 228 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 229 | stock: 123, 230 | status: "active", 231 | price: "$120.00", 232 | }, 233 | { 234 | id: 9, 235 | name: "Apple Airpods", 236 | img: 237 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 238 | stock: 123, 239 | status: "active", 240 | price: "$120.00", 241 | }, 242 | { 243 | id: 10, 244 | name: "Apple Airpods", 245 | img: 246 | "https://images.pexels.com/photos/7156886/pexels-photo-7156886.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 247 | stock: 123, 248 | status: "active", 249 | price: "$120.00", 250 | }, 251 | ]; -------------------------------------------------------------------------------- /MERN Project/admin/src/firebase.js: -------------------------------------------------------------------------------- 1 | // Import the functions you need from the SDKs you need 2 | import { initializeApp } from "firebase/app"; 3 | // TODO: Add SDKs for Firebase products that you want to use 4 | // https://firebase.google.com/docs/web/setup#available-libraries 5 | 6 | // Your web app's Firebase configuration 7 | const firebaseConfig = { 8 | apiKey: "AIzaSyCB-h_T2ZL-a7xt5zMvZmSh8GBXtawzL0c", 9 | authDomain: "shop-889c6.firebaseapp.com", 10 | projectId: "shop-889c6", 11 | storageBucket: "shop-889c6.appspot.com", 12 | messagingSenderId: "105110075028", 13 | appId: "1:105110075028:web:7cee5adf1ed39f597e6681", 14 | }; 15 | 16 | // Initialize Firebase 17 | const app = initializeApp(firebaseConfig); 18 | 19 | export default app; 20 | -------------------------------------------------------------------------------- /MERN Project/admin/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | import { Provider } from "react-redux"; 5 | import { store, persistor } from "./redux/store"; 6 | import { PersistGate } from "redux-persist/integration/react"; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | 12 | 13 | , 14 | document.getElementById("root") 15 | ); 16 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/home/Home.jsx: -------------------------------------------------------------------------------- 1 | import Chart from "../../components/chart/Chart"; 2 | import FeaturedInfo from "../../components/featuredInfo/FeaturedInfo"; 3 | import "./home.css"; 4 | import { userData } from "../../dummyData"; 5 | import WidgetSm from "../../components/widgetSm/WidgetSm"; 6 | import WidgetLg from "../../components/widgetLg/WidgetLg"; 7 | import { useEffect, useMemo, useState } from "react"; 8 | import { userRequest } from "../../requestMethods"; 9 | 10 | export default function Home() { 11 | const [userStats, setUserStats] = useState([]); 12 | 13 | const MONTHS = useMemo( 14 | () => [ 15 | "Jan", 16 | "Feb", 17 | "Mar", 18 | "Apr", 19 | "May", 20 | "Jun", 21 | "Jul", 22 | "Agu", 23 | "Sep", 24 | "Oct", 25 | "Nov", 26 | "Dec", 27 | ], 28 | [] 29 | ); 30 | 31 | useEffect(() => { 32 | const getStats = async () => { 33 | try { 34 | const res = await userRequest.get("/users/stats"); 35 | res.data.map((item) => 36 | setUserStats((prev) => [ 37 | ...prev, 38 | { name: MONTHS[item._id - 1], "Active User": item.total }, 39 | ]) 40 | ); 41 | } catch {} 42 | }; 43 | getStats(); 44 | }, [MONTHS]); 45 | 46 | return ( 47 |
48 | 49 | 55 |
56 | 57 | 58 |
59 |
60 | ); 61 | } 62 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/home/home.css: -------------------------------------------------------------------------------- 1 | .home{ 2 | flex: 4; 3 | } 4 | 5 | .homeWidgets{ 6 | display: flex; 7 | margin: 20px; 8 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/login/Login.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import { useDispatch } from "react-redux"; 3 | import { login } from "../../redux/apiCalls"; 4 | 5 | const Login = () => { 6 | const [username, setUsername] = useState(""); 7 | const [password, setPassword] = useState(""); 8 | const dispatch = useDispatch(); 9 | 10 | const handleClick = (e) => { 11 | e.preventDefault(); 12 | login(dispatch, { username, password }); 13 | }; 14 | 15 | return ( 16 |
25 | setUsername(e.target.value)} 30 | /> 31 | setPassword(e.target.value)} 36 | /> 37 | 40 |
41 | ); 42 | }; 43 | 44 | export default Login; 45 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/newProduct/NewProduct.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import "./newProduct.css"; 3 | import { 4 | getStorage, 5 | ref, 6 | uploadBytesResumable, 7 | getDownloadURL, 8 | } from "firebase/storage"; 9 | import app from "../../firebase"; 10 | import { addProduct } from "../../redux/apiCalls"; 11 | import { useDispatch } from "react-redux"; 12 | 13 | export default function NewProduct() { 14 | const [inputs, setInputs] = useState({}); 15 | const [file, setFile] = useState(null); 16 | const [cat, setCat] = useState([]); 17 | const dispatch = useDispatch(); 18 | 19 | const handleChange = (e) => { 20 | setInputs((prev) => { 21 | return { ...prev, [e.target.name]: e.target.value }; 22 | }); 23 | }; 24 | const handleCat = (e) => { 25 | setCat(e.target.value.split(",")); 26 | }; 27 | 28 | const handleClick = (e) => { 29 | e.preventDefault(); 30 | const fileName = new Date().getTime() + file.name; 31 | const storage = getStorage(app); 32 | const storageRef = ref(storage, fileName); 33 | const uploadTask = uploadBytesResumable(storageRef, file); 34 | 35 | // Register three observers: 36 | // 1. 'state_changed' observer, called any time the state changes 37 | // 2. Error observer, called on failure 38 | // 3. Completion observer, called on successful completion 39 | uploadTask.on( 40 | "state_changed", 41 | (snapshot) => { 42 | // Observe state change events such as progress, pause, and resume 43 | // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded 44 | const progress = 45 | (snapshot.bytesTransferred / snapshot.totalBytes) * 100; 46 | console.log("Upload is " + progress + "% done"); 47 | switch (snapshot.state) { 48 | case "paused": 49 | console.log("Upload is paused"); 50 | break; 51 | case "running": 52 | console.log("Upload is running"); 53 | break; 54 | default: 55 | } 56 | }, 57 | (error) => { 58 | // Handle unsuccessful uploads 59 | }, 60 | () => { 61 | // Handle successful uploads on complete 62 | // For instance, get the download URL: https://firebasestorage.googleapis.com/... 63 | getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { 64 | const product = { ...inputs, img: downloadURL, categories: cat }; 65 | addProduct(product, dispatch); 66 | }); 67 | } 68 | ); 69 | }; 70 | 71 | return ( 72 |
73 |

New Product

74 |
75 |
76 | 77 | setFile(e.target.files[0])} 81 | /> 82 |
83 |
84 | 85 | 91 |
92 |
93 | 94 | 100 |
101 |
102 | 103 | 109 |
110 |
111 | 112 | 113 |
114 |
115 | 116 | 120 |
121 | 124 |
125 |
126 | ); 127 | } 128 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/newProduct/newProduct.css: -------------------------------------------------------------------------------- 1 | .newProduct { 2 | flex: 4; 3 | margin-left: 100px; 4 | } 5 | 6 | .addProductForm { 7 | margin-top: 10px; 8 | } 9 | 10 | .addProductItem { 11 | width: 250px; 12 | display: flex; 13 | flex-direction: column; 14 | margin-bottom: 10px; 15 | } 16 | 17 | .addProductItem > label { 18 | color: gray; 19 | font-weight: 600; 20 | margin-bottom: 10px; 21 | } 22 | 23 | .addProductItem > input { 24 | padding: 10px; 25 | } 26 | 27 | .addProductItem > select { 28 | padding: 10px; 29 | } 30 | 31 | .addProductButton { 32 | margin-top: 10px; 33 | padding: 7px 10px; 34 | border: none; 35 | border-radius: 10px; 36 | background-color: darkblue; 37 | color: white; 38 | font-weight: 600; 39 | cursor: pointer; 40 | } 41 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/newUser/NewUser.jsx: -------------------------------------------------------------------------------- 1 | import "./newUser.css"; 2 | 3 | export default function NewUser() { 4 | return ( 5 |
6 |

New User

7 |
8 |
9 | 10 | 11 |
12 |
13 | 14 | 15 |
16 |
17 | 18 | 19 |
20 |
21 | 22 | 23 |
24 |
25 | 26 | 27 |
28 |
29 | 30 | 31 |
32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 | 45 | 49 |
50 | 51 |
52 |
53 | ); 54 | } 55 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/newUser/newUser.css: -------------------------------------------------------------------------------- 1 | .newUser { 2 | flex: 4; 3 | } 4 | 5 | .newUserForm { 6 | display: flex; 7 | flex-wrap: wrap; 8 | } 9 | 10 | .newUserItem { 11 | width: 400px; 12 | display: flex; 13 | flex-direction: column; 14 | margin-top: 10px; 15 | margin-right: 20px; 16 | } 17 | 18 | .newUserItem > label { 19 | margin-bottom: 10px; 20 | font-size: 14px; 21 | font-weight: 600; 22 | color: rgb(151, 150, 150); 23 | } 24 | 25 | .newUserItem > input { 26 | height: 20px; 27 | padding: 10px; 28 | border: 1px solid gray; 29 | border-radius: 5px; 30 | } 31 | 32 | .newUserGender > input { 33 | margin-top: 15px; 34 | } 35 | 36 | .newUserGender>label{ 37 | margin: 10px; 38 | font-size: 18px; 39 | color: #555; 40 | } 41 | 42 | .newUserSelect{ 43 | height: 40px; 44 | border-radius: 5px; 45 | } 46 | 47 | .newUserButton{ 48 | width: 200px; 49 | border: none; 50 | background-color: darkblue; 51 | color: white; 52 | padding: 7px 10px; 53 | font-weight: 600; 54 | border-radius: 10px; 55 | margin-top: 30px; 56 | cursor: pointer; 57 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/product/Product.jsx: -------------------------------------------------------------------------------- 1 | import { Link, useLocation } from "react-router-dom"; 2 | import "./product.css"; 3 | import Chart from "../../components/chart/Chart"; 4 | import { productData } from "../../dummyData"; 5 | import { Publish } from "@material-ui/icons"; 6 | import { useSelector } from "react-redux"; 7 | import { useEffect, useMemo, useState } from "react"; 8 | import { userRequest } from "../../requestMethods"; 9 | 10 | export default function Product() { 11 | const location = useLocation(); 12 | const productId = location.pathname.split("/")[2]; 13 | const [pStats, setPStats] = useState([]); 14 | 15 | const product = useSelector((state) => 16 | state.product.products.find((product) => product._id === productId) 17 | ); 18 | 19 | const MONTHS = useMemo( 20 | () => [ 21 | "Jan", 22 | "Feb", 23 | "Mar", 24 | "Apr", 25 | "May", 26 | "Jun", 27 | "Jul", 28 | "Agu", 29 | "Sep", 30 | "Oct", 31 | "Nov", 32 | "Dec", 33 | ], 34 | [] 35 | ); 36 | 37 | useEffect(() => { 38 | const getStats = async () => { 39 | try { 40 | const res = await userRequest.get("orders/income?pid=" + productId); 41 | const list = res.data.sort((a,b)=>{ 42 | return a._id - b._id 43 | }) 44 | list.map((item) => 45 | setPStats((prev) => [ 46 | ...prev, 47 | { name: MONTHS[item._id - 1], Sales: item.total }, 48 | ]) 49 | ); 50 | } catch (err) { 51 | console.log(err); 52 | } 53 | }; 54 | getStats(); 55 | }, [productId, MONTHS]); 56 | 57 | return ( 58 |
59 |
60 |

Product

61 | 62 | 63 | 64 |
65 |
66 |
67 | 68 |
69 |
70 |
71 | 72 | {product.title} 73 |
74 |
75 |
76 | id: 77 | {product._id} 78 |
79 |
80 | sales: 81 | 5123 82 |
83 |
84 | in stock: 85 | {product.inStock} 86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 104 |
105 |
106 |
107 | 108 | 111 | 112 |
113 | 114 |
115 |
116 |
117 |
118 | ); 119 | } 120 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/product/product.css: -------------------------------------------------------------------------------- 1 | .product { 2 | flex: 4; 3 | padding: 20px; 4 | } 5 | 6 | .productTitleContainer { 7 | display: flex; 8 | align-items: center; 9 | justify-content: space-between; 10 | } 11 | 12 | .productAddButton { 13 | width: 80px; 14 | border: none; 15 | padding: 5px; 16 | background-color: teal; 17 | color: white; 18 | border-radius: 5px; 19 | font-size: 16px; 20 | cursor: pointer; 21 | } 22 | 23 | .productTop { 24 | display: flex; 25 | } 26 | 27 | .productTopLeft, 28 | .productTopRight { 29 | flex: 1; 30 | } 31 | 32 | .productTopRight { 33 | padding: 20px; 34 | margin: 20px; 35 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 36 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 37 | } 38 | 39 | .productInfoImg { 40 | width: 40px; 41 | height: 40px; 42 | border-radius: 50%; 43 | object-fit: cover; 44 | margin-right: 20px; 45 | } 46 | 47 | .productInfoTop { 48 | display: flex; 49 | align-items: center; 50 | } 51 | 52 | .productName { 53 | font-weight: 600; 54 | } 55 | 56 | .productInfoBottom { 57 | margin-top: 10px; 58 | } 59 | 60 | .productInfoItem { 61 | width: 150px; 62 | display: flex; 63 | justify-content: space-between; 64 | } 65 | 66 | .productInfoValue { 67 | font-weight: 300; 68 | } 69 | 70 | .productBottom { 71 | padding: 20px; 72 | margin: 20px; 73 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 74 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 75 | } 76 | 77 | .productForm { 78 | display: flex; 79 | justify-content: space-between; 80 | } 81 | 82 | .productFormLeft { 83 | display: flex; 84 | flex-direction: column; 85 | } 86 | 87 | .productFormLeft > label { 88 | margin-bottom: 10px; 89 | color: gray; 90 | } 91 | 92 | .productFormLeft > input { 93 | margin-bottom: 10px; 94 | border: none; 95 | padding: 5px; 96 | border-bottom: 1px solid gray; 97 | } 98 | 99 | .productFormLeft >select{ 100 | margin-bottom: 10px; 101 | } 102 | 103 | .productUploadImg{ 104 | width: 100px; 105 | height: 100px; 106 | border-radius: 10px; 107 | object-fit: cover; 108 | margin-right: 20px; 109 | } 110 | 111 | .productFormRight{ 112 | display: flex; 113 | flex-direction: column; 114 | justify-content: space-around; 115 | } 116 | 117 | .productUpload{ 118 | display: flex; 119 | align-items: center; 120 | } 121 | 122 | .productButton{ 123 | border: none; 124 | padding: 5px; 125 | border-radius: 5px; 126 | background-color: darkblue; 127 | color:white; 128 | font-weight: 600; 129 | cursor: pointer; 130 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/productList/ProductList.jsx: -------------------------------------------------------------------------------- 1 | import "./productList.css"; 2 | import { DataGrid } from "@material-ui/data-grid"; 3 | import { DeleteOutline } from "@material-ui/icons"; 4 | import { Link } from "react-router-dom"; 5 | import { useEffect } from "react"; 6 | import { useDispatch, useSelector } from "react-redux"; 7 | import { deleteProduct, getProducts } from "../../redux/apiCalls"; 8 | 9 | export default function ProductList() { 10 | const dispatch = useDispatch(); 11 | const products = useSelector((state) => state.product.products); 12 | 13 | useEffect(() => { 14 | getProducts(dispatch); 15 | }, [dispatch]); 16 | 17 | const handleDelete = (id) => { 18 | deleteProduct(id, dispatch); 19 | }; 20 | 21 | const columns = [ 22 | { field: "_id", headerName: "ID", width: 220 }, 23 | { 24 | field: "product", 25 | headerName: "Product", 26 | width: 200, 27 | renderCell: (params) => { 28 | return ( 29 |
30 | 31 | {params.row.title} 32 |
33 | ); 34 | }, 35 | }, 36 | { field: "inStock", headerName: "Stock", width: 200 }, 37 | { 38 | field: "price", 39 | headerName: "Price", 40 | width: 160, 41 | }, 42 | { 43 | field: "action", 44 | headerName: "Action", 45 | width: 150, 46 | renderCell: (params) => { 47 | return ( 48 | <> 49 | 50 | 51 | 52 | handleDelete(params.row._id)} 55 | /> 56 | 57 | ); 58 | }, 59 | }, 60 | ]; 61 | 62 | return ( 63 |
64 | row._id} 69 | pageSize={8} 70 | checkboxSelection 71 | /> 72 |
73 | ); 74 | } 75 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/productList/productList.css: -------------------------------------------------------------------------------- 1 | .productList{ 2 | flex: 4; 3 | } 4 | 5 | .productListItem{ 6 | display: flex; 7 | align-items: center; 8 | } 9 | 10 | .productListImg { 11 | width: 32px; 12 | height: 32px; 13 | border-radius: 50%; 14 | object-fit: cover; 15 | margin-right: 10px; 16 | } 17 | 18 | .productListEdit{ 19 | border: none; 20 | border-radius: 10px; 21 | padding: 5px 10px; 22 | background-color: #3bb077; 23 | color: white; 24 | cursor: pointer; 25 | margin-right: 20px; 26 | } 27 | 28 | .productListDelete{ 29 | color: red; 30 | cursor: pointer; 31 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/user/User.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | CalendarToday, 3 | LocationSearching, 4 | MailOutline, 5 | PermIdentity, 6 | PhoneAndroid, 7 | Publish, 8 | } from "@material-ui/icons"; 9 | import { Link } from "react-router-dom"; 10 | import "./user.css"; 11 | 12 | export default function User() { 13 | return ( 14 |
15 |
16 |

Edit User

17 | 18 | 19 | 20 |
21 |
22 |
23 |
24 | 29 |
30 | Anna Becker 31 | Software Engineer 32 |
33 |
34 |
35 | Account Details 36 |
37 | 38 | annabeck99 39 |
40 |
41 | 42 | 10.12.1999 43 |
44 | Contact Details 45 |
46 | 47 | +1 123 456 67 48 |
49 |
50 | 51 | annabeck99@gmail.com 52 |
53 |
54 | 55 | New York | USA 56 |
57 |
58 |
59 |
60 | Edit 61 |
62 |
63 |
64 | 65 | 70 |
71 |
72 | 73 | 78 |
79 |
80 | 81 | 86 |
87 |
88 | 89 | 94 |
95 |
96 | 97 | 102 |
103 |
104 |
105 |
106 | 111 | 114 | 115 |
116 | 117 |
118 |
119 |
120 |
121 |
122 | ); 123 | } 124 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/user/user.css: -------------------------------------------------------------------------------- 1 | .user { 2 | flex: 4; 3 | padding: 20px; 4 | } 5 | 6 | .userTitleContainer { 7 | display: flex; 8 | align-items: center; 9 | justify-content: space-between; 10 | } 11 | 12 | .userAddButton { 13 | width: 80px; 14 | border: none; 15 | padding: 5px; 16 | background-color: teal; 17 | border-radius: 5px; 18 | cursor: pointer; 19 | color: white; 20 | font-size: 16px; 21 | } 22 | 23 | .userContainer { 24 | display: flex; 25 | margin-top: 20px; 26 | } 27 | 28 | .userShow { 29 | flex: 1; 30 | padding: 20px; 31 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 32 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 33 | } 34 | 35 | .userUpdate { 36 | flex: 2; 37 | padding: 20px; 38 | -webkit-box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 39 | box-shadow: 0px 0px 15px -10px rgba(0, 0, 0, 0.75); 40 | margin-left: 20px; 41 | } 42 | 43 | .userShowTop { 44 | display: flex; 45 | align-items: center; 46 | } 47 | 48 | .userShowImg { 49 | width: 40px; 50 | height: 40px; 51 | border-radius: 50%; 52 | object-fit: cover; 53 | } 54 | 55 | .userShowTopTitle { 56 | display: flex; 57 | flex-direction: column; 58 | margin-left: 20px; 59 | } 60 | 61 | .userShowUsername { 62 | font-weight: 600; 63 | } 64 | 65 | .userShowUserTitle { 66 | font-weight: 300; 67 | } 68 | 69 | .userShowBottom{ 70 | margin-top: 20px; 71 | } 72 | 73 | .userShowTitle { 74 | font-size: 14px; 75 | font-weight: 600; 76 | color: rgb(175, 170, 170); 77 | } 78 | 79 | .userShowInfo{ 80 | display: flex; 81 | align-items: center; 82 | margin: 20px 0px; 83 | color: #444; 84 | } 85 | 86 | .userShowIcon{ 87 | font-size: 16px !important; 88 | } 89 | 90 | .userShowInfoTitle{ 91 | margin-left: 10px; 92 | } 93 | 94 | .userUpdateTitle{ 95 | font-size: 24px; 96 | font-weight: 600; 97 | } 98 | 99 | .userUpdateForm{ 100 | display: flex; 101 | justify-content: space-between; 102 | margin-top: 20px; 103 | } 104 | 105 | .userUpdateItem{ 106 | display: flex; 107 | flex-direction: column; 108 | margin-top: 10px; 109 | } 110 | 111 | .userUpdateItem>label{ 112 | margin-bottom: 5px; 113 | font-size: 14px; 114 | } 115 | 116 | .userUpdateInput{ 117 | border: none; 118 | width: 250px; 119 | height: 30px; 120 | border-bottom: 1px solid gray; 121 | } 122 | 123 | .userUpdateRight{ 124 | display: flex; 125 | flex-direction: column; 126 | justify-content: space-between; 127 | } 128 | 129 | .userUpdateUpload{ 130 | display: flex; 131 | align-items: center; 132 | } 133 | 134 | .userUpdateImg{ 135 | width: 100px; 136 | height: 100px; 137 | border-radius: 10px; 138 | object-fit: cover; 139 | margin-right: 20px; 140 | } 141 | 142 | .userUpdateIcon{ 143 | cursor: pointer; 144 | } 145 | 146 | .userUpdateButton{ 147 | border-radius: 5px; 148 | border: none; 149 | padding: 5px; 150 | cursor: pointer; 151 | background-color: darkblue; 152 | color: white; 153 | font-weight: 600; 154 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/userList/UserList.jsx: -------------------------------------------------------------------------------- 1 | import "./userList.css"; 2 | import { DataGrid } from "@material-ui/data-grid"; 3 | import { DeleteOutline } from "@material-ui/icons"; 4 | import { userRows } from "../../dummyData"; 5 | import { Link } from "react-router-dom"; 6 | import { useState } from "react"; 7 | 8 | export default function UserList() { 9 | const [data, setData] = useState(userRows); 10 | 11 | const handleDelete = (id) => { 12 | setData(data.filter((item) => item.id !== id)); 13 | }; 14 | 15 | const columns = [ 16 | { field: "id", headerName: "ID", width: 90 }, 17 | { 18 | field: "user", 19 | headerName: "User", 20 | width: 200, 21 | renderCell: (params) => { 22 | return ( 23 |
24 | 25 | {params.row.username} 26 |
27 | ); 28 | }, 29 | }, 30 | { field: "email", headerName: "Email", width: 200 }, 31 | { 32 | field: "status", 33 | headerName: "Status", 34 | width: 120, 35 | }, 36 | { 37 | field: "transaction", 38 | headerName: "Transaction Volume", 39 | width: 160, 40 | }, 41 | { 42 | field: "action", 43 | headerName: "Action", 44 | width: 150, 45 | renderCell: (params) => { 46 | return ( 47 | <> 48 | 49 | 50 | 51 | handleDelete(params.row.id)} 54 | /> 55 | 56 | ); 57 | }, 58 | }, 59 | ]; 60 | 61 | return ( 62 |
63 | 70 |
71 | ); 72 | } 73 | -------------------------------------------------------------------------------- /MERN Project/admin/src/pages/userList/userList.css: -------------------------------------------------------------------------------- 1 | .userList { 2 | flex: 4; 3 | } 4 | 5 | .userListUser { 6 | display: flex; 7 | align-items: center; 8 | } 9 | 10 | .userListImg { 11 | width: 32px; 12 | height: 32px; 13 | border-radius: 50%; 14 | object-fit: cover; 15 | margin-right: 10px; 16 | } 17 | 18 | .userListEdit{ 19 | border: none; 20 | border-radius: 10px; 21 | padding: 5px 10px; 22 | background-color: #3bb077; 23 | color: white; 24 | cursor: pointer; 25 | margin-right: 20px; 26 | } 27 | 28 | .userListDelete{ 29 | color: red; 30 | cursor: pointer; 31 | } -------------------------------------------------------------------------------- /MERN Project/admin/src/redux/apiCalls.js: -------------------------------------------------------------------------------- 1 | import { loginFailure, loginStart, loginSuccess } from "./userRedux"; 2 | import { publicRequest, userRequest } from "../requestMethods"; 3 | import { 4 | getProductFailure, 5 | getProductStart, 6 | getProductSuccess, 7 | deleteProductFailure, 8 | deleteProductStart, 9 | deleteProductSuccess, 10 | updateProductFailure, 11 | updateProductStart, 12 | updateProductSuccess, 13 | addProductFailure, 14 | addProductStart, 15 | addProductSuccess, 16 | } from "./productRedux"; 17 | 18 | export const login = async (dispatch, user) => { 19 | dispatch(loginStart()); 20 | try { 21 | const res = await publicRequest.post("/auth/login", user); 22 | dispatch(loginSuccess(res.data)); 23 | } catch (err) { 24 | dispatch(loginFailure()); 25 | } 26 | }; 27 | 28 | export const getProducts = async (dispatch) => { 29 | dispatch(getProductStart()); 30 | try { 31 | const res = await publicRequest.get("/products"); 32 | dispatch(getProductSuccess(res.data)); 33 | } catch (err) { 34 | dispatch(getProductFailure()); 35 | } 36 | }; 37 | 38 | export const deleteProduct = async (id, dispatch) => { 39 | dispatch(deleteProductStart()); 40 | try { 41 | // const res = await userRequest.delete(`/products/${id}`); 42 | dispatch(deleteProductSuccess(id)); 43 | } catch (err) { 44 | dispatch(deleteProductFailure()); 45 | } 46 | }; 47 | 48 | export const updateProduct = async (id, product, dispatch) => { 49 | dispatch(updateProductStart()); 50 | try { 51 | // update 52 | dispatch(updateProductSuccess({ id, product })); 53 | } catch (err) { 54 | dispatch(updateProductFailure()); 55 | } 56 | }; 57 | export const addProduct = async (product, dispatch) => { 58 | dispatch(addProductStart()); 59 | try { 60 | const res = await userRequest.post(`/products`, product); 61 | dispatch(addProductSuccess(res.data)); 62 | } catch (err) { 63 | dispatch(addProductFailure()); 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /MERN Project/admin/src/redux/productRedux.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | export const productSlice = createSlice({ 4 | name: "product", 5 | initialState: { 6 | products: [], 7 | isFetching: false, 8 | error: false, 9 | }, 10 | reducers: { 11 | //GET ALL 12 | getProductStart: (state) => { 13 | state.isFetching = true; 14 | state.error = false; 15 | }, 16 | getProductSuccess: (state, action) => { 17 | state.isFetching = false; 18 | state.products = action.payload; 19 | }, 20 | getProductFailure: (state) => { 21 | state.isFetching = false; 22 | state.error = true; 23 | }, 24 | //DELETE 25 | deleteProductStart: (state) => { 26 | state.isFetching = true; 27 | state.error = false; 28 | }, 29 | deleteProductSuccess: (state, action) => { 30 | state.isFetching = false; 31 | state.products.splice( 32 | state.products.findIndex((item) => item._id === action.payload), 33 | 1 34 | ); 35 | }, 36 | deleteProductFailure: (state) => { 37 | state.isFetching = false; 38 | state.error = true; 39 | }, 40 | //UPDATE 41 | updateProductStart: (state) => { 42 | state.isFetching = true; 43 | state.error = false; 44 | }, 45 | updateProductSuccess: (state, action) => { 46 | state.isFetching = false; 47 | state.products[ 48 | state.products.findIndex((item) => item._id === action.payload.id) 49 | ] = action.payload.product; 50 | }, 51 | updateProductFailure: (state) => { 52 | state.isFetching = false; 53 | state.error = true; 54 | }, 55 | //UPDATE 56 | addProductStart: (state) => { 57 | state.isFetching = true; 58 | state.error = false; 59 | }, 60 | addProductSuccess: (state, action) => { 61 | state.isFetching = false; 62 | state.products.push(action.payload); 63 | }, 64 | addProductFailure: (state) => { 65 | state.isFetching = false; 66 | state.error = true; 67 | }, 68 | }, 69 | }); 70 | 71 | export const { 72 | getProductStart, 73 | getProductSuccess, 74 | getProductFailure, 75 | deleteProductStart, 76 | deleteProductSuccess, 77 | deleteProductFailure, 78 | updateProductStart, 79 | updateProductSuccess, 80 | updateProductFailure, 81 | addProductStart, 82 | addProductSuccess, 83 | addProductFailure, 84 | } = productSlice.actions; 85 | 86 | export default productSlice.reducer; 87 | -------------------------------------------------------------------------------- /MERN Project/admin/src/redux/store.js: -------------------------------------------------------------------------------- 1 | import { configureStore, combineReducers } from "@reduxjs/toolkit"; 2 | import userReducer from "./userRedux"; 3 | import productReducer from "./productRedux"; 4 | import { 5 | persistStore, 6 | persistReducer, 7 | FLUSH, 8 | REHYDRATE, 9 | PAUSE, 10 | PERSIST, 11 | PURGE, 12 | REGISTER, 13 | } from "redux-persist"; 14 | import storage from "redux-persist/lib/storage"; 15 | 16 | const persistConfig = { 17 | key: "root", 18 | version: 1, 19 | storage, 20 | }; 21 | 22 | const rootReducer = combineReducers({ 23 | user: userReducer, 24 | product: productReducer, 25 | }); 26 | 27 | const persistedReducer = persistReducer(persistConfig, rootReducer); 28 | 29 | export const store = configureStore({ 30 | reducer: persistedReducer, 31 | middleware: (getDefaultMiddleware) => 32 | getDefaultMiddleware({ 33 | serializableCheck: { 34 | ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER], 35 | }, 36 | }), 37 | }); 38 | 39 | export let persistor = persistStore(store); 40 | -------------------------------------------------------------------------------- /MERN Project/admin/src/redux/userRedux.js: -------------------------------------------------------------------------------- 1 | import { createSlice } from "@reduxjs/toolkit"; 2 | 3 | const userSlice = createSlice({ 4 | name: "user", 5 | initialState: { 6 | currentUser: null, 7 | isFetching: false, 8 | error: false, 9 | }, 10 | reducers: { 11 | loginStart: (state) => { 12 | state.isFetching = true; 13 | }, 14 | loginSuccess: (state, action) => { 15 | state.isFetching = false; 16 | state.currentUser = action.payload; 17 | }, 18 | loginFailure: (state) => { 19 | state.isFetching = false; 20 | state.error = true; 21 | }, 22 | logout: (state) => { 23 | state.currentUser = null; 24 | }, 25 | }, 26 | }); 27 | 28 | export const { loginStart, loginSuccess, loginFailure } = userSlice.actions; 29 | export default userSlice.reducer; 30 | -------------------------------------------------------------------------------- /MERN Project/admin/src/requestMethods.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const BASE_URL = "http://localhost:5000/api/"; 4 | const TOKEN = JSON.parse(JSON.parse(localStorage.getItem("persist:root")).user).currentUser.accessToken; 5 | 6 | export const publicRequest = axios.create({ 7 | baseURL: BASE_URL, 8 | }); 9 | 10 | export const userRequest = axios.create({ 11 | baseURL: BASE_URL, 12 | headers: { token: `Bearer ${TOKEN}` }, 13 | }); 14 | -------------------------------------------------------------------------------- /MERN Project/api/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .env.local 3 | .env.development.local 4 | .env.test.local 5 | .env.production.local 6 | node_modules -------------------------------------------------------------------------------- /MERN Project/api/index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const app = express(); 3 | const mongoose = require("mongoose"); 4 | const dotenv = require("dotenv"); 5 | dotenv.config(); 6 | const userRoute = require("./routes/user"); 7 | const authRoute = require("./routes/auth"); 8 | const productRoute = require("./routes/product"); 9 | const cartRoute = require("./routes/cart"); 10 | const orderRoute = require("./routes/order"); 11 | const stripeRoute = require("./routes/stripe"); 12 | const cors = require("cors"); 13 | 14 | 15 | mongoose 16 | .connect(process.env.MONGO_URL) 17 | .then(() => console.log("DB Connection Successfull!")) 18 | .catch((err) => { 19 | console.log(err); 20 | }); 21 | 22 | app.use(cors()); 23 | app.use(express.json()); 24 | app.use("/api/auth", authRoute); 25 | app.use("/api/users", userRoute); 26 | app.use("/api/products", productRoute); 27 | app.use("/api/carts", cartRoute); 28 | app.use("/api/orders", orderRoute); 29 | app.use("/api/checkout", stripeRoute); 30 | 31 | app.listen(process.env.PORT || 5000, () => { 32 | console.log("Backend server is running!"); 33 | }); 34 | -------------------------------------------------------------------------------- /MERN Project/api/models/Cart.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const CartSchema = new mongoose.Schema( 4 | { 5 | userId: { type: String, required: true }, 6 | products: [ 7 | { 8 | productId: { 9 | type: String, 10 | }, 11 | quantity: { 12 | type: Number, 13 | default: 1, 14 | }, 15 | }, 16 | ], 17 | }, 18 | { timestamps: true } 19 | ); 20 | 21 | module.exports = mongoose.model("Cart", CartSchema); 22 | -------------------------------------------------------------------------------- /MERN Project/api/models/Order.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const OrderSchema = new mongoose.Schema( 4 | { 5 | userId: { type: String, required: true }, 6 | products: [ 7 | { 8 | productId: { 9 | type: String, 10 | }, 11 | quantity: { 12 | type: Number, 13 | default: 1, 14 | }, 15 | }, 16 | ], 17 | amount: { type: Number, required: true }, 18 | address: { type: Object, required: true }, 19 | status: { type: String, default: "pending" }, 20 | }, 21 | { timestamps: true } 22 | ); 23 | 24 | module.exports = mongoose.model("Order", OrderSchema); 25 | -------------------------------------------------------------------------------- /MERN Project/api/models/Product.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const ProductSchema = new mongoose.Schema( 4 | { 5 | title: { type: String, required: true, unique: true }, 6 | desc: { type: String, required: true }, 7 | img: { type: String, required: true }, 8 | categories: { type: Array }, 9 | size: { type: Array }, 10 | color: { type: Array }, 11 | price: { type: Number, required: true }, 12 | inStock: { type: Boolean, default: true }, 13 | }, 14 | { timestamps: true } 15 | ); 16 | 17 | module.exports = mongoose.model("Product", ProductSchema); 18 | -------------------------------------------------------------------------------- /MERN Project/api/models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const UserSchema = new mongoose.Schema( 4 | { 5 | username: { type: String, required: true, unique: true }, 6 | email: { type: String, required: true, unique: true }, 7 | password: { type: String, required: true }, 8 | isAdmin: { 9 | type: Boolean, 10 | default: false, 11 | }, 12 | img: { type: String }, 13 | }, 14 | { timestamps: true } 15 | ); 16 | 17 | module.exports = mongoose.model("User", UserSchema); 18 | -------------------------------------------------------------------------------- /MERN Project/api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ecommerceapi", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon index.js" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "cors": "^2.8.5", 14 | "crypto-js": "^4.1.1", 15 | "dotenv": "^10.0.0", 16 | "express": "^4.17.1", 17 | "jsonwebtoken": "^8.5.1", 18 | "mongoose": "^6.0.5", 19 | "nodemon": "^2.0.12", 20 | "stripe": "^8.174.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /MERN Project/api/routes/auth.js: -------------------------------------------------------------------------------- 1 | const router = require("express").Router(); 2 | const User = require("../models/User"); 3 | const CryptoJS = require("crypto-js"); 4 | const jwt = require("jsonwebtoken"); 5 | 6 | //REGISTER 7 | router.post("/register", async (req, res) => { 8 | const newUser = new User({ 9 | username: req.body.username, 10 | email: req.body.email, 11 | password: CryptoJS.AES.encrypt( 12 | req.body.password, 13 | process.env.PASS_SEC 14 | ).toString(), 15 | }); 16 | 17 | try { 18 | const savedUser = await newUser.save(); 19 | res.status(201).json(savedUser); 20 | } catch (err) { 21 | res.status(500).json(err); 22 | } 23 | }); 24 | 25 | //LOGIN 26 | 27 | router.post("/login", async (req, res) => { 28 | try { 29 | const user = await User.findOne({ username: req.body.username }); 30 | !user && res.status(401).json("Wrong credentials!"); 31 | 32 | const hashedPassword = CryptoJS.AES.decrypt( 33 | user.password, 34 | process.env.PASS_SEC 35 | ); 36 | const OriginalPassword = hashedPassword.toString(CryptoJS.enc.Utf8); 37 | 38 | OriginalPassword !== req.body.password && 39 | res.status(401).json("Wrong credentials!"); 40 | 41 | const accessToken = jwt.sign( 42 | { 43 | id: user._id, 44 | isAdmin: user.isAdmin, 45 | }, 46 | process.env.JWT_SEC, 47 | {expiresIn:"3d"} 48 | ); 49 | 50 | const { password, ...others } = user._doc; 51 | 52 | res.status(200).json({...others, accessToken}); 53 | } catch (err) { 54 | res.status(500).json(err); 55 | } 56 | }); 57 | 58 | module.exports = router; 59 | -------------------------------------------------------------------------------- /MERN Project/api/routes/cart.js: -------------------------------------------------------------------------------- 1 | const Cart = require("../models/Cart"); 2 | const { 3 | verifyToken, 4 | verifyTokenAndAuthorization, 5 | verifyTokenAndAdmin, 6 | } = require("./verifyToken"); 7 | 8 | const router = require("express").Router(); 9 | 10 | //CREATE 11 | 12 | router.post("/", verifyToken, async (req, res) => { 13 | const newCart = new Cart(req.body); 14 | 15 | try { 16 | const savedCart = await newCart.save(); 17 | res.status(200).json(savedCart); 18 | } catch (err) { 19 | res.status(500).json(err); 20 | } 21 | }); 22 | 23 | //UPDATE 24 | router.put("/:id", verifyTokenAndAuthorization, async (req, res) => { 25 | try { 26 | const updatedCart = await Cart.findByIdAndUpdate( 27 | req.params.id, 28 | { 29 | $set: req.body, 30 | }, 31 | { new: true } 32 | ); 33 | res.status(200).json(updatedCart); 34 | } catch (err) { 35 | res.status(500).json(err); 36 | } 37 | }); 38 | 39 | //DELETE 40 | router.delete("/:id", verifyTokenAndAuthorization, async (req, res) => { 41 | try { 42 | await Cart.findByIdAndDelete(req.params.id); 43 | res.status(200).json("Cart has been deleted..."); 44 | } catch (err) { 45 | res.status(500).json(err); 46 | } 47 | }); 48 | 49 | //GET USER CART 50 | router.get("/find/:userId", verifyTokenAndAuthorization, async (req, res) => { 51 | try { 52 | const cart = await Cart.findOne({ userId: req.params.userId }); 53 | res.status(200).json(cart); 54 | } catch (err) { 55 | res.status(500).json(err); 56 | } 57 | }); 58 | 59 | // //GET ALL 60 | 61 | router.get("/", verifyTokenAndAdmin, async (req, res) => { 62 | try { 63 | const carts = await Cart.find(); 64 | res.status(200).json(carts); 65 | } catch (err) { 66 | res.status(500).json(err); 67 | } 68 | }); 69 | 70 | module.exports = router; 71 | -------------------------------------------------------------------------------- /MERN Project/api/routes/order.js: -------------------------------------------------------------------------------- 1 | const Order = require("../models/Order"); 2 | const { 3 | verifyToken, 4 | verifyTokenAndAuthorization, 5 | verifyTokenAndAdmin, 6 | } = require("./verifyToken"); 7 | 8 | const router = require("express").Router(); 9 | 10 | //CREATE 11 | 12 | router.post("/", verifyToken, async (req, res) => { 13 | const newOrder = new Order(req.body); 14 | 15 | try { 16 | const savedOrder = await newOrder.save(); 17 | res.status(200).json(savedOrder); 18 | } catch (err) { 19 | res.status(500).json(err); 20 | } 21 | }); 22 | 23 | //UPDATE 24 | router.put("/:id", verifyTokenAndAdmin, async (req, res) => { 25 | try { 26 | const updatedOrder = await Order.findByIdAndUpdate( 27 | req.params.id, 28 | { 29 | $set: req.body, 30 | }, 31 | { new: true } 32 | ); 33 | res.status(200).json(updatedOrder); 34 | } catch (err) { 35 | res.status(500).json(err); 36 | } 37 | }); 38 | 39 | //DELETE 40 | router.delete("/:id", verifyTokenAndAdmin, async (req, res) => { 41 | try { 42 | await Order.findByIdAndDelete(req.params.id); 43 | res.status(200).json("Order has been deleted..."); 44 | } catch (err) { 45 | res.status(500).json(err); 46 | } 47 | }); 48 | 49 | //GET USER ORDERS 50 | router.get("/find/:userId", verifyTokenAndAuthorization, async (req, res) => { 51 | try { 52 | const orders = await Order.find({ userId: req.params.userId }); 53 | res.status(200).json(orders); 54 | } catch (err) { 55 | res.status(500).json(err); 56 | } 57 | }); 58 | 59 | // //GET ALL 60 | 61 | router.get("/", verifyTokenAndAdmin, async (req, res) => { 62 | try { 63 | const orders = await Order.find(); 64 | res.status(200).json(orders); 65 | } catch (err) { 66 | res.status(500).json(err); 67 | } 68 | }); 69 | 70 | // GET MONTHLY INCOME 71 | 72 | router.get("/income", verifyTokenAndAdmin, async (req, res) => { 73 | const productId = req.query.pid; 74 | const date = new Date(); 75 | const lastMonth = new Date(date.setMonth(date.getMonth() - 1)); 76 | const previousMonth = new Date(new Date().setMonth(lastMonth.getMonth() - 1)); 77 | 78 | try { 79 | const income = await Order.aggregate([ 80 | { 81 | $match: { 82 | createdAt: { $gte: previousMonth }, 83 | ...(productId && { 84 | products: { $elemMatch: { productId } }, 85 | }), 86 | }, 87 | }, 88 | { 89 | $project: { 90 | month: { $month: "$createdAt" }, 91 | sales: "$amount", 92 | }, 93 | }, 94 | { 95 | $group: { 96 | _id: "$month", 97 | total: { $sum: "$sales" }, 98 | }, 99 | }, 100 | ]); 101 | res.status(200).json(income); 102 | } catch (err) { 103 | res.status(500).json(err); 104 | } 105 | }); 106 | 107 | module.exports = router; 108 | -------------------------------------------------------------------------------- /MERN Project/api/routes/product.js: -------------------------------------------------------------------------------- 1 | const Product = require("../models/Product"); 2 | const { 3 | verifyToken, 4 | verifyTokenAndAuthorization, 5 | verifyTokenAndAdmin, 6 | } = require("./verifyToken"); 7 | 8 | const router = require("express").Router(); 9 | 10 | //CREATE 11 | 12 | router.post("/", verifyTokenAndAdmin, async (req, res) => { 13 | const newProduct = new Product(req.body); 14 | 15 | try { 16 | const savedProduct = await newProduct.save(); 17 | res.status(200).json(savedProduct); 18 | } catch (err) { 19 | res.status(500).json(err); 20 | } 21 | }); 22 | 23 | //UPDATE 24 | router.put("/:id", verifyTokenAndAdmin, async (req, res) => { 25 | try { 26 | const updatedProduct = await Product.findByIdAndUpdate( 27 | req.params.id, 28 | { 29 | $set: req.body, 30 | }, 31 | { new: true } 32 | ); 33 | res.status(200).json(updatedProduct); 34 | } catch (err) { 35 | res.status(500).json(err); 36 | } 37 | }); 38 | 39 | //DELETE 40 | router.delete("/:id", verifyTokenAndAdmin, async (req, res) => { 41 | try { 42 | await Product.findByIdAndDelete(req.params.id); 43 | res.status(200).json("Product has been deleted..."); 44 | } catch (err) { 45 | res.status(500).json(err); 46 | } 47 | }); 48 | 49 | //GET PRODUCT 50 | router.get("/find/:id", async (req, res) => { 51 | try { 52 | const product = await Product.findById(req.params.id); 53 | res.status(200).json(product); 54 | } catch (err) { 55 | res.status(500).json(err); 56 | } 57 | }); 58 | 59 | //GET ALL PRODUCTS 60 | router.get("/", async (req, res) => { 61 | const qNew = req.query.new; 62 | const qCategory = req.query.category; 63 | try { 64 | let products; 65 | 66 | if (qNew) { 67 | products = await Product.find().sort({ createdAt: -1 }).limit(1); 68 | } else if (qCategory) { 69 | products = await Product.find({ 70 | categories: { 71 | $in: [qCategory], 72 | }, 73 | }); 74 | } else { 75 | products = await Product.find(); 76 | } 77 | 78 | res.status(200).json(products); 79 | } catch (err) { 80 | res.status(500).json(err); 81 | } 82 | }); 83 | 84 | module.exports = router; 85 | -------------------------------------------------------------------------------- /MERN Project/api/routes/stripe.js: -------------------------------------------------------------------------------- 1 | const router = require("express").Router(); 2 | const stripe = require("stripe")(process.env.STRIPE_KEY); 3 | 4 | router.post("/payment", (req, res) => { 5 | stripe.charges.create( 6 | { 7 | source: req.body.tokenId, 8 | amount: req.body.amount, 9 | currency: "usd", 10 | }, 11 | (stripeErr, stripeRes) => { 12 | if (stripeErr) { 13 | res.status(500).json(stripeErr); 14 | } else { 15 | res.status(200).json(stripeRes); 16 | } 17 | } 18 | ); 19 | }); 20 | 21 | module.exports = router; 22 | -------------------------------------------------------------------------------- /MERN Project/api/routes/user.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/User"); 2 | const { 3 | verifyToken, 4 | verifyTokenAndAuthorization, 5 | verifyTokenAndAdmin, 6 | } = require("./verifyToken"); 7 | 8 | const router = require("express").Router(); 9 | 10 | //UPDATE 11 | router.put("/:id", verifyTokenAndAuthorization, async (req, res) => { 12 | if (req.body.password) { 13 | req.body.password = CryptoJS.AES.encrypt( 14 | req.body.password, 15 | process.env.PASS_SEC 16 | ).toString(); 17 | } 18 | 19 | try { 20 | const updatedUser = await User.findByIdAndUpdate( 21 | req.params.id, 22 | { 23 | $set: req.body, 24 | }, 25 | { new: true } 26 | ); 27 | res.status(200).json(updatedUser); 28 | } catch (err) { 29 | res.status(500).json(err); 30 | } 31 | }); 32 | 33 | //DELETE 34 | router.delete("/:id", verifyTokenAndAuthorization, async (req, res) => { 35 | try { 36 | await User.findByIdAndDelete(req.params.id); 37 | res.status(200).json("User has been deleted..."); 38 | } catch (err) { 39 | res.status(500).json(err); 40 | } 41 | }); 42 | 43 | //GET USER 44 | router.get("/find/:id", verifyTokenAndAdmin, async (req, res) => { 45 | try { 46 | const user = await User.findById(req.params.id); 47 | const { password, ...others } = user._doc; 48 | res.status(200).json(others); 49 | } catch (err) { 50 | res.status(500).json(err); 51 | } 52 | }); 53 | 54 | //GET ALL USER 55 | router.get("/", verifyTokenAndAdmin, async (req, res) => { 56 | const query = req.query.new; 57 | try { 58 | const users = query 59 | ? await User.find().sort({ _id: -1 }).limit(5) 60 | : await User.find(); 61 | res.status(200).json(users); 62 | } catch (err) { 63 | res.status(500).json(err); 64 | } 65 | }); 66 | 67 | //GET USER STATS 68 | 69 | router.get("/stats", verifyTokenAndAdmin, async (req, res) => { 70 | const date = new Date(); 71 | const lastYear = new Date(date.setFullYear(date.getFullYear() - 1)); 72 | 73 | try { 74 | const data = await User.aggregate([ 75 | { $match: { createdAt: { $gte: lastYear } } }, 76 | { 77 | $project: { 78 | month: { $month: "$createdAt" }, 79 | }, 80 | }, 81 | { 82 | $group: { 83 | _id: "$month", 84 | total: { $sum: 1 }, 85 | }, 86 | }, 87 | ]); 88 | res.status(200).json(data) 89 | } catch (err) { 90 | res.status(500).json(err); 91 | } 92 | }); 93 | 94 | module.exports = router; 95 | -------------------------------------------------------------------------------- /MERN Project/api/routes/verifyToken.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | 3 | const verifyToken = (req, res, next) => { 4 | const authHeader = req.headers.token; 5 | if (authHeader) { 6 | const token = authHeader.split(" ")[1]; 7 | jwt.verify(token, process.env.JWT_SEC, (err, user) => { 8 | if (err) res.status(403).json("Token is not valid!"); 9 | req.user = user; 10 | next(); 11 | }); 12 | } else { 13 | return res.status(401).json("You are not authenticated!"); 14 | } 15 | }; 16 | 17 | const verifyTokenAndAuthorization = (req, res, next) => { 18 | verifyToken(req, res, () => { 19 | if (req.user.id === req.params.id || req.user.isAdmin) { 20 | next(); 21 | } else { 22 | res.status(403).json("You are not alowed to do that!"); 23 | } 24 | }); 25 | }; 26 | 27 | const verifyTokenAndAdmin = (req, res, next) => { 28 | verifyToken(req, res, () => { 29 | if (req.user.isAdmin) { 30 | next(); 31 | } else { 32 | res.status(403).json("You are not alowed to do that!"); 33 | } 34 | }); 35 | }; 36 | 37 | module.exports = { 38 | verifyToken, 39 | verifyTokenAndAuthorization, 40 | verifyTokenAndAdmin, 41 | }; 42 | -------------------------------------------------------------------------------- /MERN Project/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 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /MERN Project/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 | ### `yarn start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn 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 | ### `yarn 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 | ### `yarn 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 | ### `yarn 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 | -------------------------------------------------------------------------------- /MERN Project/client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "new", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@material-ui/core": "^4.12.3", 7 | "@material-ui/icons": "^4.11.2", 8 | "@reduxjs/toolkit": "^1.6.1", 9 | "@testing-library/jest-dom": "^5.11.4", 10 | "@testing-library/react": "^11.1.0", 11 | "@testing-library/user-event": "^12.1.10", 12 | "axios": "^0.21.4", 13 | "react": "^17.0.2", 14 | "react-dom": "^17.0.2", 15 | "react-redux": "^7.2.5", 16 | "react-router-dom": "^5.3.0", 17 | "react-scripts": "4.0.3", 18 | "react-stripe-checkout": "^2.6.3", 19 | "redux-persist": "^6.0.0", 20 | "styled-components": "^5.3.1", 21 | "web-vitals": "^1.0.1" 22 | }, 23 | "scripts": { 24 | "start": "react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject" 28 | }, 29 | "eslintConfig": { 30 | "extends": [ 31 | "react-app", 32 | "react-app/jest" 33 | ] 34 | }, 35 | "browserslist": { 36 | "production": [ 37 | ">0.2%", 38 | "not dead", 39 | "not op_mini all" 40 | ], 41 | "development": [ 42 | "last 1 chrome version", 43 | "last 1 firefox version", 44 | "last 1 safari version" 45 | ] 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /MERN Project/client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | 17 | React App 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /MERN Project/client/src/App.jsx: -------------------------------------------------------------------------------- 1 | import Product from "./pages/Product"; 2 | import Home from "./pages/Home"; 3 | import ProductList from "./pages/ProductList"; 4 | import Register from "./pages/Register"; 5 | import Login from "./pages/Login"; 6 | import Cart from "./pages/Cart"; 7 | import { 8 | BrowserRouter as Router, 9 | Switch, 10 | Route, 11 | Redirect, 12 | } from "react-router-dom"; 13 | import Success from "./pages/Success"; 14 | import { useSelector } from "react-redux"; 15 | 16 | const App = () => { 17 | const user = useSelector((state) => state.user.currentUser); 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | {user ? : } 37 | 38 | {user ? : } 39 | 40 | 41 | 42 | ); 43 | }; 44 | 45 | export default App; 46 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Announcement.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | 3 | const Container = styled.div` 4 | height: 30px; 5 | background-color: teal; 6 | color: white; 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | font-size: 14px; 11 | font-weight: 500; 12 | `; 13 | 14 | const Announcement = () => { 15 | return Super Deal! Free Shipping on Orders Over $50; 16 | }; 17 | 18 | export default Announcement; 19 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Categories.jsx: -------------------------------------------------------------------------------- 1 | import styled from "styled-components"; 2 | import { categories } from "../data"; 3 | import { mobile } from "../responsive"; 4 | import CategoryItem from "./CategoryItem"; 5 | 6 | const Container = styled.div` 7 | display: flex; 8 | padding: 20px; 9 | justify-content: space-between; 10 | ${mobile({ padding: "0px", flexDirection:"column" })} 11 | 12 | `; 13 | 14 | const Categories = () => { 15 | return ( 16 | 17 | {categories.map((item) => ( 18 | 19 | ))} 20 | 21 | ); 22 | }; 23 | 24 | export default Categories; 25 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/CategoryItem.jsx: -------------------------------------------------------------------------------- 1 | import { Link } from "react-router-dom"; 2 | import styled from "styled-components"; 3 | import { mobile } from "../responsive"; 4 | 5 | const Container = styled.div` 6 | flex: 1; 7 | margin: 3px; 8 | height: 70vh; 9 | position: relative; 10 | `; 11 | 12 | const Image = styled.img` 13 | width: 100%; 14 | height: 100%; 15 | object-fit: cover; 16 | ${mobile({ height: "20vh" })} 17 | 18 | `; 19 | 20 | const Info = styled.div` 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | width: 100%; 25 | height: 100%; 26 | display: flex; 27 | flex-direction: column; 28 | align-items: center; 29 | justify-content: center; 30 | `; 31 | 32 | const Title = styled.h1` 33 | color:white; 34 | margin-bottom: 20px; 35 | `; 36 | 37 | const Button = styled.button` 38 | border:none; 39 | padding: 10px; 40 | background-color: white; 41 | color:gray; 42 | cursor: pointer; 43 | font-weight: 600; 44 | `; 45 | 46 | const CategoryItem = ({ item }) => { 47 | return ( 48 | 49 | 50 | 51 | 52 | {item.title} 53 | 54 | 55 | 56 | 57 | ); 58 | }; 59 | 60 | export default CategoryItem; 61 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | Facebook, 3 | Instagram, 4 | MailOutline, 5 | Phone, 6 | Pinterest, 7 | Room, 8 | Twitter, 9 | } from "@material-ui/icons"; 10 | import styled from "styled-components"; 11 | import { mobile } from "../responsive"; 12 | 13 | const Container = styled.div` 14 | display: flex; 15 | ${mobile({ flexDirection: "column" })} 16 | `; 17 | 18 | const Left = styled.div` 19 | flex: 1; 20 | display: flex; 21 | flex-direction: column; 22 | padding: 20px; 23 | `; 24 | 25 | const Logo = styled.h1``; 26 | 27 | const Desc = styled.p` 28 | margin: 20px 0px; 29 | `; 30 | 31 | const SocialContainer = styled.div` 32 | display: flex; 33 | `; 34 | 35 | const SocialIcon = styled.div` 36 | width: 40px; 37 | height: 40px; 38 | border-radius: 50%; 39 | color: white; 40 | background-color: #${(props) => props.color}; 41 | display: flex; 42 | align-items: center; 43 | justify-content: center; 44 | margin-right: 20px; 45 | `; 46 | 47 | const Center = styled.div` 48 | flex: 1; 49 | padding: 20px; 50 | ${mobile({ display: "none" })} 51 | `; 52 | 53 | const Title = styled.h3` 54 | margin-bottom: 30px; 55 | `; 56 | 57 | const List = styled.ul` 58 | margin: 0; 59 | padding: 0; 60 | list-style: none; 61 | display: flex; 62 | flex-wrap: wrap; 63 | `; 64 | 65 | const ListItem = styled.li` 66 | width: 50%; 67 | margin-bottom: 10px; 68 | `; 69 | 70 | const Right = styled.div` 71 | flex: 1; 72 | padding: 20px; 73 | ${mobile({ backgroundColor: "#fff8f8" })} 74 | 75 | `; 76 | 77 | const ContactItem = styled.div` 78 | margin-bottom: 20px; 79 | display: flex; 80 | align-items: center; 81 | `; 82 | 83 | const Payment = styled.img` 84 | width: 50%; 85 | `; 86 | 87 | const Footer = () => { 88 | return ( 89 | 90 | 91 | LAMA. 92 | 93 | There are many variations of passages of Lorem Ipsum available, but 94 | the majority have suffered alteration in some form, by injected 95 | humour, or randomised words which don’t look even slightly believable. 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 |
113 | Useful Links 114 | 115 | Home 116 | Cart 117 | Man Fashion 118 | Woman Fashion 119 | Accessories 120 | My Account 121 | Order Tracking 122 | Wishlist 123 | Wishlist 124 | Terms 125 | 126 |
127 | 128 | Contact 129 | 130 | 622 Dixie Path , South Tobinchester 98336 131 | 132 | 133 | +1 234 56 78 134 | 135 | 136 | contact@lama.dev 137 | 138 | 139 | 140 |
141 | ); 142 | }; 143 | 144 | export default Footer; 145 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Navbar.jsx: -------------------------------------------------------------------------------- 1 | import { Badge } from "@material-ui/core"; 2 | import { Search, ShoppingCartOutlined } from "@material-ui/icons"; 3 | import React from "react"; 4 | import styled from "styled-components"; 5 | import { mobile } from "../responsive"; 6 | import { useSelector } from "react-redux"; 7 | import { Link } from "react-router-dom"; 8 | 9 | const Container = styled.div` 10 | height: 60px; 11 | ${mobile({ height: "50px" })} 12 | `; 13 | 14 | const Wrapper = styled.div` 15 | padding: 10px 20px; 16 | display: flex; 17 | align-items: center; 18 | justify-content: space-between; 19 | ${mobile({ padding: "10px 0px" })} 20 | `; 21 | 22 | const Left = styled.div` 23 | flex: 1; 24 | display: flex; 25 | align-items: center; 26 | `; 27 | 28 | const Language = styled.span` 29 | font-size: 14px; 30 | cursor: pointer; 31 | ${mobile({ display: "none" })} 32 | `; 33 | 34 | const SearchContainer = styled.div` 35 | border: 0.5px solid lightgray; 36 | display: flex; 37 | align-items: center; 38 | margin-left: 25px; 39 | padding: 5px; 40 | `; 41 | 42 | const Input = styled.input` 43 | border: none; 44 | ${mobile({ width: "50px" })} 45 | `; 46 | 47 | const Center = styled.div` 48 | flex: 1; 49 | text-align: center; 50 | `; 51 | 52 | const Logo = styled.h1` 53 | font-weight: bold; 54 | ${mobile({ fontSize: "24px" })} 55 | `; 56 | const Right = styled.div` 57 | flex: 1; 58 | display: flex; 59 | align-items: center; 60 | justify-content: flex-end; 61 | ${mobile({ flex: 2, justifyContent: "center" })} 62 | `; 63 | 64 | const MenuItem = styled.div` 65 | font-size: 14px; 66 | cursor: pointer; 67 | margin-left: 25px; 68 | ${mobile({ fontSize: "12px", marginLeft: "10px" })} 69 | `; 70 | 71 | const Navbar = () => { 72 | const quantity = useSelector(state=>state.cart.quantity) 73 | return ( 74 | 75 | 76 | 77 | EN 78 | 79 | 80 | 81 | 82 | 83 |
84 | LAMA. 85 |
86 | 87 | REGISTER 88 | SIGN IN 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 |
98 |
99 | ); 100 | }; 101 | 102 | export default Navbar; 103 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Newsletter.jsx: -------------------------------------------------------------------------------- 1 | import { Send } from "@material-ui/icons"; 2 | import styled from "styled-components"; 3 | import { mobile } from "../responsive"; 4 | 5 | const Container = styled.div` 6 | height: 60vh; 7 | background-color: #fcf5f5; 8 | display: flex; 9 | align-items: center; 10 | justify-content: center; 11 | flex-direction: column; 12 | `; 13 | const Title = styled.h1` 14 | font-size: 70px; 15 | margin-bottom: 20px; 16 | `; 17 | 18 | const Desc = styled.div` 19 | font-size: 24px; 20 | font-weight: 300; 21 | margin-bottom: 20px; 22 | ${mobile({ textAlign: "center" })} 23 | 24 | `; 25 | 26 | const InputContainer = styled.div` 27 | width: 50%; 28 | height: 40px; 29 | background-color: white; 30 | display: flex; 31 | justify-content: space-between; 32 | border: 1px solid lightgray; 33 | ${mobile({ width: "80%" })} 34 | `; 35 | 36 | const Input = styled.input` 37 | border: none; 38 | flex: 8; 39 | padding-left: 20px; 40 | `; 41 | 42 | const Button = styled.button` 43 | flex: 1; 44 | border: none; 45 | background-color: teal; 46 | color: white; 47 | `; 48 | 49 | const Newsletter = () => { 50 | return ( 51 | 52 | Newsletter 53 | Get timely updates from your favorite products. 54 | 55 | 56 | 59 | 60 | 61 | ); 62 | }; 63 | 64 | export default Newsletter; 65 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Product.jsx: -------------------------------------------------------------------------------- 1 | import { 2 | FavoriteBorderOutlined, 3 | SearchOutlined, 4 | ShoppingCartOutlined, 5 | } from "@material-ui/icons"; 6 | import { Link } from "react-router-dom"; 7 | import styled from "styled-components"; 8 | 9 | const Info = styled.div` 10 | opacity: 0; 11 | width: 100%; 12 | height: 100%; 13 | position: absolute; 14 | top: 0; 15 | left: 0; 16 | background-color: rgba(0, 0, 0, 0.2); 17 | z-index: 3; 18 | display: flex; 19 | align-items: center; 20 | justify-content: center; 21 | transition: all 0.5s ease; 22 | cursor: pointer; 23 | `; 24 | 25 | const Container = styled.div` 26 | flex: 1; 27 | margin: 5px; 28 | min-width: 280px; 29 | height: 350px; 30 | display: flex; 31 | align-items: center; 32 | justify-content: center; 33 | background-color: #f5fbfd; 34 | position: relative; 35 | 36 | &:hover ${Info}{ 37 | opacity: 1; 38 | } 39 | `; 40 | 41 | const Circle = styled.div` 42 | width: 200px; 43 | height: 200px; 44 | border-radius: 50%; 45 | background-color: white; 46 | position: absolute; 47 | `; 48 | 49 | const Image = styled.img` 50 | height: 75%; 51 | z-index: 2; 52 | `; 53 | 54 | const Icon = styled.div` 55 | width: 40px; 56 | height: 40px; 57 | border-radius: 50%; 58 | background-color: white; 59 | display: flex; 60 | align-items: center; 61 | justify-content: center; 62 | margin: 10px; 63 | transition: all 0.5s ease; 64 | &:hover { 65 | background-color: #e9f5f5; 66 | transform: scale(1.1); 67 | } 68 | `; 69 | 70 | const Product = ({ item }) => { 71 | return ( 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | ); 90 | }; 91 | 92 | export default Product; 93 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Products.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from "react"; 2 | import styled from "styled-components"; 3 | import { popularProducts } from "../data"; 4 | import Product from "./Product"; 5 | import axios from "axios"; 6 | 7 | const Container = styled.div` 8 | padding: 20px; 9 | display: flex; 10 | flex-wrap: wrap; 11 | justify-content: space-between; 12 | `; 13 | 14 | const Products = ({ cat, filters, sort }) => { 15 | const [products, setProducts] = useState([]); 16 | const [filteredProducts, setFilteredProducts] = useState([]); 17 | 18 | useEffect(() => { 19 | const getProducts = async () => { 20 | try { 21 | const res = await axios.get( 22 | cat 23 | ? `http://localhost:5000/api/products?category=${cat}` 24 | : "http://localhost:5000/api/products" 25 | ); 26 | setProducts(res.data); 27 | } catch (err) {} 28 | }; 29 | getProducts(); 30 | }, [cat]); 31 | 32 | useEffect(() => { 33 | cat && 34 | setFilteredProducts( 35 | products.filter((item) => 36 | Object.entries(filters).every(([key, value]) => 37 | item[key].includes(value) 38 | ) 39 | ) 40 | ); 41 | }, [products, cat, filters]); 42 | 43 | useEffect(() => { 44 | if (sort === "newest") { 45 | setFilteredProducts((prev) => 46 | [...prev].sort((a, b) => a.createdAt - b.createdAt) 47 | ); 48 | } else if (sort === "asc") { 49 | setFilteredProducts((prev) => 50 | [...prev].sort((a, b) => a.price - b.price) 51 | ); 52 | } else { 53 | setFilteredProducts((prev) => 54 | [...prev].sort((a, b) => b.price - a.price) 55 | ); 56 | } 57 | }, [sort]); 58 | 59 | return ( 60 | 61 | {cat 62 | ? filteredProducts.map((item) => ) 63 | : products 64 | .slice(0, 8) 65 | .map((item) => )} 66 | 67 | ); 68 | }; 69 | 70 | export default Products; 71 | -------------------------------------------------------------------------------- /MERN Project/client/src/components/Slider.jsx: -------------------------------------------------------------------------------- 1 | import { ArrowLeftOutlined, ArrowRightOutlined } from "@material-ui/icons"; 2 | import { useState } from "react"; 3 | import styled from "styled-components"; 4 | import { sliderItems } from "../data"; 5 | import { mobile } from "../responsive"; 6 | 7 | const Container = styled.div` 8 | width: 100%; 9 | height: 100vh; 10 | display: flex; 11 | position: relative; 12 | overflow: hidden; 13 | ${mobile({ display: "none" })} 14 | `; 15 | 16 | const Arrow = styled.div` 17 | width: 50px; 18 | height: 50px; 19 | background-color: #fff7f7; 20 | border-radius: 50%; 21 | display: flex; 22 | align-items: center; 23 | justify-content: center; 24 | position: absolute; 25 | top: 0; 26 | bottom: 0; 27 | left: ${(props) => props.direction === "left" && "10px"}; 28 | right: ${(props) => props.direction === "right" && "10px"}; 29 | margin: auto; 30 | cursor: pointer; 31 | opacity: 0.5; 32 | z-index: 2; 33 | `; 34 | 35 | const Wrapper = styled.div` 36 | height: 100%; 37 | display: flex; 38 | transition: all 1.5s ease; 39 | transform: translateX(${(props) => props.slideIndex * -100}vw); 40 | `; 41 | 42 | const Slide = styled.div` 43 | width: 100vw; 44 | height: 100vh; 45 | display: flex; 46 | align-items: center; 47 | background-color: #${(props) => props.bg}; 48 | `; 49 | 50 | const ImgContainer = styled.div` 51 | height: 100%; 52 | flex: 1; 53 | `; 54 | 55 | const Image = styled.img` 56 | height: 80%; 57 | `; 58 | 59 | const InfoContainer = styled.div` 60 | flex: 1; 61 | padding: 50px; 62 | `; 63 | 64 | const Title = styled.h1` 65 | font-size: 70px; 66 | `; 67 | 68 | const Desc = styled.p` 69 | margin: 50px 0px; 70 | font-size: 20px; 71 | font-weight: 500; 72 | letter-spacing: 3px; 73 | `; 74 | 75 | const Button = styled.button` 76 | padding: 10px; 77 | font-size: 20px; 78 | background-color: transparent; 79 | cursor: pointer; 80 | `; 81 | 82 | const Slider = () => { 83 | const [slideIndex, setSlideIndex] = useState(0); 84 | const handleClick = (direction) => { 85 | if (direction === "left") { 86 | setSlideIndex(slideIndex > 0 ? slideIndex - 1 : 2); 87 | } else { 88 | setSlideIndex(slideIndex < 2 ? slideIndex + 1 : 0); 89 | } 90 | }; 91 | 92 | return ( 93 | 94 | handleClick("left")}> 95 | 96 | 97 | 98 | {sliderItems.map((item) => ( 99 | 100 | 101 | 102 | 103 | 104 | {item.title} 105 | {item.desc} 106 | 107 | 108 | 109 | ))} 110 | 111 | handleClick("right")}> 112 | 113 | 114 | 115 | ); 116 | }; 117 | 118 | export default Slider; 119 | -------------------------------------------------------------------------------- /MERN Project/client/src/data.js: -------------------------------------------------------------------------------- 1 | export const sliderItems = [ 2 | { 3 | id: 1, 4 | img: "https://i.ibb.co/XsdmR2c/1.png", 5 | title: "SUMMER SALE", 6 | desc: "DON'T COMPROMISE ON STYLE! GET FLAT 30% OFF FOR NEW ARRIVALS.", 7 | bg: "f5fafd", 8 | }, 9 | { 10 | id: 2, 11 | img: "https://i.ibb.co/DG69bQ4/2.png", 12 | title: "AUTUMN COLLECTION", 13 | desc: "DON'T COMPROMISE ON STYLE! GET FLAT 30% OFF FOR NEW ARRIVALS.", 14 | bg: "fcf1ed", 15 | }, 16 | { 17 | id: 3, 18 | img: "https://i.ibb.co/cXFnLLV/3.png", 19 | title: "LOUNGEWEAR LOVE", 20 | desc: "DON'T COMPROMISE ON STYLE! GET FLAT 30% OFF FOR NEW ARRIVALS.", 21 | bg: "fbf0f4", 22 | }, 23 | ]; 24 | 25 | export const categories = [ 26 | { 27 | id: 1, 28 | img: "https://images.pexels.com/photos/5886041/pexels-photo-5886041.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940", 29 | title: "SHIRT STYLE!", 30 | cat:"women" 31 | }, 32 | { 33 | id: 2, 34 | img: "https://images.pexels.com/photos/2983464/pexels-photo-2983464.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940", 35 | title: "LOUNGEWEAR LOVE", 36 | cat:"coat" 37 | }, 38 | { 39 | id: 3, 40 | img: "https://images.pexels.com/photos/5480696/pexels-photo-5480696.jpeg?auto=compress&cs=tinysrgb&dpr=2&w=500", 41 | title: "LIGHT JACKETS", 42 | cat:"jeans" 43 | }, 44 | ]; 45 | 46 | export const popularProducts = [ 47 | { 48 | id:1, 49 | img:"https://d3o2e4jr3mxnm3.cloudfront.net/Mens-Jake-Guitar-Vintage-Crusher-Tee_68382_1_lg.png", 50 | }, 51 | { 52 | id:2, 53 | img:"https://cdn.shopify.com/s/files/1/0101/4832/products/Angela_Natural_Tee.png?v=1606780388", 54 | }, 55 | { 56 | id:3, 57 | img:"https://www.prada.com/content/dam/pradanux_products/U/UCS/UCS319/1YOTF010O/UCS319_1YOT_F010O_S_182_SLF.png", 58 | }, 59 | { 60 | id:4, 61 | img:"https://www.burdastyle.com/pub/media/catalog/product/cache/7bd3727382ce0a860b68816435d76e26/107/BUS-PAT-BURTE-1320516/1170x1470_BS_2016_05_132_front.png", 62 | }, 63 | { 64 | id:5, 65 | img:"https://images.ctfassets.net/5gvckmvm9289/3BlDoZxSSjqAvv1jBJP7TH/65f9a95484117730ace42abf64e89572/Noissue-x-Creatsy-Tote-Bag-Mockup-Bundle-_4_-2.png", 66 | }, 67 | { 68 | id:6, 69 | img:"https://d3o2e4jr3mxnm3.cloudfront.net/Rocket-Vintage-Chill-Cap_66374_1_lg.png", 70 | }, 71 | { 72 | id:7, 73 | img:"https://www.vintageindustries.nl/download_front/qympzk1762/2217_Arrow_Jacket_Forest.png", 74 | }, 75 | { 76 | id:8, 77 | img:"https://www.pngarts.com/files/3/Women-Jacket-PNG-High-Quality-Image.png", 78 | }, 79 | ] -------------------------------------------------------------------------------- /MERN Project/client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import App from "./App"; 4 | import { Provider } from "react-redux"; 5 | import { store, persistor } from "./redux/store"; 6 | import { PersistGate } from 'redux-persist/integration/react' 7 | 8 | ReactDOM.render( 9 | 10 | 11 | 12 | 13 | , 14 | document.getElementById("root") 15 | ); 16 | -------------------------------------------------------------------------------- /MERN Project/client/src/pages/Home.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Announcement from "../components/Announcement"; 3 | import Categories from "../components/Categories"; 4 | import Footer from "../components/Footer"; 5 | import Navbar from "../components/Navbar"; 6 | import Newsletter from "../components/Newsletter"; 7 | import Products from "../components/Products"; 8 | import Slider from "../components/Slider"; 9 | 10 | const Home = () => { 11 | return ( 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 |
21 | ); 22 | }; 23 | 24 | export default Home; 25 | -------------------------------------------------------------------------------- /MERN Project/client/src/pages/Login.jsx: -------------------------------------------------------------------------------- 1 | import { useState } from "react"; 2 | import styled from "styled-components"; 3 | import { login } from "../redux/apiCalls"; 4 | import { mobile } from "../responsive"; 5 | import { useDispatch, useSelector } from "react-redux"; 6 | 7 | const Container = styled.div` 8 | width: 100vw; 9 | height: 100vh; 10 | background: linear-gradient( 11 | rgba(255, 255, 255, 0.5), 12 | rgba(255, 255, 255, 0.5) 13 | ), 14 | url("https://images.pexels.com/photos/6984650/pexels-photo-6984650.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940") 15 | center; 16 | background-size: cover; 17 | display: flex; 18 | align-items: center; 19 | justify-content: center; 20 | `; 21 | 22 | const Wrapper = styled.div` 23 | width: 25%; 24 | padding: 20px; 25 | background-color: white; 26 | ${mobile({ width: "75%" })} 27 | `; 28 | 29 | const Title = styled.h1` 30 | font-size: 24px; 31 | font-weight: 300; 32 | `; 33 | 34 | const Form = styled.form` 35 | display: flex; 36 | flex-direction: column; 37 | `; 38 | 39 | const Input = styled.input` 40 | flex: 1; 41 | min-width: 40%; 42 | margin: 10px 0; 43 | padding: 10px; 44 | `; 45 | 46 | const Button = styled.button` 47 | width: 40%; 48 | border: none; 49 | padding: 15px 20px; 50 | background-color: teal; 51 | color: white; 52 | cursor: pointer; 53 | margin-bottom: 10px; 54 | &:disabled { 55 | color: green; 56 | cursor: not-allowed; 57 | } 58 | `; 59 | 60 | const Link = styled.a` 61 | margin: 5px 0px; 62 | font-size: 12px; 63 | text-decoration: underline; 64 | cursor: pointer; 65 | `; 66 | 67 | const Error = styled.span` 68 | color: red; 69 | `; 70 | 71 | const Login = () => { 72 | const [username, setUsername] = useState(""); 73 | const [password, setPassword] = useState(""); 74 | const dispatch = useDispatch(); 75 | const { isFetching, error } = useSelector((state) => state.user); 76 | 77 | const handleClick = (e) => { 78 | e.preventDefault(); 79 | login(dispatch, { username, password }); 80 | }; 81 | return ( 82 | 83 | 84 | SIGN IN 85 |
86 | setUsername(e.target.value)} 89 | /> 90 | setPassword(e.target.value)} 94 | /> 95 | 98 | {error && Something went wrong...} 99 | DO NOT YOU REMEMBER THE PASSWORD? 100 | CREATE A NEW ACCOUNT 101 |
102 |
103 |
104 | ); 105 | }; 106 | 107 | export default Login; 108 | -------------------------------------------------------------------------------- /MERN Project/client/src/pages/Product.jsx: -------------------------------------------------------------------------------- 1 | import { Add, Remove } from "@material-ui/icons"; 2 | import styled from "styled-components"; 3 | import Announcement from "../components/Announcement"; 4 | import Footer from "../components/Footer"; 5 | import Navbar from "../components/Navbar"; 6 | import Newsletter from "../components/Newsletter"; 7 | import { mobile } from "../responsive"; 8 | import { useLocation } from "react-router-dom"; 9 | import { useEffect, useState } from "react"; 10 | import { publicRequest } from "../requestMethods"; 11 | import { addProduct } from "../redux/cartRedux"; 12 | import { useDispatch } from "react-redux"; 13 | 14 | const Container = styled.div``; 15 | 16 | const Wrapper = styled.div` 17 | padding: 50px; 18 | display: flex; 19 | ${mobile({ padding: "10px", flexDirection: "column" })} 20 | `; 21 | 22 | const ImgContainer = styled.div` 23 | flex: 1; 24 | `; 25 | 26 | const Image = styled.img` 27 | width: 100%; 28 | height: 90vh; 29 | object-fit: cover; 30 | ${mobile({ height: "40vh" })} 31 | `; 32 | 33 | const InfoContainer = styled.div` 34 | flex: 1; 35 | padding: 0px 50px; 36 | ${mobile({ padding: "10px" })} 37 | `; 38 | 39 | const Title = styled.h1` 40 | font-weight: 200; 41 | `; 42 | 43 | const Desc = styled.p` 44 | margin: 20px 0px; 45 | `; 46 | 47 | const Price = styled.span` 48 | font-weight: 100; 49 | font-size: 40px; 50 | `; 51 | 52 | const FilterContainer = styled.div` 53 | width: 50%; 54 | margin: 30px 0px; 55 | display: flex; 56 | justify-content: space-between; 57 | ${mobile({ width: "100%" })} 58 | `; 59 | 60 | const Filter = styled.div` 61 | display: flex; 62 | align-items: center; 63 | `; 64 | 65 | const FilterTitle = styled.span` 66 | font-size: 20px; 67 | font-weight: 200; 68 | `; 69 | 70 | const FilterColor = styled.div` 71 | width: 20px; 72 | height: 20px; 73 | border-radius: 50%; 74 | background-color: ${(props) => props.color}; 75 | margin: 0px 5px; 76 | cursor: pointer; 77 | `; 78 | 79 | const FilterSize = styled.select` 80 | margin-left: 10px; 81 | padding: 5px; 82 | `; 83 | 84 | const FilterSizeOption = styled.option``; 85 | 86 | const AddContainer = styled.div` 87 | width: 50%; 88 | display: flex; 89 | align-items: center; 90 | justify-content: space-between; 91 | ${mobile({ width: "100%" })} 92 | `; 93 | 94 | const AmountContainer = styled.div` 95 | display: flex; 96 | align-items: center; 97 | font-weight: 700; 98 | `; 99 | 100 | const Amount = styled.span` 101 | width: 30px; 102 | height: 30px; 103 | border-radius: 10px; 104 | border: 1px solid teal; 105 | display: flex; 106 | align-items: center; 107 | justify-content: center; 108 | margin: 0px 5px; 109 | `; 110 | 111 | const Button = styled.button` 112 | padding: 15px; 113 | border: 2px solid teal; 114 | background-color: white; 115 | cursor: pointer; 116 | font-weight: 500; 117 | 118 | &:hover { 119 | background-color: #f8f4f4; 120 | } 121 | `; 122 | 123 | const Product = () => { 124 | const location = useLocation(); 125 | const id = location.pathname.split("/")[2]; 126 | const [product, setProduct] = useState({}); 127 | const [quantity, setQuantity] = useState(1); 128 | const [color, setColor] = useState(""); 129 | const [size, setSize] = useState(""); 130 | const dispatch = useDispatch(); 131 | 132 | useEffect(() => { 133 | const getProduct = async () => { 134 | try { 135 | const res = await publicRequest.get("/products/find/" + id); 136 | setProduct(res.data); 137 | } catch {} 138 | }; 139 | getProduct(); 140 | }, [id]); 141 | 142 | const handleQuantity = (type) => { 143 | if (type === "dec") { 144 | quantity > 1 && setQuantity(quantity - 1); 145 | } else { 146 | setQuantity(quantity + 1); 147 | } 148 | }; 149 | 150 | const handleClick = () => { 151 | dispatch( 152 | addProduct({ ...product, quantity, color, size }) 153 | ); 154 | }; 155 | return ( 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | {product.title} 165 | {product.desc} 166 | $ {product.price} 167 | 168 | 169 | Color 170 | {product.color?.map((c) => ( 171 | setColor(c)} /> 172 | ))} 173 | 174 | 175 | Size 176 | setSize(e.target.value)}> 177 | {product.size?.map((s) => ( 178 | {s} 179 | ))} 180 | 181 | 182 | 183 | 184 | 185 | handleQuantity("dec")} /> 186 | {quantity} 187 | handleQuantity("inc")} /> 188 | 189 | 190 | 191 | 192 | 193 | 194 |