diff --git a/app.js b/app.js
index 2d03586..ed41050 100644
--- a/app.js
+++ b/app.js
@@ -1,9 +1,9 @@
var createError = require("http-errors");
var express = require("express");
-var path = require("path");
+var path = require("path"); //The node:path module provides utilities for working with file and directory paths
var cookieParser = require("cookie-parser");
var logger = require("morgan");
-var expressLayouts = require("express-ejs-layouts");
+var expressLayouts = require("express-ejs-layouts"); //Layout support for ejs in express
var indexRouter = require("./routes/index");
var protectedRouter = require("./routes/protected");
var sessionAuth = require("./middlewares/sessionAuth");
@@ -12,11 +12,6 @@ var apiauth = require("./middlewares/apiauth");
var session = require("express-session");
var app = express();
-var bodyParser = require("body-parser");
-
-app.use(bodyParser.json());
-// for parsing application/xwww-
-app.use(bodyParser.urlencoded({ extended: true }));
var config = require("config");
app.use(
session({
@@ -29,20 +24,30 @@ app.use(
// const { startCronJobs } = require("./croneJobs/index");
// view engine setup
app.set("views", path.join(__dirname, "views"));
-app.set("view engine", "ejs");
-app.use(expressLayouts);
+app.set("view engine", "ejs"); //tells express that we are using ejs as rendering engine
+//view engine is responsible for rendering dynamic content on the server side
+app.use(expressLayouts); //add express layouts middleware
app.use(logger("dev"));
app.use(express.json());
-app.use(express.urlencoded({ extended: false }));
+app.use(express.urlencoded({ extended: false })); //is a middleware function that is used to parse incoming requests with urlencoded payloads e.g. form submissions
app.use(cookieParser());
app.use(express.static(path.join(__dirname, "public")));
+// his middleware is used to serve static files, such as images, CSS files, and JavaScript files, directly from a specified directory.
+
app.use("/api/public/products", require("./routes/api/public/products"));
app.use("/api/categories", require("./routes/api/catagories"));
app.use("/api/products", apiauth, require("./routes/api/products"));
+app.use("/api/calculator", require("./routes/api/calculator"));
app.use("/api/auth", require("./routes/api/auth"));
-app.use("/", sessionAuth, indexRouter);
-app.use("/my-account", sessionAuth, checkSessionAuth, protectedRouter);
-app.use("/", sessionAuth, require("./routes/shop"));
+app.use(sessionAuth); // add a middleware which should run on all server side rendering routes
+app.use("/calculator", require("./routes/calculator")); //add a calculator router on all methods with /calculator prefix
+app.use(
+ "/cookies-session-example",
+ require("./routes/cookies-session-example")
+); //add a calculator router on all methods with /calculator prefix
+app.use("/", indexRouter);
+app.use("/my-account", checkSessionAuth, protectedRouter);
+app.use("/", require("./routes/shop"));
app.get("/admin", async (req, res) => {
res.sendFile(path.join(__dirname, "admin", "build", "index.html"));
});
diff --git a/middlewares/sessionAuth.js b/middlewares/sessionAuth.js
index 8640487..141a0d9 100644
--- a/middlewares/sessionAuth.js
+++ b/middlewares/sessionAuth.js
@@ -1,5 +1,8 @@
-//sets user variable for pug files
+//sets user variable for ejs files
+let Category = require("../models/Category");
async function sessionAuth(req, res, next) {
+ let allCategories = await Category.find();
+ res.locals.allCategories = allCategories;
res.locals.user = req.session.user;
res.locals.isAdmin = false;
if (req.session.user) {
diff --git a/models/CalculatorOperation.js b/models/CalculatorOperation.js
new file mode 100644
index 0000000..8930804
--- /dev/null
+++ b/models/CalculatorOperation.js
@@ -0,0 +1,53 @@
+const mongoose = require("mongoose");
+const calculatorOperationSchema = mongoose.Schema(
+ {
+ operand1: String,
+ operand2: String,
+ operation: String,
+ result: String,
+ description: String,
+ },
+ { timestamps: true, toJSON: { virtuals: true } }
+);
+// The pre-save middleware is executed before a document is saved to the MongoDB database.
+//This is useful for performing tasks or modifications to the document just before it gets persisted to the database.
+calculatorOperationSchema.pre("save", function (next) {
+ this.description =
+ `You performed ` +
+ this.operation +
+ " on " +
+ this.operand1 +
+ " and " +
+ this.operand2;
+ next();
+});
+// a virtual is a property that is not stored in the MongoDB document itself but is computed or derived from other properties.
+//Virtuals are typically used for computed properties or for formatting data in a specific way without persisting it in the database.
+calculatorOperationSchema.virtual("virtual_result").get(function () {
+ switch (this.operation) {
+ case "+":
+ return (
+ this.operand1 +
+ this.operation +
+ this.operand2 +
+ "=" +
+ Number(Number(this.operand1) + Number(this.operand2))
+ );
+ case "-":
+ return (
+ this.operand1 +
+ this.operation +
+ this.operand2 +
+ "=" +
+ Number(Number(this.operand1) - Number(this.operand2))
+ );
+
+ default:
+ return 0;
+ }
+});
+const CalculatorOperation = mongoose.model(
+ "CalculatorOperation",
+ calculatorOperationSchema
+);
+module.exports = CalculatorOperation;
diff --git a/models/Product.js b/models/Product.js
index f3f53b5..49945ad 100644
--- a/models/Product.js
+++ b/models/Product.js
@@ -6,6 +6,7 @@ const productSchema = mongoose.Schema({
department: String,
description: String,
image: String,
+ category: { type: mongoose.Types.ObjectId, ref: "Category" },
});
const Product = mongoose.model("Product", productSchema);
module.exports = Product;
diff --git a/public/js/calculator.js b/public/js/calculator.js
new file mode 100644
index 0000000..26bcaa5
--- /dev/null
+++ b/public/js/calculator.js
@@ -0,0 +1,79 @@
+console.log("From Calculator");
+
+$(function () {
+ //this function will be executed after page load
+ $("#calculatorPostFormAjax").on("submit", handleFormSubmit);
+ // $("#calculationResultsTbl .btn-warning").on("click", deleteBtnClicked); // default binding
+ $(document).on(
+ "click",
+ "#calculationResultsTbl .btn-warning",
+ deleteBtnClicked
+ ); // event delegation countered
+ $("#deleteAllBtn").on("click", function (e) {
+ e.preventDefault();
+ $.ajax({
+ url: "/api/calculator/delete-all",
+ method: "post",
+ success: function () {
+ $("#calculationResultsTbl tbody").empty();
+ },
+ });
+ });
+});
+
+function handleFormSubmit(e) {
+ console.log(e);
+ e.preventDefault(); //stop form submission
+ let data = {
+ operand1: $("#operand1").val(),
+ operand2: $("#operand2").val(),
+ operation: $("#operation").val(),
+ };
+
+ // initiate ajax call
+ $.ajax({
+ url: "/api/calculator",
+ method: "post",
+ data,
+ success: function (res) {
+ //function to be executed after successful ajax call
+ console.log(res);
+ $("#calculationResultsTbl tbody").append(`
+ Del
+ ${res.operand1}
+ ${res.operation}
+ ${res.operand2}
+ ${res.result}
+ ${res.description}
+ ${res.virtual_result}
+ `);
+ // $("#calculationResultsTbl .btn-warning").on("click", deleteBtnClicked);
+ // above line is required as new table rows are not binded by default
+ // this is not a good way to do that
+ },
+ error: function (err) {
+ //function to be executed after ajax call failure
+ console.log(err);
+ },
+ });
+ console.log(data);
+}
+
+function deleteBtnClicked(e) {
+ // alert("del btn clicked");
+ let id = $(this).attr("data-id");
+ let tr = $(this).closest("tr");
+ $.ajax({
+ url: `/api/calculator/${id}`,
+ method: "delete",
+ success: function (res) {
+ tr.remove();
+ },
+ error: function (err) {
+ //function to be executed after ajax call failure
+ console.log(err);
+ },
+ });
+
+ e.preventDefault();
+}
diff --git a/routes/api/calculator.js b/routes/api/calculator.js
new file mode 100644
index 0000000..bbe1384
--- /dev/null
+++ b/routes/api/calculator.js
@@ -0,0 +1,30 @@
+var express = require("express");
+var router = express.Router();
+var CalculatorOperation = require("../../models/CalculatorOperation");
+router.post("/delete-all", async (req, res) => {
+ let record = await CalculatorOperation.deleteMany({});
+ return res.send("Records Deleted");
+});
+router.post("/", async (req, res) => {
+ let data = req.body;
+ data.result = 0;
+ switch (req.body.operation) {
+ case "+":
+ data.result = Number(req.body.operand1) + Number(req.body.operand2);
+ break;
+ case "-":
+ data.result = Number(req.body.operand1) - Number(req.body.operand2);
+ break;
+
+ default:
+ break;
+ }
+ let calculatorOp = new CalculatorOperation(data);
+ await calculatorOp.save();
+ return res.send(calculatorOp);
+});
+router.delete("/:id", async (req, res) => {
+ let record = await CalculatorOperation.findByIdAndDelete(req.params.id);
+ return res.send("Record Deleted");
+});
+module.exports = router;
diff --git a/routes/calculator.js b/routes/calculator.js
new file mode 100644
index 0000000..f3590d4
--- /dev/null
+++ b/routes/calculator.js
@@ -0,0 +1,47 @@
+const express = require("express");
+const CalculatorOperation = require("../models/CalculatorOperation");
+let router = express.Router();
+router.get("/ajax-example", async (req, res) => {
+ console.log("get method /calculator");
+ let results = await CalculatorOperation.find();
+ // return res.send(results);
+ return res.render("calculator/calculator-example-ajax", { results });
+});
+router.get("/delete-all", async (req, res) => {
+ await CalculatorOperation.deleteMany({});
+ return res.redirect("/calculator");
+});
+router.get("/delete/:id", async (req, res) => {
+ await CalculatorOperation.findByIdAndDelete(req.params.id);
+ return res.redirect("/calculator");
+});
+
+router.get("/", async (req, res) => {
+ console.log("get method /calculator");
+ let results = await CalculatorOperation.find();
+ // return res.send(results);
+ return res.render("calculator/calculator-example", { results });
+});
+router.post("/", async (req, res) => {
+ // return res.send(req.body);
+ console.log("post /calculator");
+ let data = req.body;
+ data.result = 0;
+ switch (req.body.operation) {
+ case "+":
+ data.result = Number(req.body.operand1) + Number(req.body.operand2);
+ break;
+ case "-":
+ data.result = Number(req.body.operand1) - Number(req.body.operand2);
+ break;
+
+ default:
+ break;
+ }
+ let calculatorOp = new CalculatorOperation(data);
+ await calculatorOp.save();
+ // return res.send(data); // we do not send data from server side form submissions
+ // return res.render("calculator/calculator-example"); //we do not render responses in form submissions either
+ return res.redirect("/calculator");
+});
+module.exports = router;
diff --git a/routes/cookies-session-example.js b/routes/cookies-session-example.js
new file mode 100644
index 0000000..b341a08
--- /dev/null
+++ b/routes/cookies-session-example.js
@@ -0,0 +1,21 @@
+const express = require("express");
+let router = express.Router();
+router.get("/cookies", (req, res) => {
+ // return res.send(req.cookies);
+ let city = req.cookies.city;
+ return res.render("cookies-session-example/cookies", { city });
+});
+router.post("/cookies", (req, res) => {
+ res.cookie("city", req.body.city);
+ res.redirect("/cookies-session-example/cookies");
+});
+router.get("/session", (req, res) => {
+ // return res.send(req.cookies);
+ let university = req.session.university;
+ return res.render("cookies-session-example/session", { university });
+});
+router.post("/session", (req, res) => {
+ req.session.university = req.body.university;
+ res.redirect("/cookies-session-example/session");
+});
+module.exports = router;
diff --git a/routes/shop.js b/routes/shop.js
index 27262c5..0104234 100644
--- a/routes/shop.js
+++ b/routes/shop.js
@@ -1,6 +1,7 @@
var express = require("express");
var router = express.Router();
var Product = require("../models/Product");
+var Category = require("../models/Category");
router.get("/cart", async function (req, res, next) {
let cart = req.cookies.cart;
if (!cart) cart = [];
@@ -21,8 +22,9 @@ router.get("/add-cart/:id", function (req, res, next) {
req.flash("success", "Product Added To Cart");
res.redirect("/");
});
-
-router.get("/:page?", async function (req, res, next) {
+router.get("/collections/:slug/:page?", async function (req, res, next) {
+ let category = await Category.findOne({ slug: req.params.slug });
+ if (!category) return next();
let page = Number(req.params.page);
let pageSize = 10;
let skip = (page - 1) * pageSize;
@@ -30,27 +32,38 @@ router.get("/:page?", async function (req, res, next) {
if (!skip) skip = 0;
// return res.send({ page, pageSize, skip });
- let products = await Product.find().skip(skip).limit(pageSize);
- let totalProducts = await Product.countDocuments();
+ let products = await Product.find({ category: category._id })
+ .skip(skip)
+ .limit(pageSize);
+ let totalProducts = await Product.countDocuments({ category: category._id });
let totalPages = Math.ceil(totalProducts / pageSize);
- return res.render("site/homepage", {
+
+ return res.render("site/category", {
pagetitle: "Awesome Products",
products,
page,
pageSize,
totalPages,
+ category,
});
});
-
-router.get("/:Catagory?", async function (req, res, next) {
- let Catagory = Number(req.params.page);
- let Catagoies_items = [shirts, pants, begs, trousels, dresses];
+router.get("/:page?", async function (req, res, next) {
+ let page = Number(req.params.page);
+ let pageSize = 10;
+ let skip = (page - 1) * pageSize;
+ if (!page) page = 1;
+ if (!skip) skip = 0;
// return res.send({ page, pageSize, skip });
+ let products = await Product.find().skip(skip).limit(pageSize);
+ let totalProducts = await Product.countDocuments();
+ let totalPages = Math.ceil(totalProducts / pageSize);
return res.render("site/homepage", {
- pagetitle: "All Catagories",
- Catagory,
- Catagoies_items,
+ pagetitle: "Awesome Products",
+ products,
+ page,
+ pageSize,
+ totalPages,
});
});
diff --git a/views/calculator/calculator-example-ajax.ejs b/views/calculator/calculator-example-ajax.ejs
new file mode 100644
index 0000000..5807ec9
--- /dev/null
+++ b/views/calculator/calculator-example-ajax.ejs
@@ -0,0 +1,53 @@
+
+Calculator Example
+This page demonstrates how a simple form submission is done in express
+
+
+
+
+Delete All Records
+
+
+
+
+ Operand 1
+ Operation
+ Operand 2
+ Result
+ Description
+ Virtual Result
+
+
+
+ <% results.forEach(element => { %>
+
+ Del
+ <%= element.operand1 %>
+ <%= element.operation %>
+ <%= element.operand2 %>
+ <%= element.result %>
+ <%= element.description %>
+ <%= element.virtual_result %>
+
+ <% }) %>
+
+
\ No newline at end of file
diff --git a/views/calculator/calculator-example.ejs b/views/calculator/calculator-example.ejs
new file mode 100644
index 0000000..9c0574b
--- /dev/null
+++ b/views/calculator/calculator-example.ejs
@@ -0,0 +1,53 @@
+
+Calculator Example
+This page demonstrates how a simple form submission is done in express
+
+
+
+
+Delete All Records
+
+
+
+
+ Operand 1
+ Operation
+ Operand 2
+ Result
+ Description
+ Virtual Result
+
+
+
+ <% results.forEach(element => { %>
+
+ Del
+ <%= element.operand1 %>
+ <%= element.operation %>
+ <%= element.operand2 %>
+ <%= element.result %>
+ <%= element.description %>
+ <%= element.virtual_result %>
+
+ <% }) %>
+
+
\ No newline at end of file
diff --git a/views/cookies-session-example/cookies.ejs b/views/cookies-session-example/cookies.ejs
new file mode 100644
index 0000000..e26e243
--- /dev/null
+++ b/views/cookies-session-example/cookies.ejs
@@ -0,0 +1,21 @@
+Cookies
+Cookies are small pieces of data that a web server sends to a user's browser and are stored on the user's device. They are typically used to store information about the user or their interactions with a website. Cookies serve various purposes, and they play a crucial role in web development.
+In this example we will demonstrate how a cookie named city will be used
+
+
+<% if (city) { %>
+
+ Cookie City has value <%= city %>
+
+<% } else { %>
+
+ Cookie City is not set
+
+<% } %>
\ No newline at end of file
diff --git a/views/cookies-session-example/session.ejs b/views/cookies-session-example/session.ejs
new file mode 100644
index 0000000..6027cec
--- /dev/null
+++ b/views/cookies-session-example/session.ejs
@@ -0,0 +1,20 @@
+Session
+A "session" in web development refers to a series of interactions or requests that occur between a user and a website within a specific timeframe. Sessions are used to maintain state and information about a user across multiple requests. This is crucial for scenarios like user authentication, where a user logs in once and their session is maintained throughout their interaction with the web application.
+
+
+<% if (university) { %>
+
+ Session university has value <%= university %>
+
+<% } else { %>
+
+ Session university is not set
+
+<% } %>
\ No newline at end of file
diff --git a/views/layout.ejs b/views/layout.ejs
index a08707c..9576f69 100644
--- a/views/layout.ejs
+++ b/views/layout.ejs
@@ -21,10 +21,12 @@
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"
>
+
- <%-include("./layouts/partials/header") %> <% if(typeof(flash)!="undefined")
+ <%-include("./layouts/partials/header") %>
+ <% if(typeof(flash)!="undefined")
{%>
<%= flash.message %>
diff --git a/views/layouts/partials/header.ejs b/views/layouts/partials/header.ejs
index 0fc1f87..05110b3 100644
--- a/views/layouts/partials/header.ejs
+++ b/views/layouts/partials/header.ejs
@@ -17,6 +17,32 @@
Home
+
+
+ Examples
+
+
+
+
+
+
+
+
+ Collections
+
+
+
Contact Us
diff --git a/views/site/category.ejs b/views/site/category.ejs
new file mode 100644
index 0000000..f5447bc
--- /dev/null
+++ b/views/site/category.ejs
@@ -0,0 +1,51 @@
+<%= category.name %>
+
+
+
+
+ All Catagories
+
+
+ Showing page <%= page %> of <%= totalPages %>
+ <% for(var i=0;i
+
+
<%=products[i].name %>
+
+
+ <%=products[i].description %>
+
+
+
+
Add To Cart
+
+ Price
+ <%=products[i].price %>
+ Color
+ <%=products[i].color %>
+ Department
+ <%=products[i].department %>
+
+
+
+ <% } %>
+
+
+
\ No newline at end of file
diff --git a/views/site/homepage.ejs b/views/site/homepage.ejs
index 99b6fcc..2290203 100644
--- a/views/site/homepage.ejs
+++ b/views/site/homepage.ejs
@@ -14,8 +14,8 @@
All Catagories
- <%= Catagory %>
- <%= Catagoies_items%>
+
+
Showing page <%= page %> of <%= totalPages %>
<% for(var i=0;i