diff --git a/.gitignore b/.gitignore
index 4f9be4d..7734288 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,9 @@
# Environment variables
.env
+#vscode files
+.vscode
+
# Node modules
node_modules/
diff --git a/app.js b/app.js
index b976e9a..ff449a4 100644
--- a/app.js
+++ b/app.js
@@ -3,6 +3,7 @@ const MongoStore = require("connect-mongo");
const session = require("express-session");
const express = require('express');
const path = require('path');
+const bcrypt = require('bcrypt');
const joi = require('joi');
require('dotenv').config();
@@ -11,7 +12,7 @@ const port = process.env.PORT || 3000;
const mongoURI = process.env.MONGO_URI;
const database = process.env.DATABASE; // Database name
-const secret = process.env.SECRET || "123-secret-xyz";
+const secret = process.env.SECRET || "123-secret-xyz";
/*** Sessions ***/
app.use(session({
@@ -37,11 +38,11 @@ let assets;
let plans;
async function initDatabase() {
const db = await connectMongo(mongoURI, database);
-
+
// For any collection, init here
- users = await getCollection(db, "users");
+ users = await getCollection(db, "users");
assets = await getCollection(db, "assets");
- plans = await getCollection(db, "plans");
+ plans = await getCollection(db, "plans");
}
/*** ROUTINGS ***/
@@ -73,6 +74,96 @@ app.get('/aboutUs', (req, res) => {
return res.status(status.Ok);
});
+app.get('/forgotPassword', (req, res) => {
+ const error = req.session.error;
+ const reset = req.session.reset;
+ req.session.reset = '';
+ req.session.error = '';
+ res.render('forgotPass', { error: error, reset: reset });
+ return res.status(status.Ok);
+});
+
+
+// Reset with token given to user via email
+app.get('/reset/:token', async (req, res) => {
+ const token = req.params.token;
+
+ const user = await users.findOne({
+ resetToken: token,
+ resetTokenExpires: { $gt: Date.now() },
+ });
+
+ if (!user) {
+ req.session.error = 'reset link not valid or has expired';
+ return res.redirect('/forgotPassword');
+ }
+ const error = req.session.error;
+ delete req.session.error;
+
+ res.render('resetPass', {
+ token: token,
+ errMessage: error,
+ });
+});
+
+app.post('/resetLink', async (req, res) => {
+ const { token, password, confirmPassword, } = req.body;
+ const passwordSchema = joi.object({
+ password: joi.string().max(20).required(),
+ confirmPassword: joi.string().max(20).required(),
+ });
+ const valid = passwordSchema.validate({ password, confirmPassword });
+ if (valid.error) {
+ console.log("houston we have a problem");
+ req.session.error = 'Invalid input';
+ res.status(status.BadRequest);
+ return res.redirect(`/reset/${token}`);
+ }
+ if (!token || !password || !confirmPassword) {
+ req.session.error = 'field may be missing';
+ return res.redirect(`/reset/${token}`);
+ }
+ if (password !== confirmPassword) {
+ req.session.error = 'passwords do not match';
+ return res.redirect(`/reset/${token}`);
+ }
+ const user = await users.findOne({
+ resetToken: token,
+ resetTokenExpires: { $gt: Date.now() },
+ });
+
+ if (!user) {
+ req.session.error = 'Reset link is invalid.';
+ return res.redirect(`/reset`);
+ }
+ const hashPassword = await bcrypt.hash(password, 12);
+
+ await users.updateOne(
+ {
+ email: user.email
+ },
+ {
+ $set: {
+ password: hashPassword,
+ resetToken: '',
+ resetTokenExpires: 0,
+ },
+ }
+ );
+ req.session.success = 'Password has been reset';
+ res.redirect('/login');
+});
+
+app.post('/api/location', async (req, res) => {
+ const { latitude, longitude } = req.body;
+
+ const response = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${latitude},${longitude}&result_type=country&key=${process.env.geolocation_api}`);
+
+ const data = await response.json();
+
+ res.json(data);
+});
+
// 404 handler - keep the actual notFound route please
// REALLY DONT DELETE THIS
app.get('/notFound', (req, res) => {
@@ -86,7 +177,9 @@ initDatabase().then(() => {
// Import authentication handler
app.use(require("./src/auth/authentication")(users));
-
+ app.use(require('./src/auth/forgotPass')(users));
+
+
// Import middleware & apply to user routes
const middleware = require("./src/auth/middleware")(users);
app.use(require('./src/router/user')(middleware, users, plans, assets));
@@ -96,7 +189,7 @@ initDatabase().then(() => {
res.render('notFound');
return res.status(status.NotFound);
});
-
+
// Start app
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
diff --git a/package-lock.json b/package-lock.json
index 95750e3..521a7be 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,12 +11,14 @@
"dependencies": {
"bcrypt": "^5.1.1",
"connect-mongo": "^5.1.0",
+ "crypto": "^1.0.1",
"dotenv": "^16.5.0",
"ejs": "^3.1.10",
"express": "^5.1.0",
"express-session": "^1.18.1",
"joi": "^17.13.3",
- "mongodb": "^6.16.0"
+ "mongodb": "^6.16.0",
+ "nodemailer": "^7.0.3"
},
"devDependencies": {
"nodemon": "^3.1.10"
@@ -483,6 +485,12 @@
"node": ">=6.6.0"
}
},
+ "node_modules/crypto": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz",
+ "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==",
+ "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in."
+ },
"node_modules/debug": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
@@ -1430,6 +1438,14 @@
"webidl-conversions": "^3.0.0"
}
},
+ "node_modules/nodemailer": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.3.tgz",
+ "integrity": "sha512-Ajq6Sz1x7cIK3pN6KesGTah+1gnwMnx5gKl3piQlQQE/PwyJ4Mbc8is2psWYxK3RJTVeqsDaCv8ZzXLCDHMTZw==",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/nodemon": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz",
diff --git a/package.json b/package.json
index 4f1048f..1071779 100755
--- a/package.json
+++ b/package.json
@@ -20,12 +20,14 @@
"dependencies": {
"bcrypt": "^5.1.1",
"connect-mongo": "^5.1.0",
+ "crypto": "^1.0.1",
"dotenv": "^16.5.0",
"ejs": "^3.1.10",
"express": "^5.1.0",
"express-session": "^1.18.1",
"joi": "^17.13.3",
- "mongodb": "^6.16.0"
+ "mongodb": "^6.16.0",
+ "nodemailer": "^7.0.3"
},
"devDependencies": {
"nodemon": "^3.1.10"
diff --git a/src/auth/forgotPass.js b/src/auth/forgotPass.js
new file mode 100644
index 0000000..62260bf
--- /dev/null
+++ b/src/auth/forgotPass.js
@@ -0,0 +1,68 @@
+const express = require('express');
+const crypto = require('crypto');
+const joi = require('joi');
+const nodeMail = require('nodemailer');
+require('dotenv').config();
+
+const transporter = nodeMail.createTransport({
+ service: 'gmail',
+ auth: {
+ user: process.env.EMAIL_USER,
+ pass: process.env.PASS,
+ }
+});
+// users info
+module.exports = (users) => {
+ const router = express.Router();
+
+ router.post('/auth/resetPass', async (req, res) => {
+ console.log("we are inside of the post");
+ const resetSchema = joi.object({
+ email: joi.string().email().required(),
+ });
+ req.session.error = '';
+ req.session.reset = '';
+
+ const valid = resetSchema.validate(req.body);
+ if (valid.error) {
+ req.session.error = 'invalid email';
+ return res.redirect('/forgotPassword')
+ }
+ const { email } = req.body;
+ const user = await users.findOne({ email });
+
+ if (!user) {
+ req.session.error = 'No user found'
+ return res.redirect('/forgotPassword');
+ }
+
+ const token = crypto.randomBytes(32).toString('hex');
+ console.log(`The reset token is ${token}`)
+ const expiration = Date.now() + 360000;
+
+ await users.updateOne({ email }, {
+ $set: { resetToken: token, resetTokenExpires: expiration }
+ });
+
+ const resetUrl = `http://localhost:3000/reset/${token}`;
+
+ const mailSend = {
+ from: process.env.EMAIL_USER,
+ to: email,
+ subject: 'Password reset',
+ text: `reset your password here ${resetUrl} this link will expire within 1 hour`,
+
+ };
+
+ try {
+ await transporter.sendMail(mailSend);
+ req.session.reset = 'Reset link sent Check your email';
+ res.redirect('/forgotPassword');
+ } catch (err) {
+ console.log('there was an error', err);
+ res.status(500).send('email failed to send try again');
+ }
+ });
+ return router;
+}
+
diff --git a/src/router/user.js b/src/router/user.js
index 8816990..c8f67f6 100644
--- a/src/router/user.js
+++ b/src/router/user.js
@@ -86,7 +86,7 @@ module.exports = (middleware, users, plans, assets) => {
router.get('/assets', async (req, res) => {
let userAssets = await assets.find({ userId: new ObjectId(req.session.user._id) }).toArray();
- res.render('assets', {
+ res.render('assets', {
user: req.session.user,
errMessage: req.session.errMessage,
assets: userAssets,
@@ -98,14 +98,14 @@ module.exports = (middleware, users, plans, assets) => {
router.get('/plans', async (req, res) => {
try {
- const userPlansFromDB = await plans.find({userId: new ObjectId(req.session.user._id) }).toArray();
-
+ const userPlansFromDB = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray();
+
// Use a for...of loop for proper async/await behavior in series for updates
for (const plan of userPlansFromDB) {
const percentage = await calculatePlanProgress(plan, assets, req.session.user._id);
await updatePlanProgressInDB(plan._id, percentage, plans); // Pass the 'plans' collection
}
-
+
// Re-fetch plans to get updated progress for rendering
const updatedUserPlans = await plans.find({ userId: new ObjectId(req.session.user._id) }).toArray();
@@ -122,12 +122,12 @@ module.exports = (middleware, users, plans, assets) => {
});
router.get('/plans/:id', async (req, res) => {
-
+
try {
const planId = req.params.id;
let userAssets = await assets.find({ userId: new ObjectId(req.session.user._id) }).toArray();
-
-
+
+
if (!ObjectId.isValid(planId)) {
req.session.errMessage = "Invalid plan ID format.";
return res.status(status.BadRequest).redirect('/plans');
@@ -140,7 +140,7 @@ module.exports = (middleware, users, plans, assets) => {
req.session.errMessage = "Plan not found or you do not have permission to view it.";
return res.status(status.NotFound).redirect('/plans');
}
-
+
// The plan.progress should be up-to-date from the database as it was updated in the /plans route
// or when assets/plans are modified. If an immediate recalculation for this specific view is absolutely needed,
// (e.g., if assets were modified without an immediate plan progress update elsewhere),
@@ -148,13 +148,13 @@ module.exports = (middleware, users, plans, assets) => {
// const currentProgress = await calculatePlanProgress(plan, assets, req.session.user._id);
// plan.progress = currentProgress; // This would only update the 'plan' object for this render, not in DB
- res.render('planDetail', {
+ res.render('planDetail', {
user: req.session.user,
plan: plan, // This plan object will have the progress from the database
geoData: req.session.geoData,
assets: userAssets,
});
-
+
} catch (err) {
console.error("Error fetching plan:", err);
req.session.errMessage = "Could not load your plan. Please try again.";
@@ -163,13 +163,13 @@ module.exports = (middleware, users, plans, assets) => {
});
router.get('/newPlan', (req, res) => {
- if(!req.session.user.financialData){
+ if (!req.session.user.financialData) {
req.session.errMessage = "Please complete your financial data before creating a plan.";
return res.status(status.Unauthorized).redirect('/questionnaire');
}
const errMessage = req.session.errMessage;
- req.session.errMessage = "";
- res.render('newPlan', {
+ req.session.errMessage = "";
+ res.render('newPlan', {
user: req.session.user,
errMessage: errMessage,
geoData: req.session.geoData
@@ -185,14 +185,14 @@ module.exports = (middleware, users, plans, assets) => {
retirementLiabilities: joi.number().min(0).required(),
});
- const validationOptions = { convert: true, abortEarly: false };
+ const validationOptions = { convert: true, abortEarly: false };
const { error, value } = planSchema.validate(req.body, validationOptions);
- if (error) {
+ if (error) {
console.error("Plan validation error:", error.details);
- req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', ');
- res.status(status.BadRequest).redirect("/newPlan");
- return;
+ req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', ');
+ res.status(status.BadRequest).redirect("/newPlan");
+ return;
}
const newPlan = {
userId: new ObjectId(req.session.user._id),
@@ -204,12 +204,12 @@ module.exports = (middleware, users, plans, assets) => {
progress: "0"
};
- try{
- await plans.insertOne({userId: new ObjectId(req.session.user._id), ...newPlan});
- req.session.errMessage = "";
- res.redirect('/plans');
+ try {
+ await plans.insertOne({ userId: new ObjectId(req.session.user._id), ...newPlan });
+ req.session.errMessage = "";
+ res.redirect('/plans');
}
- catch(err){
+ catch (err) {
console.error("Error saving plan:", err);
req.session.errMessage = "An error occurred while saving your plan. Please try again.";
res.status(status.InternalServerError).redirect("/newPlan");
@@ -217,7 +217,7 @@ module.exports = (middleware, users, plans, assets) => {
});
router.get('/more', (req, res) => {
- res.render('more', {
+ res.render('more', {
user: req.session.user,
geoData: req.session.geoData
});
@@ -225,7 +225,7 @@ module.exports = (middleware, users, plans, assets) => {
});
router.get('/profile', (req, res) => {
- res.render('profile', {
+ res.render('profile', {
user: req.session.user,
errMessage: req.session.errMessage,
geoData: req.session.geoData
@@ -234,7 +234,7 @@ module.exports = (middleware, users, plans, assets) => {
});
router.get('/settings', (req, res) => {
- res.render('settings', {
+ res.render('settings', {
user: req.session.user,
geoData: req.session.geoData
});
@@ -243,15 +243,15 @@ module.exports = (middleware, users, plans, assets) => {
router.get('/questionnaire', (req, res) => {
const errMessage = req.session.errMessage;
- req.session.errMessage = "";
- res.render('questionnaire', {
+ req.session.errMessage = "";
+ res.render('questionnaire', {
user: req.session.user,
errMessage: errMessage,
geoData: req.session.geoData
});
});
- router.post('/questionnaire', (req, res) => {
+ router.post('/questionnaire', (req, res) => {
const questionnaireSchema = joi.object({
dob: joi.date().required(),
education: joi.string().valid('primary', 'secondary', 'tertiary', 'postgraduate').required(),
@@ -261,22 +261,22 @@ module.exports = (middleware, users, plans, assets) => {
assets: joi.number().min(0).required(),
liabilities: joi.number().min(0).required(),
});
-
- const validationOptions = { convert: true, abortEarly: false };
+
+ const validationOptions = { convert: true, abortEarly: false };
const { error, value } = questionnaireSchema.validate(req.body, validationOptions);
-
- if (error) {
+
+ if (error) {
console.error("Questionnaire validation error:", error.details);
- req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', ');
- res.status(status.BadRequest).redirect("/questionnaire");
- return;
+ req.session.errMessage = "Invalid input: " + error.details.map(d => d.message.replace(/"/g, '')).join(', ');
+ res.status(status.BadRequest).redirect("/questionnaire");
+ return;
}
-
- users.updateOne(
- { _id: new ObjectId(req.session.user._id) },
- {
- $set: {
- financialData: true,
+
+ users.updateOne(
+ { _id: new ObjectId(req.session.user._id) },
+ {
+ $set: {
+ financialData: true,
dob: value.dob,
education: value.education,
maritalStatus: value.maritalStatus,
@@ -284,27 +284,27 @@ module.exports = (middleware, users, plans, assets) => {
expenses: value.expenses,
assets: value.assets,
liabilities: value.liabilities,
- }
+ }
}
- ).then((result) => {
+ ).then((result) => {
if (result.matchedCount === 0) {
console.log(`User not found during questionnaire update: ${req.session.user.email}`);
- req.session.errMessage = "User session invalid. Please log in again.";
- res.status(status.NotFound).redirect("/login");
+ req.session.errMessage = "User session invalid. Please log in again.";
+ res.status(status.NotFound).redirect("/login");
return;
}
if (result.modifiedCount === 0 && result.matchedCount === 1) {
console.log(`User questionnaire data unchanged (already up-to-date): ${req.session.user.email}`);
}
-
+
req.session.user.financialData = true;
- req.session.errMessage = "";
- res.status(status.Ok).redirect("/home");
-
- }).catch(err => {
+ req.session.errMessage = "";
+ res.status(status.Ok).redirect("/home");
+
+ }).catch(err => {
console.error("Error updating questionnaire in database:", err);
req.session.errMessage = "An error occurred while saving your information. Please try again.";
- res.status(status.InternalServerError).redirect("/questionnaire");
+ res.status(status.InternalServerError).redirect("/questionnaire");
});
});
@@ -320,7 +320,7 @@ module.exports = (middleware, users, plans, assets) => {
if (valid.err) {
req.session.errMessage = "Invalid input",
- res.status(status.BadRequest);
+ res.status(status.BadRequest);
return res.redirect("/profile");
}
@@ -343,20 +343,20 @@ module.exports = (middleware, users, plans, assets) => {
).then((result) => {
if (result.matchedCount === 0) {
console.log(`User not found during account update: ${req.session.email}`);
- req.session.errMessage = "User session invalid. Please log in again.";
- res.status(status.NotFound).redirect("/login");
+ req.session.errMessage = "User session invalid. Please log in again.";
+ res.status(status.NotFound).redirect("/login");
return;
}
if (result.modifiedCount === 0 && result.matchedCount === 1) {
console.log(`User account data unchanged (already up-to-date): ${req.session.email}`);
}
-
- req.session.errMessage = "";
- return res.status(status.Ok).redirect("/profile");
- }).catch(err => {
+
+ req.session.errMessage = "";
+ return res.status(status.Ok).redirect("/profile");
+ }).catch(err => {
console.error("Error updating account in database:", err);
req.session.errMessage = "An error occurred while saving your information. Please try again.";
- return res.status(status.InternalServerError).redirect("/profile");
+ return res.status(status.InternalServerError).redirect("/profile");
});
});
@@ -375,7 +375,7 @@ module.exports = (middleware, users, plans, assets) => {
if (valid.err) {
req.session.errMessage = "Invalid input",
- res.status(status.BadRequest);
+ res.status(status.BadRequest);
return res.redirect("/assets");
}
@@ -402,7 +402,7 @@ module.exports = (middleware, users, plans, assets) => {
}
});
- req.session.errMessage = "";
+ req.session.errMessage = "";
return res.status(status.Ok).redirect("/assets");
});
@@ -415,18 +415,18 @@ module.exports = (middleware, users, plans, assets) => {
req.session.errMessage = "Invalid input";
return res.status(status.BadRequest).redirect("/assets");
}
-
+
const valid = assetSchema.validate(req.body);
if (valid.err) {
req.session.errMessage = "Invalid input",
- res.status(status.BadRequest);
+ res.status(status.BadRequest);
return res.redirect("/assets");
}
if (req.body.userId != req.session.user._id) {
req.session.errMessage = "Cannot change asset owner",
- res.status(status.BadRequest);
+ res.status(status.BadRequest);
return res.redirect("/assets");
}
@@ -440,11 +440,11 @@ module.exports = (middleware, users, plans, assets) => {
update.value = parseFloat(update.value);
delete update.id;
delete update.userId;
-
+
assets.updateOne(
{ "_id": new ObjectId(req.body.id) },
{ $set: update },
- ).then((result) => {
+ ).then((result) => {
if (result.matchedCount === 0) {
console.log(`Asset not found: ${req.body.id}`);
req.session.errMessage = "Unable to update asset";
@@ -453,14 +453,14 @@ module.exports = (middleware, users, plans, assets) => {
if (result.modifiedCount === 0 && result.matchedCount === 1) {
console.log(`Asset data unchanged (already up-to-date): ${req.body.id}`);
}
-
- req.session.errMessage = "";
- return res.status(status.Ok).redirect("/assets");
-
- }).catch((err) => {
+
+ req.session.errMessage = "";
+ return res.status(status.Ok).redirect("/assets");
+
+ }).catch((err) => {
console.error("Error updating asset: ", err);
req.session.errMessage = "An error occurred while saving your information. Please try again.";
- return res.status(status.InternalServerError).redirect("/assets");
+ return res.status(status.InternalServerError).redirect("/assets");
});
});
@@ -469,7 +469,7 @@ module.exports = (middleware, users, plans, assets) => {
assets.deleteOne(
{ "_id": id }
- ).then((result) => {
+ ).then((result) => {
if (result.deletedCount === 0) {
console.error(`Asset not found: ${req.body.id}`);
req.session.errMessage = "Unable to delete asset. Please try again.";
@@ -481,11 +481,11 @@ module.exports = (middleware, users, plans, assets) => {
req.session.errMessage = "An error occurred while deleting an asset. Please try again.";
return res.status(status.InternalServerError).redirect("/assets");
}
-
- req.session.errMessage = "";
- return res.status(status.Ok).redirect("/assets");
-
- }).catch((err) => {
+
+ req.session.errMessage = "";
+ return res.status(status.Ok).redirect("/assets");
+
+ }).catch((err) => {
console.error("Error deleting asset: ", err);
req.session.errMessage = "An error occurred while deleting an asset. Please try again.";
return res.status(status.InternalServerError).redirect("/assets");
@@ -535,7 +535,7 @@ module.exports = (middleware, users, plans, assets) => {
if (!req.session.geoData.country) {
const response = await fetch(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${req.params.lat},${req.params.lon}&result_type=country&key=${process.env.GEOLOCATION_API}`);
const data = await response.json();
-
+
country = data.results[0].formatted_address;
let results = await getRates(country);
req.session.geoData = {
diff --git a/src/views/dashboard.ejs b/src/views/dashboard.ejs
index 519832d..d36b979 100644
--- a/src/views/dashboard.ejs
+++ b/src/views/dashboard.ejs
@@ -1,5 +1,5 @@
<%- include("./partials/fileHeader") %>
-<%- include("./partials/header") %>
+ <%- include("./partials/header") %>
@@ -22,74 +22,94 @@
class="block text-right antialiased tracking-normal font-sans text-2xl font-semibold leading-snug text-blue-gray-900">
$53k
-
-
- Make this percent bar or graph or something than lastweek
-
-
-
-
-
-
- Retirement goal
-
- $53k
-
-
-
- Make this percent bar or graph or something than last
- week
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Retirement goal
-
- $53k
-
-
-
- Make this percent bar or graph or something than last
- week
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+ Retirement goal
+
+ $53k
+
+
+
+ Make this percent bar or graph or something
+ than lastweek
+
+
+
+
+
+
+ Retirement goal
+
+ $53k
+
+
+
+ Make this percent bar or graph or something
+ than last
+ week
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Retirement goal
+
+ $53k
+
+
+
+ Make this percent bar or graph or something
+ than last
+ week
+
+
+
+
+
+
+
+
+
<%- include("./partials/navBar") %>
<%- include("./partials/scriptLoader") %>
-<%- include("./partials/footer") %>
\ No newline at end of file
+<%- include("./partials/footer") %>
diff --git a/src/views/forgotPass.ejs b/src/views/forgotPass.ejs
new file mode 100644
index 0000000..811c32d
--- /dev/null
+++ b/src/views/forgotPass.ejs
@@ -0,0 +1,38 @@
+<%- include("./partials/fileHeader") %>
+
+
+
+
+
+ <%- include("./partials/footer") %> <%- include("./partials/footer") %>
diff --git a/src/views/login.ejs b/src/views/login.ejs
index c8dbcbd..d35800f 100644
--- a/src/views/login.ejs
+++ b/src/views/login.ejs
@@ -25,7 +25,7 @@
@@ -41,4 +41,4 @@
-<%- include("./partials/footer") %>
\ No newline at end of file
+<%- include("./partials/footer") %>
diff --git a/src/views/resetPass.ejs b/src/views/resetPass.ejs
new file mode 100644
index 0000000..2673347
--- /dev/null
+++ b/src/views/resetPass.ejs
@@ -0,0 +1,36 @@
+<%- include("./partials/fileHeader") %>
+
+
+
+
+ <%- include("./partials/footer") %>
diff --git a/src/views/signup.ejs b/src/views/signup.ejs
index 7180cb5..840e839 100644
--- a/src/views/signup.ejs
+++ b/src/views/signup.ejs
@@ -1,46 +1,46 @@
<%- include("./partials/fileHeader") %>
-<%- include("./partials/headerStart") %>
+ <%- include("./partials/headerStart") %>
-
-
-
+
+