function createContentModal({ ACCOUNT_PLANS_MODAL_ID, AUTH_STATUS, CUSTOMER_FILTER_BUTTON_ID, CUSTOMER_FILTER_LIST_ID, CUSTOMER_FILTER_PANEL_ID, CUSTOMER_FILTER_SEARCH_ID, CUSTOMER_FILTER_SELECT_ALL_ID, DEBUG_PANEL_ID, ESCAPE_LISTENER_KEY, MODAL_ID, OPPORTUNITIES_TABLE_ID, OWNER_FILTER_BUTTON_ID, OWNER_FILTER_LIST_ID, OWNER_FILTER_PANEL_ID, OWNER_FILTER_SEARCH_ID, OWNER_FILTER_SELECT_ALL_ID, PERIOD_OPTIONS, PREFERENCES_MODAL_ID, PRODUCTS_CACHE_TIMESTAMP_ID, PRODUCTS_PROGRESS_ID, STAGE_DASHBOARD_ID, STAGE_FILTERS_ID, STATUS_FILTERS_ID, TABLE_SEARCH_ID, applyTheme, authSessionState, closeAccountPlansModal, closeInstallBaseModal, closeServiceRequestsModal, closeCustomerFilterPanel, closeOwnerFilterPanel, closePreferencesModal, createSettingsIcon, debugState, ensureExtensionStyles, getCustomerOptions, getOwnerOptions, getSavedOpportunityTypeValues, getSavedOpptyProductsCacheHours, getSavedTheme, openPreferencesModal, opportunitiesFilterState, opportunitiesQueryState, preferencesState, renderCustomerFilter, renderCustomerFilterList, renderOpportunitiesTable, renderOwnerFilter, renderOwnerFilterList, renderStageFilterButtons, renderStatusFilterButtons, requestOpportunitiesForPeriod, requestTokenRelayOnce, resetCustomerAndOwnerFiltersForPeriod, resetOpportunitiesTable, restoreFilterPreferences, saveFilterPreferences, toggleCustomerFilterPanel, toggleDebugPanel, toggleOwnerFilterPanel, environment }) { const { document, window } = environment; function openOpportunitiesModal() { ensureExtensionStyles(); debugState.debugSecretsVisible = false; const existingModal = document.getElementById(MODAL_ID); if (existingModal) { existingModal.hidden = false; existingModal.querySelector("select").focus(); document.documentElement.classList.add("opportunities-extension-scroll-lock"); ensureEscapeKeyHandler(); requestTokenRelayOnce().catch(() => {}); return; } const overlay = document.createElement("div"); debugState.requestLog = []; authSessionState.tokenRelayRequest = null; authSessionState.consumerTokenServiceRequest = null; authSessionState.accessToken = ""; opportunitiesQueryState.periodRequestVersion = 0; authSessionState.authStatus = AUTH_STATUS.idle; resetOpportunitiesTable(); preferencesState.selectedOpportunityTypeValues = new Set(getSavedOpportunityTypeValues()); preferencesState.opptyProductsCacheHours = getSavedOpptyProductsCacheHours(); overlay.id = MODAL_ID; overlay.className = "opportunities-extension-modal"; overlay.setAttribute("data-theme", getSavedTheme()); overlay.setAttribute("role", "dialog"); overlay.setAttribute("aria-modal", "true"); overlay.setAttribute("aria-labelledby", "opportunities-extension-title"); overlay.setAttribute("aria-describedby", "opportunities-extension-subtitle"); const shell = document.createElement("section"); shell.className = "opportunities-extension-shell"; const header = document.createElement("header"); header.className = "opportunities-extension-header"; const title = document.createElement("h1"); title.id = "opportunities-extension-title"; title.textContent = "Opportunities Extension"; const subtitle = document.createElement("p"); subtitle.id = "opportunities-extension-subtitle"; subtitle.textContent = "Lista de oportunidades do HCM Opportunities List"; const authBadge = document.createElement("span"); authBadge.className = "opportunities-extension-auth-badge opportunities-extension-auth-badge-pending"; authBadge.setAttribute("data-auth-status", AUTH_STATUS.pending); authBadge.textContent = "Authenticating"; const subtitleRow = document.createElement("div"); subtitleRow.className = "opportunities-extension-subtitle-row"; const productsProgressBadge = document.createElement("span"); productsProgressBadge.id = PRODUCTS_PROGRESS_ID; productsProgressBadge.className = "opportunities-extension-products-progress"; productsProgressBadge.setAttribute("role", "status"); productsProgressBadge.hidden = true; const productsCacheTimestamp = document.createElement("span"); productsCacheTimestamp.id = PRODUCTS_CACHE_TIMESTAMP_ID; productsCacheTimestamp.className = "opportunities-extension-products-cache-timestamp"; productsCacheTimestamp.setAttribute("role", "status"); productsCacheTimestamp.hidden = true; subtitleRow.append(subtitle, authBadge, productsProgressBadge, productsCacheTimestamp); const titleBlock = document.createElement("div"); titleBlock.append(title, subtitleRow); const closeButton = document.createElement("button"); closeButton.type = "button"; closeButton.className = "opportunities-extension-icon-button"; closeButton.setAttribute("aria-label", "Fechar"); closeButton.textContent = "X"; closeButton.addEventListener("click", closeOpportunitiesModal); const themeButton = document.createElement("button"); themeButton.type = "button"; themeButton.className = "opportunities-extension-icon-button opportunities-extension-theme-toggle"; themeButton.addEventListener("click", () => { const nextTheme = overlay.getAttribute("data-theme") === "dark" ? "light" : "dark"; applyTheme(overlay, themeButton, nextTheme); }); applyTheme(overlay, themeButton, overlay.getAttribute("data-theme")); const preferencesButton = document.createElement("button"); preferencesButton.type = "button"; preferencesButton.className = "opportunities-extension-icon-button"; preferencesButton.setAttribute("aria-label", "Abrir preferĂȘncias"); preferencesButton.title = "Preferences"; preferencesButton.append(createSettingsIcon()); preferencesButton.addEventListener("click", openPreferencesModal); const headerActions = document.createElement("div"); headerActions.className = "opportunities-extension-header-actions"; headerActions.append(themeButton, preferencesButton, closeButton); header.append(titleBlock, headerActions); const body = document.createElement("main"); body.className = "opportunities-extension-body"; const form = document.createElement("form"); form.className = "opportunities-extension-form"; const field = document.createElement("label"); field.className = "opportunities-extension-field"; const labelText = document.createElement("span"); labelText.textContent = "Reference"; const selectWrap = document.createElement("span"); selectWrap.className = "opportunities-extension-select-wrap"; const select = document.createElement("select"); select.name = "opportunityPeriod"; PERIOD_OPTIONS.forEach((optionLabel) => { const option = document.createElement("option"); option.value = optionLabel; option.textContent = optionLabel; select.append(option); }); select.addEventListener("change", () => { resetCustomerAndOwnerFiltersForPeriod(); saveFilterPreferences(select.value); requestOpportunitiesForPeriod(select.value); }); selectWrap.append(select); field.append(labelText, selectWrap); restoreFilterPreferences(select); const stageFilter = document.createElement("section"); stageFilter.className = "opportunities-extension-stage-filter"; const stageFilterLabel = document.createElement("span"); stageFilterLabel.className = "opportunities-extension-stage-filter-label"; stageFilterLabel.textContent = "Stage"; const stageFilters = document.createElement("div"); stageFilters.id = STAGE_FILTERS_ID; stageFilters.className = "opportunities-extension-stage-filter-controls"; stageFilters.setAttribute("role", "group"); stageFilters.setAttribute("aria-label", "Filter by stage"); stageFilter.append(stageFilterLabel, stageFilters); const customerFilter = document.createElement("section"); customerFilter.className = "opportunities-extension-customer-filter"; const customerFilterLabel = document.createElement("span"); customerFilterLabel.className = "opportunities-extension-customer-filter-label"; customerFilterLabel.textContent = "Customer"; const customerFilterButton = document.createElement("button"); customerFilterButton.id = CUSTOMER_FILTER_BUTTON_ID; customerFilterButton.type = "button"; customerFilterButton.className = "opportunities-extension-customer-filter-trigger"; customerFilterButton.setAttribute("aria-expanded", "false"); customerFilterButton.setAttribute("aria-controls", CUSTOMER_FILTER_PANEL_ID); customerFilterButton.addEventListener("click", toggleCustomerFilterPanel); const customerFilterPanel = document.createElement("section"); customerFilterPanel.id = CUSTOMER_FILTER_PANEL_ID; customerFilterPanel.className = "opportunities-extension-customer-filter-panel"; customerFilterPanel.hidden = true; const customerSearchInput = document.createElement("input"); customerSearchInput.id = CUSTOMER_FILTER_SEARCH_ID; customerSearchInput.className = "opportunities-extension-customer-filter-search"; customerSearchInput.type = "search"; customerSearchInput.placeholder = "Search customers"; customerSearchInput.setAttribute("aria-label", "Search customers"); customerSearchInput.addEventListener("input", () => { opportunitiesFilterState.customerSearch = customerSearchInput.value; saveFilterPreferences(); renderCustomerFilterList(); }); const selectAllLabel = document.createElement("label"); selectAllLabel.className = "opportunities-extension-customer-filter-select-all"; const selectAllCheckbox = document.createElement("input"); selectAllCheckbox.id = CUSTOMER_FILTER_SELECT_ALL_ID; selectAllCheckbox.type = "checkbox"; selectAllCheckbox.addEventListener("change", () => { const customerOptions = getCustomerOptions(); opportunitiesFilterState.selectedCustomerKeys = selectAllCheckbox.checked ? new Set(customerOptions.map((customer) => customer.key)) : new Set(); opportunitiesFilterState.hasSavedCustomerFilter = true; saveFilterPreferences(); renderCustomerFilter(); renderOpportunitiesTable(); }); const selectAllText = document.createElement("span"); selectAllText.textContent = "Select all"; selectAllLabel.append(selectAllCheckbox, selectAllText); const customerFilterList = document.createElement("div"); customerFilterList.id = CUSTOMER_FILTER_LIST_ID; customerFilterList.className = "opportunities-extension-customer-filter-list"; customerFilterPanel.append(customerSearchInput, selectAllLabel, customerFilterList); customerFilter.append(customerFilterLabel, customerFilterButton, customerFilterPanel); const ownerFilter = document.createElement("section"); ownerFilter.className = "opportunities-extension-customer-filter"; const ownerFilterLabel = document.createElement("span"); ownerFilterLabel.className = "opportunities-extension-customer-filter-label"; ownerFilterLabel.textContent = "Owner"; const ownerFilterButton = document.createElement("button"); ownerFilterButton.id = OWNER_FILTER_BUTTON_ID; ownerFilterButton.type = "button"; ownerFilterButton.className = "opportunities-extension-customer-filter-trigger"; ownerFilterButton.setAttribute("aria-expanded", "false"); ownerFilterButton.setAttribute("aria-controls", OWNER_FILTER_PANEL_ID); ownerFilterButton.addEventListener("click", toggleOwnerFilterPanel); const ownerFilterPanel = document.createElement("section"); ownerFilterPanel.id = OWNER_FILTER_PANEL_ID; ownerFilterPanel.className = "opportunities-extension-customer-filter-panel"; ownerFilterPanel.hidden = true; const ownerSearchInput = document.createElement("input"); ownerSearchInput.id = OWNER_FILTER_SEARCH_ID; ownerSearchInput.className = "opportunities-extension-customer-filter-search"; ownerSearchInput.type = "search"; ownerSearchInput.placeholder = "Search owners"; ownerSearchInput.setAttribute("aria-label", "Search owners"); ownerSearchInput.addEventListener("input", () => { opportunitiesFilterState.ownerSearch = ownerSearchInput.value; saveFilterPreferences(); renderOwnerFilterList(); }); const ownerSelectAllLabel = document.createElement("label"); ownerSelectAllLabel.className = "opportunities-extension-customer-filter-select-all"; const ownerSelectAllCheckbox = document.createElement("input"); ownerSelectAllCheckbox.id = OWNER_FILTER_SELECT_ALL_ID; ownerSelectAllCheckbox.type = "checkbox"; ownerSelectAllCheckbox.addEventListener("change", () => { const ownerOptions = getOwnerOptions(); opportunitiesFilterState.selectedOwnerKeys = ownerSelectAllCheckbox.checked ? new Set(ownerOptions.map((owner) => owner.key)) : new Set(); opportunitiesFilterState.hasSavedOwnerFilter = true; saveFilterPreferences(); renderOwnerFilter(); renderOpportunitiesTable(); }); const ownerSelectAllText = document.createElement("span"); ownerSelectAllText.textContent = "Select all"; ownerSelectAllLabel.append(ownerSelectAllCheckbox, ownerSelectAllText); const ownerFilterList = document.createElement("div"); ownerFilterList.id = OWNER_FILTER_LIST_ID; ownerFilterList.className = "opportunities-extension-customer-filter-list"; ownerFilterPanel.append(ownerSearchInput, ownerSelectAllLabel, ownerFilterList); ownerFilter.append(ownerFilterLabel, ownerFilterButton, ownerFilterPanel); const tableSearchField = document.createElement("label"); tableSearchField.className = "opportunities-extension-table-search-field"; const tableSearchLabel = document.createElement("span"); tableSearchLabel.textContent = "Search"; const tableSearchInput = document.createElement("input"); tableSearchInput.id = TABLE_SEARCH_ID; tableSearchInput.type = "search"; tableSearchInput.placeholder = "Search opportunities"; tableSearchInput.setAttribute("aria-label", "Search opportunities"); tableSearchInput.value = opportunitiesFilterState.tableSearch; tableSearchInput.addEventListener("input", () => { opportunitiesFilterState.tableSearch = tableSearchInput.value; saveFilterPreferences(); renderOpportunitiesTable(); }); tableSearchField.append(tableSearchLabel, tableSearchInput); const statusFilter = document.createElement("section"); statusFilter.className = "opportunities-extension-status-filter"; const statusFilterLabel = document.createElement("span"); statusFilterLabel.className = "opportunities-extension-status-filter-label"; statusFilterLabel.textContent = "Status"; const statusFilters = document.createElement("div"); statusFilters.id = STATUS_FILTERS_ID; statusFilters.className = "opportunities-extension-status-filter-controls"; statusFilters.setAttribute("role", "group"); statusFilters.setAttribute("aria-label", "Filter by status"); statusFilter.append(statusFilterLabel, statusFilters); form.addEventListener("submit", (event) => event.preventDefault()); form.append(field, customerFilter, ownerFilter, tableSearchField, statusFilter, stageFilter); body.append(form); const stageDashboard = document.createElement("section"); stageDashboard.id = STAGE_DASHBOARD_ID; stageDashboard.className = "opportunities-extension-stage-dashboard"; stageDashboard.setAttribute("aria-label", "Opportunity amount by stage"); body.append(stageDashboard); const tableSurface = document.createElement("section"); tableSurface.className = "opportunities-extension-table-surface"; const opportunitiesTable = document.createElement("table"); opportunitiesTable.id = OPPORTUNITIES_TABLE_ID; opportunitiesTable.className = "opportunities-extension-table"; opportunitiesTable.setAttribute("aria-label", "Opportunities"); tableSurface.append(opportunitiesTable); body.append(tableSurface); const debugPanel = document.createElement("aside"); debugPanel.id = DEBUG_PANEL_ID; debugPanel.className = "opportunities-extension-debug-panel"; debugPanel.hidden = true; body.append(debugPanel); shell.append(header, body); overlay.append(shell); document.body.append(overlay); document.documentElement.classList.add("opportunities-extension-scroll-lock"); ensureEscapeKeyHandler(); renderStageFilterButtons(); renderStatusFilterButtons(); renderCustomerFilter(); renderOwnerFilter(); renderOpportunitiesTable(); requestOpportunitiesForPeriod(select.value); select.focus(); } function updateAuthBadge(status) { const badge = document.querySelector(`#${MODAL_ID} .opportunities-extension-auth-badge`); if (!badge) { return; } const badgeStatus = status === AUTH_STATUS.authenticated || status === AUTH_STATUS.unauthenticated ? status : AUTH_STATUS.pending; badge.setAttribute("data-auth-status", badgeStatus); badge.className = `opportunities-extension-auth-badge opportunities-extension-auth-badge-${badgeStatus}`; badge.textContent = badgeStatus === AUTH_STATUS.authenticated ? "Authenticated" : badgeStatus === AUTH_STATUS.unauthenticated ? "Unauthenticated" : "Authenticating"; } function closeOpportunitiesModal() { const modal = document.getElementById(MODAL_ID); if (modal) { closePreferencesModal(); closeAccountPlansModal(); closeInstallBaseModal(); closeServiceRequestsModal(); modal.hidden = true; } debugState.debugSecretsVisible = false; document.documentElement.classList.remove("opportunities-extension-scroll-lock"); } function ensureEscapeKeyHandler() { if (window[ESCAPE_LISTENER_KEY]) { return; } window[ESCAPE_LISTENER_KEY] = true; document.addEventListener("keydown", (event) => { const modal = document.getElementById(MODAL_ID); if (!modal || modal.hidden) { return; } if (event.ctrlKey && event.key.toLowerCase() === "d") { event.preventDefault(); event.stopPropagation(); toggleDebugPanel(); return; } if (event.key === "Escape") { if (closeServiceRequestsModal()) { event.preventDefault(); return; } if (closeInstallBaseModal()) { event.preventDefault(); return; } const accountPlansModal = document.getElementById(ACCOUNT_PLANS_MODAL_ID); if (accountPlansModal && !accountPlansModal.hidden) { closeAccountPlansModal(); event.preventDefault(); return; } const preferencesModal = document.getElementById(PREFERENCES_MODAL_ID); if (preferencesModal && !preferencesModal.hidden) { closePreferencesModal(); event.preventDefault(); return; } if (closeCustomerFilterPanel()) { event.preventDefault(); return; } if (closeOwnerFilterPanel()) { event.preventDefault(); return; } closeOpportunitiesModal(); } }); document.addEventListener("pointerdown", (event) => { const modal = document.getElementById(MODAL_ID); const panel = document.getElementById(CUSTOMER_FILTER_PANEL_ID); const ownerPanel = document.getElementById(OWNER_FILTER_PANEL_ID); if (!modal || modal.hidden) { return; } if (panel && !panel.hidden) { const customerFilter = panel.closest(".opportunities-extension-customer-filter"); if (customerFilter && !customerFilter.contains(event.target)) { closeCustomerFilterPanel(false); } } if (ownerPanel && !ownerPanel.hidden) { const ownerFilter = ownerPanel.closest(".opportunities-extension-customer-filter"); if (ownerFilter && !ownerFilter.contains(event.target)) { closeOwnerFilterPanel(false); } } }); } return { openOpportunitiesModal, updateAuthBadge, closeOpportunitiesModal, ensureEscapeKeyHandler }; }