From 167139042ff647336e46009a5752d633f2793730 Mon Sep 17 00:00:00 2001
From: mdickson-adbe <95774602+mdickson-adbe@users.noreply.github.com>
Date: Tue, 4 Jun 2024 16:52:52 -0400
Subject: [PATCH] Performance refactoring (#107)
* performance refactoring
- improve thumbnail performance by makin async
- format date property to yyyy-mm-dd
- fix margin issue in program header
- refactor function that builds header dropdown for increased
performance
* resolve bug with event listeners not attaching
---
.../gmo-program-header/gmo-program-header.css | 2 +-
.../gmo-program-header/gmo-program-header.js | 43 ++++++++--------
blocks/gmo-program-list/gmo-program-list.css | 17 +++++--
blocks/gmo-program-list/gmo-program-list.js | 50 ++++++++++++-------
scripts/graphql.js | 30 -----------
5 files changed, 64 insertions(+), 78 deletions(-)
diff --git a/blocks/gmo-program-header/gmo-program-header.css b/blocks/gmo-program-header/gmo-program-header.css
index ac30d581..e00c20fb 100644
--- a/blocks/gmo-program-header/gmo-program-header.css
+++ b/blocks/gmo-program-header/gmo-program-header.css
@@ -1,4 +1,4 @@
-.gmo-campaign-header.block {
+.gmo-program-header.block {
display: flex;
flex-direction: column;
margin-top: 20px;
diff --git a/blocks/gmo-program-header/gmo-program-header.js b/blocks/gmo-program-header/gmo-program-header.js
index 98e15246..d7a9e46d 100644
--- a/blocks/gmo-program-header/gmo-program-header.js
+++ b/blocks/gmo-program-header/gmo-program-header.js
@@ -2,9 +2,6 @@ import { decorateIcons } from '../../scripts/lib-franklin.js';
import { graphqlQueryNameList, graphqlCampaignByName } from '../../scripts/graphql.js';
import { statusMapping, productList } from '../../scripts/shared-program.js';
-// Declared at the top of the file, making it accessible to all functions within this file.
-let allProducts = [];
-
export default async function decorate(block) {
block.innerHTML = `
@@ -128,32 +125,29 @@ export default async function decorate(block) {
sendGmoCampaignListBlockEvent();
});
- await initializeDropdowns();
- attachEventListeners();
+ initializeDropdowns();
decorateIcons(block);
+ document.addEventListener('click', handleClickOutside);
}
async function initializeDropdowns() {
// Business Line List
+ graphqlQueryNameList('getBusinessLine').then((response) => {
+ populateDropdown(response, 'dropdownBusinessOptions', 'businessLine');
+ });
- const businessLineResponse = await graphqlQueryNameList('getBusinessLine');
- const businessLines = businessLineResponse.data.jsonByPath.item.json.options;
- populateDropdown(businessLines, 'dropdownBusinessOptions', 'businessLine');
+ // Geo List
+ graphqlQueryNameList('getGeoList').then((response) => {
+ populateDropdown(response, 'dropdownGeoOptions', 'p0TargetGeo');
+ });
// Status List
const statusResponse = await statusMapping;
- const statuses = statusResponse.data.jsonByPath.item.json.options;
- populateDropdown(statuses, 'dropdownStatusOptions', 'status');
+ populateDropdown(statusResponse, 'dropdownStatusOptions', 'status');
// Product List
const productResponse = await productList;
- allProducts = productResponse.data.jsonByPath.item.json.options;
- populateDropdown(allProducts, 'dropdownProductOptions', 'productOffering');
-
- // Geo List
- const geoResponse = await graphqlQueryNameList('getGeoList');
- const geos = geoResponse.data.jsonByPath.item.json.options;
- populateDropdown(geos, 'dropdownGeoOptions', 'p0TargetGeo');
+ populateDropdown(productResponse, 'dropdownProductOptions', 'productOffering');
}
// Function to attach event listeners
@@ -173,12 +167,10 @@ function attachEventListeners() {
if (resetFiltersBtn) {
resetFiltersBtn.addEventListener('click', resetFiltersClickHandler);
}
-
- // Add event listener for clicks outside of dropdowns
- document.addEventListener('click', handleClickOutside);
}
-function populateDropdown(options, dropdownId, type) {
+function populateDropdown(response, dropdownId, type) {
+ const options = response.data?.jsonByPath ? response.data.jsonByPath.item.json.options : response;
let dropdownContent = document.getElementById(dropdownId);
dropdownContent.innerHTML = '';
options.forEach((option, index) => {
@@ -189,13 +181,18 @@ function populateDropdown(options, dropdownId, type) {
anchor.dataset.type = type;
anchor.className = "dropoption";
anchor.textContent = option.text;
+ anchor.addEventListener('click', dropOptionClickHandler);
dropdownContent.appendChild(anchor);
});
+ // add event listener to button
+ const button = dropdownContent.parentElement.querySelector(".dropdown-button");
+ button.addEventListener('click', dropdownButtonClickHandler);
}
// Function to filter products based on selected business line
function filterProductsByBusinessLine(businessLine) {
- const filteredProducts = allProducts.filter(product =>
+ const products = productList.data.jsonByPath.item.json.options;
+ const filteredProducts = products.filter(product =>
product['business-line'].includes(businessLine)
);
populateDropdown(filteredProducts, 'dropdownProductOptions', 'productOffering');
@@ -324,7 +321,7 @@ function resetAllFilters() {
function resetProductsDropDown(){
// Populate all products into Products dropdown
- populateDropdown(allProducts, 'dropdownProductOptions', 'productOffering');
+ populateDropdown(productList, 'dropdownProductOptions', 'productOffering');
// Reset product offering filters
removeSelectedProductOfferingFilters();
attachEventListeners();
diff --git a/blocks/gmo-program-list/gmo-program-list.css b/blocks/gmo-program-list/gmo-program-list.css
index 7ab7b32e..a417c0c9 100644
--- a/blocks/gmo-program-list/gmo-program-list.css
+++ b/blocks/gmo-program-list/gmo-program-list.css
@@ -26,9 +26,20 @@ body {
display: flex;
font-weight: bold;
margin-bottom: 20px;
-
+ position: sticky;
padding-top: 5px;
}
+.list-items {
+ display: flex;
+ flex-direction: column;
+ overflow-y: scroll;
+ height: 65vh;
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+}
.column-header-wrapper {
display: flex;
}
@@ -48,10 +59,6 @@ body {
height: 14px;
width: 14px;
}
-.list-items {
- display: flex;
- flex-direction: column;
-}
.campaign-row {
display: flex;
font-size: 14px;
diff --git a/blocks/gmo-program-list/gmo-program-list.js b/blocks/gmo-program-list/gmo-program-list.js
index 71806d5f..b86c0396 100644
--- a/blocks/gmo-program-list/gmo-program-list.js
+++ b/blocks/gmo-program-list/gmo-program-list.js
@@ -150,6 +150,10 @@ async function buildCampaignList(campaigns, numPerPage) {
for (const campaign of campaigns) {
const index = campaigns.indexOf(campaign);
const campaignRow = document.createElement('div');
+ const programName = campaign.node.programName;
+ const campaignName = campaign.node.campaignName;
+ const programRef = campaign.node.programReferenceNumber;
+
campaignRow.classList.add('campaign-row');
if ((index + 1) > numPerPage) campaignRow.classList.add('hidden');
@@ -163,35 +167,27 @@ async function buildCampaignList(campaigns, numPerPage) {
const campaignIcon = document.createElement('div');
campaignIcon.classList.add('campaign-icon');
- campaignIcon.dataset.programname = campaign.node.programName;
- campaignIcon.dataset.campaignname = campaign.node.campaignName;
- //Add Icon Image
- const iconImage = document.createElement('img');
- try {
- const imageObject = await searchAsset(campaign.node.programName, campaign.node.campaignName);
- iconImage.src = imageObject.imageUrl;
- iconImage.alt = imageObject.imageAltText;
- } catch (error) {
- }
- // Append the image to the campaignIcon div
- campaignIcon.appendChild(iconImage);
+ campaignIcon.dataset.programname = programName;
+ campaignIcon.dataset.campaignname = campaignName;
+ campaignIcon.dataset.reference = programRef;
+ addThumbnail(campaignIcon, programName, campaignName);
campaignIconLink.appendChild(campaignIcon);
- const campaignName = document.createElement('div');
- campaignName.classList.add('campaign-name-wrapper', 'vertical-center');
+ const campaignNameWrapper = document.createElement('div');
+ campaignNameWrapper.classList.add('campaign-name-wrapper', 'vertical-center');
- campaignName.innerHTML = `
+ campaignNameWrapper.innerHTML = `
- ${checkBlankString(campaign.node.programName)}
+ ${checkBlankString(programName)}
Program Name
- ${checkBlankString(campaign.node.campaignName,'Marketing Moment Not Available')}
+ ${checkBlankString(campaignName,'Marketing Moment Not Available')}
Marketing Moment
`;
campaignInfoWrapper.appendChild(campaignIconLink);
- campaignInfoWrapper.appendChild(campaignName);
+ campaignInfoWrapper.appendChild(campaignNameWrapper);
const campaignOverviewWrapper = document.createElement('div');
campaignOverviewWrapper.classList.add('column-2', 'campaign-description-wrapper', 'vertical-center');
@@ -203,7 +199,7 @@ async function buildCampaignList(campaigns, numPerPage) {
campaignOverviewWrapper.appendChild(campaignOverview);
const campaignLaunch = document.createElement('div');
- campaignLaunch.textContent = checkBlankString(campaign.node.launchDate);
+ campaignLaunch.textContent = dateFormat(campaign.node.launchDate);
campaignLaunch.classList.add('column-3', 'campaign-launch-date', 'vertical-center');
campaignLaunch.dataset.property = 'launch';
@@ -238,6 +234,17 @@ function buildStatus(statusWrapper, campaign) {
return statusWrapper;
}
+async function addThumbnail(parentElement, programName, campaignName) {
+ searchAsset(programName, campaignName).then((response) => {
+ if (response && (Object.hasOwn(response, 'imageUrl') && Object.hasOwn(response, 'imageAltText'))) {
+ const iconImage = document.createElement('img');
+ iconImage.src = response?.imageUrl;
+ iconImage.alt = response?.imageAltText;
+ parentElement.appendChild(iconImage);
+ }
+ })
+}
+
async function buildProduct(product) {
const productParent = document.createElement('div');
const productMapping = await getProductMapping(product);
@@ -470,3 +477,8 @@ function sortColumn(dir, property) {
container.appendChild(row);
});
}
+
+function dateFormat(dateString) {
+ const formattedDate = dateString ? dateString.split('T')[0] : 'Not Available';
+ return formattedDate;
+}
\ No newline at end of file
diff --git a/scripts/graphql.js b/scripts/graphql.js
index 72f6ceaa..9ed80bce 100644
--- a/scripts/graphql.js
+++ b/scripts/graphql.js
@@ -129,36 +129,6 @@ export async function graphqlCampaignByName(campaignName) {
});
}
-export async function graphqlFilterOnMarketingInitiative(marketingInitiative) {
-
- const baseApiUrl = `${await getGraphqlEndpoint()}/graphql/execute.json`;
- const projectId = 'gmo';
- const queryName = 'filter-on-marketing-initiative';
- const encodedMarketingInitiative = encodeURIComponent(marketingInitiative);
- const encodedSemiColon = encodeURIComponent(';');
- //persisted query URLs have to be encoded together with the first semicolon
- const graphqlEndpoint = `${baseApiUrl}/${projectId}/${queryName}${encodedSemiColon}marketingInitiative=${encodedMarketingInitiative}`;
- const jwtToken = await getBearerToken();
-
- // Return the fetch promise chain so that it can be awaited outside
- return fetch(graphqlEndpoint, {
- method: 'GET',
- headers: {
- Authorization: jwtToken,
- },
- }).then(response => {
- if (!response.ok) {
- throw new Error(`HTTP error! Status: ${response.status}`);
- }
- return response.json();
- }).then(data => {
- return data; // Make sure to return the data so that the promise resolves with it
- }).catch(error => {
- console.error('Error fetching data: ', error);
- throw error; // Rethrow or handle error as appropriate
- });
-}
-
async function getGraphqlEndpoint() {
const result = await getAdminConfig();
return result.aemGraphqlEndpoint;