From f1b898fb0d970bea2a2914db97dbb742de9c9141 Mon Sep 17 00:00:00 2001 From: CocoByte Date: Thu, 14 Nov 2024 10:11:41 -0700 Subject: [PATCH] modal work... --- src/registrar/assets/js/get-gov.js | 126 ++++++++++++++++++ src/registrar/config/urls.py | 5 + .../templates/portfolio_members_add_new.html | 70 +++++++++- src/registrar/views/portfolios.py | 20 ++- 4 files changed, 215 insertions(+), 6 deletions(-) diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js index adcc21d2a..adbd4068f 100644 --- a/src/registrar/assets/js/get-gov.js +++ b/src/registrar/assets/js/get-gov.js @@ -2820,3 +2820,129 @@ document.addEventListener('DOMContentLoaded', function() { // Add event listener to the suborg dropdown to show/hide the suborg details section select.addEventListener("change", () => toggleSuborganization()); })(); + + +/** + * An IIFE that handles the modal associated with adding a new member to a portfolio. + */ +(function handleNewMemberModal() { + + // Validate the form + function validateForm() { + // Perform an AJAX POST request to validate form data + const form = document.getElementById("add_member_form"); + if (!form) { + console.error("Form element not found"); + return; + } + const formData = new FormData(form); // Use the form element for FormData + fetch("/members/new-member/validate", { + method: "POST", + body: formData, + headers: { + "X-Requested-With": "XMLHttpRequest" + } + }) + .then(response => response.json()) + .then(data => { + if (data.is_valid) { + // If validation passes, display the modal and set values + openAddMemberConfirmationModal(); + } else { + // Handle validation errors + alert("Validation failed."); + } + }); + } + + function populatePermissionDetails(permission_details_div_id) { + const permissionDetailsContainer = document.getElementById("permission_details"); + permissionDetailsContainer.innerHTML = ""; // Clear previous content + + // Get all permission sections (divs with h3 and radio inputs) + const permissionSections = document.querySelectorAll("#"+permission_details_div_id+" > h3"); + + permissionSections.forEach(section => { + // Find the

element text + const sectionTitle = section.textContent; + + // Find the associated radio buttons container (next fieldset) + const fieldset = section.nextElementSibling; + + if (fieldset && fieldset.tagName.toLowerCase() === 'fieldset') { + // Get the selected radio button within this fieldset + const selectedRadio = fieldset.querySelector('input[type="radio"]:checked'); + + // If a radio button is selected, get its label text + let selectedPermission = "No permission selected"; + if (selectedRadio) { + const label = fieldset.querySelector(`label[for="${selectedRadio.id}"]`); + selectedPermission = label ? label.textContent : "No permission selected"; + } + + // Create new elements for the modal content + const titleElement = document.createElement("h3"); + titleElement.textContent = sectionTitle; + + const permissionElement = document.createElement("p"); + permissionElement.textContent = selectedPermission; + + // Append to the modal content container + permissionDetailsContainer.appendChild(titleElement); + permissionDetailsContainer.appendChild(permissionElement); + } + }); +} + + // Open the modal + function openAddMemberConfirmationModal() { + + // Get email value + let emailValue = document.getElementById('id_email').value; + document.getElementById('modalEmail').textContent = emailValue; + + // Get selected radio button for access level + let selectedAccess = document.querySelector('input[name="member_access_level"]:checked'); + let accessText = selectedAccess ? selectedAccess.value : "No access level selected"; //nextElementSibling.textContent.trim() + document.getElementById('modalAccessLevel').textContent = accessText; + + // Populate permission details based on access level + if (selectedAccess && selectedAccess.value === 'admin') { + populatePermissionDetails('new-member-admin-permissions') + } else { + populatePermissionDetails('new-member-basic-permissions') + } + + // Show the modal + modal = document.getElementById('invite-member-modal'); + showElement(modal); + } + + // Close the modal + function closeModal() { + modal = document.getElementById('invite-member-modal'); + hideElement(modal); + } + + // ---- EVENT LISTENERS + document.querySelectorAll('[data-close-modal]').forEach(button => { + button.addEventListener('click', closeModal); + }); + + // document.getElementById("confirm_new_member_submit").addEventListener("click", function() { + // // Upon confirmation, submit the form + // document.getElementById("add_member_form").submit(); + // }); + + // Attach event listener to the Invite Member button to open the modal + document.getElementById("invite_member_button").addEventListener('click', function() { + // Upon confirmation, submit the form + console.log("clicked") + openAddMemberConfirmationModal(); + }); + + document.getElementById("add_member_form").addEventListener("submit", function(event) { + event.preventDefault(); // Prevents the form from submitting + validateForm(); + }); +})(); \ No newline at end of file diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index d289eaf90..e60849460 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -125,6 +125,11 @@ urlpatterns = [ views.NewMemberView.as_view(), name="new-member", ), + path( + "members/new-member/validate", + views.NewMemberView.as_view(http_method_names=["post"]), + name="new-member-validate", + ), path( "requests/", views.PortfolioDomainRequestsView.as_view(), diff --git a/src/registrar/templates/portfolio_members_add_new.html b/src/registrar/templates/portfolio_members_add_new.html index fe9cb9752..75730a296 100644 --- a/src/registrar/templates/portfolio_members_add_new.html +++ b/src/registrar/templates/portfolio_members_add_new.html @@ -35,7 +35,7 @@ {% include "includes/required_fields.html" %} -
+

Email

@@ -108,10 +108,76 @@ aria-label="Cancel adding new member" >Cancel - + Invite Member + + + + {% endblock portfolio_content%} diff --git a/src/registrar/views/portfolios.py b/src/registrar/views/portfolios.py index 1dbab2913..8ba2e111b 100644 --- a/src/registrar/views/portfolios.py +++ b/src/registrar/views/portfolios.py @@ -1,5 +1,5 @@ import logging -from django.http import Http404 +from django.http import Http404, JsonResponse from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse from django.contrib import messages @@ -416,12 +416,24 @@ class NewMemberView(PortfolioMembersPermissionView, FormMixin): def post(self, request, *args, **kwargs): """Handle POST requests to process form submission.""" + self.object = self.get_object() form = self.get_form() + if form.is_valid(): - return self.form_valid(form) + return JsonResponse({"is_valid": True}) else: - return self.form_invalid(form) + return JsonResponse({"is_valid": False, "errors": form.errors}) + # if request.method == "POST" and request.is_ajax(): + # if form.is_valid(): + # return JsonResponse({"is_valid": True}) + # else: + # return JsonResponse({"is_valid": False, "errors": form.errors}) + + # if form.is_valid(): + # return self.form_valid(form) + # else: + # return self.form_invalid(form) def form_invalid(self, form): """Handle the case when the form is invalid.""" @@ -497,7 +509,7 @@ class NewMemberView(PortfolioMembersPermissionView, FormMixin): # raise EmailSendingError("Could not send email invitation.") from exc # else: # if add_success: - # messages.success(self.request, f"{email} has been invited to this domain.") + # messages.success(self.request, f"{email} has been invited.") # def _make_invitation(self, email_address: str, requestor: User): # """Make a Member invitation for this email and redirect with a message."""