I am trying to finish a homepage for a mini library website with these requirements.
- a left indented checkboxed form with title of the available books; has a button called borrow
- a right indented checkboxed form with title of the borrowed books; has a button called return
- when a checkbox is clicked and button is pressed, the books will be updated as per request; when borrowed it will disappear from the left side and appear on the right side and vice versa for returned books.
I tried creating .hbs file with necessary helps and escape characters. I also created a get method for the /home page and a post method for the /return and /borrow functions. I was expecting the borrow and return function to update the books and their status, however, the page only refreshes not update the "available" property of the books.
{{> Heading}}
<div class="container">
<div class="left-container">
<h2>Available Books</h2>
<form action="/borrow" method="POST">
{{#each availableBooks}}
{{#if available}}
<div class="book">
<input type="checkbox" name="books[]" value="{{title}}">
<span>{{title}}</span>
</div>
{{/if}}
{{/each}}
<button type="submit" name="action" value="borrow" id="borrowButton" disabled>Borrow</button>
</form>
</div>
<div class="right-container">
<h2>Borrowed Books</h2>
<form action="/return" method="POST">
{{#each borrowedBooks}}
{{#unless available}}
<div class="book">
<input type="checkbox" name="books[]" value="{{title}}">
<span>{{title}}</span>
</div>
{{/unless}}
{{/each}}
<button type="submit" name="action" value="return" id="returnButton" disabled>Return</button>
</form>
</div>
</div>
<script>
// Enable borrow button when at least one checkbox is selected in the left container
const borrowButton = document.getElementById('borrowButton');
const leftContainerCheckboxes = document.querySelectorAll('.left-container input[type="checkbox"]');
leftContainerCheckboxes.forEach((checkbox) => {
checkbox.addEventListener('change', () => {
const anyChecked = Array.from(leftContainerCheckboxes).some((checkbox) => checkbox.checked);
borrowButton.disabled = !anyChecked;
});
});
// Enable return button when at least one checkbox is selected in the right container
const returnButton = document.getElementById('returnButton');
const rightContainerCheckboxes = document.querySelectorAll('.right-container input[type="checkbox"]');
rightContainerCheckboxes.forEach((checkbox) => {
checkbox.addEventListener('change', () => {
returnButton.disabled = !Array.from(rightContainerCheckboxes).some((checkbox) => checkbox.checked);
});
});
</script>
const HTTP_PORT = process.env.PORT || 3000;
const express = require("express");
const exphbs = require("express-handlebars");
const path = require('path');
const fs = require('fs');
const session = require('express-session');
const bodyParser = require('body-parser');
const app = express();
app.use(express.static(path.join(__dirname, '/public')));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(session({
secret: 'your-secret-key',
resave: false,
saveUninitialized: false
}));
function onHttpStart() {
console.log("Express http server listening on: " + HTTP_PORT);
}
let booksData = [];
fs.readFile('books.json', 'utf8', (err, data) => {
if (err) {
console.error(err);
return;
}
booksData = JSON.parse(data);
});
app.engine(".hbs", exphbs.engine({
extname: ".hbs",
defaultLayout: false,
layoutsDir: path.join(__dirname, "/views")
}));
app.set("view engine", ".hbs");
// Middleware to check session authentication
function authenticateSession(req, res, next) {
if (req.session.username) {
next(); // User is authenticated, continue to the next middleware
} else {
res.redirect('/LandingPage'); // User is not authenticated, redirect to LandingPage
}
}
app.get('/', (req, res) => {
res.render('Landing Page', { layout: false });
});
app.get("/LandingPage", function(req, res) {
res.render('Landing Page', { layout: false });
});
app.get("/SignIn", function(req, res) {
res.render('Sign In', { heading: 'uLibrary', layout: false });
});
app.post('/signin', express.urlencoded({ extended: false }), (req, res) => {
const { username, password } = req.body;
// Read the users.json file
fs.readFile('./users.json', 'utf8', (err, data) => {
if (err) {
console.error(err);
return res.status(500).send('Internal Server Error');
}
const users = JSON.parse(data);
// Check if the entered username exists in the users.json file
if (!users.hasOwnProperty(username)) {
//return res.render('Sign In', {
// error: 'Not a registered username',
// layout: false
//});
return res.redirect('/LandingPage');
}
// Check if the entered password matches the stored password for the username
if (users[username] !== password) {
//return res.render('Sign In', {
// error: 'Invalid password',
// layout: false
//});
return res.redirect('/LandingPage');
}
// Successful sign in, set username in session
req.session.username = username;
// Redirect to the Home Webpage
res.redirect('/home');
});
});
app.get('/home', authenticateSession, (req, res) => {
const username = req.session.username;
const availableBooks = booksData.filter((book) => book.available);
const borrowedBooks = booksData.filter((book) => !book.available);
res.render('Home', {
heading: 'Home',
availableBooks: availableBooks,
borrowedBooks: borrowedBooks,
layout: false
});
console.log(booksData);
});
app.post('/borrow', (req, res) => {
const selectedBooks = req.body.books || []; // Array of selected book titles
console.log(selectedBooks);
// Update the availability property for selected books
selectedBooks.forEach((selectedBook) => {
const book = booksData.find((item) => item.title === selectedBook);
console.log("book selected:")
console.log(book);
if (book) {
console.log(book.available);
book.available = false;
}
});
fs.writeFile('books.json', JSON.stringify(booksData), 'utf8', (err) => {
if (err) {
console.error(err);
} else {
console.log('books.json updated successfully.');
}
});
res.redirect('/home');
});
// Handle Return button click
app.post('/return', (req, res) => {
const selectedBooks = req.body.books || []; // Array of selected book titles
console.log(selectedBooks);
// Update the availability property for selected books
selectedBooks.forEach((selectedBook) => {
const book = booksData.find((item) => item.title === selectedBook);
console.log(book);
console.log(book.available);
if (book) {
book.available = true;
}
});
fs.writeFile('books.json', JSON.stringify(booksData), 'utf8', (err) => {
if (err) {
console.error(err);
} else {
console.log('books.json updated successfully.');
}
});
res.redirect('/home');
});
app.listen(HTTP_PORT, onHttpStart);
[
{
"title": "The Shining",
"author": "Stephen King",
"available": true
},
{
"title": "Rainbow Six",
"author": "Tom Clancy",
"available": false
},
{
"title": "Steve Jobs",
"author": "Walter Isaacson",
"available": true
},
{
"title": "Elon Musk",
"author": "Ashley Vance",
"available": false
}
]