Bla Bla

Motivation

This is a collaborative project for of 5 Media Engineering major in the German University in Cairo in an attempt to secure an internship at the Canadian Chamber of Commerce by designing and employing their new website of online education aiming at offering reliable courses from various categories.



Live Demo:

https://drive.google.com/file/d/1VwryeQX14DvDACn3xs7YJh231oIbvcgK/view?usp=share_link

Design Approach:

Before the frontend web design phase, we have conducted user interviews in order to utilise the given user requiremts. Through the interviewing process, we got to understand more about not only what functionalities our users expect but also about what experience are they looking for. Our interviewees were a selection of potential students that have tried or would consider trying online learning. It is also important to mention that we also considered existing competitive platforms,such as, Udemy,Coursera, and Udacity as a reference and to what will be our own imprint on our online learing platform.
After the interview process was over the following were considered in our low-fidelity design:

  1. We aimed at designing simple yet efficient UI elements in order to make the learning process easier.
  2. In case the user has made any mistake throughout any process required, a clear message stating what the error was and how to overcome this error were required



Build Status:

  1. The project is currently in development.
  2. Unit tests need to be implemented.

Code Style:

Standard code styles that are easy to follow for any new contributors.
Backend methods are defined in controller folder then called in their designated route.

Tests:

Individual Trainee

  1. login
  2. signup
  3. view all courses with its corresponding info: rates,reviews, price,etc.
  4. search and filter the courses
  5. view a preview of any course
  6. pay for a course
  7. report problems for a course they are registered for
  8. request a refund for a course if only 50% or less of the course has been watched
  9. rate and review a course
  10. rate and review an instructor
  11. download the certificate after completing the course
  12. receive a certificate as a PDF after completing the course via email
  13. view and accept the website/ company refund/ payment policy while signing up
  14. view the most viewed/ most popular courses
  15. solve a mcq exam
  16. view his/her grade after submitting the exam
  17. view the questions with the correct solution to view the incorrect answers
  18. see his/her progress in the course as a percentage of how much of the course has been completed so far
  19. write notes while watching the video
  20. download the notes as a PDF
  21. select their country

Corporate Trainee

Same as Individual Trainee but instead of paying for a course the corporate trainee requests a course for which an admin can accept or reject based on the contract between the corporate and our website , and therefore they can't request a refund. Also, corporate trainees have no option of signing up,instead, they are added by the admins to the system.

Admin

  1. add another admin
  2. add intructors
  3. add corporate trainees
  4. view reported problems by trainees and instructors
  5. handle refund requests by trainees
  6. accept/decline course requests of corporate trainees
  7. add a discount on any course(s) or all courses for a chosen period of time

Instructor

  1. login
  2. create a course with its coressonding quizzes and exam
  3. view all courses with its corresponding info: rates,reviews, price,etc.
  4. add a discount for a chosen period of time on any of his courses
  5. view and accept the website/ company refund/ payment policy while loging in for the first time
  6. view the most viewed/ most popular courses
  7. view the ratings and reviews on all his/her courses
  8. view his/her balance
  9. edit his/her mini biography or email
  10. select their country

Notes

  1. Instructors and trainees can change their passowrd and email at any times
  2. Instructors and corporate trainees are required to change their password the first time ever they login.
  3. In case an instructor or trainee forgot their password upon logging in, an email is sent to them in order to follow the procedure of changing it.

Features

This app features some technologies and functionalities that makes it a unique website for courses.

  • Currency exchange with very high accuracy
  • Search and filter functionalities
  • Clear and instructive error messages



Technologies Used

  • nodejs
  • express
  • nodemon
  • axios
  • mongoose(MongoDB)
  • react
  • @sendgrid
  • bcrypt
  • crypto
  • bootstrap
  • HTML/CSS

Installation

1-clone the project to visual studio code

git clone "https://github.com/Advanced-Computer-Lab-2022/karimarie.git"

2-Install needed dependencies for the server side and run

cd backend
npm install --force
#run
npm start

2-Open new terminal,install needed dependencies for the client side and run

cd frontend
npm install --force
#run
npm start



API Reference(using axios)

GET (all courses)

http://localhost:2000/home

POST (login)

http://localhost:2000/login

POST (Signup)

http://localhost:2000/signup"

POST (edit password for trainee)

http://localhost:2000/corpTrainee/editpassword/${decodeID}

POST (edit password for instructor)

http://localhost:2000/instructor/editpassword/${decodeID}

GET (all countries)

https://restcountries.com/v2/all

POST (filter courses)

http://localhost:2000/postFilterAll

GET (search for courses)

http://localhost:2000/search/${search}

GET (exam solution)

http://localhost:2000/getExamSol/${id}

GET (instructor's details)

http://localhost:2000/instructor/getByid2/${Course.instructor}

POST (pay for a course)

http://localhost:2000/corpTrainee/payCourse/${id}/${currencyPrice}

GET (get admin reports)

http://localhost:2000/admin/seeMyReports/${id}

POST (a report follow up)

http://localhost:2000/followUp

POST (instructor review)

http://localhost:2000/addInstructorReview/${instid}

GET (instructor's courses)

http://localhost:2000/instructor/instCourses/:token

POST (edit instructor's email)

http://localhost:2000/instructor/editemail/:token

GET (create exam)

http://localhost:2000/instructor/createExam

POST (send certificate)

http://localhost:2000/sendCertificate

POST (add course review)

http://localhost:2000/corpTrainee/addCourseReview/:course

POST (request course refund)

http://localhost:2000/corpTrainee/refundRequest

GET (view notifications)

http://localhost:2000/getMyNotification/:userId

Contribute

Contributions are always welcome. To get Started

  1. Fork the repository
  2. Clone the repository
  3. Install dependencies
  4. Create a new branch
  5. Make your changes
  6. Commit and push your changes
  7. Create a pull request
  8. Wait for your pull request to be reviewed and merged

Code Examples

Sign up(client side)

   const sendUser = async () => {
   const res = await axios
     .post(
       "http://localhost:2000/signup",
       {
         firstName: firstName,
         lastName: lastName,
         email: email,
         userName: userName,
         password: password,
         gender: gender,
       },
       { withCredentials: true, credentials: "include" }
     )
     .catch((err) => console.log(err));
   console.log(res.data.msg);
   return res.data;
 };
 const handleSignUp = (e) => {
   e.preventDefault();
   if (document.getElementById("male").checked) {
     setGender("male");
   } else if (document.getElementById("female").checked) {
     setGender("female");
   } else {
     setGender("");
   }
   if (
     firstName === "" ||
     lastName === "" ||
     email === "" ||
     userName === "" ||
     password === "" ||
     gender === ""
   ) {
     isShowText3(true);
     isShowText(false);
     isShowText1(false);
     isShowText2(false);
   } else {
     sendUser().then((data) => {
       if (data.msg.localeCompare("Email entered is already taken") === 0) {
         isShowText(true);
         isShowText1(false);
         isShowText2(false);
         isShowText3(false);
       } else if (
         data.msg.localeCompare(
           "Password must be greater than 5 characters and less than 25 characters"
         ) === 0
       ) {
         isShowText1(true);
         isShowText(false);
         isShowText2(false);
         isShowText3(false);
       } else if (data.msg.localeCompare("Username already taken!") === 0) {
         isShowText2(true);
         isShowText(false);
         isShowText1(false);
         isShowText3(false);
       } else if (data.msg.localeCompare("Individual Trainee") === 0) {
         isShowText(false);
         isShowText1(false);
         isShowText2(false);
         isShowText3(false);
         localStorage.setItem("token", data.token);
         localStorage.setItem("userType","Trainee")
         window.location.href = "/Terms&Conditions";
       }
     });
   }
 };
 const [passwordType, setPasswordType] = useState("password");
 const togglePassword =()=>{
   if(passwordType==="password")
   {
    setPasswordType("text")
    return;
   }
   setPasswordType("password")
 };

getting a token(client side)

const VMyCourses = () => {
  const [access,hasaccess]=useState(false)
  const [datas,setdata]=useState("")
  const grantAccess = async () => {
      console.log(localStorage.getItem("token"))
      if(localStorage.getItem("token")===""){
          console.log("hi")
          hasaccess(false)
      }else {
      const res = await axios
        .get("http://localhost:2000/requireAuth/${localStorage.getItem("token")}")
        .catch((err) => console.log(err));
        const data = await res.data;
        return data;}
    };
    useEffect(() => {
      if(localStorage.getItem("token")!==""){
          grantAccess().then((data)=>{setdata(data.message)
          if(data.message==="Trainee"){
              hasaccess(true)
          }
          else {
              hasaccess(false)
          }
      });
    }}, []);

admin adding a new admin (server side)

const addAdmin=async (req,res,next)=>{
  
   const{userName,password}=req.body
   let adm;
   let x= await instTable.findOne({userName:req.body.userName})
   let y= await traineeTable.findOne({userName:req.body.userName}) 
   if(x){
      return res.json({success: false, message: 'Username already taken!'});
  }
  else  if(y){
      return res.json({success: false, message: 'Username already taken!'});
  }else {
   try{
      const salt = await bcrypt.genSalt();
      const hashedPassword = await bcrypt.hash(req.body.password, salt);
      const adm = await adminTable.create({ password: hashedPassword ,userName:userName});
       await adm.save();
       return res.json({success: true, message: 'Successfully Added!'});
      }
   catch(err){
       adminTable.find({userName:req.body.userName},function(err,person){
      if(err){
          return res.json({success: false, message: 'DataBase Error,Please Wait!'});
      }
      else{
          return res.json({success: false, message: 'Username already taken!'});
      }
  })}
}
  
}

getting all courses (server side)

const getAllCourses = async (req, res) => {
  
 
    let priceList;
    try{
     priceList = await courseTable.find({});
     return res.status(200).json({priceList})
    }
    catch(error){res.status(404).json({error:error.message}) }
  }
  const getSubjects=async(req,res)=>{
    let subjects;
    try{
        subjects=await subjectTable.find();
        subjects.save
        return res.status(200).json({subjects})
    }
    catch(error){res.status(404).json({error:error.message}) }
  }

instructor editing his password

const editPassword = async (req, res) => {

var decodeID="";
var finalres=""
if (req.params.token) {
  jwt.verify(req.params.token, 'supersecret', (err, decodedToken) => {
    if (err) {
      res.status(401).json({message:"You are not logged in."})
    } else {
      decodeID=decodedToken.name;
    }
  });
}

Using Stripe to pay for a course

const { id, currencyPrice } = useParams();
console.log(id)
const [cid,setcid]=useState(id)
console.log(cid)
const [green,setGreen]=useState(true)
useEffect(() => {
  if (!window.document.getElementById("stripe-script")) {
    var s = window.document.createElement("script");
    s.id = "stripe-script";
    s.type = "text/javascript";
    s.src = "https://js.stripe.com/v2/";
    s.onload = () => {
      window["Stripe"].setPublishableKey(
        "pk_test_51MEI8aGdZfaXR0mrrTdQCdrYn34vXH4ZzxSPDBPHy9rvej06lBu5LIb5jQeNmsX3X3Gpbmh8dJwXDQtgRthqHag900qEpQhRKa"
      );
    };
    window.document.body.appendChild(s);
  }
}, []);

Screenshots from the website

SignUp

SignUp

Login

Login

Admin Home Page

Admin Home

Create User (Admin)

Create User Create Inst

Add Discount (Admin)

Add Promo

View Reports (Admin)

view

View Refund Requests (Admin)

refund

HomePage

HomePage Home H

Payment Page

Payment

Wallet of Trainee

wallet

Tainee's Courses Page

Trainee

Course Details Page

Course Details course details2

Watching Subtitles

Watching

Solving Exam

solve solve2 solve3

Instructor Profile

Instructor Profile Inst

Create Course

Instructor Balance

Credits

Name GitHub
Angela Emil https://github.com/AngelaEmil
Kariman Kamal https://github.com/karimankamaal
Eliane Fares https://github.com/ElianeFares
Nada Nazeer https://github.com/nadanazeer11
Mariam Tarek https://github.com/Mariamtkh