diff --git a/app/controllers/main/routes.py b/app/controllers/main/routes.py index f924f9919..0941977aa 100644 --- a/app/controllers/main/routes.py +++ b/app/controllers/main/routes.py @@ -3,7 +3,7 @@ from peewee import JOIN from http import cookies from playhouse.shortcuts import model_to_dict -from flask import request, render_template, g, abort, flash, redirect, url_for +from flask import request, render_template, g, abort, flash, redirect, url_for,jsonify from app.controllers.main import main_bp from app import app @@ -55,7 +55,7 @@ def landingPage(): .distinct() .execute()) # Ensure only unique programs are included - return render_template("/main/landingPage.html", + return render_template("/main/landingPage.html", managerProgramDict=managerProgramDict, term=g.current_term, programsWithEventsList=programsWithEventsList) @@ -73,20 +73,20 @@ def events(selectedTerm, activeTab, programID): if selectedTerm: currentTerm = selectedTerm currentTime = datetime.datetime.now() - + listOfTerms = Term.select() participantRSVP = EventRsvp.select(EventRsvp, Event).join(Event).where(EventRsvp.user == g.current_user) rsvpedEventsID = [event.event.id for event in participantRSVP] - term = Term.get_by_id(currentTerm) - + term = Term.get_by_id(currentTerm) + currentEventRsvpAmount = getEventRsvpCountsForTerm(term) studentLedEvents = getStudentLedEvents(term) countUpcomingStudentLedEvents = getUpcomingStudentLedCount(term, currentTime) trainingEvents = getTrainingEvents(term, g.current_user) bonnerEvents = getBonnerEvents(term) otherEvents = getOtherEvents(term) - + managersProgramDict = getManagerProgramDict(g.current_user) return render_template("/events/event_list.html", @@ -146,7 +146,7 @@ def viewUsersProfile(username): ProgramBan.program == program, ProgramBan.endDate > datetime.datetime.now()).execute()) userParticipatedTrainingEvents = getParticipationStatusForTrainings(program, [volunteer], g.current_term) - try: + try: allTrainingsComplete = False not in [attended for event, attended in userParticipatedTrainingEvents[username]] # Did volunteer attend all events except KeyError: allTrainingsComplete = False @@ -201,7 +201,7 @@ def emergencyContactInfo(username): contactInfo=contactInfo, readOnly=readOnly ) - + elif request.method == 'POST': if g.current_user.username != username: abort(403) @@ -210,8 +210,8 @@ def emergencyContactInfo(username): if not rowsUpdated: EmergencyContact.create(user = username, **request.form) createAdminLog(f"{g.current_user} updated {username}'s emergency contact information.") - flash('Emergency contact information saved successfully!', 'success') - + flash('Emergency contact information saved successfully!', 'success') + if request.args.get('action') == 'exit': return redirect (f"/profile/{username}") else: @@ -243,7 +243,7 @@ def insuranceInfo(username): if not rowsUpdated: InsuranceInfo.create(user = username, **request.form) createAdminLog(f"{g.current_user} updated {username}'s emergency contact information.") - flash('Insurance information saved successfully!', 'success') + flash('Insurance information saved successfully!', 'success') if request.args.get('action') == 'exit': return redirect (f"/profile/{username}") @@ -254,7 +254,7 @@ def insuranceInfo(username): def travelForm(username): if not (g.current_user.username == username or g.current_user.isCeltsAdmin): abort(403) - + user = (User.select(User, EmergencyContact, InsuranceInfo) .join(EmergencyContact, JOIN.LEFT_OUTER).switch() .join(InsuranceInfo, JOIN.LEFT_OUTER) @@ -449,6 +449,47 @@ def serviceTranscript(username): startDate = startDate, userData = user) +@main_bp.route('/profile//removeFromTranscript/', methods=['GET']) +def isRemovedFromTranscript(username, program_id): + user = User.get_or_none(User.username == username) + if user is None: + abort(404) + + try: + bannedProgramsForUser = ProgramBan.get((ProgramBan.program == program_id) & (ProgramBan.user == user)) + # If the user is banned, check if it's marked for removal from transcript + if bannedProgramsForUser.removeFromTranscript: + return jsonify({'removedFromTranscript': True}) + else: + return jsonify({'removedFromTranscript': False}) + except ProgramBan.DoesNotExist: + return jsonify({'status': 'error', 'message': 'ProgramBan not found'}) + +@main_bp.route('/profile//updateTranscript/', methods=['POST']) +def updateTranscript(username, program_id): + # Check user permissions + user = User.get_or_none(User.username == username) + if user is None: + abort(404) + if user != g.current_user and not g.current_user.isAdmin: + abort(403) + + # Get the data sent from the client-side JavaScript + data = request.json + + # Retrieve removeFromTranscript value from the request data + removeFromTranscript = data.get('removeFromTranscript') + + # Update the ProgramBan object matching the program_id and username + try: + bannedProgramsForUser = ProgramBan.get((ProgramBan.program == program_id) & (ProgramBan.user == user)) + bannedProgramsForUser.removeFromTranscript = removeFromTranscript + bannedProgramsForUser.save() + return jsonify({'status': 'success'}) + except ProgramBan.DoesNotExist: + return jsonify({'status': 'error', 'message': 'ProgramBan not found'}) + + @main_bp.route('/searchUser/', methods = ['GET']) def searchUser(query): @@ -474,12 +515,12 @@ def getDietInfo(): dietaryInfo = request.form user = dietaryInfo["user"] dietInfo = dietaryInfo["dietInfo"] - + if (g.current_user.username == user) or g.current_user.isAdmin: updateDietInfo(user, dietInfo) - userInfo = User.get(User.username == user) + userInfo = User.get(User.username == user) if len(dietInfo) > 0: - createAdminLog(f"Updated {userInfo.fullName}'s dietary restrictions to {dietInfo}.") if dietInfo.strip() else None + createAdminLog(f"Updated {userInfo.fullName}'s dietary restrictions to {dietInfo}.") if dietInfo.strip() else None else: createAdminLog(f"Deleted all {userInfo.fullName}'s dietary restrictions dietary restrictions.") diff --git a/app/logic/transcript.py b/app/logic/transcript.py index 7dfb75cf8..dc7ed3d61 100644 --- a/app/logic/transcript.py +++ b/app/logic/transcript.py @@ -1,77 +1,86 @@ -from peewee import fn - -from app.models.course import Course -from app.models.courseParticipant import CourseParticipant -from app.models.program import Program -from app.models.courseInstructor import CourseInstructor -from app.models.user import User -from app.models.term import Term -from app.models.eventParticipant import EventParticipant -from app.models.event import Event - -def getProgramTranscript(username): - """ - Returns a Program query object containing all the programs for - current user. - """ - # Add up hours earned in a term for each program they've participated in - - EventData = (Event.select(Event, fn.SUM(EventParticipant.hoursEarned).alias("hoursEarned")) - .join(EventParticipant) - .where(EventParticipant.user == username) - .group_by(Event.program, Event.term) - .order_by(Event.term) - .having(fn.SUM(EventParticipant.hoursEarned > 0))) - transcriptData = {} - for event in EventData: - if event.program in transcriptData: - transcriptData[event.program].append([event.term.description, event.hoursEarned]) - else: - transcriptData[event.program] = [[event.term.description, event.hoursEarned]] - return transcriptData - -def getSlCourseTranscript(username): - """ - Returns a SLCourse query object containing all the training events for - current user. - """ - - slCourses = (Course.select(Course, fn.SUM(CourseParticipant.hoursEarned).alias("hoursEarned")) - .join(CourseParticipant, on=(Course.id == CourseParticipant.course)) - .where(CourseParticipant.user == username) - .group_by(Course.courseName, Course.term)) - - return slCourses - -def getTotalHours(username): - """ - Get the toal hours from events and courses combined. - """ - eventHours = (EventParticipant.select(fn.SUM(EventParticipant.hoursEarned)) - .where(EventParticipant.user == username)).scalar() - courseHours = (CourseParticipant.select(fn.SUM(CourseParticipant.hoursEarned)) - .where(CourseParticipant.user == username)).scalar() - - allHours = {"totalEventHours": (eventHours or 0), - "totalCourseHours": (courseHours or 0), - "totalHours": (eventHours or 0) + (courseHours or 0)} - return allHours - -def getStartYear(username): - """ - Returns the users start term for participation in the CELTS organization - """ - - startDate = (EventParticipant.select(Term.year) - .join(Event) - .join(Term).where(EventParticipant.user == username) - + CourseParticipant.select(Term.year) - .join(Course) - .join(Term) - .where(CourseParticipant.user == username) - ).order_by(Event.term.year).first() - - if startDate: - return startDate.event.term.year - - return "N/A" +from peewee import fn +from collections import defaultdict + +from app.models.course import Course +from app.models.courseParticipant import CourseParticipant +from app.models.program import Program +from app.models.programBan import ProgramBan +from app.models.courseInstructor import CourseInstructor +from app.models.user import User +from app.models.term import Term +from app.models.eventParticipant import EventParticipant +from app.models.event import Event + +def getProgramTranscript(username): + """ + Returns a Program query object containing all the programs for + the current user. + """ + # Add up hours earned in a term for each program they've participated in + + EventData = (Event.select(Event, fn.SUM(EventParticipant.hoursEarned).alias("hoursEarned")) + .join(EventParticipant) + .where(EventParticipant.user == username) + .group_by(Event.program, Event.term) + .order_by(Event.term) + .having(fn.SUM(EventParticipant.hoursEarned > 0))) + + # Fetch all ProgramBan objects for the user + bannedProgramsForParticipant = ProgramBan.select().where(ProgramBan.user == username) + + # Create a set of program IDs to remove from transcript + programsToRemoveFromTranscript = {bannedProgram.program_id for bannedProgram in bannedProgramsForParticipant if bannedProgram.removeFromTranscript} + transcriptData = defaultdict(list) + + # Iterate through EventData and populate transcriptData + for event in EventData: + if event.program.id not in programsToRemoveFromTranscript: # Check if program is not in programs to be removed from transcript + transcriptData[event.program].append([event.term.description, event.hoursEarned]) + + return dict(transcriptData) + +def getSlCourseTranscript(username): + """ + Returns a SLCourse query object containing all the training events for + current user. + """ + + slCourses = (Course.select(Course, fn.SUM(CourseParticipant.hoursEarned).alias("hoursEarned")) + .join(CourseParticipant, on=(Course.id == CourseParticipant.course)) + .where(CourseParticipant.user == username) + .group_by(Course.courseName, Course.term)) + + return slCourses + +def getTotalHours(username): + """ + Get the toal hours from events and courses combined. + """ + eventHours = (EventParticipant.select(fn.SUM(EventParticipant.hoursEarned)) + .where(EventParticipant.user == username)).scalar() + courseHours = (CourseParticipant.select(fn.SUM(CourseParticipant.hoursEarned)) + .where(CourseParticipant.user == username)).scalar() + + allHours = {"totalEventHours": (eventHours or 0), + "totalCourseHours": (courseHours or 0), + "totalHours": (eventHours or 0) + (courseHours or 0)} + return allHours + +def getStartYear(username): + """ + Returns the users start term for participation in the CELTS organization + """ + + startDate = (EventParticipant.select(Term.year) + .join(Event) + .join(Term).where(EventParticipant.user == username) + + CourseParticipant.select(Term.year) + .join(Course) + .join(Term) + .where(CourseParticipant.user == username) + ).order_by(Event.term.year).first() + + if startDate: + return startDate.event.term.year + + return "N/A" diff --git a/app/logic/users.py b/app/logic/users.py index 745f5a83a..d50957f14 100644 --- a/app/logic/users.py +++ b/app/logic/users.py @@ -5,6 +5,7 @@ from app.models.note import Note from app.models.user import User from app.models.profileNote import ProfileNote +from app.models.programBan import ProgramBan from app.models.backgroundCheck import BackgroundCheck from app.models.backgroundCheckType import BackgroundCheckType from app.logic.volunteers import addUserBackgroundCheck diff --git a/app/models/programBan.py b/app/models/programBan.py index 45a58d064..f94c6100d 100644 --- a/app/models/programBan.py +++ b/app/models/programBan.py @@ -9,3 +9,6 @@ class ProgramBan(baseModel): endDate = DateField(null=True) banNote = ForeignKeyField(Note, null=False) unbanNote = ForeignKeyField(Note, null=True) + removeFromTranscript = BooleanField(default=False) + + diff --git a/app/static/js/userProfile.js b/app/static/js/userProfile.js index 5e34eb594..9a6e2bc75 100644 --- a/app/static/js/userProfile.js +++ b/app/static/js/userProfile.js @@ -1,323 +1,361 @@ -$(document).ready(function(){ - $("#expressInterest").on("click", function() { - let username = $(this).data('username') - let data = {"username":username} - $.ajax({ - url: "/profile/"+username+"/indicateInterest", - type: "POST", - data: data, - success: function(s) { - - }, - error: function(request, status, error) { - console.log(error) - msgToast("Error!", "Failed to save changes!") - } - }); - }) - - $("#printButton").on("click", function() { - let username = $(this).data('username') - printDocument(`/profile/${username}/travelForm`) - }) - $("#actions").on("change", changeAction) - $("#phoneInput").inputmask('(999)-999-9999'); - $(".notifyInput").click(function updateInterest(){ - var programID = $(this).data("programid"); - var username = $(this).data('username'); - - - var interest = $(this).is(':checked'); - var routeUrl = interest ? "addInterest" : "removeInterest"; - interestUrl = "/" + username + "/" + routeUrl + "/" + programID ; - $.ajax({ - method: "POST", - url: interestUrl, - success: function(response) { - reloadWithAccordion("programTable") // Reloading page after user clicks on the show interest checkbox - }, - error: function(request, status, error) { - console.log(status,error); - location.reload(); - } - }); - }); - - function changeAction(e){ - let profileAction = $(this).val() - let username = $(this).data('username') - if (profileAction == "Emergency Contact"){ - window.location.href = `/profile/${username}/emergencyContact` - } else if (profileAction == "Insurance Information"){ - window.location.href = `/profile/${username}/insuranceInfo` - } else if(profileAction == "Print Travel Form"){ - printDocument(`/profile/${username}/travelForm`) - } else if (profileAction == "View Service Transcript"){ - window.location.href = `/profile/${username}/serviceTranscript` - } else if (profileAction == "Manage CCE Minor") { - window.location.href = `/profile/${username}/cceMinor` - } - $(this).val('') - } - - // This function is to disable all the dates before current date in the ban modal End Date picker - $(function(){ - var banEndDatepicker = $("#banEndDatepicker"); - banEndDatepicker.datepicker({ - changeYear: true, - changeMonth: true, - minDate:+1, - dateFormat: "yy-mm-dd", - }).attr('readonly','readonly'); - }); - - /* - * Ban Functionality - */ - $(".ban").click(function() { - var banButton = $("#banButton") - var banEndDateDiv = $("#banEndDate") // Div containing the datepicker in the ban modal - var banEndDatepicker = $("#banEndDatepicker") // Datepicker in the ban modal - var banNoteDiv = $("#banNoteDiv") // Div containing the note displaying why the user was banned previously - //Should only diplay when the modal is going to unban a user - var banNote = $("#banNote") - - banButton.text($(this).val() + " Volunteer"); - banButton.data("programID", $(this).data("programid")) - banButton.data("username", $("#notifyInput").data("username")) - banButton.data("banOrUnban", $(this).val()); - banEndDateDiv.show(); - banEndDatepicker.val("") - $(".modal-title").text($(this).val() + " Volunteer"); - $("#modalProgramName").text("Program: " + $(this).data("name ")); - $("#banModal").modal("toggle"); - banNoteDiv.hide(); - $("#banNoteTxtArea").val(""); - $("#banButton").prop("disabled", true); - if( $(this).val()=="Unban"){ - banEndDateDiv.hide() - banEndDatepicker.val("0001-01-01") //This is a placeholder value for the if statement in line 52 to work properly #PLCHLD1 - banNoteDiv.show() - banNote.text($(this).data("note")) - } - - }); - - - $("#banNoteTxtArea, #banEndDatepicker").on('input' , function (e) { //This is the if statement the placeholder in line 45 is for #PLCHLD1 - var enableButton = ($("#banNoteTxtArea").val() && $("#banEndDatepicker").val()); - $("#banButton").prop("disabled", !enableButton); - }); - - $("#banButton").click(function (){ - $("#banButton").prop("disabled", true) - var username = $(this).data("username") //Expected to be the unique username of a user in the database - var route = ($(this).data("banOrUnban")).toLowerCase() //Expected to be "ban" or "unban" - var program = $(this).data("programID") //Expected to be a program's primary ID - $.ajax({ - method: "POST", - url: "/" + username + "/" + route + "/" + program, - data: {"note": $("#banNoteTxtArea").val(), - "endDate":$("#banEndDatepicker").val() //Expected to be a date in this format YYYY-MM-DD - }, - success: function(response) { - reloadWithAccordion("programTable") - } - }); - }); - - /* - * Note Functionality - */ - function bonnerNoteOff() { - $("#bonnerInput").prop("checked", false); - $("#noteDropdown").show() - $("#bonnerStatement").hide() - $("#visibilityLabel").show() - } - - function bonnerNoteOn() { - $("#bonnerInput").prop("checked", true); - $("#noteDropdown").hide() - $("#bonnerStatement").show() - $("#visibilityLabel").hide() - } - - $("#addNoteButton").click(function() { - bonnerNoteOff() - $("#noteModal").modal("toggle") - }); - - $("#addVisibility").click(function() { - var bonnerChecked = $("input[name='bonner']:checked").val() - - if (bonnerChecked == 'on') { - bonnerNoteOn() - } else { - bonnerNoteOff() - } - }); - - $("#addBonnerNoteButton").click(function() { - bonnerNoteOn() - $("#noteModal").modal("toggle"); - }); - - $('#addNoteForm').submit(function(event) { - event.preventDefault() - let username = $("#notesSaveButton").data('username') - let isBonner = $("#bonnerInput").is(":checked") - $.ajax({ - method: "POST", - url: "/profile/addNote", - data: {"username": username, - "visibility": $("#noteDropdown").val(), - "noteTextbox": $("#addNoteTextArea").val(), - "bonner": isBonner ? "yes" : "no"}, - success: function(response) { - target = isBonner ? "bonner" : "notes" - reloadWithAccordion(target) - } - }); -}); - - $(".deleteNoteButton").click(function() { - let username = $(this).data('username') - let noteid = $(this).data('noteid') - $.ajax({ - method: "POST", - url: "/" + username + "/deleteNote", - data: {"id": noteid}, - success: function(response) { - reloadWithAccordion("notes") - } - }); - }); - - /* - * Background Check Functionality - */ - // Updates the Background check of a volunteer in the database - $(".savebtn").click(function () { - $(this).prop("disabled", true); - let bgCheckType = $(this).data("id") - - var bgStatusInput = $("#" + bgCheckType) - var bgDateInput = $("#" + bgCheckType + "_date") - - let bgDate = bgDateInput.val() - let bgStatus = $("[data-id=" + bgCheckType + "]").val() - - if (bgStatus == '') { - bgStatusInput.focus() - bgStatusInput.addClass("invalid"); - window.setTimeout(() => bgStatusInput.removeClass("invalid"), 1000); - $(this).prop("disabled", false); - return false - } - - if (bgDate == ''){ - bgDateInput.focus() - bgDateInput.addClass("invalid"); - window.setTimeout(() => bgDateInput.removeClass("invalid"), 1000); - $(this).prop("disabled", false); - return false - } - - let data = { - bgStatus: bgStatus, // Expected to be one of the three background check statuses - user: $(this).data("username"), // Expected to be the username of a volunteer in the database - bgType: $(this).attr("id"), // Expected to be the ID of a background check in the database - bgDate: bgDate // Expected to be the date of the background check completion or '' if field is empty - } - $.ajax({ - url: "/addBackgroundCheck", - type: "POST", - data: data, - success: function(s){ - var date = new Date(data.bgDate + " 12:00").toLocaleDateString() - reloadWithAccordion("background") - }, - error: function(error, status){ - console.log(error, status) - } - }) - }); - - $("#bgHistoryTable").on("click", "#deleteBgHistory", function() { - let data = { - bgID: $(this).data("id"), // Expected to be the ID of a background check in the database - } - $(this).closest("li").remove(); - - $.ajax({ - url: "/deleteBackgroundCheck", - type: "POST", - data: data, - success: function(s){ - msgToast("Background Check", "Successfully deleted background check.") - }, - error: function(error, status){ - console.log(error,status) - } - }) - }); - // Popover functionality - var requiredTraining = $(".trainingPopover"); - requiredTraining.popover({ - trigger: "hover", - sanitize: false, - html: true, - content: function() { - return $(this).attr('data-content'); - } - }); - - setupPhoneNumber("#updatePhone", "#phoneInput") - - $(".saveDiet").on('click', function() { - let data = { - dietInfo: $("#diet").val(), - user: $(this).data("user") - } - $.ajax({ - type: "POST", - url: "/updateDietInformation", - data: data, - success: function(s){ - reloadWithAccordion("dietaryInformation"); - }, - }) - }); - -}); - -function updateManagers(el, volunteer_username ){// retrieve the data of the student staff and program id if the boxes are checked or not - let program_id=$(el).attr('data-programid'); - let programName = $(el).attr('data-programName') - let name = $(el).attr('data-name') - let action= el.checked ? 'add' : 'remove'; - let removeMessage = (name + " is no longer the manager of " + programName + ".") - let addMessage = (name + " is now the manager of " + programName + ".") - - $.ajax({ - method:"POST", - url:"/updateProgramManager", - data : {"user_name":volunteer_username, //student staff: user_name - "program_id":program_id, // program id - "action":action, //action: add or remove - }, - - success: function(s){ - if(action == "add"){ - msgToast("Program manager", addMessage) - } else if(action == 'remove'){ - msgToast("Program manager", removeMessage) - } - }, - error: function(error, status){ - console.log(error, status) - } - }) -} - +$(document).ready(function(){ + $("#expressInterest").on("click", function() { + let username = $(this).data('username') + let data = {"username":username} + $.ajax({ + url: "/profile/"+username+"/indicateInterest", + type: "POST", + data: data, + success: function(s) { + + }, + error: function(request, status, error) { + console.log(error) + msgToast("Error!", "Failed to save changes!") + } + }); + }) + + $("#printButton").on("click", function() { + let username = $(this).data('username') + printDocument(`/profile/${username}/travelForm`) + }) + $("#actions").on("change", changeAction) + $("#phoneInput").inputmask('(999)-999-9999'); + $(".notifyInput").click(function updateInterest(){ + var programID = $(this).data("programid"); + var username = $(this).data('username'); + + + var interest = $(this).is(':checked'); + var routeUrl = interest ? "addInterest" : "removeInterest"; + interestUrl = "/" + username + "/" + routeUrl + "/" + programID ; + $.ajax({ + method: "POST", + url: interestUrl, + success: function(response) { + reloadWithAccordion("programTable") // Reloading page after user clicks on the show interest checkbox + }, + error: function(request, status, error) { + console.log(status,error); + location.reload(); + } + }); + }); + + $('.removeFromTranscriptCheckbox').click(function() { + var removeFromTranscript = $(this).is(':checked'); + var username = $(this).data('username'); + + + $.ajax({ + type: "POST", + url: `/profile/${username}/updateTranscript/${programID}`, + contentType: "application/json", + data: JSON.stringify({ username: username, removeFromTranscript: removeFromTranscript, programID: programID }), + success: function(response) { + console.log(response); + // Handle success response if needed + }, + error: function(error) { + console.error("An error occurred:", error); + // Handle error if needed + } + }); + }); + + + function changeAction(e){ + let profileAction = $(this).val() + let username = $(this).data('username') + if (profileAction == "Emergency Contact"){ + window.location.href = `/profile/${username}/emergencyContact` + } else if (profileAction == "Insurance Information"){ + window.location.href = `/profile/${username}/insuranceInfo` + } else if(profileAction == "Print Travel Form"){ + printDocument(`/profile/${username}/travelForm`) + } else if (profileAction == "View Service Transcript"){ + window.location.href = `/profile/${username}/serviceTranscript` + } else if (profileAction == "Manage CCE Minor") { + window.location.href = `/profile/${username}/cceMinor` + } + $(this).val('') + } + + // This function is to disable all the dates before current date in the ban modal End Date picker + $(function(){ + var banEndDatepicker = $("#banEndDatepicker"); + banEndDatepicker.datepicker({ + changeYear: true, + changeMonth: true, + minDate:+1, + dateFormat: "yy-mm-dd", + }).attr('readonly','readonly'); + }); + + /* + * Ban Functionality + */ + + + var programID; + $(".banEdit").click(function() { + $.ajax({ + url: `/profile/${$(this).data("username")}/removeFromTranscript/${$(this).data("programid")}`, + type: "GET", + success: function(response) { + // Check if the program is marked for removal from transcript + $('#removeFromTranscriptCheckbox').prop('checked', response.removedFromTranscript) + }, + error: function(error, status) { + console.log(error, status); + } + }); + + var banButton = $("#banButton") + var banEndDateDiv = $("#banEndDate") // Div containing the datepicker in the ban modal + var banEndDatepicker = $("#banEndDatepicker") // Datepicker in the ban modal + var banNoteDiv = $("#banNoteDiv") // Div containing the note displaying why the user was banned previously + banNoteDiv.hide(); //Should only diplay when the modal is going to unban a user + var banNote = $("#banNote") + var banValue = $(this).val() + + banButton.text(banValue + " Volunteer"); + programID = $(this).data("programid"); // Assign value to programID variable + banButton.data("programID", programID) + banButton.data("username", $("#notifyInput").data("username")) + banButton.data("banOrUnban", banValue); + banEndDateDiv.show(); + banEndDatepicker.val("") + $(".modal-title-ban").text(banValue + " Volunteer"); + $("#modalProgramName").text("Program: " + $(this).data("name ")); + $("#banModal").modal("toggle"); + $("#removeFromTranscriptDiv").hide(); + $("#banNoteTxtArea").val(""); + $("#banButton").prop("disabled", true); + if(banValue == "Unban"){ + banEndDateDiv.hide() + banEndDatepicker.val("0001-01-01") //This is a placeholder value for the if statement in line 52 to work properly #PLCHLD1 + banNoteDiv.show() + $("#removeFromTranscriptDiv").show(); + banNote.text($(this).data("note")) + } + }); + + + $("#banNoteTxtArea, #banEndDatepicker").on('input' , function (e) { //This is the if statement the placeholder in line 45 is for #PLCHLD1 + var enableButton = ($("#banNoteTxtArea").val() && $("#banEndDatepicker").val()); + $("#banButton").prop("disabled", !enableButton); + }); + + $("#banButton").click(function (){ + $("#banButton").prop("disabled", true) + var username = $(this).data("username") //Expected to be the unique username of a user in the database + var route = ($(this).data("banOrUnban")).toLowerCase() //Expected to be "ban" or "unban" + var program = $(this).data("programID") //Expected to be a program's primary ID + $.ajax({ + method: "POST", + url: "/" + username + "/" + route + "/" + program, + data: {"note": $("#banNoteTxtArea").val(), + "endDate":$("#banEndDatepicker").val() //Expected to be a date in this format YYYY-MM-DD + }, + success: function(response) { + reloadWithAccordion("programTable") + } + }); + }); + + /* + * Note Functionality + */ + function bonnerNoteOff() { + $("#bonnerInput").prop("checked", false); + $("#noteDropdown").show() + $("#bonnerStatement").hide() + $("#visibilityLabel").show() + } + + function bonnerNoteOn() { + $("#bonnerInput").prop("checked", true); + $("#noteDropdown").hide() + $("#bonnerStatement").show() + $("#visibilityLabel").hide() + } + + $("#addNoteButton").click(function() { + bonnerNoteOff() + $("#noteModal").modal("toggle") + }); + + $("#addVisibility").click(function() { + var bonnerChecked = $("input[name='bonner']:checked").val() + + if (bonnerChecked == 'on') { + bonnerNoteOn() + } else { + bonnerNoteOff() + } + }); + + $("#addBonnerNoteButton").click(function() { + bonnerNoteOn() + $("#noteModal").modal("toggle"); + }); + + $('#addNoteForm').submit(function(event) { + event.preventDefault() + let username = $("#notesSaveButton").data('username') + let isBonner = $("#bonnerInput").is(":checked") + $.ajax({ + method: "POST", + url: "/profile/addNote", + data: {"username": username, + "visibility": $("#noteDropdown").val(), + "noteTextbox": $("#addNoteTextArea").val(), + "bonner": isBonner ? "yes" : "no"}, + success: function(response) { + target = isBonner ? "bonner" : "notes" + reloadWithAccordion(target) + } + }); +}); + + $(".deleteNoteButton").click(function() { + let username = $(this).data('username') + let noteid = $(this).data('noteid') + $.ajax({ + method: "POST", + url: "/" + username + "/deleteNote", + data: {"id": noteid}, + success: function(response) { + reloadWithAccordion("notes") + } + }); + }); + + /* + * Background Check Functionality + */ + // Updates the Background check of a volunteer in the database + $(".savebtn").click(function () { + $(this).prop("disabled", true); + let bgCheckType = $(this).data("id") + + var bgStatusInput = $("#" + bgCheckType) + var bgDateInput = $("#" + bgCheckType + "_date") + + let bgDate = bgDateInput.val() + let bgStatus = $("[data-id=" + bgCheckType + "]").val() + + if (bgStatus == '') { + bgStatusInput.focus() + bgStatusInput.addClass("invalid"); + window.setTimeout(() => bgStatusInput.removeClass("invalid"), 1000); + $(this).prop("disabled", false); + return false + } + + if (bgDate == ''){ + bgDateInput.focus() + bgDateInput.addClass("invalid"); + window.setTimeout(() => bgDateInput.removeClass("invalid"), 1000); + $(this).prop("disabled", false); + return false + } + + let data = { + bgStatus: bgStatus, // Expected to be one of the three background check statuses + user: $(this).data("username"), // Expected to be the username of a volunteer in the database + bgType: $(this).attr("id"), // Expected to be the ID of a background check in the database + bgDate: bgDate // Expected to be the date of the background check completion or '' if field is empty + } + $.ajax({ + url: "/addBackgroundCheck", + type: "POST", + data: data, + success: function(s){ + var date = new Date(data.bgDate + " 12:00").toLocaleDateString() + reloadWithAccordion("background") + }, + error: function(error, status){ + console.log(error, status) + } + }) + }); + + $("#bgHistoryTable").on("click", "#deleteBgHistory", function() { + let data = { + bgID: $(this).data("id"), // Expected to be the ID of a background check in the database + } + $(this).closest("li").remove(); + + $.ajax({ + url: "/deleteBackgroundCheck", + type: "POST", + data: data, + success: function(s){ + msgToast("Background Check", "Successfully deleted background check.") + }, + error: function(error, status){ + console.log(error,status) + } + }) + }); + // Popover functionality + var requiredTraining = $(".trainingPopover"); + requiredTraining.popover({ + trigger: "hover", + sanitize: false, + html: true, + content: function() { + return $(this).attr('data-content'); + } + }); + + setupPhoneNumber("#updatePhone", "#phoneInput") + + $(".saveDiet").on('click', function() { + let data = { + dietInfo: $("#diet").val(), + user: $(this).data("user") + } + $.ajax({ + type: "POST", + url: "/updateDietInformation", + data: data, + success: function(s){ + reloadWithAccordion("dietaryInformation"); + }, + }) + }); + +}); + +function updateManagers(el, volunteer_username ){// retrieve the data of the student staff and program id if the boxes are checked or not + let program_id=$(el).attr('data-programid'); + let programName = $(el).attr('data-programName') + let name = $(el).attr('data-name') + let action= el.checked ? 'add' : 'remove'; + let removeMessage = (name + " is no longer the manager of " + programName + ".") + let addMessage = (name + " is now the manager of " + programName + ".") + + $.ajax({ + method:"POST", + url:"/updateProgramManager", + data : {"user_name":volunteer_username, //student staff: user_name + "program_id":program_id, // program id + "action":action, //action: add or remove + }, + + success: function(s){ + if(action == "add"){ + msgToast("Program manager", addMessage) + } else if(action == 'remove'){ + msgToast("Program manager", removeMessage) + } + }, + error: function(error, status){ + console.log(error, status) + } + }) +} diff --git a/app/templates/main/serviceTranscript.html b/app/templates/main/serviceTranscript.html index 2534bc09a..31e9d8f15 100644 --- a/app/templates/main/serviceTranscript.html +++ b/app/templates/main/serviceTranscript.html @@ -75,3 +75,5 @@
No Volunteer Record
{% endblock %} + + diff --git a/app/templates/main/userProfile.html b/app/templates/main/userProfile.html index 8333a9127..af9ead40d 100644 --- a/app/templates/main/userProfile.html +++ b/app/templates/main/userProfile.html @@ -16,7 +16,7 @@ {% block app_content %} {% if volunteer.isStudent and not totalSustainedEngagements%}
-

Did you know we have a Civic and Community Engagement Minor? Click +

Did you know we have a Civic and Community Engagement Minor? Click here for more information.

@@ -41,7 +41,7 @@

{{volunteer.firstName}} {{volunteer.lastName}}

{{volunteer.major}}
{% endif %} {% if volunteer.classLevel -%} -
{{volunteer.classLevel}}
+
{{volunteer.classLevel}}
{% endif %}
@@ -202,7 +202,7 @@

{% endif %} {% if g.current_user.isCeltsAdmin %} - + {% endif %} {% endif %} @@ -233,7 +233,7 @@

CELTS Labor History:
{% for program, term in participatedInLabor.items() %} -

{{term}}: {{program}}

+

{{term}}: {{program}}

{% endfor %}
{% endif %} @@ -515,9 +515,9 @@

- -
+ +
{% if g.current_user.isBonnerScholar and volunteer.isBonnerScholar %}
@@ -535,7 +535,7 @@
{% endif %}
- +
@@ -559,7 +559,7 @@