This commit is contained in:
SowinskiBraeden committed 2021-01-04 10:18:19 -08:00
1 parent 9163477534
commit 9fa4aa179a
12 files changed
+465 -57

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
# Port to start server on.
PORT=5000
# MongoDB connection URI.
DB_URI=mongodb://localhost/knoldus
+8 -1
View File
@@ -1 +1,8 @@
/test # Dependencies.
node_modules/*
# Tests folder.
test/*
# Enviroment variables
.env
+24 -1
View File
@@ -1,5 +1,28 @@
# XP-System # XP-System
School Project School Project
This school project is for my teacher to have students This school project is for my teacher to have students
log in and check out their XP and assignments. log in and check out their XP and assignments.
(Still not done)!
### Requirements :
1. [Node.js](https://nodejs.org/en/)
1. [MongoDB](https://docs.mongodb.com/manual/administration/install-community/)
### Getting Started with Code :
1. [Set Up MongoDB](#setting-up-mongodb) and start mongodb
2. Clone repo from https://github.com/Braeden57/XP-System.git
3. Run `npm install` to install dependencies.
4. Duplicate `.env.example` and rename the new file to `.env`. Edit to your configurations.
1. Run `npm start` to boot up server.
1. Go to http://localhost:5000.
### Setting up MongoDB
1. Install mongodb via brew. `brew install mongodb`
1. Start mongodb via brew. `brew services restart mongodb`
2. Or Install mongodb compass https://www.mongodb.com/try/download/compass
### Accessing the Database
1. Locally this will use the knoldus db (or whatever you specify manually)
1. launch mongo via your command-line: `mongo`
1. Use `show dbs` to see all that are available. You should see `knoldus` in the list.
1. Lets use that db: `use knoldus`.
+3 -2
View File
@@ -7,7 +7,8 @@ const session = require('express-session');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
var path = require('path'); var path = require('path');
var fs = require('fs'); var fs = require('fs');
require('dotenv/config'); var dotenv = require('dotenv');
dotenv.config();
const app = express(); const app = express();
@@ -20,7 +21,7 @@ const db = require('./config/keys').mongoURI;
// Connect to MongoDB // Connect to MongoDB
mongoose mongoose
.connect( .connect(
db, process.env.DB_URI || 'mongodb://localhost/knoldus',
{ useNewUrlParser: true, useUnifiedTopology: true} { useNewUrlParser: true, useUnifiedTopology: true}
) )
.then(() => console.log('MongoDB Connected')) .then(() => console.log('MongoDB Connected'))
+5 -1
View File
@@ -1,4 +1,8 @@
let dbPassword = 'mongodb+srv://client:backyardpassclient@backyard-pass-data.nbikf.mongodb.net/XPmockDB?retryWrites=true&w=majority'; const dotenv = require('dotenv');
// Load environment variables into process
dotenv.config()
let dbPassword = process.env.DB_URI;
module.exports = { module.exports = {
mongoURI: dbPassword mongoURI: dbPassword
+28
View File
@@ -0,0 +1,28 @@
const mongoose = require('mongoose');
const QuestSchema = new mongoose.Schema({
title: {
type: String,
required: true
},
campaign: {
type: String,
required: true
},
expiry: {
type: Date,
default: Date.now
},
xp: {
type: Number,
required: true
},
instruction: {
type: String,
required: true
}
});
const Quest = mongoose.model('Quest', QuestSchema);
module.exports = Quest;
+6 -6
View File
@@ -1,19 +1,19 @@
{ {
"_from": "dotenv", "_from": "dotenv@^8.2.0",
"_id": "dotenv@8.2.0", "_id": "dotenv@8.2.0",
"_inBundle": false, "_inBundle": false,
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", "_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
"_location": "/dotenv", "_location": "/dotenv",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"type": "tag", "type": "range",
"registry": true, "registry": true,
"raw": "dotenv", "raw": "dotenv@^8.2.0",
"name": "dotenv", "name": "dotenv",
"escapedName": "dotenv", "escapedName": "dotenv",
"rawSpec": "", "rawSpec": "^8.2.0",
"saveSpec": null, "saveSpec": null,
"fetchSpec": "latest" "fetchSpec": "^8.2.0"
}, },
"_requiredBy": [ "_requiredBy": [
"#USER", "#USER",
@@ -21,7 +21,7 @@
], ],
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", "_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a", "_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
"_spec": "dotenv", "_spec": "dotenv@^8.2.0",
"_where": "C:\\Users\\flami\\OneDrive\\Desktop\\Projects\\XP-System", "_where": "C:\\Users\\flami\\OneDrive\\Desktop\\Projects\\XP-System",
"bugs": { "bugs": {
"url": "https://github.com/motdotla/dotenv/issues" "url": "https://github.com/motdotla/dotenv/issues"
+12 -3
View File
@@ -1,17 +1,26 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { ensureAuthenticated, forwardAuthenticated } = require('../config/auth'); const { ensureAuthenticated, forwardAuthenticated } = require('../config/auth');
var UserModel = require('../models/User.js'); // DB Config
const db = require('../config/keys').mongoURI;
let MongoClient = require('mongodb').MongoClient;
let UserModal = require('../models/User.js');
let QuestModal = require('../models/Quest.js')
// Welcome Page // Welcome Page
router.get('/', forwardAuthenticated, (req, res) => res.render('welcome')); router.get('/', forwardAuthenticated, (req, res) => res.render('welcome'));
// Dashboard // Dashboard
router.get('/dashboard', ensureAuthenticated, function(req, res) { router.get('/dashboard', ensureAuthenticated, function(req, res) {
UserModel.find({}, function(err, data) { // Collects Quest Data
QuestModal.find({}, function(err, quests) {
// Collects User Data
UserModal.find({}, function(err, data) {
res.render('dashboard', { res.render('dashboard', {
user : req.user, user : req.user,
members: data members: data,
quests: quests
});
}); });
}); });
}); });
+57 -1
View File
@@ -5,6 +5,7 @@ const bcrypt = require('bcryptjs');
const passport = require('passport'); const passport = require('passport');
const MongoClient = require('mongodb').MongoClient; const MongoClient = require('mongodb').MongoClient;
const ObjectId = require('mongodb').ObjectId; const ObjectId = require('mongodb').ObjectId;
const Quest = require('../models/Quest');
// Load Profanity filter // Load Profanity filter
const Filter = require('bad-words'); const Filter = require('bad-words');
@@ -33,6 +34,15 @@ let storage = multer.diskStorage({
let upload = multer({ storage: storage }); let upload = multer({ storage: storage });
let questsList;
// Collects Quest Data
Quest.find({}, function(err, quests) {
questsList = quests;
});
// Show Quest page
router.get('/quests', (req, res) => res.render('quests', { quests: questsList }));
// Login Page // Login Page
router.get('/login', forwardAuthenticated, (req, res) => res.render('login')); router.get('/login', forwardAuthenticated, (req, res) => res.render('login'));
@@ -42,6 +52,52 @@ router.get('/register', forwardAuthenticated, (req, res) => res.render('register
// Edit page // Edit page
router.get('/edit', (req, res) => res.render('edit')); router.get('/edit', (req, res) => res.render('edit'));
// Create Quest
router.post('/createQuest', (req, res, next) => {
const { title, amount, instructions, campaign} = req.body;
let errors = [];
// Checks if Quest with title exists
Quest.findOne({ title: title }).then(quest => {
if (quest) {
errors.push({ msg: 'Quest Already Exists' });
// Redirect to dashboard page with errors
res.render('dashboard', {
errors,
name,
email,
password,
password2
});
} else {
try {
// Creates new User Object
const newQuest = new Quest({
title: title,
campaign: campaign,
xp: amount,
instruction: instructions
});
newQuest
.save()
.then(user => {
req.flash(
'success_msg'
);
// Takes to Dashboard on success
let value = encodeURIComponent('createdQuest')
res.redirect('/dashboard?successRate=' + value);
})
.catch(err => console.log(err));
} catch (err) {
if (err) throw err;
}
}
});
});
// Add XP // Add XP
router.post('/addXP', (req, res, next) => { router.post('/addXP', (req, res, next) => {
const { _id_add, current_xp, amount } = req.body; const { _id_add, current_xp, amount } = req.body;
@@ -59,7 +115,7 @@ router.post('/addXP', (req, res, next) => {
} }
if (amount < 50 && amount > 0 && current_xp < 800) { if (amount < 50 && amount > 0 && current_xp < 800) {
let newXP = current_xp + amount; let newXP = parseInt(current_xp) + parseInt(amount);
if (newXP > 800) { if (newXP > 800) {
newXP = 800; newXP = 800;
} }
+36
View File
@@ -0,0 +1,36 @@
<style>
#back {
position: absolute;
left: 10px;
top: 10px;
}
#div-container {
position: absolute;
left: 300px;
top: 50px;
}
</style>
<script>
// Catch url Parameter
window.onload = function () {
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const id = urlParams.get('id');
<% quests.forEach(function (quest) { %>
if('<%= quest._id %>' == id) {
document.getElementById('div-container').innerHTML += '<div id="quest">';
document.getElementById('quest').innerHTML += '<h1 class="title"><%= quest.title %></h1>';
document.getElementById('quest').innerHTML += '<h2 class="title">Campaign: <%= quest.campaign %></h2>'
document.getElementById('quest').innerHTML += '<p class="info">XP: <%= quest.xp %></p>';
document.getElementById('quest').innerHTML += '<p class="info">Expires: <%= quest.expiry %></p>';
document.getElementById('quest').innerHTML += '<h3 class="info">Instructions: <%= quest.instruction %></h3>';
}
<% }) %>
}
</script>
<a id='back' href="/dashboard" class="btn btn-secondary">Back to Dashboard</a>
<!-- Quest container -->
<div id='div-container'></div>
+153 -8
View File
@@ -1,5 +1,23 @@
<!-- Simple Syling for layout --> <!-- Simple Syling for layout -->
<style> <style>
.quests-container {
position: absolute;
width: 650px;
height: 645px;
top: 100px;
left: 450px;
border-style: solid;
border-color: rgba(0, 0, 0, .2);
border-radius: 15px;
background-color: rgba(0, 0, 0, .2);
}
.menu-buttons {
width: 200px;
}
.quest-buttons {
margin-left: 25px;
margin-top: 10px;
}
#myProgress { #myProgress {
position: relative; position: relative;
height: 200px; height: 200px;
@@ -10,7 +28,11 @@
border-radius: 12px; border-radius: 12px;
overflow: hidden; overflow: hidden;
} }
#quest-title {
position: absolute;
left: 720px;
top: 25px;
}
#myBar { #myBar {
position: absolute; position: absolute;
bottom: 0px; bottom: 0px;
@@ -19,11 +41,6 @@
height: 1%; height: 1%;
background-color: #46c7f2; background-color: #46c7f2;
} }
#bug-btn {
position: absolute;
bottom: 60px;
left: 25px;
}
#pro-pic { #pro-pic {
position: absolute; position: absolute;
top: 25px; top: 25px;
@@ -39,7 +56,7 @@
.student-container { .student-container {
position: absolute; position: absolute;
width: 400px; width: 400px;
height: 700px; height: 720px;
top: 25px; top: 25px;
left: 25px; left: 25px;
border: solid #5b94f0 2px; border: solid #5b94f0 2px;
@@ -50,6 +67,42 @@
.content { .content {
margin-left: 25px; margin-left: 25px;
} }
.list-button {
margin-left: 25px;
margin-top: 25px;
}
.quest-box {
margin-top: 15px;
margin-left: 30px;
transition: .2s;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
li {
font: 200 20px/1.5 Helvetica, Verdana, sans-serif;
border-bottom: 1px solid #ccc;
}
li:last-child {
border: none;
}
li a {
text-decoration: none;
color: #000;
display: block;
width: 200px;
-webkit-transition: font-size 0.3s ease, background-color 0.3s ease;
-moz-transition: font-size 0.3s ease, background-color 0.3s ease;
-o-transition: font-size 0.3s ease, background-color 0.3s ease;
-ms-transition: font-size 0.3s ease, background-color 0.3s ease;
transition: font-size 0.3s ease, background-color 0.3s ease;
}
li a:hover {
font-size: 30px;
background: #f6f6f6;
}
</style> </style>
<div class="student-container"> <div class="student-container">
@@ -78,10 +131,97 @@
<!-- Action Buttons --> <!-- Action Buttons -->
<a href="/users/logout" class="btn btn-secondary">Logout</a> <a href="/users/logout" class="btn btn-secondary">Logout</a>
<button onClick='passData()' class='btn btn-secondary'>Edit</button> <button onClick='passData()' class='btn btn-secondary'>Edit</button>
<a id='bug-btn' href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='btn btn-danger'>Report Bug</a> <a href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='btn btn-danger'>Report Bug</a>
</div> </div>
</div> </div>
<div>
<h1 id="quest-title">Quests</h1>
<div class='quests-container'>
<div class='quest-buttons'>
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label onClick="showHTML()" class="menu-buttons btn btn-info active">
<input type="radio" name="options" id="option1" autocomplete="off" checked> HTML
</label>
<label onClick="showCSS()" class="menu-buttons btn btn-info">
<input type="radio" name="options" id="option2" autocomplete="off"> CSS
</label>
<label onClick="showJS()" class="menu-buttons btn btn-info">
<input type="radio" name="options" id="option3" autocomplete="off"> JavaScript
</label>
</div>
</div>
<div class='quests-content'>
<div style="display: none;" id="HTML-Display">
<ul>
<% quests.forEach(function (quest) { %>
<% if(quest.campaign == "HTML") { %>
<!-- Creates Quest Button link -->
<li><button class='list-button btn btn-outline-success mt-2' onclick="redirect('<%= quest._id %>')"><%= quest.title %></button></li>
<% } %>
<% }) %>
</ul>
</div>
<div style="display: none;" id="CSS-Display">
<ul>
<% quests.forEach(function (quest) { %>
<% if(quest.campaign == "CSS") { %>
<!-- Creates Quest Button link -->
<li><button class='list-button btn btn-outline-success mt-2' onclick="redirect('<%= quest._id %>')"><%= quest.title %></button></li>
<% } %>
<% }) %>
</ul>
</div>
<div style="display: none;" id="JS-Display">
<ul>
<% quests.forEach(function (quest) { %>
<% if(quest.campaign == "JS") { %>
<!-- Creates Quest Button link -->
<li><button class='list-button btn btn-outline-success mt-2' onclick="redirect('<%= quest._id %>')"><%= quest.title %></button></li>
<% } %>
<% }) %>
</ul>
</div>
</div>
</div>
</div>
<!-- Quest Display -->
<script>
function showHTML() {
let state = document.getElementById('HTML-Display').style.display;
if (state == "block") {
document.getElementById('HTML-Display').style.display = 'none';
} else {
document.getElementById('JS-Display').style.display = 'none';
document.getElementById('CSS-Display').style.display = 'none';
document.getElementById('HTML-Display').style.display = 'block';
}
}
function showCSS() {
let state = document.getElementById('CSS-Display').style.display;
if (state == "block") {
document.getElementById('CSS-Display').style.display = 'none';
} else {
document.getElementById('HTML-Display').style.display = 'none';
document.getElementById('JS-Display').style.display = 'none';
document.getElementById('CSS-Display').style.display = 'block';
}
}
function showJS() {
let state = document.getElementById('JS-Display').style.display;
if (state == "block") {
document.getElementById('JS-Display').style.display = 'none';
} else {
document.getElementById('HTML-Display').style.display = 'none';
document.getElementById('CSS-Display').style.display = 'none';
document.getElementById('JS-Display').style.display = 'block';
}
}
</script>
<!-- Passing user _id to edit page script --> <!-- Passing user _id to edit page script -->
<script> <script>
function passData() { function passData() {
@@ -160,4 +300,9 @@
document.getElementById('userRank').innerHTML = currRank; document.getElementById('userRank').innerHTML = currRank;
document.getElementById('XP-Till').innerHTML = remain + 'XP till your next Rank: ' + rankUp; document.getElementById('XP-Till').innerHTML = remain + 'XP till your next Rank: ' + rankUp;
function redirect(id) {
let url = '/users/quests?id=' + encodeURIComponent(id);
document.location.href = url;
}
</script> </script>
+128 -34
View File
@@ -5,12 +5,43 @@
display: inline-block; display: inline-block;
} }
.head { .head {
margin-bottom: 100px; position: absolute;
width: 345px;
height: 600px;
top: 25px;
left: 25px;
border: solid #5b94f0 2px;
border-style: solid;
border-radius: 10px;
background-color: rgba(112, 196, 255, .3);
}
.head-content {
position: absolute;
left: 15px;
} }
.teacher-container { .teacher-container {
position: absolute; position: absolute;
width: 300px; width: 300px;
left: 205px; }
.members-container {
position: absolute;
left: 400px;
}
.quests-container {
position: absolute;
left: 800px;
background: rgba(0, 0, 0, .2);
border-radius: 24px;
border-style: solid;
border-color: rgba(0, 0, 0, .2);
}
.quest-content {
margin-left: 15px;
margin-top: 10px;
margin-right: 15px;
}
.quest {
color: #e05f3a;
} }
#pro-pic { #pro-pic {
position: absolute; position: absolute;
@@ -35,14 +66,13 @@
} }
.buttons-container { .buttons-container {
position: absolute; position: absolute;
width: 174px; top: 425px;
height: 500px; right: 180px;
top: 25px; }
right: 25px; .button-content {
border: solid #5b94f0 2px; width: 127px;
border-style: solid; margin-left: 25px;
border-radius: 10px; margin-top: 10px;
background-color: rgba(112, 196, 255, .3);
} }
#edit-btn { #edit-btn {
width: 127px; width: 127px;
@@ -99,9 +129,9 @@
</style> </style>
<!-- Welcome Message & Profile Picture --> <!-- Welcome Message & Profile Picture -->
<h1 class="mt-4">Teacher Dashboard</h1>
<div class='head'> <div class='head'>
<div> <div class='head-content'>
<h1 class="mt-4">Teacher Dashboard</h1>
<div class="teacher-container"> <div class="teacher-container">
<p id='welcome' class="lead mb-3">Welcome <%= user.name %></p> <p id='welcome' class="lead mb-3">Welcome <%= user.name %></p>
<img id='pro-pic' src='data:image/<%=user.image.contentType%>;base64, <img id='pro-pic' src='data:image/<%=user.image.contentType%>;base64,
@@ -111,9 +141,11 @@
<div class="buttons-container"> <div class="buttons-container">
<!-- Action Buttons --> <!-- Action Buttons -->
<a id='logout-btn' href="/users/logout" class="btn btn-outline-info btn-sm">Logout</a> <a href="/users/logout" class="button-content btn btn-outline-info btn-sm">Logout</a>
<button id='edit-btn' onClick='passData()' class='btn btn-outline-info btn-sm'>Edit</button> <button onClick='passData()' class='button-content btn btn-outline-info btn-sm'>Edit</button>
<a id='bug-btn' href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='btn btn-outline-info btn-sm'>Report Bug</a> <a href="https://github.com/Braeden57/XP-System/issues" target="_blank" class='button-content btn btn-outline-info btn-sm'>Report Bug</a>
<button class="button-content btn btn-outline-info btn-sm" data-toggle="modal" data-target="#createQuest">New Quest</button>
</div>
</div> </div>
<!-- Passing user _id to edit page script --> <!-- Passing user _id to edit page script -->
@@ -125,11 +157,9 @@
} }
</script> </script>
</div> </div>
</div>
<br> <br>
<!-- Sets Variables for calculating users data --> <!-- Sets Variables for calculating users data -->
<div>
<script> <script>
let xp; let xp;
let currRank; let currRank;
@@ -157,7 +187,7 @@
<!-- Alert container --> <!-- Alert container -->
<div id='div-container'></div> <div id='div-container'></div>
<!-- Modal --> <!-- Add XP Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
@@ -201,6 +231,73 @@
</div> </div>
</div> </div>
<!-- Create Quest Modal -->
<div class="modal fade" id="createQuest" tabindex="-1" role="dialog" aria-labelledby="createQuestLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="createQuestLabel"</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<form action="/users/createQuest" method="POST">
<div>
<label for="title">Title</label>
<input
id="title"
name="title"
type="text"
value=""
class="form-control"
required
>
</div>
<div class="form-group">
<label for="amount">Amount</label>
<input
id="amount"
name="amount"
type="number"
min="1"
max="50"
value=""
class="form-control"
required
>
</div>
<div>
<label for="instructions">Instructions</label>
<textarea
id="instructions"
name="instructions"
value=""
class="form-control"
required
></textarea>
</div>
<div>
<label for="campaign">Campaign</label>
<select required name="campaign" id="campaign">
<option value="">--Please choose an option--</option>
<option value="HTML">HTML</option>
<option value="CSS">CSS</option>
<option value="JS">JavaScript</option>
</select>
</div>
<button type="submit" class="btn btn-primary">
Create Quest
</button>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script> <script>
// Creates unique ID // Creates unique ID
function makeid(length) { function makeid(length) {
@@ -229,22 +326,6 @@
document.getElementById('new-div-'+id).style.display = "block"; document.getElementById('new-div-'+id).style.display = "block";
} }
// // Check amount
// function amountCheck(_id) {
// const amount = document.getElementById("amount").value;
// if (amount > 50) {
// createDiv('error', "Can't add more than 50 XP");
// }
// if (amount == 0 || amount < 0) {
// createDiv('error', "XP Must be more than 0");
// }
//
// if (amount > 0 && amount < 50) {
//
// createDiv('message', "Succesfully added XP");
// }
// }
// Pass name to Modal // Pass name to Modal
function passName(name, xp, member_id) { function passName(name, xp, member_id) {
if (xp < 800) { if (xp < 800) {
@@ -274,9 +355,13 @@
if(parseInt(successRate) > 0 && parseInt(successRate) < 50 || parseInt(successRate) == 50) { if(parseInt(successRate) > 0 && parseInt(successRate) < 50 || parseInt(successRate) == 50) {
createDiv('message', "Gave " + successRate + "XP to a Student"); createDiv('message', "Gave " + successRate + "XP to a Student");
} }
if(successRate == 'createdQuest') {
createDiv('message', "Successfully Created Quest");
}
} }
</script> </script>
<div class="members-container">
<!-- List of all site students (not teachers) --> <!-- List of all site students (not teachers) -->
<h2>Studen Members</h2> <h2>Studen Members</h2>
<div class='members'> <div class='members'>
@@ -342,6 +427,15 @@
</div> </div>
</div> </div>
<div class="quests-container">
<!-- List of Quests -->
<div class='quest-content'>
<h2>All Quests</h2>
<% quests.forEach(function (quest) { %>
<p class='quest'><%= quest.title %></p>
<% }) %>
</div>
<!-- Script for show/hide user profile data --> <!-- Script for show/hide user profile data -->
<script> <script>
function openProfile(id) { function openProfile(id) {