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
5 changes: 5 additions & 0 deletions reading-list-manager/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 80
}
19 changes: 18 additions & 1 deletion reading-list-manager/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,23 @@
// 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 * as readingListFunctions from './readingList.js';

console.log('📚 MY READING LIST 📚\n');

// Your implementation here
console.log('All Books:');
readingListFunctions.printAllBooks();

readingListFunctions.printSummary();

console.log(chalk.magenta('\n📖 UNREAD BOOKS EXAMPLE (uses filter()):'));
const unreadBooksArray = readingListFunctions.getUnreadBooks();
console.log('Unread books count:', unreadBooksArray.length);

console.log(chalk.magenta('\n📖 MARKING BOOK AS READ EXAMPLE (uses map()):'));
const duneBookId = 2;
readingListFunctions.markAsRead(duneBookId);
console.log(chalk.green('✅ Book marked as read!'));

console.log(chalk.green('\n✅ All 5 TODOs demonstrated!'));
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": true
},
{
"id": 3,
"title": "The Hobbit",
"author": "J.R.R. Tolkien",
"genre": "Fantasy",
"read": true
},
{
"id": 4,
"title": "Clean Code",
"author": "Robert C. Martin",
"genre": "Tech",
"read": false
},
{
"id": 5,
"title": "Sapiens",
"author": "Yuval Noah Harari",
"genre": "History",
"read": true
}
]
96 changes: 96 additions & 0 deletions reading-list-manager/package-lock.json

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

18 changes: 18 additions & 0 deletions reading-list-manager/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "reading-list-manager",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node app.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "module",
"dependencies": {
"chalk": "^4.1.2",
"readline-sync": "^1.4.10"
}
}
124 changes: 91 additions & 33 deletions reading-list-manager/readingList.js
Original file line number Diff line number Diff line change
@@ -1,53 +1,111 @@
// Place here the file operation functions for loading and saving books
import fs from 'fs';
import chalk from 'chalk';

function loadBooks() {
// TODO: Implement this function
// Read from books.json
// Handle missing file (create empty array)
// Handle invalid JSON (notify user, use empty array)
// Use try-catch for error handling
const BOOKS_FILE = 'books.json';

export function loadBooks() {
try {
// Check if file exists first
if (!fs.existsSync(BOOKS_FILE)) {
console.log('No books.json found, starting empty');
return [];
}

// Read and parse the file
const data = fs.readFileSync(BOOKS_FILE, 'utf8');
const books = JSON.parse(data);

// Make sure it's an array
if (Array.isArray(books)) {
return books;
} else {
console.log('books.json is not valid, starting empty');
return [];
}
} catch (error) {
console.log('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
export function saveBooks(books) {
try {
fs.writeFileSync(BOOKS_FILE, JSON.stringify(books, null, 2));
} catch (error) {
console.log('Error saving books:', error.message);
}
}

function addBook(book) {
// TODO: Implement this function
export function addBook(bookInfo) {
const books = loadBooks();
const newId = books.length + 1;
Copy link

Choose a reason for hiding this comment

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

What if you've removed a book, and the ID count doesn't match the length anymore? You don't neewd to change anything now, but I want you to think how else this could've been done.

const newBook = {
id: newId,
title: bookInfo.title,
author: bookInfo.author,
genre: bookInfo.genre,
read: false
};
books.push(newBook);
saveBooks(books);
return newBook;
}

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

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

function markAsRead(id) {
// TODO: Implement this function using map()
export function markAsRead(id) {
// TODO: Use map()
const books = loadBooks();
const newBooks = books.map(book => {
if (book.id === id) {
return { ...book, read: true };
}
return book;
});
saveBooks(newBooks);
return newBooks;
}

function getTotalBooks() {
// TODO: Implement this function using length
export function getTotalBooks() {
// TODO: Use length
return loadBooks().length;
}

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

function printAllBooks() {
// TODO: Implement this function
// Loop through and display with chalk
// Use green for read books, yellow for unread
// Use cyan for titles
export function printAllBooks() {
// Loop with chalk colors
const books = loadBooks();
books.forEach(book => {
const symbol = book.read ? chalk.green('✓') : chalk.yellow('⚠');
const titleColor = chalk.cyan(book.title);
const status = book.read ? chalk.green('Read') : chalk.yellow('Unread');

console.log(`${book.id}. ${titleColor} by ${book.author} (${book.genre}) ${symbol} ${status}`);
});
}

function printSummary() {
// TODO: Implement this function
// Show statistics with chalk
// Display total books, read count, unread count
// Use bold for stats
}
export function printSummary() {
const books = loadBooks();
const readCount = books.filter(book => book.read).length;
const unreadCount = books.length - readCount;

console.log(chalk.bold('\n📊 SUMMARY'));
console.log(chalk.bold(`Total: ${books.length}`));
console.log(chalk.green.bold(`Read: ${readCount}`));
console.log(chalk.yellow.bold(`Unread: ${unreadCount}`));
}