From 412afee0fb25aeeafc018d072556390f492489f3 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sat, 24 Jan 2026 12:44:05 -0800 Subject: [PATCH 1/5] added break day feature to calendar --- .../calendar/2024-12-16-calendar.md | 105 +++++++++++++++--- 1 file changed, 92 insertions(+), 13 deletions(-) diff --git a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md index 73e57ee9e..84480fd5f 100644 --- a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md +++ b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md @@ -57,7 +57,15 @@ active_tab: calendar .fc .fc-day-today { background-color: color-mix(in srgb, var(--accent) 20%, var(--bg-0) 80%) !important; } +/* Break day highlighting */ +.fc-event-break { + background-color: #2a2a2a !important; + border-color: #1a1a1a !important; +} +.fc-daygrid-day.break-day { + background-color: #2a2a2a !important; +} /* Priority-based event colors - saturated colors with white text */ .fc-event.priority-p0 { background-color: #dc2626 !important; /* Red 600 */ @@ -130,6 +138,7 @@ active_tab: calendar @@ -170,14 +179,12 @@ active_tab: calendar // Extract priority from title if present (format: [P0], [P1], [P2], [P3]) let priority = event.priority || 'P2'; let displayTitle = event.title || ''; - // Check if title starts with priority tag like [P0], [P1], etc. const priorityMatch = displayTitle.match(/^\[(P[0-3])\]\s*/); if (priorityMatch) { priority = priorityMatch[1]; displayTitle = displayTitle.replace(/^\[(P[0-3])\]\s*/, ''); // Remove priority tag from display } - // Priority-based colors (saturated for white text) const priorityColors = { 'P0': '#dc2626', // Red 600 @@ -185,9 +192,7 @@ active_tab: calendar 'P2': '#ca8a04', // Yellow 600 'P3': '#16a34a' // Green 600 }; - let color = priorityColors[priority] || "#808080"; - // Fall back to class-based colors if no priority detected if (!priorityMatch && !event.priority) { if (event.class == "CSP") { @@ -196,7 +201,6 @@ active_tab: calendar color = "#008000"; } } - allEvents.push({ id: event.id, period: event.period || null, @@ -265,6 +269,7 @@ active_tab: calendar events: events, eventClick: function (info) { document.getElementById("saveButton").style.display = "none"; + document.getElementById("makeBreakButton").style.display = "none"; currentEvent = info.event; document.getElementById('eventTitle').textContent = currentEvent.title; document.getElementById('editTitle').innerHTML = currentEvent.title; @@ -276,10 +281,25 @@ active_tab: calendar document.getElementById("editPriority").value = currentEvent.extendedProps.priority || "P2"; document.getElementById("editPriority").disabled = true; document.getElementById("eventModal").style.display = "block"; - document.getElementById("deleteButton").style.display = "inline-block"; - document.getElementById("editButton").style.display = "inline-block"; + // Check if this is a break event + if (currentEvent.extendedProps.isBreak) { + // For break events, only show delete button + document.getElementById("deleteButton").style.display = "inline-block"; + document.getElementById("editButton").style.display = "none"; + document.getElementById("makeBreakButton").style.display = "none"; + } else { + // For regular events, show edit and delete buttons + document.getElementById("deleteButton").style.display = "inline-block"; + document.getElementById("editButton").style.display = "inline-block"; + } }, dateClick: function (info) { + const selectedDate = formatDate(info.date); + // Check if this date is a break day + if (isBreakDay(selectedDate)) { + alert(`There is already a break on ${formatDisplayDate(info.date)}`); + return; + } isAddingNewEvent = true; document.getElementById("eventTitle").textContent = "Add New Event"; document.getElementById("editTitle").innerHTML = ""; @@ -290,11 +310,12 @@ active_tab: calendar document.getElementById("editPriority").disabled = false; // Enable priority dropdown for new events document.getElementById("editPriority").value = "P2"; // Default to medium priority document.getElementById('editDateDisplay').textContent = formatDisplayDate(info.date); - document.getElementById('editDate').value = formatDate(info.date); + document.getElementById('editDate').value = selectedDate; document.getElementById("eventModal").style.display = "block"; document.getElementById("deleteButton").style.display = "none"; document.getElementById("editButton").style.display = "none"; document.getElementById("saveButton").style.display = "inline-block"; + document.getElementById("makeBreakButton").style.display = "inline-block"; document.getElementById("saveButton").onclick = function () { const updatedTitle = document.getElementById("editTitle").innerHTML.trim(); const updatedDescription = document.getElementById("editDescription").innerHTML; @@ -367,10 +388,16 @@ active_tab: calendar function filterEventsByClass(className) { let filtered = allEvents; if (className) { - filtered = allEvents.filter(event => event.period === className); + // Include break events regardless of filter, plus filtered regular events + filtered = allEvents.filter(event => event.isBreak || event.period === className); } - // Sort by priority (P0 first, then P1, P2, P3) + // Sort by priority (P0 first, then P1, P2, P3), breaks are not prioritized return filtered.sort((a, b) => { + // Breaks always come first + if (a.isBreak && !b.isBreak) return -1; + if (!a.isBreak && b.isBreak) return 1; + if (a.isBreak && b.isBreak) return 0; + // For non-break events, sort by priority const priorityOrder = { 'P0': 0, 'P1': 1, 'P2': 2, 'P3': 3 }; const aPriority = priorityOrder[a.priority] ?? 2; const bPriority = priorityOrder[b.priority] ?? 2; @@ -397,12 +424,10 @@ active_tab: calendar const updatedTitle = document.getElementById("editTitle").innerHTML.trim(); const updatedDescription = document.getElementById("editDescription").innerHTML; const updatedDate = document.getElementById("editDate").value; - // Priority-based colors const priorityColors = { 'P0': '#fecaca', 'P1': '#fed7aa', 'P2': '#fef08a', 'P3': '#bbf7d0' }; - document.getElementById("saveButton").style.display = "none"; document.getElementById('editDateDisplay').style.display = 'block'; document.getElementById('editDate').style.display = 'none'; @@ -534,6 +559,60 @@ active_tab: calendar document.getElementById("eventModal").style.display = "none"; }); }; + document.getElementById("makeBreakButton").onclick = function () { + const breakDate = document.getElementById("editDate").value; + const breakTitle = document.getElementById("editTitle").innerHTML.trim(); + const breakDescription = document.getElementById("editDescription").innerHTML; + console.log("Break creation - Title:", breakTitle, "Date:", breakDate, "Description:", breakDescription); + if (!breakDate) { + alert("Please select a date for the break!"); + return; + } + if (!breakTitle) { + alert("Please enter a name for the break!"); + return; + } + // Check if a break already exists on this date + if (isBreakDay(breakDate)) { + alert(`There is already a break on ${formatDisplayDate(new Date(breakDate.split('-').map(Number)[0], breakDate.split('-').map(Number)[1] - 1, breakDate.split('-').map(Number)[2]))}`); + return; + } + // Parse date string safely to avoid timezone issues + const [year, month, day] = breakDate.split('-').map(Number); + const localDate = new Date(year, month - 1, day); + const confirmation = confirm(`Are you sure you want to make ${formatDisplayDate(localDate)} a break day with the name "${breakTitle}"? Events on this day will be moved to the next non-break day.`); + if (!confirmation) return; + const breakPayload = { + date: breakDate, + name: breakTitle, + description: breakDescription, + moveToNextNonBreakDay: true + }; + console.log("Sending break payload:", breakPayload); + fetch(`${javaURI}/api/calendar/breaks/create`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(breakPayload), + }) + .then(response => { + if (!response.ok) { + return response.text().then(text => { + throw new Error(`Failed to create break: ${response.status} ${response.statusText} - ${text}`); + }); + } + return response.json(); + }) + .then((result) => { + console.log("Break creation response:", result); + alert("Break day created successfully. Events on this day have been moved to the next non-break day."); + document.getElementById("eventModal").style.display = "none"; + handleRequest(); // Refresh the calendar + }) + .catch(error => { + console.error("Error creating break:", error); + alert("Failed to create break day. Please try again.\n\nError: " + error.message); + }); + }; handleRequest(); }); document.addEventListener('keydown', function (event) { @@ -621,4 +700,4 @@ active_tab: calendar day: 'numeric' }); } - + \ No newline at end of file From 7999051643af039ab99a3857c59f850f8b6339a9 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sat, 24 Jan 2026 12:47:03 -0800 Subject: [PATCH 2/5] added break saving functionality to backend API from frontend --- .../calendar/2024-12-16-calendar.md | 78 ++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md index 84480fd5f..68f59d974 100644 --- a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md +++ b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md @@ -155,6 +155,15 @@ active_tab: calendar let currentEvent = null; let isAddingNewEvent = false; let calendar; + function isBreakDay(dateString) { + // Check if the given date is a break day + return allEvents.some(event => event.isBreak && event.start === dateString); + } + function getBreakName(dateString) { + // Get the break name for a given date + const breakEvent = allEvents.find(event => event.isBreak && event.start === dateString); + return breakEvent ? breakEvent.breakName : null; + } function request() { return fetch(`${javaURI}/api/calendar/events`, fetchOptions) .then(response => { @@ -169,9 +178,36 @@ active_tab: calendar return null; }); } + function getAssignments() { + return fetch(`${javaURI}/api/assignments/`) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .catch(error => { + console.error("Error fetching assignments:", error); + return null; + }); + } + function getBreaks() { + return fetch(`${javaURI}/api/calendar/breaks`, fetchOptions) + .then(response => { + if (response.status !== 200) { + console.error("HTTP status code for breaks: " + response.status); + return []; + } + return response.json(); + }) + .catch(error => { + console.error("Fetch error for breaks: ", error); + return []; + }); + } function handleRequest() { - request() - .then((calendarEvents) => { + Promise.all([request(), getAssignments(), getBreaks()]) + .then(([calendarEvents, assignments, breaks]) => { allEvents = []; // Reset allEvents if (calendarEvents !== null) { calendarEvents.forEach(event => { @@ -209,6 +245,7 @@ active_tab: calendar description: event.description, start: event.date, color: color, + isBreak: false, classNames: [`priority-${priority.toLowerCase()}`] }); } catch (err) { @@ -216,6 +253,43 @@ active_tab: calendar } }); } + if (assignments !== null) { + assignments.forEach(assignment => { + try { + const [month, day, year] = assignment.dueDate.split('/'); + const dueDate = new Date(year, month - 1, day).getTime(); + allEvents.push({ + id: assignment.id, + period: assignment.period || null, + title: assignment.name, + description: assignment.description, + start: formatDate(dueDate), + color: "#FFA500", + isBreak: false + }); + } catch (err) { + console.error("Error loading assignment:", assignment, err); + } + }); + } + if (breaks && breaks.length > 0) { + breaks.forEach(breakItem => { + try { + allEvents.push({ + id: breakItem.id, + title: `Break: ${breakItem.name || 'Break'}`, + description: breakItem.description || breakItem.name || 'Break', + start: breakItem.date, + color: "#2a2a2a", + isBreak: true, + breakName: breakItem.name || 'Break', + classNames: ['fc-event-break'] + }); + } catch (err) { + console.error("Error loading break:", breakItem, err); + } + }); + } displayCalendar(filterEventsByClass(currentFilter)); // Display filtered events }); } From fde91920515473d1688b17f290e83bd04786a7a4 Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sun, 25 Jan 2026 19:28:54 -0800 Subject: [PATCH 3/5] breaks display on the calendar, fixed issue with events moving to next non-break day --- .../calendar/2024-12-16-calendar.md | 149 +++++++++++++----- 1 file changed, 107 insertions(+), 42 deletions(-) diff --git a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md index 68f59d974..2ef17e98f 100644 --- a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md +++ b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md @@ -60,7 +60,9 @@ active_tab: calendar /* Break day highlighting */ .fc-event-break { background-color: #2a2a2a !important; - border-color: #1a1a1a !important; + border-color: transparent !important; + border: none !important; + box-shadow: none !important; } .fc-daygrid-day.break-day { @@ -156,13 +158,24 @@ active_tab: calendar let isAddingNewEvent = false; let calendar; function isBreakDay(dateString) { - // Check if the given date is a break day - return allEvents.some(event => event.isBreak && event.start === dateString); + // Check if the given date is a break day by looking at allEvents + const breakEvent = allEvents.find(event => { + const isBreak = (event.extendedProps && event.extendedProps.isBreak === true) || event.isBreak === true; + const dateMatch = formatDate(event.start) === dateString; + console.log(`Checking event: ${event.title}, isBreak: ${isBreak}, dateMatch: ${dateMatch}, eventDate: ${event.start}, checkDate: ${dateString}`); + return isBreak && dateMatch; + }); + console.log(`isBreakDay(${dateString}): ${breakEvent ? 'YES' : 'NO'}`, breakEvent); + return !!breakEvent; } function getBreakName(dateString) { - // Get the break name for a given date - const breakEvent = allEvents.find(event => event.isBreak && event.start === dateString); - return breakEvent ? breakEvent.breakName : null; + // Get the break name for a given date (robust for either top-level or extendedProps storage) + const breakEvent = allEvents.find(event => { + const isBreak = (event.extendedProps && event.extendedProps.isBreak === true) || event.isBreak === true; + return isBreak && formatDate(event.start) === dateString; + }); + if (!breakEvent) return null; + return (breakEvent.extendedProps && breakEvent.extendedProps.breakName) || breakEvent.breakName || breakEvent.title || null; } function request() { return fetch(`${javaURI}/api/calendar/events`, fetchOptions) @@ -192,10 +205,18 @@ active_tab: calendar }); } function getBreaks() { + // Try primary endpoint, then fallback to trailing slash if 404 (some servers require it) return fetch(`${javaURI}/api/calendar/breaks`, fetchOptions) .then(response => { - if (response.status !== 200) { - console.error("HTTP status code for breaks: " + response.status); + if (response.status === 404) { + console.warn('Breaks endpoint returned 404, retrying with trailing slash'); + return fetch(`${javaURI}/api/calendar/breaks/`, fetchOptions); + } + return response; + }) + .then(response => { + if (!response || response.status !== 200) { + console.error("HTTP status code for breaks: " + (response && response.status)); return []; } return response.json(); @@ -208,6 +229,7 @@ active_tab: calendar function handleRequest() { Promise.all([request(), getAssignments(), getBreaks()]) .then(([calendarEvents, assignments, breaks]) => { + console.log("handleRequest - All data loaded. Breaks:", breaks); allEvents = []; // Reset allEvents if (calendarEvents !== null) { calendarEvents.forEach(event => { @@ -243,7 +265,8 @@ active_tab: calendar priority: priority, title: displayTitle.replace(/\(P[13]\)/gi, ""), description: event.description, - start: event.date, + // Normalize stored start to YYYY-MM-DD to avoid timezone parsing as UTC + start: formatDate(event.date), color: color, isBreak: false, classNames: [`priority-${priority.toLowerCase()}`] @@ -273,22 +296,37 @@ active_tab: calendar }); } if (breaks && breaks.length > 0) { + console.log("Breaks loaded:", breaks); breaks.forEach(breakItem => { try { - allEvents.push({ + const breakEvent = { id: breakItem.id, + // Title kept for compatibility but primary name stored in extendedProps.breakName title: `Break: ${breakItem.name || 'Break'}`, description: breakItem.description || breakItem.name || 'Break', - start: breakItem.date, - color: "#2a2a2a", + // Normalize break date to YYYY-MM-DD local representation + start: formatDate(breakItem.date), + backgroundColor: "#2a2a2a", + borderColor: "#1a1a1a", + textColor: "#ffffff", + // Mark consistently on both extendedProps and top-level for different code paths isBreak: true, breakName: breakItem.name || 'Break', + extendedProps: { + isBreak: true, + breakName: breakItem.name || 'Break', + description: breakItem.description || '' + }, classNames: ['fc-event-break'] - }); + }; + console.log("Adding break event:", breakEvent); + allEvents.push(breakEvent); } catch (err) { console.error("Error loading break:", breakItem, err); } }); + } else { + console.log("No breaks found"); } displayCalendar(filterEventsByClass(currentFilter)); // Display filtered events }); @@ -340,13 +378,28 @@ active_tab: calendar dayGridWeek: { buttonText: 'Week' }, dayGridDay: { buttonText: 'Day' } }, + // Highlight break days (no text in the cell; the break event shows the name) + dayCellDidMount: function(arg) { + try { + const dateStr = formatDate(arg.date); + if (isBreakDay(dateStr)) { + arg.el.classList.add('break-day'); + } else { + arg.el.classList.remove('break-day'); + } + } catch (e) { + console.error('dayCellDidMount error:', e); + } + }, events: events, eventClick: function (info) { document.getElementById("saveButton").style.display = "none"; document.getElementById("makeBreakButton").style.display = "none"; currentEvent = info.event; + const isBreak = (currentEvent.extendedProps && currentEvent.extendedProps.isBreak === true) || currentEvent.isBreak === true; + console.log("Event clicked:", currentEvent.title, "isBreak:", isBreak); document.getElementById('eventTitle').textContent = currentEvent.title; - document.getElementById('editTitle').innerHTML = currentEvent.title; + document.getElementById('editTitle').innerHTML = isBreak ? ((currentEvent.extendedProps && currentEvent.extendedProps.breakName) || currentEvent.breakName || currentEvent.title) : currentEvent.title; document.getElementById('editDescription').innerHTML = slackToHtml(currentEvent.extendedProps.description || ""); document.getElementById('editDateDisplay').textContent = formatDisplayDate(currentEvent.start); document.getElementById('editDate').value = formatDate(currentEvent.start); @@ -356,15 +409,17 @@ active_tab: calendar document.getElementById("editPriority").disabled = true; document.getElementById("eventModal").style.display = "block"; // Check if this is a break event - if (currentEvent.extendedProps.isBreak) { - // For break events, only show delete button + if (isBreak) { + // For break events, show edit and delete buttons document.getElementById("deleteButton").style.display = "inline-block"; - document.getElementById("editButton").style.display = "none"; + document.getElementById("editButton").style.display = "inline-block"; document.getElementById("makeBreakButton").style.display = "none"; + document.getElementById("eventModal").dataset.isBreak = "true"; } else { // For regular events, show edit and delete buttons document.getElementById("deleteButton").style.display = "inline-block"; document.getElementById("editButton").style.display = "inline-block"; + document.getElementById("eventModal").dataset.isBreak = "false"; } }, dateClick: function (info) { @@ -463,14 +518,19 @@ active_tab: calendar let filtered = allEvents; if (className) { // Include break events regardless of filter, plus filtered regular events - filtered = allEvents.filter(event => event.isBreak || event.period === className); + filtered = allEvents.filter(event => { + const isBreak = event.extendedProps && event.extendedProps.isBreak === true; + return isBreak || event.period === className; + }); } // Sort by priority (P0 first, then P1, P2, P3), breaks are not prioritized return filtered.sort((a, b) => { // Breaks always come first - if (a.isBreak && !b.isBreak) return -1; - if (!a.isBreak && b.isBreak) return 1; - if (a.isBreak && b.isBreak) return 0; + const aIsBreak = a.extendedProps && a.extendedProps.isBreak === true; + const bIsBreak = b.extendedProps && b.extendedProps.isBreak === true; + if (aIsBreak && !bIsBreak) return -1; + if (!aIsBreak && bIsBreak) return 1; + if (aIsBreak && bIsBreak) return 0; // For non-break events, sort by priority const priorityOrder = { 'P0': 0, 'P1': 1, 'P2': 2, 'P3': 3 }; const aPriority = priorityOrder[a.priority] ?? 2; @@ -478,9 +538,15 @@ active_tab: calendar return aPriority - bPriority; }); } - function formatDate(dateString) { - const date = new Date(dateString); - return date.toISOString().split("T")[0]; + function formatDate(dateInput) { + // If already a YYYY-MM-DD string, return as-is to avoid UTC parsing issues + if (!dateInput && dateInput !== 0) return ''; + if (typeof dateInput === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(dateInput)) return dateInput; + const d = (dateInput instanceof Date) ? dateInput : new Date(dateInput); + const year = d.getFullYear(); + const month = String(d.getMonth() + 1).padStart(2, '0'); + const day = String(d.getDate()).padStart(2, '0'); + return `${year}-${month}-${day}`; } document.getElementById("closeModal").onclick = function () { document.getElementById('editDateDisplay').style.display = 'block'; @@ -493,20 +559,15 @@ active_tab: calendar document.getElementById("eventModal").style.display = "none"; }; document.getElementById("saveButton").onclick = function () { - const updatedPeriod = document.getElementById("editPeriod").value; - const updatedPriority = document.getElementById("editPriority").value; + const isBreak = document.getElementById("eventModal").dataset.isBreak === "true"; const updatedTitle = document.getElementById("editTitle").innerHTML.trim(); - const updatedDescription = document.getElementById("editDescription").innerHTML; - const updatedDate = document.getElementById("editDate").value; - // Priority-based colors - const priorityColors = { - 'P0': '#fecaca', 'P1': '#fed7aa', 'P2': '#fef08a', 'P3': '#bbf7d0' - }; + const updatedDescription = document.getElementById("editDescription").innerHTML; + // Reset UI state document.getElementById("saveButton").style.display = "none"; document.getElementById('editDateDisplay').style.display = 'block'; document.getElementById('editDate').style.display = 'none'; - document.getElementById('editDateDisplay').textContent = formatDisplayDate(new Date(updatedDate)); document.getElementById("editDescription").contentEditable = false; + document.getElementById("editTitle").contentEditable = false; document.getElementById("editPeriod").disabled = true; document.getElementById("editPriority").disabled = true; if (!updatedTitle || !updatedDescription || !updatedDate) { @@ -597,40 +658,44 @@ active_tab: calendar } }; document.getElementById("editButton").onclick = function () { + const isBreak = document.getElementById("eventModal").dataset.isBreak === "true"; document.getElementById('editDateDisplay').style.display = 'none'; - document.getElementById('editDate').style.display = 'block'; + document.getElementById('editDate').style.display = isBreak ? 'none' : 'block'; document.getElementById("deleteButton").style.display = 'none'; document.getElementById("saveButton").style.display = 'inline-block'; document.getElementById("editDescription").contentEditable = true; document.getElementById("editTitle").contentEditable = true; - document.getElementById("editPeriod").disabled = false; // Enable only on edit - document.getElementById("editPriority").disabled = false; // Enable priority on edit + if (!isBreak) { + document.getElementById("editPeriod").disabled = false; + document.getElementById("editPriority").disabled = false; + } document.getElementById("editDescription").innerHTML = currentEvent.extendedProps.description || ""; }; document.getElementById("deleteButton").onclick = function () { if (!currentEvent) return; + const isBreak = document.getElementById("eventModal").dataset.isBreak === "true"; const id = currentEvent.id; const confirmation = confirm(`Are you sure you want to delete "${currentEvent.title}"?`); if (!confirmation) return; - fetch(`${javaURI}/api/calendar/delete/${id}`, { + const endpoint = isBreak ? `${javaURI}/api/calendar/breaks/${id}` : `${javaURI}/api/calendar/delete/${id}`; + fetch(endpoint, { method: "DELETE", headers: { "Content-Type": "application/json" } }) .then(response => { if (!response.ok) { - throw new Error(`Failed to delete event: ${response.status} ${response.statusText}`); + throw new Error(`Failed to delete: ${response.status} ${response.statusText}`); } return response.text(); }) .then(() => { currentEvent.remove(); document.getElementById("eventModal").style.display = "none"; + handleRequest(); }) .catch(error => { - console.error("Error deleting event:", error); - alert("This event has been removed from the calendar but could not be deleted from Slack."); - currentEvent.remove(); - document.getElementById("eventModal").style.display = "none"; + console.error("Error deleting:", error); + alert("Failed to delete. Please try again.\n\nError: " + error.message); }); }; document.getElementById("makeBreakButton").onclick = function () { From e12ab9468baab003da37dd327e5c80fbdab8292a Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sun, 25 Jan 2026 19:30:53 -0800 Subject: [PATCH 4/5] added editing and deleting functionality to breaks --- .../calendar/2024-12-16-calendar.md | 150 +++++++++--------- 1 file changed, 79 insertions(+), 71 deletions(-) diff --git a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md index 2ef17e98f..61c22e0d8 100644 --- a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md +++ b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md @@ -569,92 +569,100 @@ active_tab: calendar document.getElementById("editDescription").contentEditable = false; document.getElementById("editTitle").contentEditable = false; document.getElementById("editPeriod").disabled = true; - document.getElementById("editPriority").disabled = true; - if (!updatedTitle || !updatedDescription || !updatedDate) { - alert("Title, Description, and Date cannot be empty!"); + document.getElementById("editPriority").disabled = true; + if (!updatedTitle || !updatedDescription) { + alert("Title and Description cannot be empty!"); return; - } - if (isAddingNewEvent) { - const newEventPayload = { - title: updatedTitle, - description: updatedDescription, - date: updatedDate, - period: updatedPeriod, // Event class (CSA, CSP, CSSE) - priority: updatedPriority - }; - console.log(updatedPeriod); - fetch(`${javaURI}/api/calendar/add_event`, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify(newEventPayload), - }) - .then(response => { - if (!response.ok) { - throw new Error(`Failed to add new event: ${response.status} ${response.statusText}`); - } - return response.json(); // Parse the response JSON if needed - }) - .then(newEvent => { - calendar.addEvent({ - id: newEvent.id, - title: newEvent.title, - start: newEvent.date, - description: newEvent.description, - priority: updatedPriority, - color: priorityColors[updatedPriority] || "#808080", - classNames: [`priority-${updatedPriority.toLowerCase()}`] - }); - document.getElementById("eventModal").style.display = "none"; - }) - .catch(error => { - console.warn("Error adding event to Slack:", error); - alert("This event has been added to the calendar but could not be updated in Slack."); - calendar.addEvent({ - title: updatedTitle, - start: updatedDate, - description: updatedDescription, - priority: updatedPriority, - color: priorityColors[updatedPriority] || "#808080", - classNames: [`priority-${updatedPriority.toLowerCase()}`] - }); - document.getElementById("eventModal").style.display = "none"; - }); - } else { - const payload = { newTitle: updatedTitle, description: updatedDescription, date: updatedDate, period: updatedPeriod, priority: updatedPriority }; + } + if (isBreak) { + // Handle break editing const id = currentEvent.id; - fetch(`${javaURI}/api/calendar/edit/${id}`, { + const breakPayload = { + name: updatedTitle, + description: updatedDescription + }; + fetch(`${javaURI}/api/calendar/breaks/${id}`, { method: "PUT", headers: { "Content-Type": "application/json" }, - body: JSON.stringify(payload), + body: JSON.stringify(breakPayload), }) .then(response => { if (!response.ok) { - throw new Error(`Failed to update event: ${response.status} ${response.statusText}`); + throw new Error(`Failed to update break: ${response.status} ${response.statusText}`); } - return response.text(); + return response.json(); }) .then(() => { - currentEvent.setProp("title", updatedTitle); - currentEvent.setExtendedProp("description", updatedDescription); - currentEvent.setStart(updatedDate); - currentEvent.setExtendedProp("period", updatedPeriod); - currentEvent.setExtendedProp("priority", updatedPriority); - currentEvent.setProp("color", priorityColors[updatedPriority] || "#808080"); document.getElementById("eventModal").style.display = "none"; - // Refresh calendar to apply new priority styling handleRequest(); }) .catch(error => { - console.warn("Error updating event in Slack:", error); - alert("This event has been updated in the calendar but could not be updated in Slack."); - currentEvent.setProp("title", updatedTitle); - currentEvent.setExtendedProp("description", updatedDescription); - currentEvent.setStart(updatedDate); - currentEvent.setExtendedProp("priority", updatedPriority); - currentEvent.setProp("color", priorityColors[updatedPriority] || "#808080"); - document.getElementById("eventModal").style.display = "none"; - handleRequest(); + console.error("Error updating break:", error); + alert("Failed to update break. Please try again.\n\nError: " + error.message); }); + } else { + // Handle regular event editing + const updatedPeriod = document.getElementById("editPeriod").value; + const updatedPriority = document.getElementById("editPriority").value; + const updatedDate = document.getElementById("editDate").value; + const priorityColors = { + 'P0': '#fecaca', 'P1': '#fed7aa', 'P2': '#fef08a', 'P3': '#bbf7d0' + }; + document.getElementById('editDateDisplay').textContent = formatDisplayDate(new Date(updatedDate)); + if (!updatedDate) { + alert("Date cannot be empty!"); + return; + } + if (isAddingNewEvent) { + const newEventPayload = { + title: updatedTitle, + description: updatedDescription, + date: updatedDate, + period: updatedPeriod, + priority: updatedPriority + }; + fetch(`${javaURI}/api/calendar/add_event`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(newEventPayload), + }) + .then(response => { + if (!response.ok) { + throw new Error(`Failed to add new event: ${response.status} ${response.statusText}`); + } + return response.json(); + }) + .then(() => { + document.getElementById("eventModal").style.display = "none"; + handleRequest(); + }) + .catch(error => { + console.error("Error adding event:", error); + alert("Failed to add event. Please try again.\n\nError: " + error.message); + }); + } else { + const payload = { newTitle: updatedTitle, description: updatedDescription, date: updatedDate, period: updatedPeriod, priority: updatedPriority }; + const id = currentEvent.id; + fetch(`${javaURI}/api/calendar/edit/${id}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }) + .then(response => { + if (!response.ok) { + throw new Error(`Failed to update event: ${response.status} ${response.statusText}`); + } + return response.text(); + }) + .then(() => { + document.getElementById("eventModal").style.display = "none"; + handleRequest(); + }) + .catch(error => { + console.error("Error updating event:", error); + alert("Failed to update event. Please try again.\n\nError: " + error.message); + }); + } } }; document.getElementById("editButton").onclick = function () { From c46a653215f9026714a674583dafb3948cc0d37b Mon Sep 17 00:00:00 2001 From: anonymous-dyce Date: Sun, 25 Jan 2026 19:40:48 -0800 Subject: [PATCH 5/5] fixed issues with editing events, removed getAsssignments() function --- .../calendar/2024-12-16-calendar.md | 42 ++++--------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md index 61c22e0d8..5f92c19da 100644 --- a/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md +++ b/_posts/student_toolkit/ProductivityFrontend/calendar/2024-12-16-calendar.md @@ -191,19 +191,7 @@ active_tab: calendar return null; }); } - function getAssignments() { - return fetch(`${javaURI}/api/assignments/`) - .then(response => { - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - return response.json(); - }) - .catch(error => { - console.error("Error fetching assignments:", error); - return null; - }); - } + // getAssignments removed - assignments are no longer fetched here function getBreaks() { // Try primary endpoint, then fallback to trailing slash if 404 (some servers require it) return fetch(`${javaURI}/api/calendar/breaks`, fetchOptions) @@ -227,8 +215,8 @@ active_tab: calendar }); } function handleRequest() { - Promise.all([request(), getAssignments(), getBreaks()]) - .then(([calendarEvents, assignments, breaks]) => { + Promise.all([request(), getBreaks()]) + .then(([calendarEvents, breaks]) => { console.log("handleRequest - All data loaded. Breaks:", breaks); allEvents = []; // Reset allEvents if (calendarEvents !== null) { @@ -276,25 +264,7 @@ active_tab: calendar } }); } - if (assignments !== null) { - assignments.forEach(assignment => { - try { - const [month, day, year] = assignment.dueDate.split('/'); - const dueDate = new Date(year, month - 1, day).getTime(); - allEvents.push({ - id: assignment.id, - period: assignment.period || null, - title: assignment.name, - description: assignment.description, - start: formatDate(dueDate), - color: "#FFA500", - isBreak: false - }); - } catch (err) { - console.error("Error loading assignment:", assignment, err); - } - }); - } + // assignments removed from frontend; no processing here if (breaks && breaks.length > 0) { console.log("Breaks loaded:", breaks); breaks.forEach(breakItem => { @@ -396,6 +366,8 @@ active_tab: calendar document.getElementById("saveButton").style.display = "none"; document.getElementById("makeBreakButton").style.display = "none"; currentEvent = info.event; + // When an existing event is clicked, this is not an 'add' flow + isAddingNewEvent = false; const isBreak = (currentEvent.extendedProps && currentEvent.extendedProps.isBreak === true) || currentEvent.isBreak === true; console.log("Event clicked:", currentEvent.title, "isBreak:", isBreak); document.getElementById('eventTitle').textContent = currentEvent.title; @@ -673,6 +645,8 @@ active_tab: calendar document.getElementById("saveButton").style.display = 'inline-block'; document.getElementById("editDescription").contentEditable = true; document.getElementById("editTitle").contentEditable = true; + // Editing an existing event should not create a new one + isAddingNewEvent = false; if (!isBreak) { document.getElementById("editPeriod").disabled = false; document.getElementById("editPriority").disabled = false;