PPR 1:

  • Defines the procedure’s name and return type (if necessary).
  • Contains and uses one or more parameters that have an effect on the functionality of the procedure.
  • Implements an algorithm that includes:
    • Sequencing
    • Selection
    • Iteration
function renderCalendar() {
    const monthYear = document.getElementById("month-year");
    const calendarDays = document.getElementById("calendar-days");
    monthYear.textContent = `${new Date(currentYear, currentMonth).toLocaleString('default', { month: 'long' })} ${currentYear}`;
    calendarDays.innerHTML = "";

    const firstDay = new Date(currentYear, currentMonth, 1).getDay();
    const daysInMonth = new Date(currentYear, currentMonth + 1, 0).getDate();

    for (let i = 0; i < firstDay; i++) {
        calendarDays.appendChild(document.createElement("div"));
    }

    for (let day = 1; day <= daysInMonth; day++) {
        const dayCell = document.createElement("div");
        dayCell.classList.add("day");
        dayCell.textContent = day;

        const formattedDate = `${currentYear}-${String(currentMonth + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
        const eventsOnDay = events.filter(event => new Date(event.date).toISOString().split("T")[0] === formattedDate);

        if (eventsOnDay.length > 0) {
            dayCell.classList.add("event-day");

            eventsOnDay.forEach(event => {
                const emoji = document.createElement("div");
                emoji.classList.add("event-emoji");
                emoji.textContent = "❗";
                emoji.title = `${event.name} @ ${event.location}`;
                dayCell.appendChild(emoji);
            });
        }

        dayCell.addEventListener("click", () => {
            document.getElementById("startDate").value = formattedDate;
        });

        calendarDays.appendChild(dayCell);
    }
}

Why This Works

Defines a Student-Developed Procedure

  • The function renderCalendar() is a student-developed procedure with a meaningful name.
  • It is responsible for dynamically generating a calendar layout based on the current month and year.

Uses Parameters That Affect Functionality

  • The function relies on two global parameters: currentYear and currentMonth.
  • These parameters determine which month’s calendar is displayed, affecting the output.

Implements an Algorithm That Includes:

Sequencing (Step-by-step execution)

  • The function first updates the month-year display.
  • Then, it clears the previous calendar content.
  • It determines the number of days in the month and iterates to create the calendar structure.

Selection (Conditional logic)

  • The if (eventsOnDay.length > 0) statement checks if there are events on a particular day.
  • If events exist, it marks the day and adds an emoji to indicate an event.

Iteration (Loops)

  • A for loop (for (let i = 0; i < firstDay; i++)) adds empty placeholders for days before the first of the month.
  • Another for loop (for (let day = 1; day <= daysInMonth; day++)) iterates through all the days in the month, generating a calendar cell for each.
  • The .forEach(event => {...}) inside the selection statement iterates through events occurring on a given day.

This function effectively meets all rubric requirements for the AP CSP PPR submission.

PPR 2

The second program code segment must show where your student-developed procedure is being called in your program.

window.changeMonth = function (direction) {
    currentMonth += direction;
    if (currentMonth < 0) {
        currentMonth = 11;
        currentYear--;
    } else if (currentMonth > 11) {
        currentMonth = 0;
        currentYear++;
    }
    fetchEvents(); // Fetch events for the new month
    renderCalendar(); // Update the calendar view immediately
};

Why This Works:

  • renderCalendar() is called inside changeMonth(), ensuring that the calendar updates dynamically when the user navigates between months.
  • This demonstrates how the student-developed procedure is integrated into the program’s functionality.
  • The function updates currentMonth and currentYear, fetches events for the new month, and then calls renderCalendar() to reflect the changes.

PPR 3

The first program code segment must show how data have been stored in the list.

document.getElementById("eventForm").addEventListener("submit", async function(event) {
    event.preventDefault();

    const postData = {
        name: document.getElementById("eventName").value,
        location: document.getElementById("eventLocation").value,
        date: document.getElementById("startDate").value,  // YYYY-MM-DD format
    };

    console.log("Event Data:", postData);  // Log event data for debugging

    try {
        const response = await fetch(`${pythonURI}/api/event`, {
            ...fetchOptions,
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(postData)
        });

        if (!response.ok) {
            const errorMessage = await response.text();
            throw new Error(`Failed to add event: ${response.statusText} - ${errorMessage}`);
        }

        const createdEvent = await response.json();
        alert("Event added successfully!");

        if (createdEvent.id) {
            events.push(createdEvent);  //  Storing the new event in the list
            renderCalendar(); // Update calendar display
            displayEvents(); // Show updated event list
        } else {
            console.error("Error: Event created but no ID returned from API");
        }

        this.reset(); // Clear the form
    } catch (error) {
        console.error("Error:", error);
        alert("Error adding event. Please try again.");
    }
});

Why This Works:

  • The events list is used to store newly added events.
  • The push() method adds new events to the list.
  • The stored events are later displayed in the calendar and event list.

PPR 4

The second program code segment must show the data in the same list being used, such as creating new data from the existing data or accessing multiple elements in the list, as part of fulfilling the program’s purpose.

const eventsOnDay = events.filter(event => 
    new Date(event.date).toISOString().split("T")[0] === formattedDate
);

if (eventsOnDay.length > 0) {
    dayCell.classList.add("event-day");

    eventsOnDay.forEach(event => {
        const emoji = document.createElement("div");
        emoji.classList.add("event-emoji");
        emoji.textContent = "❗";
        emoji.title = `${event.name} @ ${event.location}`;
        dayCell.appendChild(emoji);
    });
}

Why This Works:

  • The events list is used to retrieve events occurring on a specific day.
  • The .filter() method accesses multiple elements in the list to check for matching dates.
  • The retrieved events are then displayed in the calendar, fulfilling the program’s purpose of tracking and visualizing events.