├── Procfile ├── .vscode └── settings.json ├── frontend ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── logo192.png │ ├── logo512.png │ ├── images │ │ └── react.jpg │ ├── manifest.json │ └── index.html ├── src │ ├── components │ │ ├── utils │ │ │ ├── notification │ │ │ │ ├── notification.css │ │ │ │ └── Notification.js │ │ │ ├── Error.js │ │ │ ├── validation │ │ │ │ └── Validation.js │ │ │ └── NotFound │ │ │ │ └── NotFound.js │ │ ├── body │ │ │ ├── auth │ │ │ │ ├── wavev.png │ │ │ │ ├── img │ │ │ │ │ ├── wavev.png │ │ │ │ │ ├── avatare.svg │ │ │ │ │ ├── avatarRegister.svg │ │ │ │ │ └── login.svg │ │ │ │ ├── ActivationEmail.js │ │ │ │ ├── ForgotPassword.js │ │ │ │ ├── ResetPassword.js │ │ │ │ ├── Login.js │ │ │ │ ├── auth.css │ │ │ │ └── Register.js │ │ │ └── profile │ │ │ │ ├── editcourse.css │ │ │ │ ├── EditUser.js │ │ │ │ └── profile.css │ │ ├── CategoryCard │ │ │ ├── CategoryCard.js │ │ │ └── CategoryCard.css │ │ ├── CourseCard │ │ │ └── CourseCard.js │ │ ├── Footer │ │ │ ├── Footer.js │ │ │ └── footer.css │ │ └── Navbar │ │ │ ├── Navbar.css │ │ │ └── Navbar.js │ ├── redux │ │ ├── actions │ │ │ ├── index.js │ │ │ ├── usersAction.js │ │ │ ├── authAction.js │ │ │ ├── cartActions.js │ │ │ └── orderActions.js │ │ ├── reducers │ │ │ ├── tokenReducer.js │ │ │ ├── usersInfoReducer.js │ │ │ ├── authReducer.js │ │ │ ├── index.js │ │ │ ├── cartReducer.js │ │ │ └── orderReducers.js │ │ ├── constants │ │ │ ├── cartconstants.js │ │ │ ├── orderconstants.js │ │ │ └── courseconstants.js │ │ └── store.js │ ├── setupTests.js │ ├── App.test.js │ ├── reportWebVitals.js │ ├── pages │ │ ├── Coursepage │ │ │ ├── Editor.js │ │ │ ├── CommentList.js │ │ │ ├── Rating.js │ │ │ ├── Comments.js │ │ │ └── Collapsible.js │ │ ├── Cart │ │ │ ├── Empty.js │ │ │ ├── Productcart.js │ │ │ ├── Cart.js │ │ │ └── Cart.css │ │ ├── CourseFilter │ │ │ ├── CollapsibleFilter.css │ │ │ ├── Coursesblock.js │ │ │ ├── Subcategory.js │ │ │ ├── CollapsibleFilter.js │ │ │ ├── CourseFilter.css │ │ │ └── CourseFilter.js │ │ ├── Placeorderscreen │ │ │ ├── Paypal.js │ │ │ └── PlaceOrder.js │ │ ├── CourseSearch │ │ │ └── CourseSeacrh.js │ │ ├── Mycourses │ │ │ └── Mycourses.js │ │ ├── checkout │ │ │ └── CheckoutScreen.css │ │ ├── Orderscreen │ │ │ └── OrderScreen.js │ │ └── Home │ │ │ └── Home.css │ ├── index.js │ ├── useWindowDimensions.js │ ├── App.css │ └── App.js ├── .gitignore ├── package.json └── README.md ├── backend ├── .gitignore ├── middleware │ ├── isTeacher.js │ ├── authAdmin.js │ ├── auth.js │ └── uploadImage.js ├── routes │ ├── upload.js │ ├── orderRoutes.js │ ├── userRouter.js │ └── courseRouter.js ├── package.json ├── models │ ├── userModel.js │ ├── orderModel.js │ └── CourseModel.js ├── controllers │ ├── uploadCtrl.js │ ├── sendMail.js │ └── orderControler.js ├── seeder.js └── server.js ├── .gitignore ├── .env ├── README.md └── package.json /Procfile: -------------------------------------------------------------------------------- 1 | web: node backend/server.js -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "git.ignoreLimitWarning": true 3 | } -------------------------------------------------------------------------------- /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/Bourhjoul/E-learning-platform-Mern/HEAD/frontend/public/favicon.ico -------------------------------------------------------------------------------- /frontend/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bourhjoul/E-learning-platform-Mern/HEAD/frontend/public/logo192.png -------------------------------------------------------------------------------- /frontend/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bourhjoul/E-learning-platform-Mern/HEAD/frontend/public/logo512.png -------------------------------------------------------------------------------- /frontend/public/images/react.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bourhjoul/E-learning-platform-Mern/HEAD/frontend/public/images/react.jpg -------------------------------------------------------------------------------- /frontend/src/components/utils/notification/notification.css: -------------------------------------------------------------------------------- 1 | .ant-alert-close-icon{ 2 | background: transparent !important; 3 | } 4 | -------------------------------------------------------------------------------- /frontend/src/components/body/auth/wavev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bourhjoul/E-learning-platform-Mern/HEAD/frontend/src/components/body/auth/wavev.png -------------------------------------------------------------------------------- /frontend/src/components/body/auth/img/wavev.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bourhjoul/E-learning-platform-Mern/HEAD/frontend/src/components/body/auth/img/wavev.png -------------------------------------------------------------------------------- /frontend/src/redux/actions/index.js: -------------------------------------------------------------------------------- 1 | const ACTIONS = { 2 | LOGIN : 'LOGIN', 3 | GET_TOKEN : 'GET_TOKEN', 4 | GET_USER: 'GET_USER', 5 | GET_ALL_USERS : 'GET_ALL_USERS', 6 | GET_ALL_USERS_REQUEST : 'GET_ALL_USERS_REQUEST' 7 | } 8 | export default ACTIONS 9 | -------------------------------------------------------------------------------- /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/redux/reducers/tokenReducer.js: -------------------------------------------------------------------------------- 1 | import ACTIONS from '../actions' 2 | 3 | const token = "" 4 | 5 | const tokenReducer = (state=token, action) => { 6 | switch (action.type) { 7 | case ACTIONS.GET_TOKEN: 8 | return action.payload 9 | default: 10 | return state 11 | } 12 | } 13 | export default tokenReducer -------------------------------------------------------------------------------- /frontend/src/redux/constants/cartconstants.js: -------------------------------------------------------------------------------- 1 | export const ADD_ITEM_CART = 'ADD_ITEM_CART' 2 | export const REMOVE_ITEM_CART = 'REMOVE_ITEM_CART' 3 | 4 | export const CART_SAVE_COUNTRY_CUSTOMER = 'CART_SAVE_COUNTRY_CUSTOMER' 5 | 6 | export const CART_SAVE_PAYMENT = 'CART_SAVE_PAYMENT' 7 | export const CART_NAME_PAYMENT = 'CART_NAME_PAYMENT' 8 | 9 | export const REMOVE_ALL_FROM_CART = 'REMOVE_ALL_FROM_CART' -------------------------------------------------------------------------------- /backend/.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/.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 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | .env 3 | 4 | # dependencies 5 | /node_modules 6 | /.pnp 7 | .pnp.js 8 | 9 | # testing 10 | /coverage 11 | 12 | # production 13 | /frontend/build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | -------------------------------------------------------------------------------- /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/middleware/isTeacher.js: -------------------------------------------------------------------------------- 1 | const Users = require('../models/userModel') 2 | 3 | const isTeacher = async (req, res, next) => { 4 | try { 5 | const user = await Users.findOne({_id: req.user.id}) 6 | if(!user.Teacher) 7 | return res.status(500).json({msg: "Teacher resources access denied."}) 8 | 9 | next() 10 | } catch (err) { 11 | return res.status(500).json({msg: err.message}) 12 | } 13 | } 14 | 15 | module.exports = isTeacher -------------------------------------------------------------------------------- /backend/middleware/authAdmin.js: -------------------------------------------------------------------------------- 1 | const Users = require('../models/userModel') 2 | 3 | const authAdmin = async (req, res, next) => { 4 | try { 5 | const user = await Users.findOne({_id: req.user.id}) 6 | 7 | if(user.role !== 1) 8 | return res.status(500).json({msg: "Admin resources access denied."}) 9 | 10 | next() 11 | } catch (err) { 12 | return res.status(500).json({msg: err.message}) 13 | } 14 | } 15 | 16 | module.exports = authAdmin -------------------------------------------------------------------------------- /backend/routes/upload.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router() 2 | const uploadImage = require('../middleware/uploadImage') 3 | const uploadCtrl = require('../controllers/uploadCtrl') 4 | const auth = require('../middleware/auth') 5 | 6 | // login as normal user -> refresh_token -> uploadAvatar 7 | router.post('/upload_avatar', uploadImage, auth, uploadCtrl.uploadAvatar) 8 | router.post('/upload_crsimage', uploadImage, auth, uploadCtrl.uploadCourseimage) 9 | 10 | module.exports = router -------------------------------------------------------------------------------- /frontend/src/components/utils/Error.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Result, Button } from 'antd'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | const Error = ({error}) => { 6 | 7 | return ( 8 | 13 | 14 | 15 | 16 | } 17 | /> 18 | ) 19 | } 20 | 21 | export default Error 22 | -------------------------------------------------------------------------------- /frontend/src/redux/reducers/usersInfoReducer.js: -------------------------------------------------------------------------------- 1 | import ACTIONS from '../actions' 2 | 3 | const users = [] 4 | const usersInfoReducer = (state = users, action) => { 5 | switch(action.type){ 6 | case ACTIONS.GET_ALL_USERS_REQUEST : 7 | return {...state, loadingtab : true } 8 | case ACTIONS.GET_ALL_USERS: 9 | return { users: action.payload ,loadingtab : false} 10 | default: 11 | return state 12 | } 13 | } 14 | 15 | export default usersInfoReducer -------------------------------------------------------------------------------- /frontend/src/components/CategoryCard/CategoryCard.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Link } from "react-router-dom"; 3 | import "./CategoryCard.css"; 4 | const CategoryCard = ({ image, title }) => { 5 | return ( 6 |
7 | 8 |
9 | 10 |
11 |

{title}

{" "} 12 | 13 |
14 | ); 15 | }; 16 | 17 | export default CategoryCard; 18 | -------------------------------------------------------------------------------- /frontend/src/pages/Coursepage/Editor.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Comment, Avatar, Form, Button, List, Input } from 'antd'; 3 | 4 | const Editor = () => { 5 | return ( 6 | <> 7 | 8 |