Skip to content

Commit

Permalink
[Issue: #26]: Course Creation Wizard | Page layout added (#45)
Browse files Browse the repository at this point in the history
  • Loading branch information
Artlfmj authored Oct 8, 2023
2 parents 5922917 + b5281c2 commit 5b5e95b
Show file tree
Hide file tree
Showing 5 changed files with 535 additions and 5 deletions.
50 changes: 48 additions & 2 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,6 @@ app.use(morgan("dev"));

app.use(mongoSanitize());



//Regular middleware
app.use(cookieParser());
const csrf = require("csurf");
Expand Down Expand Up @@ -72,7 +70,55 @@ app.use("/courses", limiter, isAuthenticated, async function (req, res) {
return res.render("course", { courses: courses });
});

app.post("/search-course", limiter, isAuthenticated, async function (req, res) {
const query = req.body.query;
const regexQuery = {
title: { $regex: query, $options: "i" },
};
try {
const searchCourses = await courseModel.findOne(regexQuery);
res.json(searchCourses);
} catch (err) {
console.error(err);
res.json({ message: "An error occurred while searching." });
}
});

app.get("/create-course", csrfProtection, limiter, isAuthenticated, async function (req, res) {
return res.render("course-create", { messageError: req.flash("error"), messageSuccess: req.flash("success"), csrfToken: req.csrfToken() });
});

app.post("/create-course", limiter, isAuthenticated, csrfProtection, async function (req, res) {
// TODO: Need to implement upload image logic
try {
const { courseName, shortDescription, longDescription, duration, durationType, imageFile, difficulty } = req.body;
const userName = req.user.fullName;
const findExistingCourse = await courseModel.findOne({ title: {'$regex': `^${courseName}$`, $options: 'i'} });
if (!findExistingCourse) {
const newCourse = new courseModel({
title: courseName,
shortDescription: shortDescription,
longDescription: { longDescription: longDescription },
duration: duration,
durationType: durationType?.toLowerCase(),
difficulty: difficulty,
image: imageFile,
author: userName
});

await newCourse.save();
req.flash("success", "Course created successfully");
return res.redirect("/create-course");
} else {
req.flash("error", "This course is already available.");
return res.redirect("/create-course");
}
} catch (error) {
console.error("Error during course creation:", error);
req.flash("error", "Failed to create the course. Please try again.");
res.redirect("/create-course");
}
});

app.use("/css", express.static("src/css"));

Expand Down
258 changes: 258 additions & 0 deletions src/css/course-create.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
body {
background-color: #ffffff;
color: #444444;
font-family: "Roboto", sans-serif;
font-size: 16px;
font-weight: 300;
margin: 0;
padding: 0;
}
.alert {
padding: 10px;
margin-bottom: 20px;
border-radius: 4px;
position: absolute;
top: 0;
right: 0;
}

.alert-danger {
color: #721c24;
background-color: #f8d7da;
border: 1px solid #f5c6cb;
}

.alert-success {
color: #155724;
background-color: #d4edda;
border: 1px solid #c3e6cb;
}

.wizard-content-left {
background-blend-mode: darken;
background-color: rgba(0, 0, 0, 0.45);
background-image: url("https://i.ibb.co/X292hJF/form-wizard-bg-2.jpg");
background-position: center center;
background-size: cover;
height: 100vh;
padding: 30px;
}
.wizard-content-left h1 {
color: #ffffff;
font-size: 38px;
font-weight: 600;
padding: 12px 20px;
text-align: center;
}

.form-wizard {
color: #888888;
padding: 30px;
}
.form-wizard .wizard-form-radio {
display: inline-block;
margin-left: 5px;
position: relative;
}
.form-wizard .wizard-form-radio input[type="radio"] {
-webkit-appearance: none;
-moz-appearance: none;
-ms-appearance: none;
-o-appearance: none;
appearance: none;
background-color: #dddddd;
height: 25px;
width: 25px;
display: inline-block;
vertical-align: middle;
border-radius: 50%;
position: relative;
cursor: pointer;
}
.form-wizard .wizard-form-radio input[type="radio"]:focus {
outline: 0;
}
.form-wizard .wizard-form-radio input[type="radio"]:checked {
background-color: #fb1647;
}
.form-wizard .wizard-form-radio input[type="radio"]:checked::before {
content: "";
position: absolute;
width: 10px;
height: 10px;
display: inline-block;
background-color: #ffffff;
border-radius: 50%;
left: 1px;
right: 0;
margin: 0 auto;
top: 8px;
}
.form-wizard .wizard-form-radio input[type="radio"]:checked::after {
content: "";
display: inline-block;
webkit-animation: click-radio-wave 0.65s;
-moz-animation: click-radio-wave 0.65s;
animation: click-radio-wave 0.65s;
background: #000000;
content: "";
display: block;
position: relative;
z-index: 100;
border-radius: 50%;
}
.form-wizard .wizard-form-radio input[type="radio"] ~ label {
padding-left: 10px;
cursor: pointer;
}
.form-wizard .form-wizard-header {
text-align: center;
}
.form-wizard .form-wizard-next-btn,
.form-wizard .form-wizard-previous-btn,
.form-wizard .form-wizard-submit {
background-color: #d65470;
color: #ffffff;
display: inline-block;
min-width: 100px;
min-width: 120px;
padding: 10px;
text-align: center;
}
.form-wizard .form-wizard-next-btn:hover,
.form-wizard .form-wizard-next-btn:focus,
.form-wizard .form-wizard-previous-btn:hover,
.form-wizard .form-wizard-previous-btn:focus,
.form-wizard .form-wizard-submit:hover,
.form-wizard .form-wizard-submit:focus {
color: #ffffff;
opacity: 0.6;
text-decoration: none;
}
.form-wizard .wizard-fieldset {
display: none;
}
.form-wizard .wizard-fieldset.show {
display: block;
}
.form-wizard .wizard-form-error {
display: none;
background-color: #d70b0b;
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 2px;
width: 100%;
}
.form-wizard .form-wizard-previous-btn {
background-color: #fb1647;
}
.form-wizard .form-control {
font-weight: 300;
height: auto !important;
padding: 15px;
color: #888888;
background-color: #f1f1f1;
border: none;
}
.form-wizard .form-control:focus {
box-shadow: none;
}
.form-wizard .form-group {
position: relative;
margin: 25px 0;
}
.form-wizard .wizard-form-text-label {
position: absolute;
left: 10px;
top: 16px;
transition: 0.2s linear all;
}
.form-wizard .focus-input .wizard-form-text-label {
color: #d65470;
top: -18px;
transition: 0.2s linear all;
font-size: 12px;
}
.form-wizard .form-wizard-steps {
margin: 30px 0;
}
.form-wizard .form-wizard-steps li {
width: 33%;
float: left;
position: relative;
}
.form-wizard .form-wizard-steps li::after {
background-color: #f3f3f3;
content: "";
height: 5px;
left: 0;
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 100%;
border-bottom: 1px solid #dddddd;
border-top: 1px solid #dddddd;
}
.form-wizard .form-wizard-steps li span {
background-color: #dddddd;
border-radius: 50%;
display: inline-block;
height: 40px;
line-height: 40px;
position: relative;
text-align: center;
width: 40px;
z-index: 1;
}
.form-wizard .form-wizard-steps li:last-child::after {
width: 50%;
}
.form-wizard .form-wizard-steps li.active span,
.form-wizard .form-wizard-steps li.activated span {
background-color: #d65470;
color: #ffffff;
}
.form-wizard .form-wizard-steps li.active::after,
.form-wizard .form-wizard-steps li.activated::after {
background-color: #d65470;
left: 50%;
width: 50%;
border-color: #d65470;
}
.form-wizard .form-wizard-steps li.activated::after {
width: 100%;
border-color: #d65470;
}
.form-wizard .form-wizard-steps li:last-child::after {
left: 0;
}
.form-wizard .wizard-password-eye {
position: absolute;
right: 32px;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
}
@keyframes click-radio-wave {
0% {
width: 25px;
height: 25px;
opacity: 0.35;
position: relative;
}
100% {
width: 60px;
height: 60px;
margin-left: -15px;
margin-top: -15px;
opacity: 0;
}
}
@media screen and (max-width: 767px) {
.wizard-content-left {
height: auto;
}
}
6 changes: 3 additions & 3 deletions src/db/courseDB.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@ const courseSchema = new mongoose.Schema({
maxLength: 30,
},
longDescription: {
name: String,
values: mongoose.Schema.Types.Mixed,
type: mongoose.Schema.Types.Map, // [Issue: #26][Fix] | Should contain type instead of values
of: mongoose.Schema.Types.Mixed,
},
duration: {
type: Number,
required: true,
},
durationType: {
type: String,
enum: ["hours", "minutes", "seconds"],
enum: ["years", "months", "days", "hours", "minutes", "seconds"],
},
difficulty: {
type: String,
Expand Down
Empty file added src/js/coures-create.js
Empty file.
Loading

0 comments on commit 5b5e95b

Please sign in to comment.