mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-05 01:11:55 +02:00
309 lines
13 KiB
JavaScript
309 lines
13 KiB
JavaScript
import { hideElement, showElement } from './helpers-admin.js';
|
|
|
|
/**
|
|
* A function for dynamically changing some fields on the portfolio admin model
|
|
* IMPORTANT NOTE: The business logic in this function is related to handlePortfolioSelection
|
|
*/
|
|
function handlePortfolioFields(){
|
|
|
|
let isPageLoading = true
|
|
// $ symbolically denotes that this is using jQuery
|
|
const $seniorOfficialDropdown = django.jQuery("#id_senior_official");
|
|
const seniorOfficialField = document.querySelector(".field-senior_official");
|
|
const seniorOfficialAddress = seniorOfficialField.querySelector(".dja-address-contact-list");
|
|
const seniorOfficialReadonly = seniorOfficialField.querySelector(".readonly");
|
|
const $federalAgencyDropdown = django.jQuery("#id_federal_agency");
|
|
const federalAgencyField = document.querySelector(".field-federal_agency");
|
|
const organizationTypeField = document.querySelector(".field-organization_type");
|
|
const organizationTypeReadonly = organizationTypeField.querySelector(".readonly");
|
|
const organizationTypeDropdown = document.getElementById("id_organization_type");
|
|
const organizationNameField = document.querySelector(".field-organization_name");
|
|
const federalTypeField = document.querySelector(".field-federal_type");
|
|
const urbanizationField = document.querySelector(".field-urbanization");
|
|
const stateTerritoryDropdown = document.getElementById("id_state_territory");
|
|
const stateTerritoryField = document.querySelector(".field-state_territory");
|
|
const stateTerritoryReadonly = stateTerritoryField.querySelector(".readonly");
|
|
const seniorOfficialAddUrl = document.getElementById("senior-official-add-url").value;
|
|
const seniorOfficialApi = document.getElementById("senior_official_from_agency_json_url").value;
|
|
const federalPortfolioApi = document.getElementById("federal_and_portfolio_types_from_agency_json_url").value;
|
|
|
|
/**
|
|
* Fetches federal type data based on a selected agency using an AJAX call.
|
|
*
|
|
* @param {string} agency
|
|
* @returns {Promise<Object|null>} - A promise that resolves to the portfolio data object if successful,
|
|
* or null if there was an error.
|
|
*/
|
|
function getFederalTypeFromAgency(agency) {
|
|
return fetch(`${federalPortfolioApi}?&agency_name=${agency}`)
|
|
.then(response => {
|
|
const statusCode = response.status;
|
|
return response.json().then(data => ({ statusCode, data }));
|
|
})
|
|
.then(({ statusCode, data }) => {
|
|
if (data.error) {
|
|
console.error("Error in AJAX call: " + data.error);
|
|
return;
|
|
}
|
|
return data.federal_type
|
|
})
|
|
.catch(error => {
|
|
console.error("Error fetching federal and portfolio types: ", error);
|
|
return null
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Fetches senior official contact data based on a selected agency using an AJAX call.
|
|
*
|
|
* @param {string} agency
|
|
* @returns {Promise<Object|null>} - A promise that resolves to the portfolio data object if successful,
|
|
* or null if there was an error.
|
|
*/
|
|
function getSeniorOfficialFromAgency(agency) {
|
|
return fetch(`${seniorOfficialApi}?agency_name=${agency}`)
|
|
.then(response => {
|
|
const statusCode = response.status;
|
|
return response.json().then(data => ({ statusCode, data }));
|
|
})
|
|
.then(({ statusCode, data }) => {
|
|
if (data.error) {
|
|
// Throw an error with status code and message
|
|
throw { statusCode, message: data.error };
|
|
} else {
|
|
return data;
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error("Error fetching senior official: ", error);
|
|
throw error; // Re-throw for external handling
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Handles the side effects of change on the organization type field
|
|
*
|
|
* 1. If selection is federal, hide org name, show federal agency, show federal type if applicable
|
|
* 2. else show org name, hide federal agency, hide federal type if applicable
|
|
*/
|
|
function handleOrganizationTypeChange() {
|
|
if (organizationTypeField && organizationNameField) {
|
|
let selectedValue = organizationTypeDropdown ? organizationTypeDropdown.value : organizationTypeReadonly.innerText;
|
|
if (selectedValue === "federal" || selectedValue === "Federal") {
|
|
hideElement(organizationNameField);
|
|
showElement(federalAgencyField);
|
|
if (federalTypeField) {
|
|
showElement(federalTypeField);
|
|
}
|
|
} else {
|
|
showElement(organizationNameField);
|
|
hideElement(federalAgencyField);
|
|
if (federalTypeField) {
|
|
hideElement(federalTypeField);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handles the side effects of change on the federal agency field
|
|
*
|
|
* 1. handle org type dropdown or readonly
|
|
* 2. call handleOrganizationTypeChange
|
|
* 3. call getFederalTypeFromAgency and update federal type
|
|
* 4. call getSeniorOfficialFromAgency and update the SO fieldset
|
|
*/
|
|
function handleFederalAgencyChange() {
|
|
if (!isPageLoading) {
|
|
|
|
let selectedFederalAgency = $federalAgencyDropdown.find("option:selected").text();
|
|
if (!selectedFederalAgency) {
|
|
return;
|
|
}
|
|
|
|
// 1. Handle organization type
|
|
let organizationTypeValue = organizationTypeDropdown ? organizationTypeDropdown.value : organizationTypeReadonly.innerText.toLowerCase();
|
|
if (selectedFederalAgency !== "Non-Federal Agency") {
|
|
if (organizationTypeValue !== "federal") {
|
|
if (organizationTypeDropdown){
|
|
organizationTypeDropdown.value = "federal";
|
|
} else {
|
|
organizationTypeReadonly.innerText = "Federal"
|
|
}
|
|
}
|
|
} else {
|
|
if (organizationTypeValue === "federal") {
|
|
if (organizationTypeDropdown){
|
|
organizationTypeDropdown.value = "";
|
|
} else {
|
|
organizationTypeReadonly.innerText = "-"
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Handle organization type change side effects
|
|
handleOrganizationTypeChange();
|
|
|
|
// 3. Handle federal type
|
|
getFederalTypeFromAgency(selectedFederalAgency).then((federalType) => updateReadOnly(federalType, '.field-federal_type'));
|
|
|
|
// 4. Handle senior official
|
|
hideElement(seniorOfficialAddress.parentElement);
|
|
getSeniorOfficialFromAgency(selectedFederalAgency).then((senior_official) => {
|
|
// Update the "contact details" blurb beneath senior official
|
|
updateSeniorOfficialContactInfo(senior_official);
|
|
showElement(seniorOfficialAddress.parentElement);
|
|
// Get the associated senior official with this federal agency
|
|
let seniorOfficialId = senior_official.id;
|
|
let seniorOfficialName = [senior_official.first_name, senior_official.last_name].join(" ");
|
|
if ($seniorOfficialDropdown && $seniorOfficialDropdown.length > 0) {
|
|
// If the senior official is a dropdown field, edit that
|
|
updateSeniorOfficialDropdown(seniorOfficialId, seniorOfficialName);
|
|
} else {
|
|
if (seniorOfficialReadonly) {
|
|
let seniorOfficialLink = `<a href=/admin/registrar/seniorofficial/${seniorOfficialId}/change/>${seniorOfficialName}</a>`
|
|
seniorOfficialReadonly.innerHTML = seniorOfficialName ? seniorOfficialLink : "-";
|
|
}
|
|
}
|
|
})
|
|
.catch(error => {
|
|
if (error.statusCode === 404) {
|
|
// Handle "not found" senior official
|
|
if ($seniorOfficialDropdown && $seniorOfficialDropdown.length > 0) {
|
|
$seniorOfficialDropdown.val("").trigger("change");
|
|
} else {
|
|
seniorOfficialReadonly.innerHTML = `<a href="${seniorOfficialAddUrl}">No senior official found. Create one now.</a>`;
|
|
}
|
|
} else {
|
|
// Handle other errors
|
|
console.error("An error occurred:", error.message);
|
|
}
|
|
});
|
|
} else {
|
|
isPageLoading = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper for updating federal type field
|
|
*/
|
|
function updateSeniorOfficialDropdown(seniorOfficialId, seniorOfficialName) {
|
|
if (!seniorOfficialId || !seniorOfficialName || !seniorOfficialName.trim()){
|
|
// Clear the field if the SO doesn't exist
|
|
$seniorOfficialDropdown.val("").trigger("change");
|
|
return;
|
|
}
|
|
// Add the senior official to the dropdown.
|
|
// This format supports select2 - if we decide to convert this field in the future.
|
|
if ($seniorOfficialDropdown.find(`option[value='${seniorOfficialId}']`).length) {
|
|
// Select the value that is associated with the current Senior Official.
|
|
$seniorOfficialDropdown.val(seniorOfficialId).trigger("change");
|
|
} else {
|
|
// Create a DOM Option that matches the desired Senior Official. Then append it and select it.
|
|
let userOption = new Option(seniorOfficialName, seniorOfficialId, true, true);
|
|
$seniorOfficialDropdown.append(userOption).trigger("change");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle urbanization
|
|
*/
|
|
function handleStateTerritoryChange() {
|
|
let selectedValue = stateTerritoryDropdown ? stateTerritoryDropdown.value : stateTerritoryReadonly.innerText;
|
|
if (selectedValue === "PR" || selectedValue === "Puerto Rico (PR)") {
|
|
showElement(urbanizationField)
|
|
} else {
|
|
hideElement(urbanizationField)
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper for updating senior official dropdown
|
|
*/
|
|
function updateReadOnly(updateText, selectorString) {
|
|
// find the div by selectorString
|
|
const selectedDiv = document.querySelector(selectorString);
|
|
if (selectedDiv) {
|
|
// find the nested div with class 'readonly' inside the selectorString div
|
|
const readonlyDiv = selectedDiv.querySelector('.readonly');
|
|
if (readonlyDiv) {
|
|
// Update the text content of the readonly div
|
|
readonlyDiv.textContent = updateText !== null ? updateText : '-';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper for updating senior official contact info
|
|
*/
|
|
function updateSeniorOfficialContactInfo(senior_official) {
|
|
if (!seniorOfficialAddress) return;
|
|
const titleSpan = seniorOfficialAddress.querySelector(".contact_info_title");
|
|
const emailSpan = seniorOfficialAddress.querySelector(".contact_info_email");
|
|
const phoneSpan = seniorOfficialAddress.querySelector(".contact_info_phone");
|
|
if (titleSpan) {
|
|
titleSpan.textContent = senior_official.title || "None";
|
|
};
|
|
// Update the email field and the content for the clipboard
|
|
if (emailSpan) {
|
|
let copyButton = seniorOfficialAddress.querySelector(".admin-icon-group");
|
|
emailSpan.textContent = senior_official.email || "None";
|
|
if (senior_official.email) {
|
|
const clipboardInput = seniorOfficialAddress.querySelector(".admin-icon-group input");
|
|
if (clipboardInput) {
|
|
clipboardInput.value = senior_official.email;
|
|
};
|
|
showElement(copyButton);
|
|
}else {
|
|
hideElement(copyButton);
|
|
}
|
|
}
|
|
if (phoneSpan) {
|
|
phoneSpan.textContent = senior_official.phone || "None";
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Initializes necessary data and display configurations for the portfolio fields.
|
|
*/
|
|
function initializePortfolioSettings() {
|
|
if (urbanizationField && stateTerritoryField) {
|
|
handleStateTerritoryChange();
|
|
}
|
|
handleOrganizationTypeChange();
|
|
}
|
|
|
|
/**
|
|
* Sets event listeners for key UI elements.
|
|
*/
|
|
function setEventListeners() {
|
|
if ($federalAgencyDropdown && (organizationTypeDropdown || organizationTypeReadonly)) {
|
|
$federalAgencyDropdown.on("change", function() {
|
|
handleFederalAgencyChange();
|
|
});
|
|
}
|
|
if (urbanizationField && stateTerritoryDropdown) {
|
|
stateTerritoryDropdown.addEventListener("change", function() {
|
|
handleStateTerritoryChange();
|
|
});
|
|
}
|
|
if (organizationTypeDropdown) {
|
|
organizationTypeDropdown.addEventListener("change", function() {
|
|
handleOrganizationTypeChange();
|
|
});
|
|
}
|
|
}
|
|
|
|
// Run initial setup functions
|
|
initializePortfolioSettings();
|
|
setEventListeners();
|
|
}
|
|
|
|
export function initDynamicPortfolioFields() {
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
let isPortfolioPage = document.getElementById("portfolio_form");
|
|
if (isPortfolioPage) {
|
|
handlePortfolioFields();
|
|
}
|
|
});
|
|
}
|