Skip to content

Commit

Permalink
Performance refactoring (#107)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
mdickson-adbe authored and Shivani gupta committed Oct 1, 2024
1 parent f0f9c0e commit 1671390
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 78 deletions.
2 changes: 1 addition & 1 deletion blocks/gmo-program-header/gmo-program-header.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.gmo-campaign-header.block {
.gmo-program-header.block {
display: flex;
flex-direction: column;
margin-top: 20px;
Expand Down
43 changes: 20 additions & 23 deletions blocks/gmo-program-header/gmo-program-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = `
<div class="inputs-wrapper">
Expand Down Expand Up @@ -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
Expand All @@ -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) => {
Expand All @@ -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');
Expand Down Expand Up @@ -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();
Expand Down
17 changes: 12 additions & 5 deletions blocks/gmo-program-list/gmo-program-list.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -48,10 +59,6 @@ body {
height: 14px;
width: 14px;
}
.list-items {
display: flex;
flex-direction: column;
}
.campaign-row {
display: flex;
font-size: 14px;
Expand Down
50 changes: 31 additions & 19 deletions blocks/gmo-program-list/gmo-program-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -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 = `
<div class='campaign-name-label' data-property='campaign'>
${checkBlankString(campaign.node.programName)}
${checkBlankString(programName)}
<span class="tooltip">Program Name</span>
</div>
<div class='campaign-name'>
${checkBlankString(campaign.node.campaignName,'Marketing Moment Not Available')}
${checkBlankString(campaignName,'Marketing Moment Not Available')}
<span class="tooltip">Marketing Moment</span>
</div>
`;

campaignInfoWrapper.appendChild(campaignIconLink);
campaignInfoWrapper.appendChild(campaignName);
campaignInfoWrapper.appendChild(campaignNameWrapper);

const campaignOverviewWrapper = document.createElement('div');
campaignOverviewWrapper.classList.add('column-2', 'campaign-description-wrapper', 'vertical-center');
Expand All @@ -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';

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
30 changes: 0 additions & 30 deletions scripts/graphql.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 1671390

Please sign in to comment.