├── backend ├── .gitignore ├── .env ├── utils │ ├── errorResponse.js │ └── cloudinary.js ├── routes │ ├── banner.js │ ├── category.js │ ├── user.js │ ├── auth.js │ └── product.js ├── models │ ├── category.js │ ├── banner.js │ ├── product.js │ └── user.js ├── package.json ├── controllers │ ├── categoryController.js │ ├── bannerController.js │ ├── user.js │ ├── auth.js │ └── productController.js ├── middleware │ ├── error.js │ └── auth.js └── app.js ├── frontend ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── index.html ├── src │ ├── setupTests.js │ ├── App.test.js │ ├── pages │ │ ├── admin │ │ │ ├── AdminDashboard.js │ │ │ ├── AdminAddBanner.js │ │ │ └── AdminCreateProduct.js │ │ ├── user │ │ │ └── UserDashboard.js │ │ ├── SignIn.js │ │ ├── SignUp.js │ │ └── Home.js │ ├── component │ │ ├── PrivateRoute.js │ │ ├── Footer.js │ │ ├── Card.js │ │ ├── Header.js │ │ └── Banner.js │ ├── index.css │ ├── reportWebVitals.js │ ├── index.js │ ├── App.js │ └── App.css ├── .gitignore ├── package.json └── README.md └── README.md /backend/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /frontend/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /frontend/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmannweb/mernstackproject/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmannweb/mernstackproject/HEAD/frontend/public/logo192.png -------------------------------------------------------------------------------- /frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/emmannweb/mernstackproject/HEAD/frontend/public/logo512.png -------------------------------------------------------------------------------- /backend/.env: -------------------------------------------------------------------------------- 1 | PORT = 8000 2 | DATABASE = 3 | JWT_SECRET = JBFSJKEFNJK23INU78 4 | EXPIRE_TOKEN = 1*60*60*1000 5 | CLOUD_NAME= 6 | CLOUD_KEY= 7 | CLOUD_KEY_SECRET= -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MERN stack Project 2 | ## This is a Youtube series, where we are building a MERN stack project from scratch. 3 | 4 | ### Youtube Link: https://www.youtube.com/playlist?list=PLw9dqMP7HQV77fkIZvUfsVJkM_WPvw-J- 5 | -------------------------------------------------------------------------------- /backend/utils/errorResponse.js: -------------------------------------------------------------------------------- 1 | class ErrorResponse extends Error{ 2 | 3 | constructor(message, statusCode){ 4 | super(message); 5 | this.statusCode = statusCode; 6 | } 7 | 8 | } 9 | 10 | module.exports = ErrorResponse; -------------------------------------------------------------------------------- /backend/utils/cloudinary.js: -------------------------------------------------------------------------------- 1 | const cloudinary = require('cloudinary').v2; 2 | 3 | cloudinary.config({ 4 | cloud_name: process.env.CLOUD_NAME, 5 | api_key: process.env.CLOUD_KEY, 6 | api_secret: process.env.CLOUD_KEY_SECRET 7 | }); 8 | 9 | module.exports= cloudinary; -------------------------------------------------------------------------------- /frontend/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /frontend/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /frontend/src/pages/admin/AdminDashboard.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const AdminDashboard = () => { 4 | return ( 5 | <> 6 |
7 |

Test dash

8 |
9 | 10 | 11 | ) 12 | } 13 | 14 | export default AdminDashboard -------------------------------------------------------------------------------- /backend/routes/banner.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const {createBanner, displayBanner} = require("../controllers/bannerController") 4 | 5 | 6 | router.post('/banner/create', createBanner ); 7 | router.get('/fetch/banner', displayBanner ); 8 | 9 | 10 | 11 | 12 | module.exports = router; -------------------------------------------------------------------------------- /backend/routes/category.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const {createCategory, getCategories} = require("../controllers/categoryController") 4 | 5 | 6 | router.post('/category/create', createCategory ); 7 | router.get('/category/all', getCategories ); 8 | 9 | 10 | 11 | module.exports = router; -------------------------------------------------------------------------------- /backend/routes/user.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const {signup, signin, logout, singleUser } = require("../controllers/user") 4 | 5 | 6 | router.post('/signup', signup ); 7 | router.post('/signin', signin ); 8 | router.get('/logout', logout ); 9 | router.get('/user/:id', singleUser ); 10 | 11 | 12 | 13 | module.exports = router; -------------------------------------------------------------------------------- /backend/models/category.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | 4 | 5 | const categorySchema = new mongoose.Schema({ 6 | 7 | name: { 8 | type: String, 9 | trim: true, 10 | required : [true, 'Please add a category Name'], 11 | 12 | }, 13 | 14 | 15 | 16 | }, {timestamps: true}); 17 | 18 | 19 | 20 | 21 | 22 | 23 | module.exports = mongoose.model("Category", categorySchema); -------------------------------------------------------------------------------- /frontend/src/component/PrivateRoute.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {Route, Redirect} from 'react-router-dom' 3 | 4 | const PrivateRoute = ({...rest}) => { 5 | const auth = JSON.parse(localStorage.getItem('token')); 6 | if (auth){ 7 | if (auth.token){ 8 | return 9 | } 10 | } 11 | return 12 | }; 13 | 14 | export default PrivateRoute; 15 | -------------------------------------------------------------------------------- /frontend/.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 | -------------------------------------------------------------------------------- /frontend/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /frontend/src/component/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const Footer = () => { 4 | return ( 5 |
6 |
7 | © 2022 Copyright: MERN STACK APP 8 |
9 |
10 | ) 11 | } 12 | 13 | export default Footer 14 | -------------------------------------------------------------------------------- /frontend/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /backend/models/banner.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const bannerSchema = new mongoose.Schema({ 4 | 5 | 6 | images: [ 7 | { 8 | public_id: { 9 | type: String, 10 | required: true 11 | }, 12 | url: { 13 | type: String, 14 | required: true 15 | } 16 | } 17 | ], 18 | 19 | 20 | }, {timestamps: true}); 21 | 22 | module.exports = mongoose.model("Banner", bannerSchema); -------------------------------------------------------------------------------- /backend/routes/auth.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const {signup, signin, logout, singleUser, userProfile } = require("../controllers/auth"); 4 | const {isAuthenticated} = require("../middleware/auth"); 5 | 6 | 7 | router.post('/signup', signup ); 8 | router.post('/signin', signin ); 9 | router.get('/logout', logout ); 10 | router.get('/getme', isAuthenticated, userProfile ); 11 | router.get('/user/:id', singleUser ); 12 | 13 | 14 | 15 | module.exports = router; -------------------------------------------------------------------------------- /frontend/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /backend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon app.js" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "bcryptjs": "^2.4.3", 13 | "body-parser": "^1.19.0", 14 | "cloudinary": "^1.30.0", 15 | "cookie-parser": "^1.4.6", 16 | "cors": "^2.8.5", 17 | "dotenv": "^10.0.0", 18 | "express": "^4.17.1", 19 | "jsonwebtoken": "^8.5.1", 20 | "mongoose": "^5.13.9", 21 | "morgan": "^1.10.0", 22 | "nodemon": "^2.0.14" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /frontend/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /backend/routes/product.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const { createProduct, displayProduct, deleteProduct, productCategory, updateProduct } = require("../controllers/productController") 4 | const { isAuthenticated, isAdmin } = require("../middleware/auth"); 5 | 6 | 7 | router.post('/product/create', isAuthenticated, isAdmin, createProduct); 8 | router.get('/products/all', displayProduct); 9 | router.delete('/product/delete/:id', isAuthenticated, isAdmin, deleteProduct); 10 | router.put('/product/update/:id', isAuthenticated, isAdmin, updateProduct); 11 | router.get('/product/categories', productCategory); 12 | 13 | 14 | 15 | 16 | 17 | module.exports = router; -------------------------------------------------------------------------------- /backend/controllers/categoryController.js: -------------------------------------------------------------------------------- 1 | const Category = require("../models/category"); 2 | const ErrorResponse = require('../utils/errorResponse'); 3 | 4 | 5 | exports.createCategory = async (req, res, next)=>{ 6 | 7 | 8 | try { 9 | const category = await Category.create(req.body); 10 | res.status(201).json({ 11 | success: true, 12 | category 13 | }) 14 | 15 | } catch (error) { 16 | console.log(error); 17 | next(error); 18 | 19 | } 20 | 21 | } 22 | 23 | //get all caregories 24 | exports.getCategories = async (req, res, next)=>{ 25 | 26 | try { 27 | const categories = await Category.find(); 28 | res.status(201).json({ 29 | success: true, 30 | categories 31 | }) 32 | 33 | } catch (error) { 34 | console.log(error); 35 | next(error); 36 | 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /backend/middleware/error.js: -------------------------------------------------------------------------------- 1 | const ErrorResponse = require('../utils/errorResponse'); 2 | 3 | const errorHandler = (err, req, res, next) =>{ 4 | 5 | console.log(err); 6 | 7 | let error = {...err} 8 | error.message = err.message; 9 | 10 | // Mongoose Bad ObjectId 11 | if (err.name === 'CastError'){ 12 | const message = "Ressource not found"; 13 | error = new ErrorResponse(message, 404); 14 | } 15 | 16 | if (err.code === 11000){ 17 | const message = "Duplicate field value entered"; 18 | error = new ErrorResponse(message, 400); 19 | } 20 | 21 | if (err.name === 'ValidationError'){ 22 | const message = Object.values(err.errors).map(value => value.message); 23 | error = new ErrorResponse(message, 400); 24 | 25 | } 26 | 27 | 28 | 29 | res.status(error.statusCode || 500).json({ 30 | success: false, 31 | error: error.message || 'Server Error' 32 | }) 33 | } 34 | 35 | module.exports = errorHandler; -------------------------------------------------------------------------------- /backend/middleware/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | const User = require("../models/user"); 3 | const ErrorResponse = require('../utils/errorResponse'); 4 | 5 | 6 | // check if user is authenticated 7 | exports.isAuthenticated = async (req, res, next) =>{ 8 | 9 | const {token} = req.cookies; 10 | 11 | // make sure token exists 12 | if (!token){ 13 | return next (new ErrorResponse('You must log in to access this ressource', 401)); 14 | } 15 | 16 | try { 17 | //verify token 18 | const decoded = jwt.verify(token, process.env.JWT_SECRET); 19 | req.user = await User.findById(decoded.id); 20 | next(); 21 | 22 | } catch (error) { 23 | return next (new ErrorResponse('You must log in to access this ressource', 401)); 24 | } 25 | } 26 | 27 | // admin middleware 28 | exports.isAdmin = (req, res, next) =>{ 29 | if (req.user.role === 0){ 30 | return next (new ErrorResponse('Access denied, you must be an admin', 401)); 31 | } 32 | next(); 33 | 34 | } -------------------------------------------------------------------------------- /frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "frontend", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@testing-library/jest-dom": "^5.16.1", 7 | "@testing-library/react": "^12.1.2", 8 | "@testing-library/user-event": "^13.5.0", 9 | "antd": "^4.22.3", 10 | "axios": "^0.24.0", 11 | "react": "^17.0.2", 12 | "react-dom": "^17.0.2", 13 | "react-router-dom": "^5.3.0", 14 | "react-scripts": "5.0.0", 15 | "react-toastify": "^8.1.0", 16 | "web-vitals": "^2.1.2" 17 | }, 18 | "scripts": { 19 | "start": "react-scripts start", 20 | "build": "react-scripts build", 21 | "test": "react-scripts test", 22 | "eject": "react-scripts eject" 23 | }, 24 | "eslintConfig": { 25 | "extends": [ 26 | "react-app", 27 | "react-app/jest" 28 | ] 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | ">0.2%", 33 | "not dead", 34 | "not op_mini all" 35 | ], 36 | "development": [ 37 | "last 1 chrome version", 38 | "last 1 firefox version", 39 | "last 1 safari version" 40 | ] 41 | }, 42 | "proxy": "http://localhost:8000" 43 | } 44 | -------------------------------------------------------------------------------- /frontend/src/component/Card.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Link } from 'react-router-dom' 3 | 4 | const Card = ({image, productName, prodLink, prodCategory, price}) => { 5 | return ( 6 | <> 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |

{productName}

15 |
{prodCategory}
16 |

${price}

17 |
18 |

19 | 20 |
Details
21 | 22 |
23 |
24 |
25 | 26 | ) 27 | } 28 | 29 | export default Card -------------------------------------------------------------------------------- /backend/models/product.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const {ObjectId} = mongoose.Schema; 3 | 4 | 5 | const productSchema = new mongoose.Schema({ 6 | 7 | name: { 8 | type: String, 9 | trim: true, 10 | required : [true, 'Please add a product Name'], 11 | maxlength: 32 12 | }, 13 | 14 | description: { 15 | type: String, 16 | trim: true, 17 | required : [true, 'Please add a product Description'], 18 | maxlength: 2000, 19 | }, 20 | 21 | price: { 22 | type: Number, 23 | trim: true, 24 | required : [true, 'Product must have a price'], 25 | maxlength: 32 26 | }, 27 | 28 | image: { 29 | public_id: { 30 | type: String, 31 | required: true 32 | }, 33 | url: { 34 | type: String, 35 | required: true 36 | } 37 | 38 | }, 39 | 40 | category: { 41 | type: ObjectId, 42 | ref: "Category", 43 | required : [true, 'Product must belong to a category'], 44 | 45 | }, 46 | 47 | 48 | 49 | 50 | }, {timestamps: true}); 51 | 52 | 53 | 54 | 55 | 56 | 57 | module.exports = mongoose.model("Product", productSchema); -------------------------------------------------------------------------------- /frontend/src/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import './App.css'; 3 | import Home from './pages/Home' 4 | import SignUp from './pages/SignUp' 5 | import SignIn from './pages/SignIn' 6 | import UserDashboard from './pages/user/UserDashboard' 7 | import {BrowserRouter, Route} from 'react-router-dom' 8 | import { ToastContainer} from 'react-toastify'; 9 | import 'react-toastify/dist/ReactToastify.css'; 10 | import PrivateRoute from './component/PrivateRoute'; 11 | import AdminCreateProduct from './pages/admin/AdminCreateProduct'; 12 | import AdminAddBanner from './pages/admin/AdminAddBanner'; 13 | import AdminDashboard from './pages/admin/AdminDashboard'; 14 | 15 | 16 | 17 | 18 | const App = () => { 19 | return ( 20 | <> 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ) 35 | } 36 | 37 | export default App 38 | -------------------------------------------------------------------------------- /backend/controllers/bannerController.js: -------------------------------------------------------------------------------- 1 | const Banner = require("../models/banner"); 2 | const ErrorResponse = require('../utils/errorResponse'); 3 | const cloudinary = require('../utils/cloudinary'); 4 | 5 | 6 | 7 | exports.createBanner = async (req, res, next)=>{ 8 | 9 | try { 10 | 11 | let images = [...req.body.images]; 12 | let imagesBuffer = []; 13 | 14 | for (let i =0; i < images.length; i++){ 15 | const result = await cloudinary.uploader.upload(images[i], { 16 | folder: "banners", 17 | width: 1920, 18 | crop: "scale" 19 | }); 20 | 21 | imagesBuffer.push({ 22 | public_id: result.public_id, 23 | url: result.secure_url 24 | }) 25 | 26 | } 27 | 28 | req.body.images = imagesBuffer 29 | const banner = await Banner.create(req.body) 30 | 31 | res.status(201).json({ 32 | success: true, 33 | banner 34 | }) 35 | 36 | } catch (error) { 37 | console.log(error); 38 | next(error); 39 | 40 | } 41 | 42 | } 43 | 44 | 45 | //display banner 46 | exports.displayBanner = async (req, res, next)=>{ 47 | 48 | try { 49 | const banners = await Banner.find() 50 | 51 | res.status(201).json({ 52 | success: true, 53 | banners, 54 | }) 55 | 56 | } catch (error) { 57 | console.log(error); 58 | next(error); 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /backend/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const app = express(); 3 | require('dotenv').config(); 4 | const mongoose = require('mongoose'); 5 | const bodyParser = require('body-parser'); 6 | const morgan = require('morgan'); 7 | const cors = require('cors'); 8 | const cookieParser = require('cookie-parser'); 9 | const errorHandler = require('./middleware/error'); 10 | 11 | 12 | //IMPORT ROUTES 13 | const authRoutes = require('./routes/auth'); 14 | const productRoutes = require('./routes/product'); 15 | const categoryRoutes = require('./routes/category'); 16 | const bannerRoutes = require('./routes/banner'); 17 | 18 | 19 | 20 | 21 | // CONNECT DATABASE 22 | mongoose.connect(process.env.DATABASE, { 23 | useNewUrlParser: true, 24 | useUnifiedTopology: true, 25 | useCreateIndex: true 26 | }) 27 | .then(()=> console.log('DB connected')) 28 | .catch((err)=> console.log(err)); 29 | 30 | // MIDDLEWARE 31 | app.use(morgan('dev')); 32 | app.use(bodyParser.json({limit: '100mb'})); 33 | app.use(bodyParser.urlencoded({ // to support URL-encoded bodies 34 | limit: '100mb', 35 | extended: true 36 | })); 37 | app.use(cookieParser()); 38 | app.use(cors()); 39 | 40 | 41 | // ROUTES MIDDLEWARE 42 | app.use("/api", authRoutes) 43 | app.use("/api", productRoutes) 44 | app.use("/api", categoryRoutes) 45 | app.use("/api", bannerRoutes) 46 | 47 | 48 | 49 | //ERROR MIDDLEWARE 50 | app.use(errorHandler); 51 | 52 | const port = process.env.PORT || 8000; 53 | 54 | 55 | app.listen(port, ()=>{ 56 | console.log(`App is running on port ${port}`); 57 | }) -------------------------------------------------------------------------------- /frontend/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | 40 | .signup_form{ 41 | /* box-shadow: 0 7px 10px rgb(0 0 0 / 20%);*/ 42 | /* margin-top: 50px; */ 43 | box-shadow: 0px 0px 38px rgb(0 0 0 / 5%); 44 | padding-bottom: 10px; 45 | border-radius: 10px; 46 | padding:15px; 47 | } 48 | 49 | .signup_title{ 50 | text-align: center; 51 | padding-bottom: 30px; 52 | color: #1266f1; 53 | } 54 | 55 | 56 | .form-outline input[type=text], 57 | .form-outline input[type=email], 58 | .form-outline input[type=select], 59 | .form-outline textarea, 60 | .form-outline input[type=password] { 61 | border-bottom: 1px solid #f4f4f4; 62 | } 63 | select#category, 64 | textarea#form4Example2, 65 | input#form4Example3 { 66 | border-bottom: 1px solid #f4f4f4; 67 | } 68 | 69 | /* sign in */ 70 | .custom_class{ 71 | padding-top: 80px; 72 | padding-bottom: 100px; 73 | } 74 | 75 | 76 | /* dashboard styling */ 77 | .dashboard_container { 78 | padding: 100px 30px; 79 | } 80 | 81 | /* product card */ 82 | .card{ 83 | min-height: 493px!important; 84 | margin-bottom: 20px; 85 | } -------------------------------------------------------------------------------- /frontend/src/pages/user/UserDashboard.js: -------------------------------------------------------------------------------- 1 | import React, {useState, useEffect} from 'react'; 2 | import Header from '../../component/Header' 3 | import Footer from '../../component/Footer' 4 | 5 | 6 | const UserDashboard = () => { 7 | 8 | const [profile, setProfile] = useState(""); 9 | const {name, email, role, createdAt} = profile; 10 | 11 | useEffect(()=>{ 12 | fetch('/api/getme') 13 | .then(res =>{ 14 | return res.json() 15 | }) 16 | .then(result =>{ 17 | //console.log(result) 18 | setProfile(result.user) 19 | }) 20 | .catch(error => { 21 | console.log(error); 22 | }) 23 | }, []); 24 | 25 | return ( 26 | <> 27 | 28 |
29 | 30 |
31 |
32 |
33 |
34 |
35 | User Dashboard 36 |
37 |
    38 |
  • Name: {name}
  • 39 |
  • E-mail: {email}
  • 40 |
  • Join at: {new Date(createdAt).toLocaleDateString()}
  • 41 |
  • {role===1 ? "Admin" : "Registred User"}
  • 42 |
43 |
44 |
45 |
46 |

other col

47 |
48 |
49 |
50 | 51 |