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.
https://drive.google.com/file/d/1VwryeQX14DvDACn3xs7YJh231oIbvcgK/view?usp=share_link
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:
- We aimed at designing simple yet efficient UI elements in order to make the learning process easier.
- 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
- The project is currently in development.
- Unit tests need to be implemented.
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.
Individual Trainee
- login
- signup
- view all courses with its corresponding info: rates,reviews, price,etc.
- search and filter the courses
- view a preview of any course
- pay for a course
- report problems for a course they are registered for
- request a refund for a course if only 50% or less of the course has been watched
- rate and review a course
- rate and review an instructor
- download the certificate after completing the course
- receive a certificate as a PDF after completing the course via email
- view and accept the website/ company refund/ payment policy while signing up
- view the most viewed/ most popular courses
- solve a mcq exam
- view his/her grade after submitting the exam
- view the questions with the correct solution to view the incorrect answers
- see his/her progress in the course as a percentage of how much of the course has been completed so far
- write notes while watching the video
- download the notes as a PDF
- 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
- add another admin
- add intructors
- add corporate trainees
- view reported problems by trainees and instructors
- handle refund requests by trainees
- accept/decline course requests of corporate trainees
- add a discount on any course(s) or all courses for a chosen period of time
Instructor
- login
- create a course with its coressonding quizzes and exam
- view all courses with its corresponding info: rates,reviews, price,etc.
- add a discount for a chosen period of time on any of his courses
- view and accept the website/ company refund/ payment policy while loging in for the first time
- view the most viewed/ most popular courses
- view the ratings and reviews on all his/her courses
- view his/her balance
- edit his/her mini biography or email
- select their country
Notes
- Instructors and trainees can change their passowrd and email at any times
- Instructors and corporate trainees are required to change their password the first time ever they login.
- 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.
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
- nodejs
- express
- nodemon
- axios
- mongoose(MongoDB)
- react
- @sendgrid
- bcrypt
- crypto
- bootstrap
- HTML/CSS
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
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
Contributions are always welcome. To get Started
- Fork the repository
- Clone the repository
- Install dependencies
- Create a new branch
- Make your changes
- Commit and push your changes
- Create a pull request
- Wait for your pull request to be reviewed and merged
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);
}
}, []);
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 |