fixed javascript and other issues on domain request admin

This commit is contained in:
David Kennedy 2025-03-06 22:00:37 -05:00
parent fe1e64828b
commit 343d8dc962
No known key found for this signature in database
GPG key ID: 6528A5386E66B96B
3 changed files with 149 additions and 92 deletions

View file

@ -2976,6 +2976,10 @@ class DomainRequestAdmin(ListHeaderAdmin, ImportExportRegistrarModelAdmin):
"federally_recognized_tribe",
"state_recognized_tribe",
"about_your_organization",
"rejection_reason",
"rejection_reason_email",
"action_needed_reason",
"action_needed_reason_email",
]
autocomplete_fields = [

View file

@ -106,7 +106,9 @@ export function initApprovedDomain() {
}
const statusToCheck = "approved";
const readonlyStatusToCheck = "Approved";
const statusSelect = document.getElementById("id_status");
const statusField = document.querySelector("field-status");
const sessionVariableName = "showApprovedDomain";
let approvedDomainFormGroup = document.querySelector(".field-approved_domain");
@ -120,11 +122,22 @@ export function initApprovedDomain() {
// Handle showing/hiding the related fields on page load.
function initializeFormGroups() {
let isStatus = statusSelect.value == statusToCheck;
let isStatus = false;
if (statusSelect) {
isStatus = statusSelect.value == statusToCheck;
} else {
// statusSelect does not exist, indicating readonly
if (statusField) {
let readonlyDiv = statusField.querySelector("div.readonly");
let readonlyStatusText = readonlyDiv.textContent.trim();
isStatus = readonlyStatusText == readonlyStatusToCheck;
}
}
// Initial handling of these groups.
updateFormGroupVisibility(isStatus);
if (statusSelect) {
// Listen to change events and handle rejectionReasonFormGroup display, then save status to session storage
statusSelect.addEventListener('change', () => {
// Show the approved if the status is what we expect.
@ -132,6 +145,7 @@ export function initApprovedDomain() {
updateFormGroupVisibility(isStatus);
addOrRemoveSessionBoolean(sessionVariableName, isStatus);
});
}
// Listen to Back/Forward button navigation and handle approvedDomainFormGroup display based on session storage
// When you navigate using forward/back after changing status but not saving, when you land back on the DA page the
@ -322,6 +336,7 @@ class CustomizableEmailBase {
* @property {HTMLElement} modalConfirm - The confirm button in the modal.
* @property {string} apiUrl - The API URL for fetching email content.
* @property {string} statusToCheck - The status to check against. Used for show/hide on textAreaFormGroup/dropdownFormGroup.
* @property {string} readonlyStatusToCheck - The status to check against when readonly. Used for show/hide on textAreaFormGroup/dropdownFormGroup.
* @property {string} sessionVariableName - The session variable name. Used for show/hide on textAreaFormGroup/dropdownFormGroup.
* @property {string} apiErrorMessage - The error message that the ajax call returns.
*/
@ -338,6 +353,7 @@ class CustomizableEmailBase {
this.textAreaFormGroup = config.textAreaFormGroup;
this.dropdownFormGroup = config.dropdownFormGroup;
this.statusToCheck = config.statusToCheck;
this.readonlyStatusToCheck = config.readonlyStatusToCheck;
this.sessionVariableName = config.sessionVariableName;
// Non-configurable variables
@ -363,11 +379,22 @@ class CustomizableEmailBase {
// Handle showing/hiding the related fields on page load.
initializeFormGroups() {
let isStatus = this.statusSelect.value == this.statusToCheck;
let isStatus = false;
if (this.statusSelect) {
this.statusSelect.value == this.statusToCheck;
} else {
// statusSelect does not exist, indicating readonly
if (this.dropdownFormGroup) {
let readonlyDiv = this.dropdownFormGroup.querySelector("div.readonly");
let readonlyStatusText = readonlyDiv.textContent.trim();
isStatus = readonlyStatusText == this.readonlyStatusToCheck;
}
}
// Initial handling of these groups.
this.updateFormGroupVisibility(isStatus);
if (this.statusSelect) {
// Listen to change events and handle rejectionReasonFormGroup display, then save status to session storage
this.statusSelect.addEventListener('change', () => {
// Show the action needed field if the status is what we expect.
@ -376,6 +403,7 @@ class CustomizableEmailBase {
this.updateFormGroupVisibility(isStatus);
addOrRemoveSessionBoolean(this.sessionVariableName, isStatus);
});
}
// Listen to Back/Forward button navigation and handle rejectionReasonFormGroup display based on session storage
// When you navigate using forward/back after changing status but not saving, when you land back on the DA page the
@ -403,6 +431,7 @@ class CustomizableEmailBase {
}
initializeDropdown() {
if (this.dropdown) {
this.dropdown.addEventListener("change", () => {
let reason = this.dropdown.value;
if (this.initialDropdownValue !== this.dropdown.value || this.initialEmailValue !== this.textarea.value) {
@ -431,8 +460,10 @@ class CustomizableEmailBase {
}
});
}
}
initializeModalConfirm() {
if (this.modalConfirm) {
this.modalConfirm.addEventListener("click", () => {
this.textarea.removeAttribute('readonly');
this.textarea.focus();
@ -440,8 +471,10 @@ class CustomizableEmailBase {
hideElement(this.modalTrigger);
});
}
}
initializeDirectEditButton() {
if (this.directEditButton) {
this.directEditButton.addEventListener("click", () => {
this.textarea.removeAttribute('readonly');
this.textarea.focus();
@ -449,12 +482,13 @@ class CustomizableEmailBase {
hideElement(this.modalTrigger);
});
}
}
isEmailAlreadySent() {
return this.lastSentEmailContent.value.replace(/\s+/g, '') === this.textarea.value.replace(/\s+/g, '');
}
updateUserInterface(reason=this.dropdown.value, excluded_reasons=["other"]) {
updateUserInterface(reason, excluded_reasons=["other"]) {
if (!reason) {
// No reason selected, we will set the label to "Email", show the "Make a selection" placeholder, hide the trigger, textarea, hide the help text
this.showPlaceholderNoReason();
@ -468,6 +502,7 @@ class CustomizableEmailBase {
// Helper function that makes overriding the readonly textarea easy
showReadonlyTextarea() {
if (this.textarea && this.textareaPlaceholder) {
// A triggering selection is selected, all hands on board:
this.textarea.setAttribute('readonly', true);
showElement(this.textarea);
@ -487,6 +522,7 @@ class CustomizableEmailBase {
this.formLabel.innerHTML = "Email:";
}
}
}
// Helper function that makes overriding the placeholder reason easy
showPlaceholderNoReason() {
@ -516,9 +552,10 @@ class customActionNeededEmail extends CustomizableEmailBase {
lastSentEmailContent: document.getElementById("last-sent-action-needed-email-content"),
modalConfirm: document.getElementById("action-needed-reason__confirm-edit-email"),
apiUrl: document.getElementById("get-action-needed-email-for-user-json")?.value || null,
textAreaFormGroup: document.querySelector('.field-action_needed_reason'),
dropdownFormGroup: document.querySelector('.field-action_needed_reason_email'),
textAreaFormGroup: document.querySelector('.field-action_needed_reason_email'),
dropdownFormGroup: document.querySelector('.field-action_needed_reason'),
statusToCheck: "action needed",
readonlyStatusToCheck: "Action needed",
sessionVariableName: "showActionNeededReason",
apiErrorMessage: "Error when attempting to grab action needed email: "
}
@ -529,7 +566,15 @@ class customActionNeededEmail extends CustomizableEmailBase {
// Hide/show the email fields depending on the current status
this.initializeFormGroups();
// Setup the textarea, edit button, helper text
this.updateUserInterface();
let reason = null;
if (this.dropdown) {
reason = this.dropdown.value;
} else if (this.dropdownFormGroup && this.dropdownFormGroup.querySelector("div.readonly")) {
if (this.dropdownFormGroup.querySelector("div.readonly").textContent) {
reason = this.dropdownFormGroup.querySelector("div.readonly").textContent.trim()
}
}
this.updateUserInterface(reason);
this.initializeDropdown();
this.initializeModalConfirm();
this.initializeDirectEditButton();
@ -560,12 +605,12 @@ export function initActionNeededEmail() {
// Initialize UI
const customEmail = new customActionNeededEmail();
// Check that every variable was setup correctly
const nullItems = Object.entries(customEmail.config).filter(([key, value]) => value === null).map(([key]) => key);
if (nullItems.length > 0) {
console.error(`Failed to load customActionNeededEmail(). Some variables were null: ${nullItems.join(", ")}`)
return;
}
// // Check that every variable was setup correctly
// const nullItems = Object.entries(customEmail.config).filter(([key, value]) => value === null).map(([key]) => key);
// if (nullItems.length > 0) {
// console.error(`Failed to load customActionNeededEmail(). Some variables were null: ${nullItems.join(", ")}`)
// return;
// }
customEmail.loadActionNeededEmail()
});
}
@ -581,6 +626,7 @@ class customRejectedEmail extends CustomizableEmailBase {
textAreaFormGroup: document.querySelector('.field-rejection_reason'),
dropdownFormGroup: document.querySelector('.field-rejection_reason_email'),
statusToCheck: "rejected",
readonlyStatusToCheck: "Rejected",
sessionVariableName: "showRejectionReason",
errorMessage: "Error when attempting to grab rejected email: "
};
@ -589,7 +635,15 @@ class customRejectedEmail extends CustomizableEmailBase {
loadRejectedEmail() {
this.initializeFormGroups();
this.updateUserInterface();
let reason = null;
if (this.dropdown) {
reason = this.dropdown.value;
} else if (this.dropdownFormGroup && this.dropdownFormGroup.querySelector("div.readonly")) {
if (this.dropdownFormGroup.querySelector("div.readonly").textContent) {
reason = this.dropdownFormGroup.querySelector("div.readonly").textContent.trim()
}
}
this.updateUserInterface(reason);
this.initializeDropdown();
this.initializeModalConfirm();
this.initializeDirectEditButton();
@ -600,7 +654,7 @@ class customRejectedEmail extends CustomizableEmailBase {
this.showPlaceholder("Email:", "Select a rejection reason to see email");
}
updateUserInterface(reason=this.dropdown.value, excluded_reasons=[]) {
updateUserInterface(reason, excluded_reasons=[]) {
super.updateUserInterface(reason, excluded_reasons);
}
}
@ -619,12 +673,12 @@ export function initRejectedEmail() {
// Initialize UI
const customEmail = new customRejectedEmail();
// Check that every variable was setup correctly
const nullItems = Object.entries(customEmail.config).filter(([key, value]) => value === null).map(([key]) => key);
if (nullItems.length > 0) {
console.error(`Failed to load customRejectedEmail(). Some variables were null: ${nullItems.join(", ")}`)
return;
}
// // Check that every variable was setup correctly
// const nullItems = Object.entries(customEmail.config).filter(([key, value]) => value === null).map(([key]) => key);
// if (nullItems.length > 0) {
// console.error(`Failed to load customRejectedEmail(). Some variables were null: ${nullItems.join(", ")}`)
// return;
// }
customEmail.loadRejectedEmail()
});
}
@ -648,7 +702,6 @@ function handleSuborgFieldsAndButtons() {
// Ensure that every variable is present before proceeding
if (!requestedSuborganizationField || !suborganizationCity || !suborganizationStateTerritory || !rejectButton) {
console.warn("handleSuborganizationSelection() => Could not find required fields.")
return;
}

View file

@ -404,7 +404,7 @@ export function handlePortfolioSelection(
updateSubOrganizationDropdown(portfolio_id);
// Show fields relevant to a selected portfolio
showElement(suborganizationField);
if (suborganizationField) showElement(suborganizationField);
hideElement(seniorOfficialField);
showElement(portfolioSeniorOfficialField);
@ -427,7 +427,7 @@ export function handlePortfolioSelection(
// No portfolio is selected - reverse visibility of fields
// Hide suborganization field as no portfolio is selected
hideElement(suborganizationField);
if (suborganizationField) hideElement(suborganizationField);
// Show fields that are relevant when no portfolio is selected
showElement(seniorOfficialField);