Skip to the content.

Project Feature Write Up

My features and their relations to the CPT requirements

CPT Requirements:

  • Instructions for input (from the user, a device, an online data stream, or a file)
  • Use of at least one list or other collection type to represent stored data
  • At least one procedure that contributes to the intended purpose of the program (with the name, the return type, and one or more parameters)
  • An algorithm including sequencing, selection, and iteration
  • Instructions for output (tactile, audible, visual, or textual) that are based on inputs and the program’s functionality

Feature 1 - Preferences Page

Feature 2 - Favorite Books Page

Feature 3 - Reading Progress Tracker Page

Requirement 1: Instructions for Input (user)

Preferences

<button class="color-button" id="white">White</button>
<button class="color-button" id="black">Black</button>
<button class="color-button" id="changeMenu">Change Menu Color</button>
  Cell In[1], line 1
    <button class="color-button" id="white">White</button>
    ^
SyntaxError: invalid syntax

Favorite Books

<div class="container">
<input type="text" id="bookTitle" placeholder="Enter book title" />
<button class="button" onclick="addBook()">Add Book</button>
</div>

Reading Progress Tracker

<input type="text" id="bookTitle" placeholder="Book Title">
<input type="number" id="bookPercent" placeholder="Percent Read" min="0" max="100">
<button class="button" onclick="addBook()">Add Book</button>
<button class="button" onclick="fetchBooks()">Load Books</button>

In each of my pages, there are buttons to click which do different things such as change a color or prompt the user to enter more specifications inside a popup. In some of the pages, there are also empty text boxes already placed on the page for users to use with the buttons.

Requirement 2: Use of a Collection Type (dictionaries/lists)

Preferences

preferences = {
    "menu": "red",
    "text": "white"
}

Favorite Books

favorite_book_list = [
            FavoriteBook(title="Hunger Games"), 
            FavoriteBook(title="Maze Runner"),
        ]

Reading Progress Tracker

book_progress_list = [
            BookProgress(title="Hunger Games", percent_read=30.0), 
            BookProgress(title="Maze Runner", percent_read=50.0),
        ]

The data for each of my pages is stored inside of its own dictionary or list where it is repeatedly accessed to add, update, and delete information.

Requirement 3: Use of at least one procedure

Preferences

def update_preferences():
    # Check if the request contains JSON
    if request.is_json:
        # Get the new preferences data from the JSON body
        data = request.get_json()
       
        # Update preferences dictionary with the new data
        preferences.update(data)
       
        # Return the updated preferences as a response
        return jsonify(preferences), 200
    else:
        return jsonify({"error": "Request must be in JSON format"}), 400

Favorite Books

def get(self):
        favorite_books = FavoriteBook.query.all()
        return {"books": [book.read() for book in favorite_books]}, 200  

Reading Progress Tracker

def put(self, book_progress_id):
        data = request.get_json()
        if not data or 'title' not in data:
            return {'error': 'Title is required.'}, 400

        book_progress = BookProgress.query.get(book_progress_id)
        if not book_progress:
            return {'error': 'Book progress not found.'}, 404

        book_progress.title = data['title']
        book_progress.percent_read = data.get('percent_read', book_progress.percent_read)
        db.session.commit()  # Save update to database

        return book_progress.read(), 200 

Each of the procedures in my features is defined, takes input, and returns data. While it may not seem like the function in Preferences is taking any parameters, it does use the JSON data and updates the dictionary with the preferences stored based on the data.

Requirement 4: Algorith with Sequencing, Selection, and Iteration

Preferences

def update_preferences():
    # Check if the request contains JSON
    if request.is_json:
        # Get the new preferences data from the JSON body
        data = request.get_json()
       
        # Update preferences dictionary with the new data
        preferences.update(data)
       
        # Return the updated preferences as a response
        return jsonify(preferences), 200
    else:
        return jsonify({"error": "Request must be in JSON format"}), 400

Favorite Books

function fetchBooks() {
    fetch(apiUrl)
        .then(response => response.json())
        .then(data => {
            const tableBody = document.getElementById('booksTable');
            tableBody.innerHTML = '';

            data.books.forEach(book => {
                const row = `<tr>
                    <td>${book.id}</td>
                    <td>${book.title}</td>
                    <td>
                        <button class="button edit" onclick="editBook(${book.id}, '${book.title}')">Edit</button>
                        <button class="button delete" onclick="deleteBook(${book.id})">Delete</button>
                    </td>
                </tr>`;
                tableBody.innerHTML += row;
            });
        })
        .catch(error => console.error('Error fetching books:', error));
}

Reading Progress Tracker

function addBook() {
      const title = document.getElementById('bookTitle').value;
      const percentRead = document.getElementById('bookPercent').value || 0;
      
      if (!title) {
        alert('Please enter a book title');
        return;
      }
      
      fetch(apiUrl, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title, percent_read: parseFloat(percentRead) })
      })
      .then(response => response.json())
      .then(data => {
        if (data.error) {
          alert(data.error);
        } else {
          fetchBooks();
        }
      })
      .catch(error => console.error('Error adding book:', error));
    }

Each of the above functions contain sequencing, as they all follow a guided set of steps. In these examples, Preferences and Reading Progress Tracker both have selection as well, as they contain if statements to select data and ensure that it is correct. Finally, Favorite Books has iteration as it contains the line data.books.forEach(parameters) which iterates through the data and does an action for each book.

Requirement 5: Instructions for Output (visual)

Preferences

let pColors = document.querySelectorAll('p');
pColors.forEach(p => {
  p.style.color = data.text;
});

let menuItems = document.querySelectorAll('.menu-item');
menuItems.forEach(item => {
  item.style.backgroundColor = data.menu;
});

Favorite Books

function editBook(bookId, currentTitle) {
    const newTitle = prompt('Enter new book title:', currentTitle);
    if (!newTitle || newTitle === currentTitle) return;

    fetch(`${apiUrl}/${bookId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ title: newTitle })
    })
    .then(response => response.json())
    .then(data => {
        if (data.error) {
            alert(data.error);
        } else {
            fetchBooks();
        }
    });
}

Reading Progress Tracker

function addBook() {
    const title = document.getElementById('bookTitle').value;
    const percentRead = document.getElementById('bookPercent').value || 0;
    
    if (!title) {
      alert('Please enter a book title');
      return;
    }
    
    fetch(apiUrl, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title, percent_read: parseFloat(percentRead) })
    })
    .then(response => response.json())
    .then(data => {
      if (data.error) {
        alert(data.error);
      } else {
        fetchBooks();
      }
    })
    .catch(error => console.error('Error adding book:', error));
  }

These code segments outline some of the outputs that users would get upon interacting with my features. For Preferences, when they use the buttons to change the colors of the page, the styling will be updated and they will see different colors based on their choice. For the other two, the user interaction will either change text that is already in a table or add new text to a table.

Overall

I believe that my features in the project all individually meet the CPT requirements as they contain all that is requested at a fairly advanced level.

N@tM Feedback

Most of the feedback that our group recieved was unfortunately not directed to my 5 contributions. However, I did recieve some comments.

Firstly, for my Reading Progress Tracker, Noah’s dad gave me the idea to take an input of (pages read)/(total pages) to make it easier for the users to track their progress. However, though I wanted to make this change, I could not figure out a way to make the database with the information stored take two values and also show a percentage based on those.

Other than that, most people said that the colors of the page and the design were good as a whole. They also said that we had a clean interface and that it was nice that the page loaded quickly.

PPR

Student-Developed Procedure

def get(self):
        book_progress_list = BookProgress.query.all()
        return {"books": [book.read() for book in book_progress_list]}, 200  

def post(self):
        data = request.get_json()
        if not data or 'title' not in data:
            return {'error': 'Title is required.'}, 400

These functions are defined with parameters and have sequencing, selection, and iteration

Student-Developed Procedure Being Called

const apiUrl = "https://litconnect.stu.nighthawkcodingsociety.com/api/book_progress";
    
    function fetchBooks() {
      fetch(apiUrl)
        .then(response => response.json())
        .then(data => {
          const tableBody = document.getElementById('bookTableBody');
          const bookSelect = document.getElementById('bookSelect');
          tableBody.innerHTML = '';
          bookSelect.innerHTML = '';  // Clear previous options
          
          data.books.forEach(book => {
            // Add to table
            const row = `<tr>
                          <td>${book.title}</td>
                          <td>${book.percent_read}%</td>
                          <td><button class="button" onclick="deleteBook(${book.id})">Delete</button></td>
                        </tr>`;
            tableBody.innerHTML += row;
            
            // Add to select dropdown for update
            const option = `<option value="${book.id}">${book.title}</option>`;
            bookSelect.innerHTML += option;
          });
        })
        .catch(error => console.error('Error fetching books:', error));
    }

Frontend calling of my feature (book progress)

A Container in my Program

preferences = {
    "menu": "red",
    "text": "white"
}

Dictionary to store preferences

The Container Being Used

function loadPreferences() {
    fetch(apiUrl)
      .then(response => response.json())
      .then(data => {
        document.getElementById('menu').innerText = `Menu Color: ${data.menu}`;
        document.getElementById('text').innerText = `Text Color: ${data.text}`;
        
        let pColors = document.querySelectorAll('p');
        pColors.forEach(p => {
          p.style.color = data.text;
        });

        let menuItems = document.querySelectorAll('.menu-item');
        menuItems.forEach(item => {
          item.style.backgroundColor = data.menu;
        });
      })
      .catch(error => {
        console.error('Error fetching preferences:', error);
      });
  }

Preferences being pulled from the dictionary and used to replace frontend styling