Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": true,
"singleQuote": true,
"tabWidth": 2
}

105 changes: 105 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "c55-core-week-6",
"version": "1.0.0",
"description": "The week 6 assignment for the HackYourFuture Core program can be found at the following link: https://hub.hackyourfuture.nl/core-program-week-6-assignment",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/mareh-aboghanem/c55-core-week-6.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"bugs": {
"url": "https://github.com/mareh-aboghanem/c55-core-week-6/issues"
},
"homepage": "https://github.com/mareh-aboghanem/c55-core-week-6#readme",
"dependencies": {
"chalk": "^4.1.2"
},
"devDependencies": {
"prettier": "^3.8.1"
}
}
21 changes: 20 additions & 1 deletion reading-list-manager/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,26 @@
// 3. Show summary statistics
// 4. Add example of filtering by genre or read/unread status
// 5. Add example of marking a book as read

import chalk from 'chalk';
import {
printAllBooks,
printSummary,
getUnreadBooks,
getBooksByGenre,
markAsRead
} from './readingList.js';
console.log('📚 MY READING LIST 📚\n');

// Your implementation here
printAllBooks();
printSummary();

console.log(chalk.bold('\nUnread Books:'));
const unread = getUnreadBooks();
unread.forEach(book => {
console.log(`${book.id}. ${chalk.cyan(book.title)} by ${book.author} (${book.genre})`);
});

const exampleId = 1;
console.log(chalk.bold(`\nMarking book ${exampleId} as read...`));
markAsRead(exampleId);
38 changes: 37 additions & 1 deletion reading-list-manager/books.json
Original file line number Diff line number Diff line change
@@ -1 +1,37 @@
[]
[
{
"id": 1,
"title": "1984",
"author": "George Orwell",
"genre": "Fiction",
"read": true
},
{
"id": 2,
"title": "Dune",
"author": "Frank Herbert",
"genre": "Sci-Fi",
"read": false
},
{
"id": 3,
"title": "The Hobbit",
"author": "J.R.R. Tolkien",
"genre": "Fantasy",
"read": true
},
{
"id": 4,
"title": "Atomic Habits",
"author": "James Clear",
"genre": "Self-Help",
"read": false
},
{
"id": 5,
"title": "Clean Code",
"author": "Robert C. Martin",
"genre": "Programming",
"read": true
}
]
105 changes: 99 additions & 6 deletions reading-list-manager/readingList.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,146 @@
// Place here the file operation functions for loading and saving books
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import chalk from 'chalk';
// to make sure we can read and write to books.json in the same directory as this file.
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const booksPath = path.join(__dirname, 'books.json');

function loadBooks() {
// TODO: Implement this function
Copy link

@sycons sycons Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's good practice to remove TODO comments after you've implemented them. Keeps the code cleaner and shows more clearly the requirement has been implemented.

// Read from books.json
// Handle missing file (create empty array)
// Handle invalid JSON (notify user, use empty array)
// Use try-catch for error handling
try{
const readBooks = fs.readFileSync(booksPath, 'utf8');
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pay attention to indenting code. This increases readability.

const books = JSON.parse(readBooks);
return Array.isArray(books) ? books : [];
}
catch (error) {
console.error('Error loading books:', error.message);
return [];
}

}

function saveBooks(books) {
// TODO: Implement this function
// Write books array to books.json
// Use try-catch for error handling
}
try {
fs.writeFileSync(booksPath, JSON.stringify(books, null, 2), 'utf8');}
catch (error) {
/*This will occur when No write permission, Disk full, the folder is missing, File locked*/
console.error('Error saving books:', error.message);
}}

function addBook(book) {
// TODO: Implement this function
// Check for duplicate title using some()
try{
const books = loadBooks();
const isDuplicate = books.some(existingBook => existingBook.title.toLowerCase() === book.title.toLowerCase());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice touch converting to lower case when comparing strings ⭐
Also a real world scenario that happens often in apps.

if (isDuplicate) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job thinking of duplicate book being added ⭐
This is actually a real world scenario that needs to be accounted for in many apps. This shows your thinking about the data stored.

throw new Error('Book with this title already exists');
}
// Generate new ID
const lastBook = books[books.length - 1];
const newId = lastBook ? lastBook.id + 1 : 1;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job generating the id instead of using the one passed in the book parameter ⭐

const newBook = {
id: newId,
title: book.title,
author: book.author,
genre: book.genre,
read: false
};
books.push(newBook);
saveBooks(books);
console.log('Book added successfully!');
}
catch (error) {
console.error('Error adding book:', error.message);
}
}

function getUnreadBooks() {
export function getUnreadBooks() {
// TODO: Implement this function using filter()
const books = loadBooks();
return books.filter(book => !book.read);
}

function getBooksByGenre(genre) {
export function getBooksByGenre(genre) {
// TODO: Implement this function using filter()
const books = loadBooks();
return books.filter(book => book.genre.toLowerCase() === genre.toLowerCase());
}

function markAsRead(id) {
export function markAsRead(id) {
// TODO: Implement this function using map()
const books= loadBooks();
const bookId = Number(id);
let found = false;
const statusofBooks = books.map(book => {
if (book.id === bookId) {
found = true;
return { ...book, read: true };
}
return book;
});
if (!found) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job checking the book exists for the given id and returning an informative message ⭐
This is often needed in many real world apps.

console.log('No book found with this id.');
return;
}
saveBooks(statusofBooks);
}

function getTotalBooks() {
// TODO: Implement this function using length
const books = loadBooks();
return books.length;
}

function hasUnreadBooks() {
// TODO: Implement this function using some()
const books = loadBooks();
return books.some(book => !book.read);
}

function printAllBooks() {
export function printAllBooks() {
// TODO: Implement this function
// Loop through and display with chalk
// Use green for read books, yellow for unread
// Use cyan for titles
const books = loadBooks();
if (books.length === 0) {
console.log(chalk.yellow('No books in the reading list.'));
return;
}
//console.log(chalk.bold('\n📚 MY READING LIST 📚\n'));
books.forEach(book => {
const status = book.read
? chalk.green('✓ Read')
: chalk.yellow('⚠ Unread');
console.log(
`${book.id}. ${chalk.cyan(book.title)} by ${book.author} (${book.genre}) ${status}`
);
});

}

function printSummary() {
export function printSummary() {
// TODO: Implement this function
// Show statistics with chalk
// Display total books, read count, unread count
// Use bold for stats
const books = loadBooks();
const totalBooks = books.length;
const readBooks = books.filter(book => book.read).length;
const unreadBooks = books.filter(book => !book.read).length;
console.log(chalk.bold('\n📊 SUMMARY 📊\n'));
console.log(chalk.bold(`Total Books: ${totalBooks}`));
console.log(chalk.bold(`Read: ${readBooks}`));
console.log(chalk.bold(`Unread: ${unreadBooks}`));
}