From 91a87ebe9cd1254059ee7e4bd7211e35e29d662f Mon Sep 17 00:00:00 2001 From: Besher Kitaz Date: Tue, 24 Jun 2025 14:52:10 -0400 Subject: [PATCH 01/33] Added the field for location in HTML only --- app/templates/events/createEvent.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/templates/events/createEvent.html b/app/templates/events/createEvent.html index 3a69a75a7..f82082e85 100644 --- a/app/templates/events/createEvent.html +++ b/app/templates/events/createEvent.html @@ -534,11 +534,16 @@

Generated Events:


-
+
+
+ + +
From 766a9b25c5aaaf114362ba9d0dce29dae56a0d9e Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Wed, 25 Jun 2025 16:41:55 -0400 Subject: [PATCH 02/33] Fixed the location field in the create event form to disappear when the user selects multimodal offer. --- app/static/js/createEvents.js | 22 ++++++++++++---------- app/templates/events/createEvent.html | 5 +++-- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 769a6421f..943b3f4c7 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -61,6 +61,8 @@ function calculateRepeatingEventFrequency(){ function setViewForSingleOffering(){ $(".startDatePicker").prop('required', true); $("#multipleOfferingTableDiv").addClass('d-none'); + $("#eventLocation-main").removeClass('d-none'); + $("#inputEventLocation-main").prop('required', true); $('#eventTime, #eventDate').removeClass('d-none'); $('#checkIsSeriesToggleContainer').addClass('col-md-6') $('#checkIsSeriesToggleContainer').removeClass('col-md-12') @@ -69,6 +71,8 @@ function setViewForSingleOffering(){ function setViewForSeries(){ $(".startDatePicker").prop('required', false); $("#multipleOfferingTableDiv").removeClass('d-none'); + $("#eventLocation-main").addClass('d-none'); + $("#inputEventLocation-main").prop('required', false); $('#eventTime, #eventDate').addClass('d-none'); $('#checkIsSeriesToggleContainer').removeClass('col-md-6') $('#checkIsSeriesToggleContainer').addClass('col-md-12') @@ -256,12 +260,7 @@ function updateEventNameField() { // Check if the event is weekly if (!isSeries) { // if not weeekly, add them to a set to remove duplicates, then put them in a string to populate the field - let names = new Set() - offerings.forEach(offering => { - names.add(offering.eventName) - }); - let offeringsText = Array.from(names).join(", ") - $('#inputEventName').prop('placeholder', offeringsText) + $('#inputEventName').prop('placeholder', '') } else { // if weekly, take the name of the first item (which is the same for all) and take the word 'week' @@ -290,16 +289,17 @@ function saveOfferingsFromModal() { else { rowData = $.map($(element).find("input"), (el) => $(el).val()); } - - let startTime = isRepeatingStatus ? $("#repeatingEventsStartTime").val() : rowData[2] - let endTime = isRepeatingStatus ? $("#repeatingEventsEndTime").val() : rowData[3] + console.log(rowData); + let startTime = isRepeatingStatus ? $("#repeatingEventsStartTime").val() : rowData[3] + let endTime = isRepeatingStatus ? $("#repeatingEventsEndTime").val() : rowData[4] if (navigator.userAgent.indexOf("Chrome") == -1) { startTime = format12to24HourTime(startTime) endTime = format12to24HourTime(endTime) } offerings.push({ eventName: rowData[0], - eventDate: rowData[1], + eventLocation: rowData[1], + eventDate: rowData[2], startTime: startTime, endTime: endTime, }) @@ -369,6 +369,7 @@ function updateOfferingsTable() { "" + formattedEventDate + "" + "" + startTime + "" + "" + endTime + "" + + "" + offering.eventLocation + "" + "" ); }); @@ -463,6 +464,7 @@ $(document).ready(function() { if ($("#checkIsSeries").is(":checked")){ setViewForSeries(); } + let modalOpenedByEditButton = false; //#checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page diff --git a/app/templates/events/createEvent.html b/app/templates/events/createEvent.html index 86d1cc30c..b620dcced 100644 --- a/app/templates/events/createEvent.html +++ b/app/templates/events/createEvent.html @@ -61,7 +61,7 @@

{{page_title}}

{% endblock %} {% macro locationTimeMacro(eventData, isNewEvent, pageLocation) %} -
+
@@ -89,7 +89,7 @@

{{page_title}}

- +
@@ -176,6 +176,7 @@

{{page_title}}

Date Start Time End Time + Location From eb96c7977a08bfa0d36fcd6a4c3e132c57dcd3cb Mon Sep 17 00:00:00 2001 From: Besher Kitaz Date: Thu, 26 Jun 2025 16:04:46 -0400 Subject: [PATCH 03/33] Now it is mandatory to enter a name before toggling the multi offerings toggle --- app/static/js/createEvents.js | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 769a6421f..cb97ed847 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -106,8 +106,8 @@ function initializeFlatpickr(obj) { }); } +let eventSessionNum = 2 function createOfferingModalRow({eventName=null, eventDate=null, startTime=null, endTime=null}={}){ - let clonedOffering = $("#multipleOfferingEvent").clone().removeClass('d-none').removeAttr("id"); // insert values for the newly created row @@ -115,7 +115,8 @@ function createOfferingModalRow({eventName=null, eventDate=null, startTime=null, if (eventDate) {clonedOffering.find('.multipleOfferingDatePicker').val(eventDate)} if (startTime) {clonedOffering.find('.multipleOfferingStartTime').val(startTime)} if (endTime) {clonedOffering.find('.multipleOfferingEndTime').val(endTime)} - + $('#eventName').val($('#inputEventName').val() + ': session ' + eventSessionNum); + eventSessionNum++; $("#multipleOfferingSlots").append(clonedOffering); pendingmultipleEvents.push(clonedOffering); @@ -253,7 +254,6 @@ function updateEventNameField() { let offerings = JSON.parse($("#seriesData").val()) let isSeries = $("#checkIsRepeating").is(":checked") - // Check if the event is weekly if (!isSeries) { // if not weeekly, add them to a set to remove duplicates, then put them in a string to populate the field let names = new Set() @@ -369,6 +369,7 @@ function updateOfferingsTable() { "" + formattedEventDate + "" + "" + startTime + "" + "" + endTime + "" + + ""+ offering.location +"" + "" ); }); @@ -465,24 +466,29 @@ $(document).ready(function() { } let modalOpenedByEditButton = false; - //#checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page + //#checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page] + + $("#checkIsSeries, #edit_modal").click(function(event) { + eventSessionNum = 2 + $('#eventName').val($('#inputEventName').val() + ': session 1') - if(!($('#inputEventName').val().trim() == '')){ - //keeps main page event name for multiple event modal - $('#eventName').val($('#inputEventName').val()); - } let isSeries = $("#checkIsSeries").is(":checked") modalOpenedByEditButton = ($(this).attr('id') === 'edit_modal'); if (isSeries) { + if(($('#inputEventName').val().trim() == '')){ + //keeps main page event name for multiple event modal + $('#checkIsSeries').prop('checked', false) + msgFlash("Please type the event name first") + return + } setViewForSeries(); loadOfferingsToModal(); $('#modalSeries').modal('show'); // Disable single event name field $('#inputEventName').prop('readonly', true) - $('#inputEventName').val('') } else { setViewForSingleOffering() $('#multipleOfferingTableDiv').addClass('d-none'); From 96a49bcf6e72bf6545524d75b54225affe3ebe3b Mon Sep 17 00:00:00 2001 From: Besher Kitaz Date: Thu, 26 Jun 2025 17:01:12 -0400 Subject: [PATCH 04/33] Added location field for weekly event offerings modal. --- app/templates/events/createEvent.html | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/templates/events/createEvent.html b/app/templates/events/createEvent.html index 6d694bb6b..915c59eaa 100644 --- a/app/templates/events/createEvent.html +++ b/app/templates/events/createEvent.html @@ -452,11 +452,9 @@ {% endif %}
-
- -
+
This is an event with multiple time offerings. id='repeatingEventsNamePicker' />
+
+ +
+ +
+
From 4c5559b4aec295e391b3b4c9930b53a5458ee3ff Mon Sep 17 00:00:00 2001 From: Besher Kitaz Date: Sat, 28 Jun 2025 12:43:59 -0400 Subject: [PATCH 05/33] Location field moved to the modal for weekly events --- app/logic/events.py | 8 ++++---- app/static/js/createEvents.js | 18 ++++++++++++------ app/templates/events/createEvent.html | 5 +++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/app/logic/events.py b/app/logic/events.py index f7e63cfac..b1f5a077e 100644 --- a/app/logic/events.py +++ b/app/logic/events.py @@ -130,7 +130,8 @@ def attemptSaveMultipleOfferings(eventData, attachmentFiles = None): 'timeStart': event['startTime'], 'timeEnd': event['endTime'], 'seriesId': seriesId, - 'isRepeating': bool(isRepeating) + 'isRepeating': bool(isRepeating), + 'location': event['eventLocation'], }) # Try to save each offering savedEvents, validationErrorMessage = attemptSaveEvent(eventInfo, attachmentFiles) @@ -453,9 +454,9 @@ def getRepeatingEventsData(eventData): Return a list of events to create from the event data. """ - return [ {'name': f"{eventData['name']} Week {counter+1}", 'date': eventData['startDate'] + timedelta(days=7*counter), + 'location': eventData['location'], "week": counter+1} for counter in range(0, ((eventData['endDate']-eventData['startDate']).days//7)+1)] @@ -499,7 +500,7 @@ def preprocessEventData(eventData): eventData['term'] = Term.get_by_id(eventData['term']) except DoesNotExist: eventData['term'] = '' - + # Process requirement if 'certRequirement' in eventData: try: @@ -516,7 +517,6 @@ def preprocessEventData(eventData): if 'timeEnd' in eventData: eventData['timeEnd'] = format24HourTime(eventData['timeEnd']) - return eventData def getTomorrowsEvents(): diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index ccd5f6ee1..1987b7257 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -37,7 +37,10 @@ function calculateRepeatingEventFrequency(){ var eventDatesAndName = {name:$("#repeatingEventsNamePicker").val(), isRepeating: true, startDate:$("#repeatingEventsStartDate").val(), - endDate:$("#repeatingEventsEndDate").val()} + endDate:$("#repeatingEventsEndDate").val(), + location:$("#repeatingEventsLocationPicker").val() + } + console.log(eventDatesAndName); $.ajax({ type:"POST", url: "/makeRepeatingEvents", @@ -157,6 +160,7 @@ $('#saveSeries').on('click', function() { //Requires that modal info updated before it can be saved, gives notifier if there are empty fields let eventOfferings = $('#multipleOfferingSlots .eventOffering'); let eventNameInputs = $('#multipleOfferingSlots .multipleOfferingNameField'); + let eventLocationInput = $('') let datePickerInputs = $('#multipleOfferingSlots .multipleOfferingDatePicker'); let startTimeInputs = $('#multipleOfferingSlots .multipleOfferingStartTime'); let endTimeInputs = $('#multipleOfferingSlots .multipleOfferingEndTime'); @@ -188,7 +192,6 @@ $('#saveSeries').on('click', function() { } }); - // Check if the start time is after the end time for(let i = 0; i < startTimeInputs.length; i++){ let startTime = startTimeInputs[i].value @@ -220,7 +223,7 @@ $('#saveSeries').on('click', function() { let eventName = eventNameInputs[i].value let date = datePickerInputs[i].value.trim() let startTime = startTimeInputs[i].value - let eventListing = JSON.stringify([eventName, date, startTime]) + let eventListing = JSON.stringify([eventName, date, startTime, location]) if (eventListing in eventListings){ // If we've seen this event before mark this event and the previous as duplicates hasDuplicateListings = true @@ -289,7 +292,7 @@ function saveOfferingsFromModal() { else { rowData = $.map($(element).find("input"), (el) => $(el).val()); } - console.log(rowData); + let startTime = isRepeatingStatus ? $("#repeatingEventsStartTime").val() : rowData[3] let endTime = isRepeatingStatus ? $("#repeatingEventsEndTime").val() : rowData[4] if (navigator.userAgent.indexOf("Chrome") == -1) { @@ -298,8 +301,8 @@ function saveOfferingsFromModal() { } offerings.push({ eventName: rowData[0], - eventLocation: rowData[1], - eventDate: rowData[2], + eventLocation: isRepeatingStatus ? rowData[2] : rowData[1], + eventDate: isRepeatingStatus ? rowData[1] : rowData[2], startTime: startTime, endTime: endTime, }) @@ -345,10 +348,13 @@ function loadOfferingsToModal(){ function loadRepeatingOfferingToModal(offering){ var seriesTable = $("#generatedEventsTable"); var eventDate = new Date(offering.date || offering.eventDate).toLocaleDateString(); + console.log(offering); + seriesTable.append( "" + "" + (offering.name || offering.eventName) + "" + "" + eventDate + "" + + "" + offering.location + "" + "
" + "" ); diff --git a/app/templates/events/createEvent.html b/app/templates/events/createEvent.html index 915c59eaa..9300b65c3 100644 --- a/app/templates/events/createEvent.html +++ b/app/templates/events/createEvent.html @@ -464,12 +464,12 @@
- +
+ id='repeatingEventsLocationPicker' />
@@ -536,6 +536,7 @@

Generated Events:

Event Name Date + Location Action From 8610ab6c15e22513f9c0ee56fe216998bf73a8ca Mon Sep 17 00:00:00 2001 From: chapagainp Date: Mon, 30 Jun 2025 11:29:21 -0400 Subject: [PATCH 06/33] Added the eventLocation --- app/logic/events.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/logic/events.py b/app/logic/events.py index b1f5a077e..94b7f8ab2 100644 --- a/app/logic/events.py +++ b/app/logic/events.py @@ -130,8 +130,8 @@ def attemptSaveMultipleOfferings(eventData, attachmentFiles = None): 'timeStart': event['startTime'], 'timeEnd': event['endTime'], 'seriesId': seriesId, - 'isRepeating': bool(isRepeating), - 'location': event['eventLocation'], + 'isRepeating': bool(isRepeating), + 'location': event['eventLocation'] }) # Try to save each offering savedEvents, validationErrorMessage = attemptSaveEvent(eventInfo, attachmentFiles) @@ -454,10 +454,12 @@ def getRepeatingEventsData(eventData): Return a list of events to create from the event data. """ + return [ {'name': f"{eventData['name']} Week {counter+1}", 'date': eventData['startDate'] + timedelta(days=7*counter), - 'location': eventData['location'], - "week": counter+1} + "week": counter+1, + 'location': eventData['location'] + } for counter in range(0, ((eventData['endDate']-eventData['startDate']).days//7)+1)] def preprocessEventData(eventData): @@ -500,7 +502,7 @@ def preprocessEventData(eventData): eventData['term'] = Term.get_by_id(eventData['term']) except DoesNotExist: eventData['term'] = '' - + # Process requirement if 'certRequirement' in eventData: try: @@ -517,6 +519,7 @@ def preprocessEventData(eventData): if 'timeEnd' in eventData: eventData['timeEnd'] = format24HourTime(eventData['timeEnd']) + return eventData def getTomorrowsEvents(): From 15fddfc85f0f2c2de1113b42316709e85da573e8 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Tue, 1 Jul 2025 11:28:13 -0400 Subject: [PATCH 07/33] fixed the location error --- app/logic/events.py | 2 +- tests/code/test_events.py | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/logic/events.py b/app/logic/events.py index 94b7f8ab2..0f40f9da8 100644 --- a/app/logic/events.py +++ b/app/logic/events.py @@ -129,9 +129,9 @@ def attemptSaveMultipleOfferings(eventData, attachmentFiles = None): 'startDate': event['eventDate'], 'timeStart': event['startTime'], 'timeEnd': event['endTime'], + 'location': eventData['location'], 'seriesId': seriesId, 'isRepeating': bool(isRepeating), - 'location': event['eventLocation'] }) # Try to save each offering savedEvents, validationErrorMessage = attemptSaveEvent(eventInfo, attachmentFiles) diff --git a/tests/code/test_events.py b/tests/code/test_events.py index c7a8ebdda..4065c7017 100644 --- a/tests/code/test_events.py +++ b/tests/code/test_events.py @@ -299,13 +299,15 @@ def test_calculateRecurringEventFrequency(): eventInfo = {'name': "testEvent", 'startDate': parser.parse("02/22/2023"), - 'endDate': parser.parse("03/11/2023")} + 'endDate': parser.parse("03/11/2023"), + 'location':("a big room")} # test correct response returnedEvents = getRepeatingEventsData(eventInfo) - assert returnedEvents[0] == {'name': 'testEvent Week 1', 'date': parser.parse('02/22/2023'), 'week': 1} - assert returnedEvents[1] == {'name': 'testEvent Week 2', 'date': parser.parse('03/01/2023'), 'week': 2} - assert returnedEvents[2] == {'name': 'testEvent Week 3', 'date': parser.parse('03/08/2023'), 'week': 3} + assert returnedEvents[0] == {'name': 'testEvent Week 1', 'date': parser.parse('02/22/2023'), 'week': 1, 'location': 'a big room'} + assert returnedEvents[1] == {'name': 'testEvent Week 2', 'date': parser.parse('03/01/2023'), 'week': 2, 'location': 'a big room'} + assert returnedEvents[2] == {'name': 'testEvent Week 3', 'date': parser.parse('03/08/2023'), 'week': 3, 'location': 'a big room'} + # test non-datetime eventInfo["startDate"] = '2021/06/07' From e01f7d741de2240ad3465a622f0299f75db0601e Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Tue, 1 Jul 2025 15:34:24 -0400 Subject: [PATCH 08/33] added event location --- app/controllers/admin/routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index 88ca5f655..baf4a7b2e 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -71,7 +71,7 @@ def switchUser(): @admin_bp.route('/eventTemplates') def templateSelect(): - if g.current_user.isCeltsAdmin or g.current_user.isCeltsStudentStaff: + if g.current_user.isCeltsAdmin or g.current_user.isCeltsStudentStaff or g.current_user.isStudent: allprograms = getAllowedPrograms(g.current_user) visibleTemplates = getAllowedTemplates(g.current_user) return render_template("/events/templateSelector.html", @@ -84,7 +84,7 @@ def templateSelect(): @admin_bp.route('/eventTemplates///create', methods=['GET','POST']) def createEvent(templateid, programid): - if not (g.current_user.isAdmin or g.current_user.isProgramManagerFor(programid)): + if not (g.current_user.isAdmin or g.current_user.isProgramManagerFor(programid) or g.current_user.isStudent): abort(403) # Validate given URL From bbe4ee842a11b38a82d3a9c660c2a66ec2d6e8d7 Mon Sep 17 00:00:00 2001 From: chapagainp Date: Wed, 2 Jul 2025 16:34:16 -0400 Subject: [PATCH 09/33] Fixed the issue for Location in the Modal --- app/static/js/createEvents.js | 96 ++++++++++++++++++--------- app/templates/events/createEvent.html | 2 +- 2 files changed, 65 insertions(+), 33 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 1987b7257..7e097dae4 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -113,16 +113,21 @@ function initializeFlatpickr(obj) { }); } -let eventSessionNum = 2 -function createOfferingModalRow({eventName=null, eventDate=null, startTime=null, endTime=null}={}){ +let eventSessionNum = 0; +function createOfferingModalRow({eventName=null, eventDate=null, startTime=null, endTime=null, eventLocation = null}={}){ let clonedOffering = $("#multipleOfferingEvent").clone().removeClass('d-none').removeAttr("id"); + const baseName = $('#inputEventName').val(); + const fullName = baseName + ': session ' + (eventSessionNum + 1); + clonedOffering.find('.multipleOfferingNameField').val(fullName); + // insert values for the newly created row if (eventName) {clonedOffering.find('.multipleOfferingNameField').val(eventName)} if (eventDate) {clonedOffering.find('.multipleOfferingDatePicker').val(eventDate)} if (startTime) {clonedOffering.find('.multipleOfferingStartTime').val(startTime)} if (endTime) {clonedOffering.find('.multipleOfferingEndTime').val(endTime)} - $('#eventName').val($('#inputEventName').val() + ': session ' + eventSessionNum); + if (eventLocation) {clonedOffering.find('.multipleOfferingLocationField').val(eventLocation)} + eventSessionNum++; $("#multipleOfferingSlots").append(clonedOffering); pendingmultipleEvents.push(clonedOffering); @@ -164,6 +169,7 @@ $('#saveSeries').on('click', function() { let datePickerInputs = $('#multipleOfferingSlots .multipleOfferingDatePicker'); let startTimeInputs = $('#multipleOfferingSlots .multipleOfferingStartTime'); let endTimeInputs = $('#multipleOfferingSlots .multipleOfferingEndTime'); + let locationInputs = $('#multipleOfferingSlots .multipleOfferingLocationField'); let isRepeatingStatus = $("#checkIsRepeating").is(":checked"); let dataTable = isRepeatingStatus ? "#generatedEventsList" : "#multipleOfferingSlots"; let isEmpty = false; @@ -190,7 +196,16 @@ $('#saveSeries').on('click', function() { } else { $(datePickerInput).removeClass('border-red'); } - }); + }); + + locationInputs.each((index, locationInput) => { + if (locationInput.value.trim() === '') { + isEmpty = true; + $(locationInput).addClass('border-red'); + } else { + $(locationInput).removeClass('border-red'); + } + }); // Check if the start time is after the end time for(let i = 0; i < startTimeInputs.length; i++){ @@ -233,7 +248,7 @@ $('#saveSeries').on('click', function() { } if (isEmpty){ - let emptyFieldMessage = "Event name or date field is empty"; + let emptyFieldMessage = "Event name, date or location field is empty"; displayNotification(emptyFieldMessage); } else if (!hasValidTimes) { @@ -334,15 +349,19 @@ function loadOfferingsToModal(){ let offerings = JSON.parse($("#seriesData").val()) if (offerings.length < 1) {return;} let isRepeatingStatus = $("#checkIsRepeating").is(":checked"); + let mainLocation = $('#inputEventLocation-main').val(); if (isRepeatingStatus) {$("#generatedEvents").removeClass("d-none"); $("#generatedEventsTable tbody tr").remove();}; offerings.forEach((offering, i) =>{ if (isRepeatingStatus){ loadRepeatingOfferingToModal(offering); } else { - let newOfferingModalRow = createOfferingModalRow(offering); + let newOfferingModalRow = createOfferingModalRow({ + ...offering, + eventLocation: offering.eventLocation || mainLocation + }); //stripes odd event sections in event modal newOfferingModalRow.css('background-color', i % 2 ?'#f2f2f2':'#fff'); - }}) + }}); } function loadRepeatingOfferingToModal(offering){ @@ -472,38 +491,45 @@ $(document).ready(function() { } - let modalOpenedByEditButton = false; - //#checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page] - +let modalOpenedByEditButton = false; +// #checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page - $("#checkIsSeries, #edit_modal").click(function(event) { - eventSessionNum = 2 - $('#eventName').val($('#inputEventName').val() + ': session 1') +$("#checkIsSeries, #edit_modal").click(function(event) { + eventSessionNum = 0; + // Set all modal location fields to the main location value (if needed) + $('.multipleOfferingLocationField').val($('#inputEventLocation-main').val()); - let isSeries = $("#checkIsSeries").is(":checked") - modalOpenedByEditButton = ($(this).attr('id') === 'edit_modal'); + let isSeries = $("#checkIsSeries").is(":checked") + modalOpenedByEditButton = ($(this).attr('id') === 'edit_modal'); - if (isSeries) { - if(($('#inputEventName').val().trim() == '')){ - //keeps main page event name for multiple event modal + if (isSeries) { + if ($('#inputEventName').val().trim() == '') { $('#checkIsSeries').prop('checked', false) msgFlash("Please type the event name first") return } - setViewForSeries(); - loadOfferingsToModal(); - $('#modalSeries').modal('show'); - - // Disable single event name field - $('#inputEventName').prop('readonly', true) - } else { - setViewForSingleOffering() - $('#multipleOfferingTableDiv').addClass('d-none'); - // Enable single event name field - $('#inputEventName').prop('readonly', false) - $('#inputEventName').prop('placeholder', 'Enter event name') + if ($('#inputEventLocation-main').val().trim() == '') { + $('#checkIsSeries').prop('checked', false) + msgFlash("Please type the event location first") + return } - }); + setViewForSeries(); + loadOfferingsToModal(); + $('#modalSeries').modal('show'); + + // Disable single event name and location fields + $('#inputEventName').prop('readonly', true) + $('#inputEventLocation-main').prop('readonly', true) + } else { + setViewForSingleOffering() + $('#multipleOfferingTableDiv').addClass('d-none'); + // Enable single event name and location fields + $('#inputEventName').prop('readonly', false) + $('#inputEventName').prop('placeholder', 'Enter event name') + $('#inputEventLocation-main').prop('readonly', false) + $('#inputEventLocation-main').prop('placeholder', 'Enter event location') + } +}); //untoggles the button when the modal cancel or close button is clicked $("#cancelModalPreview, #multipleOfferingXbutton").click(function(){ @@ -521,6 +547,8 @@ $(document).ready(function() { $('#inputEventName').prop('readonly', false) $('#inputEventName').prop('placeholder', 'Enter event name') checkIfDateInPast(); + $('#inputEventLocation-main').prop('readonly', false) + $('#inputEventLocation-main').prop('placeholder', 'Enter event location') } }); @@ -581,7 +609,11 @@ $(document).ready(function() { /*cloning the div with ID multipleOfferingEvent and cloning, changing the ID of each clone going up by 1. This also changes the ID of the deleteMultipleOffering so that when the trash icon is clicked, that specific row will be deleted*/ - $(".addMultipleOfferingEvent").click(createOfferingModalRow) + $(".addMultipleOfferingEvent").click(function() { + // Get the current value from the main location input + let mainLocation = $("#inputEventLocation-main").val(); + createOfferingModalRow({eventLocation: mainLocation}); +}); var minDate = new Date('10/25/1999') $("#startDatePicker-main").datepicker("option", "minDate", minDate) diff --git a/app/templates/events/createEvent.html b/app/templates/events/createEvent.html index 9300b65c3..7ad701203 100644 --- a/app/templates/events/createEvent.html +++ b/app/templates/events/createEvent.html @@ -554,7 +554,7 @@

Generated Events:

-
From 101a9df2bde8f1e7f869a170583592ad8eb312a9 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Thu, 3 Jul 2025 11:59:34 -0400 Subject: [PATCH 10/33] We fixed the location field in multiple offering so that it shows up in the table and not as undefined. --- app/static/js/createEvents.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 7e097dae4..ce1532451 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -38,7 +38,7 @@ function calculateRepeatingEventFrequency(){ isRepeating: true, startDate:$("#repeatingEventsStartDate").val(), endDate:$("#repeatingEventsEndDate").val(), - location:$("#repeatingEventsLocationPicker").val() + location:$("#repeatingEventsLocationPicker").val() || '' } console.log(eventDatesAndName); $.ajax({ @@ -373,7 +373,7 @@ function loadRepeatingOfferingToModal(offering){ "" + "" + (offering.name || offering.eventName) + "" + "" + eventDate + "" + - "" + offering.location + "" + + "" + (offering.eventLocation || offering.location)+ "" + "
" + "" ); @@ -394,7 +394,7 @@ function updateOfferingsTable() { "" + formattedEventDate + "" + "" + startTime + "" + "" + endTime + "" + - "" + offering.eventLocation + "" + + "" + (offering.eventLocation || offering.location || "") + "" + "" ); }); @@ -574,6 +574,7 @@ $("#checkIsSeries, #edit_modal").click(function(event) { let endDate = new Date($("#repeatingEventsEndDate").val()); let startTime = $("#repeatingEventsStartTime").val(); let endTime = $("#repeatingEventsEndTime").val(); + let eventLocation = $("#repeatingEventsLocationPicker").val() || ''; if (navigator.userAgent.indexOf("Chrome") == -1) { startTime = format12to24HourTime(startTime) From 986c38b9e6641431344bf1a29fb8b1221c7fc04d Mon Sep 17 00:00:00 2001 From: chapagainp Date: Thu, 3 Jul 2025 16:24:47 -0400 Subject: [PATCH 11/33] Removed some non-essential code, used .hide() and .show() instead of removeClass() and addClass(), and changed the message for flash --- app/static/js/createEvents.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index ce1532451..cd1f57b6c 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -63,20 +63,20 @@ function calculateRepeatingEventFrequency(){ function setViewForSingleOffering(){ $(".startDatePicker").prop('required', true); - $("#multipleOfferingTableDiv").addClass('d-none'); - $("#eventLocation-main").removeClass('d-none'); + $("#multipleOfferingTableDiv").hide(); + $("#eventLocation-main").show(); $("#inputEventLocation-main").prop('required', true); - $('#eventTime, #eventDate').removeClass('d-none'); + $('#eventTime, #eventDate').show(); $('#checkIsSeriesToggleContainer').addClass('col-md-6') $('#checkIsSeriesToggleContainer').removeClass('col-md-12') } function setViewForSeries(){ $(".startDatePicker").prop('required', false); - $("#multipleOfferingTableDiv").removeClass('d-none'); - $("#eventLocation-main").addClass('d-none'); + $("#multipleOfferingTableDiv").show(); + $("#eventLocation-main").hide(); $("#inputEventLocation-main").prop('required', false); - $('#eventTime, #eventDate').addClass('d-none'); + $('#eventTime, #eventDate').hide(); $('#checkIsSeriesToggleContainer').removeClass('col-md-6') $('#checkIsSeriesToggleContainer').addClass('col-md-12') $("#pastDateWarningText").text("") @@ -256,7 +256,7 @@ $('#saveSeries').on('click', function() { displayNotification(invalidTimeMessage); } else if (hasDuplicateListings) { - let eventConflictMessage = "Event listings cannot have the same event name, date, and start time"; + let eventConflictMessage = "Event listings cannot have the same event name, date, location and start time"; displayNotification(eventConflictMessage); } else { saveOfferingsFromModal(); From 3abb92ade0192536d3acca05ddc088f650994836 Mon Sep 17 00:00:00 2001 From: chapagainp Date: Tue, 8 Jul 2025 11:04:30 -0400 Subject: [PATCH 12/33] Fixed the table issue --- app/static/js/createEvents.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index cd1f57b6c..ea58703a9 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -63,20 +63,21 @@ function calculateRepeatingEventFrequency(){ function setViewForSingleOffering(){ $(".startDatePicker").prop('required', true); - $("#multipleOfferingTableDiv").hide(); - $("#eventLocation-main").show(); + $("#multipleOfferingTableDiv").addClass('d-none'); + $("#eventLocation-main").addClass('d-none'); + $("#eventLocation-main").removeClass('d-none'); $("#inputEventLocation-main").prop('required', true); - $('#eventTime, #eventDate').show(); + $('#eventTime, #eventDate').removeClass('d-none'); $('#checkIsSeriesToggleContainer').addClass('col-md-6') $('#checkIsSeriesToggleContainer').removeClass('col-md-12') } function setViewForSeries(){ $(".startDatePicker").prop('required', false); - $("#multipleOfferingTableDiv").show(); - $("#eventLocation-main").hide(); + $("#multipleOfferingTableDiv").removeClass('d-none'); + $("#eventLocation-main").removeClass('d-none'); $("#inputEventLocation-main").prop('required', false); - $('#eventTime, #eventDate').hide(); + $('#eventTime, #eventDate').addClass('d-none'); $('#checkIsSeriesToggleContainer').removeClass('col-md-6') $('#checkIsSeriesToggleContainer').addClass('col-md-12') $("#pastDateWarningText").text("") From 21be475e6e4008e93bd5cbb613318f5ad9062ef5 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Tue, 8 Jul 2025 15:08:26 -0400 Subject: [PATCH 13/33] Removed the flash messages from the main event page based on Karina's suggestion. Removed the ability for student user to create an event. --- app/controllers/admin/routes.py | 2 +- app/static/js/createEvents.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index 8d5b75aa9..542704985 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -84,7 +84,7 @@ def templateSelect(): @admin_bp.route('/eventTemplates///create', methods=['GET','POST']) def createEvent(templateid, programid): - if not (g.current_user.isAdmin or g.current_user.isProgramManagerFor(programid) or g.current_user.isStudent): + if not (g.current_user.isAdmin or g.current_user.isProgramManagerFor(programid)): abort(403) # Validate given URL diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index ea58703a9..a61052e0e 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -506,12 +506,10 @@ $("#checkIsSeries, #edit_modal").click(function(event) { if (isSeries) { if ($('#inputEventName').val().trim() == '') { $('#checkIsSeries').prop('checked', false) - msgFlash("Please type the event name first") return } if ($('#inputEventLocation-main').val().trim() == '') { $('#checkIsSeries').prop('checked', false) - msgFlash("Please type the event location first") return } setViewForSeries(); From 2ccb1f1414338a0990d20efdc6b4ea67fa19b4d8 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Tue, 8 Jul 2025 15:14:46 -0400 Subject: [PATCH 14/33] Replace flash messages with input focus on validation failure --- app/static/js/createEvents.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index a61052e0e..9dfffbe31 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -506,10 +506,12 @@ $("#checkIsSeries, #edit_modal").click(function(event) { if (isSeries) { if ($('#inputEventName').val().trim() == '') { $('#checkIsSeries').prop('checked', false) + $('#inputEventName').focus(); return } if ($('#inputEventLocation-main').val().trim() == '') { $('#checkIsSeries').prop('checked', false) + $('#inputEventLocation-main').focus(); return } setViewForSeries(); From 2a759bc34b864731072755f0231139a067ba8f88 Mon Sep 17 00:00:00 2001 From: chapagainp Date: Wed, 9 Jul 2025 10:56:00 -0400 Subject: [PATCH 15/33] Using a combination of hide/show and addClass/removeClass --- app/static/js/createEvents.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 9dfffbe31..8c6cf3405 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -64,20 +64,20 @@ function calculateRepeatingEventFrequency(){ function setViewForSingleOffering(){ $(".startDatePicker").prop('required', true); $("#multipleOfferingTableDiv").addClass('d-none'); - $("#eventLocation-main").addClass('d-none'); - $("#eventLocation-main").removeClass('d-none'); + $("#eventLocation-main").hide(); + $("#eventLocation-main").show(); $("#inputEventLocation-main").prop('required', true); - $('#eventTime, #eventDate').removeClass('d-none'); - $('#checkIsSeriesToggleContainer').addClass('col-md-6') - $('#checkIsSeriesToggleContainer').removeClass('col-md-12') + $('#eventTime, #eventDate').show(); + $('#checkIsSeriesToggleContainer').removeClass('col-md-6') + $('#checkIsSeriesToggleContainer').addClass('col-md-12') } function setViewForSeries(){ $(".startDatePicker").prop('required', false); $("#multipleOfferingTableDiv").removeClass('d-none'); - $("#eventLocation-main").removeClass('d-none'); + $("#eventLocation-main").show(); $("#inputEventLocation-main").prop('required', false); - $('#eventTime, #eventDate').addClass('d-none'); + $('#eventTime, #eventDate').hide(); $('#checkIsSeriesToggleContainer').removeClass('col-md-6') $('#checkIsSeriesToggleContainer').addClass('col-md-12') $("#pastDateWarningText").text("") @@ -93,6 +93,7 @@ function displayNotification(message) { }); } + function isDateInPast(dateString, timeString) { const combineDateTime = `${dateString}T${timeString}:00`; const setDate = new Date(combineDateTime).getTime(); From 2491d9fb475ef747eb9b467766ede0c810a94798 Mon Sep 17 00:00:00 2001 From: chapagainp Date: Wed, 9 Jul 2025 11:03:18 -0400 Subject: [PATCH 16/33] Assigning a variable in front of eventSessionNum --- app/static/js/createEvents.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 8c6cf3405..2df409d0c 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -497,7 +497,7 @@ let modalOpenedByEditButton = false; // #checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page $("#checkIsSeries, #edit_modal").click(function(event) { - eventSessionNum = 0; + let eventSessionNum = 0; // Set all modal location fields to the main location value (if needed) $('.multipleOfferingLocationField').val($('#inputEventLocation-main').val()); From e072911217656a2789523f3106c7728d010ee73f Mon Sep 17 00:00:00 2001 From: chapagainp Date: Wed, 9 Jul 2025 11:06:49 -0400 Subject: [PATCH 17/33] Removed the student users ability to create event --- app/controllers/admin/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/routes.py b/app/controllers/admin/routes.py index 542704985..e48bd0fba 100644 --- a/app/controllers/admin/routes.py +++ b/app/controllers/admin/routes.py @@ -71,7 +71,7 @@ def switchUser(): @admin_bp.route('/eventTemplates') def templateSelect(): - if g.current_user.isCeltsAdmin or g.current_user.isCeltsStudentStaff or g.current_user.isStudent: + if g.current_user.isCeltsAdmin or g.current_user.isCeltsStudentStaff: allprograms = getAllowedPrograms(g.current_user) visibleTemplates = getAllowedTemplates(g.current_user) return render_template("/events/templateSelector.html", From a6ac5cff8f8fe5d9fadf8f3638f6256fd511b6d8 Mon Sep 17 00:00:00 2001 From: chapagainp Date: Wed, 9 Jul 2025 11:30:17 -0400 Subject: [PATCH 18/33] Add missing semicolons and clean up indentation and formatting --- app/static/js/createEvents.js | 335 +++++++++++++++++----------------- 1 file changed, 169 insertions(+), 166 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 2df409d0c..914f41134 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -21,9 +21,9 @@ function format12to24HourTime(timeStr) { let [hours, minutes] = timePart.split(":").map(Number); if (meridian === "PM" && hours !== 12) { - hours += 12; + hours += 12; } else if (meridian === "AM" && hours === 12) { - hours = 0; // midnight + hours = 0; // midnight } // format hours and minutes to always be 2 digits @@ -33,35 +33,36 @@ function format12to24HourTime(timeStr) { return `${formattedHours}:${formattedMinutes}`; } -function calculateRepeatingEventFrequency(){ - var eventDatesAndName = {name:$("#repeatingEventsNamePicker").val(), - isRepeating: true, - startDate:$("#repeatingEventsStartDate").val(), - endDate:$("#repeatingEventsEndDate").val(), - location:$("#repeatingEventsLocationPicker").val() || '' - } +function calculateRepeatingEventFrequency() { + var eventDatesAndName = { + name: $("#repeatingEventsNamePicker").val(), + isRepeating: true, + startDate: $("#repeatingEventsStartDate").val(), + endDate: $("#repeatingEventsEndDate").val(), + location: $("#repeatingEventsLocationPicker").val() || '' + } console.log(eventDatesAndName); $.ajax({ - type:"POST", + type: "POST", url: "/makeRepeatingEvents", //get the startDate, endDate and name as a dictionary data: eventDatesAndName, - success: function(jsonData){ + success: function (jsonData) { var generatedEvents = JSON.parse(jsonData) $("#generatedEventsTable tbody tr").remove(); - for(var event of generatedEvents){ + for (var event of generatedEvents) { loadRepeatingOfferingToModal(event) } $("#generatedEvents").removeClass("d-none"); }, - error: function(error){ + error: function (error) { console.log(error) displayNotification("Failed to generate events."); } }); } -function setViewForSingleOffering(){ +function setViewForSingleOffering() { $(".startDatePicker").prop('required', true); $("#multipleOfferingTableDiv").addClass('d-none'); $("#eventLocation-main").hide(); @@ -72,11 +73,11 @@ function setViewForSingleOffering(){ $('#checkIsSeriesToggleContainer').addClass('col-md-12') } -function setViewForSeries(){ +function setViewForSeries() { $(".startDatePicker").prop('required', false); $("#multipleOfferingTableDiv").removeClass('d-none'); $("#eventLocation-main").show(); - $("#inputEventLocation-main").prop('required', false); + $("#inputEventLocation-main").prop('required', false); $('#eventTime, #eventDate').hide(); $('#checkIsSeriesToggleContainer').removeClass('col-md-6') $('#checkIsSeriesToggleContainer').addClass('col-md-12') @@ -86,8 +87,8 @@ function setViewForSeries(){ function displayNotification(message) { $('#textNotifierPadding').addClass('pt-5'); $('.invalidFeedback').text(message); - $('.invalidFeedback').css('display', 'block'); - $('.invalidFeedback').on('animationend', function() { + $('.invalidFeedback').css('display', 'block'); + $('.invalidFeedback').on('animationend', function () { $('.invalidFeedback').css('display', 'none'); $('#textNotifierPadding').removeClass('pt-5') }); @@ -111,12 +112,12 @@ function initializeFlatpickr(obj) { minTime: "08:00", maxTime: "22:00", minuteIncrement: 15, - allowInput: true + allowInput: true }); } let eventSessionNum = 0; -function createOfferingModalRow({eventName=null, eventDate=null, startTime=null, endTime=null, eventLocation = null}={}){ +function createOfferingModalRow({ eventName = null, eventDate = null, startTime = null, endTime = null, eventLocation = null } = {}) { let clonedOffering = $("#multipleOfferingEvent").clone().removeClass('d-none').removeAttr("id"); const baseName = $('#inputEventName').val(); const fullName = baseName + ': session ' + (eventSessionNum + 1); @@ -124,11 +125,11 @@ function createOfferingModalRow({eventName=null, eventDate=null, startTime=null, // insert values for the newly created row - if (eventName) {clonedOffering.find('.multipleOfferingNameField').val(eventName)} - if (eventDate) {clonedOffering.find('.multipleOfferingDatePicker').val(eventDate)} - if (startTime) {clonedOffering.find('.multipleOfferingStartTime').val(startTime)} - if (endTime) {clonedOffering.find('.multipleOfferingEndTime').val(endTime)} - if (eventLocation) {clonedOffering.find('.multipleOfferingLocationField').val(eventLocation)} + if (eventName) { clonedOffering.find('.multipleOfferingNameField').val(eventName) } + if (eventDate) { clonedOffering.find('.multipleOfferingDatePicker').val(eventDate) } + if (startTime) { clonedOffering.find('.multipleOfferingStartTime').val(startTime) } + if (endTime) { clonedOffering.find('.multipleOfferingEndTime').val(endTime) } + if (eventLocation) { clonedOffering.find('.multipleOfferingLocationField').val(eventLocation) } eventSessionNum++; $("#multipleOfferingSlots").append(clonedOffering); @@ -163,7 +164,7 @@ function createOfferingModalRow({eventName=null, eventDate=null, startTime=null, return clonedOffering } -$('#saveSeries').on('click', function() { +$('#saveSeries').on('click', function () { //Requires that modal info updated before it can be saved, gives notifier if there are empty fields let eventOfferings = $('#multipleOfferingSlots .eventOffering'); let eventNameInputs = $('#multipleOfferingSlots .multipleOfferingNameField'); @@ -193,13 +194,13 @@ $('#saveSeries').on('click', function() { // Check if the date input field is empty datePickerInputs.each((index, datePickerInput) => { if (datePickerInput.value.trim() === '') { - isEmpty = true; - $(datePickerInput).addClass('border-red'); + isEmpty = true; + $(datePickerInput).addClass('border-red'); } else { - $(datePickerInput).removeClass('border-red'); + $(datePickerInput).removeClass('border-red'); } - }); - + }); + locationInputs.each((index, locationInput) => { if (locationInput.value.trim() === '') { isEmpty = true; @@ -210,16 +211,16 @@ $('#saveSeries').on('click', function() { }); // Check if the start time is after the end time - for(let i = 0; i < startTimeInputs.length; i++){ + for (let i = 0; i < startTimeInputs.length; i++) { let startTime = startTimeInputs[i].value let endTime = endTimeInputs[i].value - + if (navigator.userAgent.indexOf("Chrome") == -1) { startTime = format12to24HourTime(startTime) endTime = format12to24HourTime(endTime) } - if(startTime < endTime){ + if (startTime < endTime) { hasValidTimes = true; $(startTimeInputs[i]).removeClass('border-red'); $(endTimeInputs[i]).removeClass('border-red'); @@ -230,26 +231,26 @@ $('#saveSeries').on('click', function() { } } - if ($(dataTable).children().length < 1){ + if ($(dataTable).children().length < 1) { displayNotification("Please create events.") } // Check if there are duplicate event offerings let eventListings = {}; - for(let i = 0; i < eventOfferings.length; i++){ + for (let i = 0; i < eventOfferings.length; i++) { let eventName = eventNameInputs[i].value let date = datePickerInputs[i].value.trim() let startTime = startTimeInputs[i].value let eventListing = JSON.stringify([eventName, date, startTime, location]) - if (eventListing in eventListings){ // If we've seen this event before mark this event and the previous as duplicates + if (eventListing in eventListings) { // If we've seen this event before mark this event and the previous as duplicates hasDuplicateListings = true } else { // If we haven't seen this event before eventListings[eventListing] = i } } - if (isEmpty){ + if (isEmpty) { let emptyFieldMessage = "Event name, date or location field is empty"; displayNotification(emptyFieldMessage); } @@ -286,7 +287,7 @@ function updateEventNameField() { // if weekly, take the name of the first item (which is the same for all) and take the word 'week' let offeringText = $("#repeatingEventsNamePicker").val() $('#inputEventName').prop('placeholder', offeringText) - } + } } // Save the offerings from the modal to the hidden input field @@ -295,33 +296,34 @@ function saveOfferingsFromModal() { let isRepeatingStatus = $("#checkIsRepeating").is(":checked"); $("#formIsRepeating").prop("checked", isRepeatingStatus); let dataTable = isRepeatingStatus ? "#generatedEventsList" : "#multipleOfferingSlots"; - $(dataTable).children().each(function(index, element) { + $(dataTable).children().each(function (index, element) { let rowData; - if (isRepeatingStatus){ - rowData = $.map($(element).find("td"), function(td){ + if (isRepeatingStatus) { + rowData = $.map($(element).find("td"), function (td) { let input = $(td).find("input"); - if (input.length){ + if (input.length) { return input.val(); } else { return $(td).text().trim(); } - })} + }) + } else { rowData = $.map($(element).find("input"), (el) => $(el).val()); } - + let startTime = isRepeatingStatus ? $("#repeatingEventsStartTime").val() : rowData[3] let endTime = isRepeatingStatus ? $("#repeatingEventsEndTime").val() : rowData[4] if (navigator.userAgent.indexOf("Chrome") == -1) { - startTime = format12to24HourTime(startTime) - endTime = format12to24HourTime(endTime) + startTime = format12to24HourTime(startTime) + endTime = format12to24HourTime(endTime) } offerings.push({ - eventName: rowData[0], - eventLocation: isRepeatingStatus ? rowData[2] : rowData[1], - eventDate: isRepeatingStatus ? rowData[1] : rowData[2], - startTime: startTime, - endTime: endTime, + eventName: rowData[0], + eventLocation: isRepeatingStatus ? rowData[2] : rowData[1], + eventDate: isRepeatingStatus ? rowData[1] : rowData[2], + startTime: startTime, + endTime: endTime, }) }); @@ -331,13 +333,13 @@ function saveOfferingsFromModal() { $("#seriesData").val(offeringsJson); } -function verifyRepeatingFields(){ +function verifyRepeatingFields() { // verifies all fields in the repeating table are not empty. let repeatingFields = $(".repeatingEventsField"); let allFieldsFilled = true; - repeatingFields.each(function() { + repeatingFields.each(function () { let value = $(this).val(); - if (value === "" || value == null){ + if (value === "" || value == null) { allFieldsFilled = false; return false; } @@ -347,14 +349,14 @@ function verifyRepeatingFields(){ -function loadOfferingsToModal(){ +function loadOfferingsToModal() { let offerings = JSON.parse($("#seriesData").val()) - if (offerings.length < 1) {return;} + if (offerings.length < 1) { return; } let isRepeatingStatus = $("#checkIsRepeating").is(":checked"); let mainLocation = $('#inputEventLocation-main').val(); - if (isRepeatingStatus) {$("#generatedEvents").removeClass("d-none"); $("#generatedEventsTable tbody tr").remove();}; - offerings.forEach((offering, i) =>{ - if (isRepeatingStatus){ + if (isRepeatingStatus) { $("#generatedEvents").removeClass("d-none"); $("#generatedEventsTable tbody tr").remove(); }; + offerings.forEach((offering, i) => { + if (isRepeatingStatus) { loadRepeatingOfferingToModal(offering); } else { let newOfferingModalRow = createOfferingModalRow({ @@ -362,20 +364,21 @@ function loadOfferingsToModal(){ eventLocation: offering.eventLocation || mainLocation }); //stripes odd event sections in event modal - newOfferingModalRow.css('background-color', i % 2 ?'#f2f2f2':'#fff'); - }}); + newOfferingModalRow.css('background-color', i % 2 ? '#f2f2f2' : '#fff'); + } + }); } -function loadRepeatingOfferingToModal(offering){ +function loadRepeatingOfferingToModal(offering) { var seriesTable = $("#generatedEventsTable"); var eventDate = new Date(offering.date || offering.eventDate).toLocaleDateString(); console.log(offering); - + seriesTable.append( "" + - "" + (offering.name || offering.eventName) + "" + + "" + (offering.name || offering.eventName) + "" + "" + eventDate + "" + - "" + (offering.eventLocation || offering.location)+ "" + + "" + (offering.eventLocation || offering.location) + "" + "
" + "" ); @@ -386,19 +389,19 @@ function updateOfferingsTable() { let offerings = JSON.parse($("#seriesData").val()) var offeringsTable = $("#offeringsTable"); offeringsTable.find("tbody tr").remove(); // Clear existing rows - offerings.forEach(function(offering){ + offerings.forEach(function (offering) { //format to 12hr time for display var formattedEventDate = formatDate(offering.eventDate); var startTime = format24to12HourTime(offering.startTime); var endTime = format24to12HourTime(offering.endTime); offeringsTable.append(`` + - "" + offering.eventName + "" + - "" + formattedEventDate + "" + - "" + startTime + "" + - "" + endTime + "" + - "" + (offering.eventLocation || offering.location || "") + "" + - "" - ); + "" + offering.eventName + "" + + "" + formattedEventDate + "" + + "" + startTime + "" + + "" + endTime + "" + + "" + (offering.eventLocation || offering.location || "") + "" + + "" + ); }); } @@ -415,7 +418,7 @@ function formatDate(originalDate) { /* * Run when the webpage is ready for javascript */ -$(document).ready(function() { +$(document).ready(function () { var isEditPage = (window.location.pathname == '/event/' + $('#newEventID').val() + '/edit') //makes sure bonners toggle will stay on between event pages @@ -428,7 +431,7 @@ $(document).ready(function() { // don't use a minimum if we are editing an existing event var minDate = new Date() if (isEditPage) { - minDate = null; + minDate = null; } // Initialize datepicker with proper options @@ -442,7 +445,7 @@ $(document).ready(function() { minDate: minDate }); - $(".datePicker").each(function(idx, el) { + $(".datePicker").each(function (idx, el) { var dateStr = $(el).val(); if (dateStr) { var dateObj = new Date(dateStr); @@ -476,75 +479,75 @@ $(document).ready(function() { //check if user has selected a toggle, cancel form submission if not let isAllVolunteer = $("#pageTitle").text() == 'Create All Volunteer Training' - if(trainingStatus || serviceHourStatus || engagementStatus || bonnersStatus || isAllVolunteer) { + if (trainingStatus || serviceHourStatus || engagementStatus || bonnersStatus || isAllVolunteer) { // Disable button when we are ready to submit $(this).find("input[type=submit]").prop("disabled", true); } else { msgFlash("You must indicate whether the event is a training, is an engagement, earns service hours, or is a Bonners Scholars event!", "danger"); event.preventDefault(); - } + } }); updateOfferingsTable(); - - if ($("#checkIsSeries").is(":checked")){ + + if ($("#checkIsSeries").is(":checked")) { setViewForSeries(); } - -let modalOpenedByEditButton = false; -// #checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page -$("#checkIsSeries, #edit_modal").click(function(event) { - let eventSessionNum = 0; - // Set all modal location fields to the main location value (if needed) - $('.multipleOfferingLocationField').val($('#inputEventLocation-main').val()); + let modalOpenedByEditButton = false; + // #checkIsRepeating, #checkIsSeries are attributes for the toggle buttons on create event page - let isSeries = $("#checkIsSeries").is(":checked") - modalOpenedByEditButton = ($(this).attr('id') === 'edit_modal'); + $("#checkIsSeries, #edit_modal").click(function (event) { + let eventSessionNum = 0; + // Set all modal location fields to the main location value (if needed) + $('.multipleOfferingLocationField').val($('#inputEventLocation-main').val()); - if (isSeries) { - if ($('#inputEventName').val().trim() == '') { - $('#checkIsSeries').prop('checked', false) - $('#inputEventName').focus(); - return - } - if ($('#inputEventLocation-main').val().trim() == '') { - $('#checkIsSeries').prop('checked', false) - $('#inputEventLocation-main').focus(); - return - } - setViewForSeries(); - loadOfferingsToModal(); - $('#modalSeries').modal('show'); + let isSeries = $("#checkIsSeries").is(":checked"); + modalOpenedByEditButton = ($(this).attr('id') === 'edit_modal'); - // Disable single event name and location fields - $('#inputEventName').prop('readonly', true) - $('#inputEventLocation-main').prop('readonly', true) - } else { - setViewForSingleOffering() - $('#multipleOfferingTableDiv').addClass('d-none'); - // Enable single event name and location fields - $('#inputEventName').prop('readonly', false) - $('#inputEventName').prop('placeholder', 'Enter event name') - $('#inputEventLocation-main').prop('readonly', false) - $('#inputEventLocation-main').prop('placeholder', 'Enter event location') - } -}); + if (isSeries) { + if ($('#inputEventName').val().trim() == '') { + $('#checkIsSeries').prop('checked', false); + $('#inputEventName').focus(); + return; + } + if ($('#inputEventLocation-main').val().trim() == '') { + $('#checkIsSeries').prop('checked', false); + $('#inputEventLocation-main').focus(); + return; + } + setViewForSeries(); + loadOfferingsToModal(); + $('#modalSeries').modal('show'); + + // Disable single event name and location fields + $('#inputEventName').prop('readonly', true); + $('#inputEventLocation-main').prop('readonly', true); + } else { + setViewForSingleOffering(); + $('#multipleOfferingTableDiv').addClass('d-none'); + // Enable single event name and location fields + $('#inputEventName').prop('readonly', false); + $('#inputEventName').prop('placeholder', 'Enter event name'); + $('#inputEventLocation-main').prop('readonly', false); + $('#inputEventLocation-main').prop('placeholder', 'Enter event location'); + } + }); //untoggles the button when the modal cancel or close button is clicked - $("#cancelModalPreview, #multipleOfferingXbutton").click(function(){ + $("#cancelModalPreview, #multipleOfferingXbutton").click(function () { if (modalOpenedByEditButton == false) { $('#modalSeries').modal('hide'); $("#checkIsSeries").prop('checked', false); - setViewForSingleOffering() + setViewForSingleOffering(); } - pendingmultipleEvents.forEach(function(element){ + pendingmultipleEvents.forEach(function (element) { element.remove(); }); let isSeries = $("#checkIsSeries").is(":checked") - if (!isSeries){ + if (!isSeries) { // Enable single event name field $('#inputEventName').prop('readonly', false) $('#inputEventName').prop('placeholder', 'Enter event name') @@ -554,19 +557,19 @@ $("#checkIsSeries, #edit_modal").click(function(event) { } }); - $("#checkIsRepeating").change(function() { + $("#checkIsRepeating").change(function () { if ($(this).is(':checked')) { $('.addMultipleOfferingEvent').hide(); $("#repeatingEventsDiv").removeClass('d-none'); $("#multipleOfferingSlots").children().remove(); $("#multipleOfferingSlots").addClass('d-none'); } else { - $('.addMultipleOfferingEvent').show(); + $('.addMultipleOfferingEvent').show(); $("#repeatingEventsDiv").addClass('d-none'); $("#multipleOfferingSlots").removeClass('d-none'); } }); - + $("#repeatingEventsDiv").change(handleRepeatingEventsChange) function handleRepeatingEventsChange() { @@ -585,13 +588,13 @@ $("#checkIsSeries, #edit_modal").click(function(event) { if (endDate <= startDate) { displayNotification("The end date must be after the start date."); - table.each(function(){$(this).remove()}) + table.each(function () { $(this).remove() }) $("#generatedEvents").addClass('d-none'); return; } - if (endTime <= startTime){ + if (endTime <= startTime) { displayNotification("The end time must be after the start time."); - table.each(function(){$(this).remove()}) + table.each(function () { $(this).remove() }) $("#generatedEvents").addClass('d-none'); return; } @@ -600,56 +603,56 @@ $("#checkIsSeries, #edit_modal").click(function(event) { } } - $(document).on("click", ".deleteGeneratedEvent, .deleteMultipleOffering", function() { + $(document).on("click", ".deleteGeneratedEvent, .deleteMultipleOffering", function () { let attachedRow = $(this).closest(".eventOffering") attachedRow.animate({ opacity: 0, - }, 500, function() { - // After the animation completes, remove the row - attachedRow.remove(); + }, 500, function () { + // After the animation completes, remove the row + attachedRow.remove(); }); }); - + /*cloning the div with ID multipleOfferingEvent and cloning, changing the ID of each clone going up by 1. This also changes the ID of the deleteMultipleOffering so that when the trash icon is clicked, that specific row will be deleted*/ - $(".addMultipleOfferingEvent").click(function() { - // Get the current value from the main location input - let mainLocation = $("#inputEventLocation-main").val(); - createOfferingModalRow({eventLocation: mainLocation}); -}); + $(".addMultipleOfferingEvent").click(function () { + // Get the current value from the main location input + let mainLocation = $("#inputEventLocation-main").val(); + createOfferingModalRow({ eventLocation: mainLocation }); + }); - var minDate = new Date('10/25/1999') - $("#startDatePicker-main").datepicker("option", "minDate", minDate) + var minDate = new Date('10/25/1999') + $("#startDatePicker-main").datepicker("option", "minDate", minDate) // This converts the time to 24 hour format in case it is in 12 hour format (like in Firefox) -function handleTimeFormatting(timeArray){ - let time = timeArray[0] - let timeSuffix = timeArray[1] // looks for AM or PM in time - let [hours , min] = time. split(':') - - if (timeArray.length === 2) { - hours = parseInt(hours, 10) - if (timeSuffix === 'PM' && hours !== 12) { - hours += 12; - } else if (timeSuffix === 'AM' && hours === 12) { - hours = 0; + function handleTimeFormatting(timeArray) { + let time = timeArray[0] + let timeSuffix = timeArray[1] // looks for AM or PM in time + let [hours, min] = time.split(':') + + if (timeArray.length === 2) { + hours = parseInt(hours, 10) + if (timeSuffix === 'PM' && hours !== 12) { + hours += 12; + } else if (timeSuffix === 'AM' && hours === 12) { + hours = 0; + } + const hoursStr = hours.toString().padStart(2, '0'); + return [hoursStr, min] } - const hoursStr = hours.toString().padStart(2, '0'); - return [hoursStr, min] + return [hours, min] } - return [hours, min] -} function checkIfDateInPast() { const [month, day, year] = $("#startDatePicker-main").val().split('/') - const startTimeArray = $("#startTime-main").val().split(' ') + const startTimeArray = $("#startTime-main").val().split(' ') const [startHour, startMin] = handleTimeFormatting(startTimeArray) const endTimeArray = $('#endTime-main').val().split(' ') - const [endHour, endMin] = handleTimeFormatting (endTimeArray) - let startDateSelected =new Date(+year, +month - 1, +day, +startHour, +startMin); + const [endHour, endMin] = handleTimeFormatting(endTimeArray) + let startDateSelected = new Date(+year, +month - 1, +day, +startHour, +startMin); let endDateSelected = new Date(+year, +month - 1, +day, +endHour, +endMin) let now = new Date() - + if (startDateSelected < now && endDateSelected > now) { $("#pastDateWarningText").text("This event is currently in progress!") @@ -657,26 +660,26 @@ function handleTimeFormatting(timeArray){ else if (startDateSelected < now && endDateSelected < now) { $("#pastDateWarningText").text("This event is in the past!") } - else + else $("#pastDateWarningText").text("") } - $("#startDatePicker-main").on("change", function() { + $("#startDatePicker-main").on("change", function () { checkIfDateInPast() }) - $("#startTime-main").on("change", function() { + $("#startTime-main").on("change", function () { checkIfDateInPast() }) - - $("#endTime-main").on("change", function() { + + $("#endTime-main").on("change", function () { checkIfDateInPast() }) // everything except Chrome if (navigator.userAgent.indexOf("Chrome") == -1) { initializeFlatpickr(".flatpickr") - + $(".timepicker").prop("type", "text"); $(".timeIcons").prop("hidden", false); @@ -694,7 +697,7 @@ function handleTimeFormatting(timeArray){ $(".datePicker").datepicker("option", "disabled", true); } - $(".readonly").on('keydown paste', function(e) { + $(".readonly").on('keydown paste', function (e) { if (e.keyCode != 9) // ignore tab e.preventDefault(); }); @@ -742,7 +745,7 @@ function handleTimeFormatting(timeArray){ setCharacterLimit(this, "#remainingCharacters"); }); - setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); + setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); }); From 5d7f8fe8d2cab7e471226f6acb46e919b6147805 Mon Sep 17 00:00:00 2001 From: chapagainp Date: Wed, 9 Jul 2025 14:59:04 -0400 Subject: [PATCH 19/33] prefill event name and location from main input --- app/static/js/createEvents.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 914f41134..0ee2d664c 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -559,6 +559,8 @@ $(document).ready(function () { $("#checkIsRepeating").change(function () { if ($(this).is(':checked')) { + $("#repeatingEventsNamePicker").val($("#inputEventName").val()); + $("#repeatingEventsLocationPicker").val($("#inputEventLocation-main").val()); $('.addMultipleOfferingEvent').hide(); $("#repeatingEventsDiv").removeClass('d-none'); $("#multipleOfferingSlots").children().remove(); From 52dbcfc38cfd4c2582a9dfac9ab93b9f173794dd Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Thu, 17 Jul 2025 08:57:07 -0400 Subject: [PATCH 20/33] removed the debug output --- app/static/js/createEvents.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 0ee2d664c..fcd1d3f8c 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -41,7 +41,6 @@ function calculateRepeatingEventFrequency() { endDate: $("#repeatingEventsEndDate").val(), location: $("#repeatingEventsLocationPicker").val() || '' } - console.log(eventDatesAndName); $.ajax({ type: "POST", url: "/makeRepeatingEvents", @@ -372,7 +371,7 @@ function loadOfferingsToModal() { function loadRepeatingOfferingToModal(offering) { var seriesTable = $("#generatedEventsTable"); var eventDate = new Date(offering.date || offering.eventDate).toLocaleDateString(); - console.log(offering); + seriesTable.append( "" + From 540bd02b01ffc68e832670272087754a6959e264 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Thu, 17 Jul 2025 11:26:47 -0400 Subject: [PATCH 21/33] Removed another debug out put --- app/static/js/createEvents.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index fcd1d3f8c..2c3073733 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -41,6 +41,7 @@ function calculateRepeatingEventFrequency() { endDate: $("#repeatingEventsEndDate").val(), location: $("#repeatingEventsLocationPicker").val() || '' } + $.ajax({ type: "POST", url: "/makeRepeatingEvents", @@ -55,7 +56,7 @@ function calculateRepeatingEventFrequency() { $("#generatedEvents").removeClass("d-none"); }, error: function (error) { - console.log(error) + displayNotification("Failed to generate events."); } }); @@ -371,7 +372,7 @@ function loadOfferingsToModal() { function loadRepeatingOfferingToModal(offering) { var seriesTable = $("#generatedEventsTable"); var eventDate = new Date(offering.date || offering.eventDate).toLocaleDateString(); - + seriesTable.append( "" + From f4b03d4885fae70082abfa8e1ab70864376f8c1e Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Thu, 17 Jul 2025 16:05:09 -0400 Subject: [PATCH 22/33] add input handling for name, location, and dates --- app/static/js/createEvents.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 2c3073733..87e444a60 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -230,10 +230,7 @@ $('#saveSeries').on('click', function () { $(endTimeInputs[i]).addClass('border-red'); } } - - if ($(dataTable).children().length < 1) { - displayNotification("Please create events.") - } + let noEventsCreated = ($(dataTable).children().length < 1); // Check if there are duplicate event offerings let eventListings = {}; @@ -249,8 +246,9 @@ $('#saveSeries').on('click', function () { eventListings[eventListing] = i } } - - if (isEmpty) { + if(noEventsCreated) { + displayNotification("Please create events."); + } else if (isEmpty) { let emptyFieldMessage = "Event name, date or location field is empty"; displayNotification(emptyFieldMessage); } @@ -571,8 +569,14 @@ $(document).ready(function () { $("#multipleOfferingSlots").removeClass('d-none'); } }); - - $("#repeatingEventsDiv").change(handleRepeatingEventsChange) + + $("#repeatingEventsNamePicker, " + "#repeatingEventsLocationPicker").on("input", handleRepeatingEventsChange); + + $("#repeatingEventsStartDate, " + + "#repeatingEventsEndDate, " + + "#repeatingEventsStartTime, " + + "#repeatingEventsEndTime" + ).on("change", handleRepeatingEventsChange); function handleRepeatingEventsChange() { if (verifyRepeatingFields()) { From fb03c6c3dd41730000dcc61fb40fd24854681059 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Fri, 18 Jul 2025 09:41:04 -0400 Subject: [PATCH 23/33] set 7-second timer for repeating event updates --- app/static/js/createEvents.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 87e444a60..f46afdea5 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -418,7 +418,15 @@ function formatDate(originalDate) { */ $(document).ready(function () { var isEditPage = (window.location.pathname == '/event/' + $('#newEventID').val() + '/edit') - + + // This is to prevent the server from being overloaded with requests while the user is typing + let debounceTimer; + $("#repeatingEventsNamePicker, #repeatingEventsLocationPicker").on("input", function () { + clearTimeout(debounceTimer); + debounceTimer = setTimeout(function () { + handleRepeatingEventsChange(); + }, 7000); + }); //makes sure bonners toggle will stay on between event pages if (isEditPage) { if ($("#checkBonners")) { From fccccb83c087472e2a590e9e99303fda2dcf426d Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Fri, 18 Jul 2025 10:06:27 -0400 Subject: [PATCH 24/33] Change passing location as a list to a string --- tests/code/test_events.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/code/test_events.py b/tests/code/test_events.py index 4065c7017..c1f75bd39 100644 --- a/tests/code/test_events.py +++ b/tests/code/test_events.py @@ -300,7 +300,7 @@ def test_calculateRecurringEventFrequency(): eventInfo = {'name': "testEvent", 'startDate': parser.parse("02/22/2023"), 'endDate': parser.parse("03/11/2023"), - 'location':("a big room")} + 'location': "a big room"} # test correct response returnedEvents = getRepeatingEventsData(eventInfo) From a23aa23191aa72025d66264bf8cf80782f1f11fc Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Fri, 18 Jul 2025 11:09:55 -0400 Subject: [PATCH 25/33] set the timer to 7 secs instead of 3 --- app/static/js/createEvents.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index f46afdea5..599b46684 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -419,6 +419,7 @@ function formatDate(originalDate) { $(document).ready(function () { var isEditPage = (window.location.pathname == '/event/' + $('#newEventID').val() + '/edit') + // This is to prevent the server from being overloaded with requests while the user is typing let debounceTimer; $("#repeatingEventsNamePicker, #repeatingEventsLocationPicker").on("input", function () { From 2f6e925ac109e7f303f159b8d679af688948c01c Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Sun, 20 Jul 2025 14:03:51 -0400 Subject: [PATCH 26/33] changed the timer to 3000 milliseconds --- app/static/js/createEvents.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 0027521b4..16a7362ce 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -516,8 +516,6 @@ function checkValidation() { } } - - /* * Run when the webpage is ready for javascript */ @@ -531,7 +529,7 @@ $(document).ready(function () { clearTimeout(debounceTimer); debounceTimer = setTimeout(function () { handleRepeatingEventsChange(); - }, 7000); + }, 3000); }); //makes sure bonners toggle will stay on between event pages if (isEditPage) { @@ -671,8 +669,14 @@ $("#cancelEvent").on('click', function (event) { $("#multipleOfferingSlots").removeClass('d-none'); } }); + + $("#repeatingEventsNamePicker, " + "#repeatingEventsLocationPicker").on("input", handleRepeatingEventsChange); - $("#repeatingEventsDiv").change(handleRepeatingEventsChange) + $("#repeatingEventsStartDate, " + + "#repeatingEventsEndDate, " + + "#repeatingEventsStartTime, " + + "#repeatingEventsEndTime" + ).on("change", handleRepeatingEventsChange); // this handels start date, end date, last event date, start time, and end time function handleRepeatingEventsChange() { if (!verifyRepeatingFields()) { From 620728bab8fffc0a400612f9a3f97ac279d2bbd7 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Mon, 21 Jul 2025 10:16:54 -0400 Subject: [PATCH 27/33] fixed Assertion Issue in the test --- tests/code/test_search.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/code/test_search.py b/tests/code/test_search.py index bea7c05fb..837a3f9cf 100644 --- a/tests/code/test_search.py +++ b/tests/code/test_search.py @@ -35,7 +35,7 @@ def test_searchUsers(): searchResults = searchUsers('sa') assert len(searchResults) == 2 assert searchResults['lamichhanes2'] == model_to_dict(User.get_by_id('lamichhanes2')) - assert searchResults["sawconc"] == model_to_dict(secondUser) + assert searchResults["sawconc"] == model_to_dict (User.get_by_id('sawconc')) assert '(555)555-5555' in searchResults["lamichhanes2"].values() transaction.rollback() From 73d0d2cbb14398f112f70678063655519d68963b Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Mon, 21 Jul 2025 15:53:22 -0400 Subject: [PATCH 28/33] fixed indentation --- app/static/js/createEvents.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 16a7362ce..00acf4076 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -671,12 +671,10 @@ $("#cancelEvent").on('click', function (event) { }); $("#repeatingEventsNamePicker, " + "#repeatingEventsLocationPicker").on("input", handleRepeatingEventsChange); - $("#repeatingEventsStartDate, " + - "#repeatingEventsEndDate, " + + "#repeatingEventsEndDate, " + "#repeatingEventsStartTime, " + - "#repeatingEventsEndTime" - ).on("change", handleRepeatingEventsChange); + "#repeatingEventsEndTime").on("change", handleRepeatingEventsChange); // this handels start date, end date, last event date, start time, and end time function handleRepeatingEventsChange() { if (!verifyRepeatingFields()) { From f418eb06a3a7b13d488726da5ff6044a5a3ade18 Mon Sep 17 00:00:00 2001 From: Joyce J Nimely Date: Mon, 21 Jul 2025 16:26:15 -0400 Subject: [PATCH 29/33] fixed else statement --- app/static/js/createEvents.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 00acf4076..943103e7c 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -761,11 +761,9 @@ $("#cancelEvent").on('click', function (event) { if (startDateSelected < now && endDateSelected > now) { $("#pastDateWarningText").text("This event is currently in progress!") - } - else if (startDateSelected < now && endDateSelected < now) { + } else if (startDateSelected < now && endDateSelected < now) { $("#pastDateWarningText").text("This event is in the past!") - } - else + }else{ $("#pastDateWarningText").text("") } @@ -797,6 +795,7 @@ $("#cancelEvent").on('click', function (event) { $(".timepicker").prop("type", "time"); $(".timeIcons").prop("hidden", true); } + } if ($(".datePicker").is("readonly")) { $(".datePicker").datepicker("option", "disabled", true); @@ -851,8 +850,9 @@ $("#cancelEvent").on('click', function (event) { }); setCharacterLimit($("#inputCharacters"), "#remainingCharacters"); - -}); + }); + + From cb6d5c3f68064db77d6ee4d42c064e485a626fbc Mon Sep 17 00:00:00 2001 From: zawn Date: Wed, 8 Oct 2025 18:57:54 -0400 Subject: [PATCH 30/33] merging into main --- app/static/js/createEvents.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 0f82bacc5..0a6ef09f5 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -326,18 +326,12 @@ function updateEventNameField() { if (!isSeries) { // if not weeekly, add them to a set to remove duplicates, then put them in a string to populate the field - let names = new Set() - offerings.forEach(offering => { - names.add(offering.eventName) - }); - let offeringsText = Array.from(names).join(", ") - $('#inputEventName').val(offeringsText) + $('#inputEventName').prop('placeholder', '') } else { // if weekly, take the name of the first item (which is the same for all) and take the word 'week' let offeringText = $("#repeatingEventsNamePicker").val() - $('#inputEventName').val(offeringText) - } + $('#inputEventName').prop('placeholder', offeringText) } } // Save the offerings from the modal to the hidden input field From 21e79efd83e80f667e45839e811bd2cbbad35f17 Mon Sep 17 00:00:00 2001 From: Besher Kitaz Date: Fri, 19 Dec 2025 20:32:14 -0500 Subject: [PATCH 31/33] Error Found. Now need to fix it! --- app/static/js/createEvents.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index b2f9314df..81e811ebc 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -75,6 +75,7 @@ function setViewForSingleOffering() { function setViewForSeries() { $(".startDatePicker").prop('required', false); + $(".startDatePicker").hide(); $("#multipleOfferingTableDiv").removeClass('d-none'); $("#eventLocation-main").show(); $("#inputEventLocation-main").prop('required', false); @@ -89,8 +90,8 @@ function displayNotification(message) { $('.invalidFeedback').text(message); $('.invalidFeedback').css('display', 'block'); $('.invalidFeedback').on('animationend', function () { - $('.invalidFeedback').css('display', 'none'); - $('#textNotifierPadding').removeClass('pt-5') + $('.invalidFeedback').css('display', 'none'); + $('#textNotifierPadding').removeClass('pt-5'); }); } @@ -205,11 +206,10 @@ $('#saveSeries').on('click', function(e) { enableLiveCustomValidityClearing([".multipleOfferingNameField"]) let eventOfferings = $('#multipleOfferingSlots .eventOffering'); let eventNameInputs = $('#multipleOfferingSlots .multipleOfferingNameField'); - let eventLocationInput = $('') + let eventLocationInputs = $('#multipleOfferingSlots .multipleOfferingLocationField'); let datePickerInputs = $('#multipleOfferingSlots .multipleOfferingDatePicker'); let startTimeInputs = $('#multipleOfferingSlots .multipleOfferingStartTime'); let endTimeInputs = $('#multipleOfferingSlots .multipleOfferingEndTime'); - let locationInputs = $('#multipleOfferingSlots .multipleOfferingLocationField'); let isRepeatingStatus = $("#checkIsRepeating").is(":checked"); let startDateInput = $("#repeatingEventsStartDate"); let endDateInput = $("#repeatingEventsEndDate"); @@ -238,6 +238,7 @@ $('#saveSeries').on('click', function(e) { } else { // Validate individual event offerings for non-repeating events + // Check event name fields eventNameInputs.each((index, eventNameInput) => { if (eventNameInput.value.trim() === '') { @@ -247,6 +248,18 @@ $('#saveSeries').on('click', function(e) { } else { $(eventNameInput)[0].setCustomValidity(""); } + }); + + + // Check location fields + eventLocationInputs.each((index, eventLocationInput) => { + if (eventLocationInput.value.trim() === '') { + hasErrors = true; + $(eventLocationInput)[0].setCustomValidity("Please enter an event location"); + $(eventLocationInput)[0].reportValidity(); + } else { + $(eventLocationInput)[0].setCustomValidity(""); + } }); // Check date picker fields @@ -326,7 +339,7 @@ function updateEventNameField() { if (!isSeries) { // if not weeekly, add them to a set to remove duplicates, then put them in a string to populate the field - $('#inputEventName').val('') + $('#inputEventName').val('') // ERROR IS HERE! FINALLY FOUND IT!! } else { // if weekly, take the name of the first item (which is the same for all) and take the word 'week' @@ -640,7 +653,7 @@ $("#cancelEvent").on('click', function (event) { setViewForSeries(); loadOfferingsToModal(); $('#modalSeries').modal('show'); - + // Disable single event name and location fields $('#inputEventName').prop('readonly', true); $('#inputEventLocation-main').prop('readonly', true); From b12d56b4e0b724e4af95778d01d09eedd573eaaa Mon Sep 17 00:00:00 2001 From: Besher Kitaz Date: Sun, 21 Dec 2025 18:50:04 -0500 Subject: [PATCH 32/33] Fixed the issue by preventing the name from being depopulated in the original name field --- app/static/js/createEvents.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 81e811ebc..012c28ba0 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -64,13 +64,14 @@ function calculateRepeatingEventFrequency() { function setViewForSingleOffering() { $(".startDatePicker").prop('required', true); + $(".startDatePicker").show(); $("#multipleOfferingTableDiv").addClass('d-none'); $("#eventLocation-main").hide(); $("#eventLocation-main").show(); $("#inputEventLocation-main").prop('required', true); $('#eventTime, #eventDate').show(); - $('#checkIsSeriesToggleContainer').removeClass('col-md-6') - $('#checkIsSeriesToggleContainer').addClass('col-md-12') + $('#checkIsSeriesToggleContainer').removeClass('col-md-12') + $('#checkIsSeriesToggleContainer').addClass('col-md-6') } function setViewForSeries() { @@ -117,12 +118,10 @@ function initializeFlatpickr(obj) { }); } -let eventSessionNum = 0; function createOfferingModalRow({ eventName = null, eventDate = null, startTime = null, endTime = null, eventLocation = null } = {}) { let clonedOffering = $("#multipleOfferingEvent").clone().removeClass('d-none').removeAttr("id"); - const baseName = $('#inputEventName').val(); - const fullName = baseName + ': session ' + (eventSessionNum + 1); - clonedOffering.find('.multipleOfferingNameField').val(fullName); + const Name = $('#inputEventName').val(); + clonedOffering.find('.multipleOfferingNameField').val(Name); // insert values for the newly created row @@ -132,7 +131,6 @@ function createOfferingModalRow({ eventName = null, eventDate = null, startTime if (endTime) { clonedOffering.find('.multipleOfferingEndTime').val(endTime) } if (eventLocation) { clonedOffering.find('.multipleOfferingLocationField').val(eventLocation) } - eventSessionNum++; $("#multipleOfferingSlots").append(clonedOffering); pendingmultipleEvents.push(clonedOffering); @@ -334,15 +332,8 @@ $('#saveSeries').on('click', function(e) { // Populate the Event Name field in the main page with the entered repeating events function updateEventNameField() { - let offerings = JSON.parse($("#seriesData").val()) let isSeries = $("#checkIsRepeating").is(":checked") - - if (!isSeries) { - // if not weeekly, add them to a set to remove duplicates, then put them in a string to populate the field - $('#inputEventName').val('') // ERROR IS HERE! FINALLY FOUND IT!! - } - else { - // if weekly, take the name of the first item (which is the same for all) and take the word 'week' + if (isSeries) { let offeringText = $("#repeatingEventsNamePicker").val() $('#inputEventName').val(offeringText) } From 4dceb35a7f56a617f3fbefc5f24ca990968888c1 Mon Sep 17 00:00:00 2001 From: Besher Kitaz Date: Mon, 29 Dec 2025 16:05:27 -0500 Subject: [PATCH 33/33] Added one line to sort multiple offerings --- app/static/js/createEvents.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/static/js/createEvents.js b/app/static/js/createEvents.js index 012c28ba0..a934a8174 100644 --- a/app/static/js/createEvents.js +++ b/app/static/js/createEvents.js @@ -66,8 +66,8 @@ function setViewForSingleOffering() { $(".startDatePicker").prop('required', true); $(".startDatePicker").show(); $("#multipleOfferingTableDiv").addClass('d-none'); - $("#eventLocation-main").hide(); $("#eventLocation-main").show(); + $("#inputEventLocation-main").attr('readonly', false); $("#inputEventLocation-main").prop('required', true); $('#eventTime, #eventDate').show(); $('#checkIsSeriesToggleContainer').removeClass('col-md-12') @@ -422,6 +422,10 @@ function loadRepeatingOfferingToModal(offering){ function updateOfferingsTable() { let offerings = JSON.parse($("#seriesData").val()) var offeringsTable = $("#offeringsTable"); + + // Sorting the offerings by data and time in case user inputs in an unsorted manner + offerings.sort((a, b) => new Date(a.eventDate) - new Date(b.eventDate) || a.startTime.localeCompare(b.startTime)); + offeringsTable.find("tbody tr").remove(); // Clear existing rows offerings.forEach(function (offering) { //format to 12hr time for display