diff --git a/src/registrar/assets/js/get-gov.js b/src/registrar/assets/js/get-gov.js index 02e6ea242..47217c495 100644 --- a/src/registrar/assets/js/get-gov.js +++ b/src/registrar/assets/js/get-gov.js @@ -912,180 +912,183 @@ function ScrollToElement(attributeName, attributeValue) { * */ document.addEventListener('DOMContentLoaded', function() { - let currentSortBy = 'id'; - let currentOrder = 'asc'; let domainsWrapper = document.querySelector('.domains-wrapper'); - let noDomainsWrapper = document.querySelector('.no-domains-wrapper'); - let hasLoaded = false; - /** - * Loads rows in the domains list, as well as updates pagination around the domains list - * based on the supplied attributes. - * @param {*} page - the page number of the results (starts with 1) - * @param {*} sortBy - the sort column option - * @param {*} order - the sort order {asc, desc} - * @param {*} loaded - control for the scrollToElement functionality - */ - function loadDomains(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) { - //fetch json of page of domains, given page # and sort - fetch(`/get-domains-json/?page=${page}&sort_by=${sortBy}&order=${order}`) - .then(response => response.json()) - .then(data => { - if (data.error) { - console.log('Error in AJAX call: ' + data.error); - return; - } + if (domainsWrapper) { + let currentSortBy = 'id'; + let currentOrder = 'asc'; + let noDomainsWrapper = document.querySelector('.no-domains-wrapper'); + let hasLoaded = false; - // handle the display of proper messaging in the event that no domains exist in the list - if (data.domains.length) { - domainsWrapper.classList.remove('display-none'); - noDomainsWrapper.classList.add('display-none'); - } else { - domainsWrapper.classList.add('display-none'); - noDomainsWrapper.classList.remove('display-none'); - } + /** + * Loads rows in the domains list, as well as updates pagination around the domains list + * based on the supplied attributes. + * @param {*} page - the page number of the results (starts with 1) + * @param {*} sortBy - the sort column option + * @param {*} order - the sort order {asc, desc} + * @param {*} loaded - control for the scrollToElement functionality + */ + function loadDomains(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) { + //fetch json of page of domains, given page # and sort + fetch(`/get-domains-json/?page=${page}&sort_by=${sortBy}&order=${order}`) + .then(response => response.json()) + .then(data => { + if (data.error) { + console.log('Error in AJAX call: ' + data.error); + return; + } - // identify the DOM element where the domain list will be inserted into the DOM - const domainList = document.querySelector('.dotgov-table__registered-domains tbody'); - domainList.innerHTML = ''; + // handle the display of proper messaging in the event that no domains exist in the list + if (data.domains.length) { + domainsWrapper.classList.remove('display-none'); + noDomainsWrapper.classList.add('display-none'); + } else { + domainsWrapper.classList.add('display-none'); + noDomainsWrapper.classList.remove('display-none'); + } - data.domains.forEach(domain => { - const expirationDate = domain.expiration_date ? new Date(domain.expiration_date) : null; - const expirationDateSortValue = expirationDate ? expirationDate.getTime() : ''; - const actionUrl = domain.action_url; - - const row = document.createElement('tr'); - row.innerHTML = ` - - ${domain.name} - - - ${expirationDate ? expirationDate.toLocaleDateString() : ''} - - - ${domain.state_display} - - - - - - - ${domain.name} - - - `; - domainList.appendChild(row); - }); - // initialize tool tips immediately after the associated DOM elements are added - initializeTooltips(); - if (loaded) - ScrollToElement('id', 'domains-header'); + + + + + ${domain.state === 'deleted' || domain.state === 'on hold' ? 'View' : 'Manage'} ${domain.name} + + + `; + domainList.appendChild(row); + }); + // initialize tool tips immediately after the associated DOM elements are added + initializeTooltips(); + if (loaded) + ScrollToElement('id', 'domains-header'); - hasLoaded = true; + hasLoaded = true; - // update pagination - updateDomainsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total); - currentSortBy = sortBy; - currentOrder = order; - }) - .catch(error => console.error('Error fetching domains:', error)); - } - - /** - * Update the pagination below the domains list. - * @param {*} currentPage - the current page number (starting with 1) - * @param {*} numPages - the number of pages indicated by the domains list response - * @param {*} hasPrevious - if there is a page of results prior to the current page - * @param {*} hasNext - if there is a page of results after the current page - */ - function updateDomainsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) { - // identify the DOM element where the pagination will be inserted - const paginationContainer = document.querySelector('#domains-pagination'); - const paginationCounter = document.querySelector('#domains-pagination .usa-pagination__counter'); - const paginationButtons = document.querySelector('#domains-pagination .usa-pagination__list'); - paginationCounter.innerHTML = ''; - paginationButtons.innerHTML = ''; - - // Buttons should only be displayed if there are more than one pages of results - paginationButtons.classList.toggle('display-none', numPages <= 1); - - // Counter should only be displayed if there is more than 1 item - paginationContainer.classList.toggle('display-none', totalItems < 1); - - paginationCounter.innerHTML = `${totalItems} domain${totalItems > 1 ? 's' : ''}`; - - if (hasPrevious) { - const prevPageItem = document.createElement('li'); - prevPageItem.className = 'usa-pagination__item usa-pagination__arrow'; - prevPageItem.innerHTML = ` - - - Previous - - `; - prevPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage - 1)); - paginationButtons.appendChild(prevPageItem); + // update pagination + updateDomainsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total); + currentSortBy = sortBy; + currentOrder = order; + }) + .catch(error => console.error('Error fetching domains:', error)); } - for (let i = 1; i <= numPages; i++) { - const pageItem = document.createElement('li'); - pageItem.className = 'usa-pagination__item usa-pagination__page-no'; - pageItem.innerHTML = ` - ${i} - `; - if (i === currentPage) { - pageItem.querySelector('a').classList.add('usa-current'); - pageItem.querySelector('a').setAttribute('aria-current', 'page'); + /** + * Update the pagination below the domains list. + * @param {*} currentPage - the current page number (starting with 1) + * @param {*} numPages - the number of pages indicated by the domains list response + * @param {*} hasPrevious - if there is a page of results prior to the current page + * @param {*} hasNext - if there is a page of results after the current page + */ + function updateDomainsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) { + // identify the DOM element where the pagination will be inserted + const paginationContainer = document.querySelector('#domains-pagination'); + const paginationCounter = document.querySelector('#domains-pagination .usa-pagination__counter'); + const paginationButtons = document.querySelector('#domains-pagination .usa-pagination__list'); + paginationCounter.innerHTML = ''; + paginationButtons.innerHTML = ''; + + // Buttons should only be displayed if there are more than one pages of results + paginationButtons.classList.toggle('display-none', numPages <= 1); + + // Counter should only be displayed if there is more than 1 item + paginationContainer.classList.toggle('display-none', totalItems < 1); + + paginationCounter.innerHTML = `${totalItems} domain${totalItems > 1 ? 's' : ''}`; + + if (hasPrevious) { + const prevPageItem = document.createElement('li'); + prevPageItem.className = 'usa-pagination__item usa-pagination__arrow'; + prevPageItem.innerHTML = ` + + + Previous + + `; + prevPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage - 1)); + paginationButtons.appendChild(prevPageItem); } - pageItem.querySelector('a').addEventListener('click', () => loadDomains(i)); - paginationButtons.appendChild(pageItem); - } - if (hasNext) { - const nextPageItem = document.createElement('li'); - nextPageItem.className = 'usa-pagination__item usa-pagination__arrow'; - nextPageItem.innerHTML = ` - - Next - - - `; - nextPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage + 1)); - paginationButtons.appendChild(nextPageItem); - } - } - - // Add event listeners to table headers for sorting - document.querySelectorAll('.dotgov-table__registered-domains th[data-sortable]').forEach(header => { - header.addEventListener('click', function() { - const sortBy = this.getAttribute('data-sortable'); - let order = 'asc'; - // sort order will be ascending, unless the currently sorted column is ascending, and the user - // is selecting the same column to sort in descending order - if (sortBy === currentSortBy) { - order = currentOrder === 'asc' ? 'desc' : 'asc'; + for (let i = 1; i <= numPages; i++) { + const pageItem = document.createElement('li'); + pageItem.className = 'usa-pagination__item usa-pagination__page-no'; + pageItem.innerHTML = ` + ${i} + `; + if (i === currentPage) { + pageItem.querySelector('a').classList.add('usa-current'); + pageItem.querySelector('a').setAttribute('aria-current', 'page'); + } + pageItem.querySelector('a').addEventListener('click', () => loadDomains(i)); + paginationButtons.appendChild(pageItem); } - // load the results with the updated sort - loadDomains(1, sortBy, order); + + if (hasNext) { + const nextPageItem = document.createElement('li'); + nextPageItem.className = 'usa-pagination__item usa-pagination__arrow'; + nextPageItem.innerHTML = ` + + Next + + + `; + nextPageItem.querySelector('a').addEventListener('click', () => loadDomains(currentPage + 1)); + paginationButtons.appendChild(nextPageItem); + } + } + + // Add event listeners to table headers for sorting + document.querySelectorAll('.dotgov-table__registered-domains th[data-sortable]').forEach(header => { + header.addEventListener('click', function() { + const sortBy = this.getAttribute('data-sortable'); + let order = 'asc'; + // sort order will be ascending, unless the currently sorted column is ascending, and the user + // is selecting the same column to sort in descending order + if (sortBy === currentSortBy) { + order = currentOrder === 'asc' ? 'desc' : 'asc'; + } + // load the results with the updated sort + loadDomains(1, sortBy, order); + }); }); - }); - // Load the first page initially - loadDomains(1); + // Load the first page initially + loadDomains(1); + } }); /** @@ -1094,185 +1097,188 @@ document.addEventListener('DOMContentLoaded', function() { * */ document.addEventListener('DOMContentLoaded', function() { - let currentSortBy = 'id'; - let currentOrder = 'asc'; let domainRequestsWrapper = document.querySelector('.domain-requests-wrapper'); - let noDomainRequestsWrapper = document.querySelector('.no-domain-requests-wrapper'); - let hasLoaded = false; - /** - * Loads rows in the domain requests list, as well as updates pagination around the domain requests list - * based on the supplied attributes. - * @param {*} page - the page number of the results (starts with 1) - * @param {*} sortBy - the sort column option - * @param {*} order - the sort order {asc, desc} - * @param {*} loaded - control for the scrollToElement functionality - */ - function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) { - //fetch json of page of domain requests, given page # and sort - fetch(`/get-domain-requests-json/?page=${page}&sort_by=${sortBy}&order=${order}`) - .then(response => response.json()) - .then(data => { - if (data.error) { - console.log('Error in AJAX call: ' + data.error); - return; - } + if (domainRequestsWrapper) { + let currentSortBy = 'id'; + let currentOrder = 'asc'; + let noDomainRequestsWrapper = document.querySelector('.no-domain-requests-wrapper'); + let hasLoaded = false; - // handle the display of proper messaging in the event that no domain requests exist in the list - if (data.domain_requests.length) { - domainRequestsWrapper.classList.remove('display-none'); - noDomainRequestsWrapper.classList.add('display-none'); - } else { - domainRequestsWrapper.classList.add('display-none'); - noDomainRequestsWrapper.classList.remove('display-none'); - } + /** + * Loads rows in the domain requests list, as well as updates pagination around the domain requests list + * based on the supplied attributes. + * @param {*} page - the page number of the results (starts with 1) + * @param {*} sortBy - the sort column option + * @param {*} order - the sort order {asc, desc} + * @param {*} loaded - control for the scrollToElement functionality + */ + function loadDomainRequests(page, sortBy = currentSortBy, order = currentOrder, loaded = hasLoaded) { + //fetch json of page of domain requests, given page # and sort + fetch(`/get-domain-requests-json/?page=${page}&sort_by=${sortBy}&order=${order}`) + .then(response => response.json()) + .then(data => { + if (data.error) { + console.log('Error in AJAX call: ' + data.error); + return; + } - // identify the DOM element where the domain request list will be inserted into the DOM - const tbody = document.querySelector('.dotgov-table__domain-requests tbody'); - tbody.innerHTML = ''; + // handle the display of proper messaging in the event that no domain requests exist in the list + if (data.domain_requests.length) { + domainRequestsWrapper.classList.remove('display-none'); + noDomainRequestsWrapper.classList.add('display-none'); + } else { + domainRequestsWrapper.classList.add('display-none'); + noDomainRequestsWrapper.classList.remove('display-none'); + } - // remove any existing modal elements from the DOM so they can be properly re-initialized - // after the DOM content changes and there are new delete modal buttons added - unloadModals(); - data.domain_requests.forEach(request => { - const domainName = request.requested_domain ? request.requested_domain : `New domain request (${new Date(request.created_at).toLocaleString()} UTC)`; - const submissionDate = request.submission_date ? new Date(request.submission_date).toLocaleDateString() : `Not submitted`; - const actionUrl = request.action_url; - const actionLabel = request.action_label; - const deleteButton = request.is_deletable ? ` - - Delete ${domainName} - ` : ''; + // identify the DOM element where the domain request list will be inserted into the DOM + const tbody = document.querySelector('.dotgov-table__domain-requests tbody'); + tbody.innerHTML = ''; - const row = document.createElement('tr'); - row.innerHTML = ` - - ${domainName} - - - ${submissionDate} - - - ${request.status} - - - + // remove any existing modal elements from the DOM so they can be properly re-initialized + // after the DOM content changes and there are new delete modal buttons added + unloadModals(); + data.domain_requests.forEach(request => { + const domainName = request.requested_domain ? request.requested_domain : `New domain request (${new Date(request.created_at).toLocaleString()} UTC)`; + const submissionDate = request.submission_date ? new Date(request.submission_date).toLocaleDateString() : `Not submitted`; + const actionUrl = request.action_url; + const actionLabel = request.action_label; + const deleteButton = request.is_deletable ? ` + - ${actionLabel} ${request.requested_domain ? request.requested_domain : 'New domain request'} - - - ${deleteButton} - `; - tbody.appendChild(row); - }); - // initialize modals immediately after the DOM content is updated - initializeModals(); - if (loaded) - ScrollToElement('id', 'domain-requests-header'); + + Delete ${domainName} + ` : ''; - hasLoaded = true; + const row = document.createElement('tr'); + row.innerHTML = ` + + ${domainName} + + + ${submissionDate} + + + ${request.status} + + + + + ${actionLabel} ${request.requested_domain ? request.requested_domain : 'New domain request'} + + + ${deleteButton} + `; + tbody.appendChild(row); + }); + // initialize modals immediately after the DOM content is updated + initializeModals(); + if (loaded) + ScrollToElement('id', 'domain-requests-header'); - // update the pagination after the domain requests list is updated - updateDomainRequestsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total); - currentSortBy = sortBy; - currentOrder = order; - }) - .catch(error => console.error('Error fetching domain requests:', error)); - } + hasLoaded = true; - /** - * Update the pagination below the domain requests list. - * @param {*} currentPage - the current page number (starting with 1) - * @param {*} numPages - the number of pages indicated by the domain request list response - * @param {*} hasPrevious - if there is a page of results prior to the current page - * @param {*} hasNext - if there is a page of results after the current page - */ - function updateDomainRequestsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) { - // identify the DOM element where pagination is contained - const paginationContainer = document.querySelector('#domain-requests-pagination'); - const paginationCounter = document.querySelector('#domain-requests-pagination .usa-pagination__counter'); - const paginationButtons = document.querySelector('#domain-requests-pagination .usa-pagination__list'); - paginationCounter.innerHTML = ''; - paginationButtons.innerHTML = ''; - - // Buttons should only be displayed if there are more than one pages of results - paginationButtons.classList.toggle('display-none', numPages <= 1); - - // Counter should only be displayed if there is more than 1 item - paginationContainer.classList.toggle('display-none', totalItems < 1); - - paginationCounter.innerHTML = `${totalItems} domain request${totalItems > 1 ? 's' : ''}`; - - if (hasPrevious) { - const prevPageItem = document.createElement('li'); - prevPageItem.className = 'usa-pagination__item usa-pagination__arrow'; - prevPageItem.innerHTML = ` - - - Previous - - `; - prevPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage - 1)); - paginationButtons.appendChild(prevPageItem); + // update the pagination after the domain requests list is updated + updateDomainRequestsPagination(data.page, data.num_pages, data.has_previous, data.has_next, data.total); + currentSortBy = sortBy; + currentOrder = order; + }) + .catch(error => console.error('Error fetching domain requests:', error)); } - for (let i = 1; i <= numPages; i++) { - const pageItem = document.createElement('li'); - pageItem.className = 'usa-pagination__item usa-pagination__page-no'; - pageItem.innerHTML = ` - ${i} - `; - if (i === currentPage) { - pageItem.querySelector('a').classList.add('usa-current'); - pageItem.querySelector('a').setAttribute('aria-current', 'page'); + /** + * Update the pagination below the domain requests list. + * @param {*} currentPage - the current page number (starting with 1) + * @param {*} numPages - the number of pages indicated by the domain request list response + * @param {*} hasPrevious - if there is a page of results prior to the current page + * @param {*} hasNext - if there is a page of results after the current page + */ + function updateDomainRequestsPagination(currentPage, numPages, hasPrevious, hasNext, totalItems) { + // identify the DOM element where pagination is contained + const paginationContainer = document.querySelector('#domain-requests-pagination'); + const paginationCounter = document.querySelector('#domain-requests-pagination .usa-pagination__counter'); + const paginationButtons = document.querySelector('#domain-requests-pagination .usa-pagination__list'); + paginationCounter.innerHTML = ''; + paginationButtons.innerHTML = ''; + + // Buttons should only be displayed if there are more than one pages of results + paginationButtons.classList.toggle('display-none', numPages <= 1); + + // Counter should only be displayed if there is more than 1 item + paginationContainer.classList.toggle('display-none', totalItems < 1); + + paginationCounter.innerHTML = `${totalItems} domain request${totalItems > 1 ? 's' : ''}`; + + if (hasPrevious) { + const prevPageItem = document.createElement('li'); + prevPageItem.className = 'usa-pagination__item usa-pagination__arrow'; + prevPageItem.innerHTML = ` + + + Previous + + `; + prevPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage - 1)); + paginationButtons.appendChild(prevPageItem); } - pageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(i)); - paginationButtons.appendChild(pageItem); - } - if (hasNext) { - const nextPageItem = document.createElement('li'); - nextPageItem.className = 'usa-pagination__item usa-pagination__arrow'; - nextPageItem.innerHTML = ` - - Next - - - `; - nextPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage + 1)); - paginationButtons.appendChild(nextPageItem); - } - } - - // Add event listeners to table headers for sorting - document.querySelectorAll('.dotgov-table__domain-requests th[data-sortable]').forEach(header => { - header.addEventListener('click', function() { - const sortBy = this.getAttribute('data-sortable'); - let order = 'asc'; - // sort order will be ascending, unless the currently sorted column is ascending, and the user - // is selecting the same column to sort in descending order - if (sortBy === currentSortBy) { - order = currentOrder === 'asc' ? 'desc' : 'asc'; + for (let i = 1; i <= numPages; i++) { + const pageItem = document.createElement('li'); + pageItem.className = 'usa-pagination__item usa-pagination__page-no'; + pageItem.innerHTML = ` + ${i} + `; + if (i === currentPage) { + pageItem.querySelector('a').classList.add('usa-current'); + pageItem.querySelector('a').setAttribute('aria-current', 'page'); + } + pageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(i)); + paginationButtons.appendChild(pageItem); } - loadDomainRequests(1, sortBy, order); + + if (hasNext) { + const nextPageItem = document.createElement('li'); + nextPageItem.className = 'usa-pagination__item usa-pagination__arrow'; + nextPageItem.innerHTML = ` + + Next + + + `; + nextPageItem.querySelector('a').addEventListener('click', () => loadDomainRequests(currentPage + 1)); + paginationButtons.appendChild(nextPageItem); + } + } + + // Add event listeners to table headers for sorting + document.querySelectorAll('.dotgov-table__domain-requests th[data-sortable]').forEach(header => { + header.addEventListener('click', function() { + const sortBy = this.getAttribute('data-sortable'); + let order = 'asc'; + // sort order will be ascending, unless the currently sorted column is ascending, and the user + // is selecting the same column to sort in descending order + if (sortBy === currentSortBy) { + order = currentOrder === 'asc' ? 'desc' : 'asc'; + } + loadDomainRequests(1, sortBy, order); + }); }); - }); - // Load the first page initially - loadDomainRequests(1); + // Load the first page initially + loadDomainRequests(1); + } }); diff --git a/src/registrar/views/domain_requests_json.py b/src/registrar/views/domain_requests_json.py index 81dccefc2..319cbdea3 100644 --- a/src/registrar/views/domain_requests_json.py +++ b/src/registrar/views/domain_requests_json.py @@ -2,15 +2,13 @@ from django.http import JsonResponse from django.core.paginator import Paginator from registrar.models import DomainRequest from django.utils.dateformat import format +from django.contrib.auth.decorators import login_required - +@login_required def get_domain_requests_json(request): """Given the current request, get all domain requests that are associated with the request user and exclude the APPROVED ones""" - if not request.user.is_authenticated: - return JsonResponse({"error": "User not authenticated"}, status=401) - domain_requests = DomainRequest.objects.filter(creator=request.user).exclude( status=DomainRequest.DomainRequestStatus.APPROVED ) diff --git a/src/registrar/views/domains_json.py b/src/registrar/views/domains_json.py index 52f886848..d0581ba64 100644 --- a/src/registrar/views/domains_json.py +++ b/src/registrar/views/domains_json.py @@ -1,15 +1,13 @@ from django.http import JsonResponse from django.core.paginator import Paginator from registrar.models import UserDomainRole, Domain +from django.contrib.auth.decorators import login_required - +@login_required def get_domains_json(request): """Given the current request, get all domains that are associated with the UserDomainRole object""" - if not request.user.is_authenticated: - return JsonResponse({"error": "User not authenticated"}, status=401) - user_domain_roles = UserDomainRole.objects.filter(user=request.user) domain_ids = user_domain_roles.values_list("domain_id", flat=True)