Skip to content

Commit

Permalink
ASSETS-88901 : (Backend) Campaign Page: Filters (#72)
Browse files Browse the repository at this point in the history
* graphql.js : Added functions graphqlProductList and graphqlStatusList
gmo-campaign-header.js : Updated code to build Status dropdown from function graphqlStatusList
Updated code to build Product dropdown from function graphqlProductList

* /blocks/gmo-campaign-list/gmo-campaign-list.js => Added custom event listener for custom event  gmoCampaignListBlock
which allows the event gmoCampaignListBlock to be called from the block component gmo-campaign-header.js

/blocks/gmo-campaign-header/gmo-campaign-header.js :
Created new function sendGmoCampaignListBlockEvent()
that calls the custom event   gmoCampaignListBlock
from the gmo-campaign-header.

This will trigger the custom event in the /blocks/gmo-campaign-list
to call the graphql persisted query getAllCampaigns with a filter based on the selected values from the dropdown lists for
Business Line
Status and Product

* graphql.js : Added test function graphAllCampaignsFilterfirst,cursor,filter) : Which has the filter parameter which is the graphQL filter object
Added function generateFilterJSON(filterParams)  which generates the graphQL filter object from an Array of parameters.

/blocks/gmo-campaign-header/gmo-campaign-header.js : Added event on the campaign-search field, to trigger the sendGmoCampaignBlockEvent after 3 characters are typed, later this will be replaced by a Campaign Suggested List generated as the user types

/blocks/gmo-campaign-list/gmo-campaign-list.js : Added code build the graphQL filter object from the Campaign Search fields and Drop Downs
Updated the function decorate to have new parameter graphQLFilter
So that the function graphqlAllCampaignsFilter(numPerPage,  cursor,graphQLFilter) can be called

* Adde autocomplete list CSS, JS and HMTL for the campaign search field.

* graphql.js Update function graphCampaignByName to use persisted query getCampaignNames used for autocomplete list for Campaign Name search
gmo-campaign-list.js : Changed campaignName search to use filter operater : '='
/gmo-campaign-header.js : Updated campaign search autocompleteList to trigger sendCampaignListBlockEvent to make autocomplete search work

* gmo-campaign-header.js : Updated function resetAllFilters() to call function sendGmoCampaignListBlockEvent();
gmo-campaign-list.js : Updated campaignCount to call function graphqlCampaignCount(graphqlFilter) with graphqlFilter
graphql.js : Updated function graphCampaignCount : Added filter parameter, and call persisted query  getCampaignNameFilter

* Removed console.log messages

* Fixed bug with currentPageInfo.nextCursor

* Fixed bug in calculation of cursor to use for the previous page logic

* graphql.js : Deleted function graphqlAllCampaigns(first,cursor) , replaced function  graphqlStatusList()  and  graphqlProductList()  with  function graphqlQueryNameList(queryNameList)
Variables baseApiUrl and projectId are now global/class level variables.

gmo-campaign-header.js : Close dropdown list when a value is selected

* update campaign with program

---------

Co-authored-by: Shivani gupta <[email protected]>
  • Loading branch information
TyroneAEM and Shivani gupta authored May 2, 2024
1 parent 853b9e9 commit 27e2467
Show file tree
Hide file tree
Showing 4 changed files with 325 additions and 80 deletions.
36 changes: 36 additions & 0 deletions blocks/gmo-campaign-header/gmo-campaign-header.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
border-radius: 4px;
display: flex;
align-items: center;
position: relative; /* Added to be the anchor for absolute positioning for autocomplete feature*/
& > .icon {
background-color: #FFF;
height: 14px;
Expand Down Expand Up @@ -161,3 +162,38 @@
}
}
}

/* Add the following for autocomplete styling */

.autocomplete-items {
position: absolute;
top: 100%;
left: 0;
right: 0;
border: 1px solid #cccccc;
border-top: none;
z-index: 10;
background: #ffffff;
overflow-y: auto;
max-height: 200px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}

.autocomplete-items div {
padding: 10px 15px;
cursor: pointer;
border-bottom: 1px solid #f0f0f0;
font-size: 14px; /* Adjust the font-size as needed */
color: #333; /* Adjust the text color as needed */
line-height: 1.4; /* Adjust line-height for better readability if necessary */
}

.autocomplete-items div:hover {
background-color: #e9e9e9;
}

.autocomplete-items div:last-child {
border-bottom: none;
}
186 changes: 136 additions & 50 deletions blocks/gmo-campaign-header/gmo-campaign-header.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,25 @@
import { decorateIcons } from '../../scripts/lib-franklin.js';
import { graphqlQueryNameList, graphqlCampaignByName } from '../../scripts/graphql.js';

export default async function decorate(block) {
block.innerHTML = `
<div class="inputs-wrapper">
<div class="search-wrapper">
<span class="icon icon-search"></span>
<input id="campaign-search" maxlength="512" type="search" class="campaign-search" placeholder="Search Marketing Moments...">
<!-- autocomplete feature-->
<div id="autocomplete-list" class="autocomplete-items"></div>
</div>
<div class="filter-wrapper">
<div class="label">Categories</div>
<div class="filter-dropdown" id="campaign-categories">
<div class="label">Business Line</div>
<div class="filter-dropdown" id="campaign-business-line">
<div class="dropdown-button">
<div class="dropdown-label">All Categories</div>
<div class="dropdown-label">All Business Line</div>
<span class="icon icon-chevronDown"></span>
<span class="icon icon-chevronUp inactive"></span>
</div>
<div class="dropdown-content" id="dropdownOptions">
<a href="#" id="option1" data-value="option1" data-type="category" class="dropoption">Option 1</a>
<a href="#" id="option2" data-value="option2" data-type="category" class="dropoption">Option 2</a>
<a href="#" id="option3" data-value="option3" data-type="category" class="dropoption">Option 3</a>
<a href="#" id="option4" data-value="option4" data-type="category" class="dropoption">Option 4</a>
<a href="#" id="option5" data-value="option5" data-type="category" class="dropoption">Option 5</a>
<div class="dropdown-content" id="dropdownBusinessOptions">
<a href="#" id="option1" data-value="digital-media-dme" data-type="businessLine" class="dropoption">Digital Media (DMe)</a>
</div>
</div>
</div>
Expand All @@ -32,7 +31,7 @@ export default async function decorate(block) {
<span class="icon icon-chevronDown"></span>
<span class="icon icon-chevronUp inactive"></span>
</div>
<div class="dropdown-content" id="dropdownOptions">
<div class="dropdown-content" id="dropdownStatusOptions">
<a href="#" id="option1" data-value="option1" data-type="status" class="dropoption">Option 1</a>
<a href="#" id="option2" data-value="option2" data-type="status" class="dropoption">Option 2</a>
<a href="#" id="option3" data-value="option3" data-type="status" class="dropoption">Option 3</a>
Expand All @@ -41,23 +40,7 @@ export default async function decorate(block) {
</div>
</div>
</div>
<div class="filter-wrapper">
<div class="label">Cloud Business</div>
<div class="filter-dropdown" id="campaign-business">
<div class="dropdown-button">
<div class="dropdown-label">All Cloud Businesses</div>
<span class="icon icon-chevronDown"></span>
<span class="icon icon-chevronUp inactive"></span>
</div>
<div class="dropdown-content" id="dropdownOptions">
<a href="#" id="option1" data-value="option1" data-type="business" class="dropoption">Option 1</a>
<a href="#" id="option2" data-value="option2" data-type="business" class="dropoption">Option 2</a>
<a href="#" id="option3" data-value="option3" data-type="business" class="dropoption">Option 3</a>
<a href="#" id="option4" data-value="option4" data-type="business" class="dropoption">Option 4</a>
<a href="#" id="option5" data-value="option5" data-type="business" class="dropoption">Option 5</a>
</div>
</div>
</div>
<div class="filter-wrapper">
<div class="label">Products</div>
<div class="filter-dropdown" id="campaign-products">
Expand All @@ -66,29 +49,12 @@ export default async function decorate(block) {
<span class="icon icon-chevronDown"></span>
<span class="icon icon-chevronUp inactive"></span>
</div>
<div class="dropdown-content" id="dropdownOptions">
<a href="#" id="option1" data-value="option1" data-type="product" class="dropoption">Option 1</a>
<a href="#" id="option2" data-value="option2" data-type="product" class="dropoption">Option 2</a>
<a href="#" id="option3" data-value="option3" data-type="product" class="dropoption">Option 3</a>
<a href="#" id="option4" data-value="option4" data-type="product" class="dropoption">Option 4</a>
<a href="#" id="option5" data-value="option5" data-type="product" class="dropoption">Option 5</a>
</div>
</div>
</div>
<div class="filter-wrapper">
<div class="label">Other (TBD)</div>
<div class="filter-dropdown" id="campaign-other">
<div class="dropdown-button">
<div class="dropdown-label">Other</div>
<span class="icon icon-chevronDown"></span>
<span class="icon icon-chevronUp inactive"></span>
</div>
<div class="dropdown-content" id="dropdownOptions">
<a href="#" id="option1" data-value="option1" data-type="other" class="dropoption">Option 1</a>
<a href="#" id="option2" data-value="option2" data-type="other" class="dropoption">Option 2</a>
<a href="#" id="option3" data-value="option3" data-type="other" class="dropoption">Option 3</a>
<a href="#" id="option4" data-value="option4" data-type="other" class="dropoption">Option 4</a>
<a href="#" id="option5" data-value="option5" data-type="other" class="dropoption">Option 5</a>
<div class="dropdown-content" id="dropdownProductOptions">
<a href="#" id="option1" data-value="option1" data-type="productOffering" class="dropoption">Option 1</a>
<a href="#" id="option2" data-value="option2" data-type="productOffering" class="dropoption">Option 2</a>
<a href="#" id="option3" data-value="option3" data-type="productOffering" class="dropoption">Option 3</a>
<a href="#" id="option4" data-value="option4" data-type="productOffering" class="dropoption">Option 4</a>
<a href="#" id="option5" data-value="option5" data-type="productOffering" class="dropoption">Option 5</a>
</div>
</div>
</div>
Expand All @@ -100,6 +66,110 @@ export default async function decorate(block) {
</div>
<span class="icon icon-close inactive"></span>
`;

// autocomplete feature
const autocompleteList = document.getElementById('autocomplete-list');
// Get the input element by its ID
const searchInput = document.getElementById('campaign-search');
searchInput.addEventListener('input', async function() {
const value = this.value;
if (value)
{
const graphqlData = await graphqlCampaignByName(value);
//Get unique values
const searchItems = Array.from(new Set(graphqlData.data.programList.items.map(item => item.campaignName)));
autocomplete(value, searchItems);
}
else
{
//The value has been cleard so trigger the gmo-campaign-list block from the gmo-campaign-header
sendGmoCampaignListBlockEvent();
}
});

function autocomplete(value, items) {
clearAutocomplete();
if (!value) return;
const filteredItems = items.filter(item => item.toLowerCase().includes(value.toLowerCase()));
filteredItems.forEach(item => {
const entry = document.createElement('div');
entry.innerHTML = item;
entry.addEventListener('click', function() {
searchInput.value = this.innerText;
clearAutocomplete();
});
autocompleteList.appendChild(entry);
});
}

function clearAutocomplete() {
while (autocompleteList.firstChild) {
autocompleteList.removeChild(autocompleteList.firstChild);
}
}

// Listen for click events on the autocomplete list
autocompleteList.addEventListener('click', function(event) {
//Trigger the gmo-campaign-list block from the gmo-campaign-header
sendGmoCampaignListBlockEvent();
});

// Listen for change events on the autocomplete list
autocompleteList.addEventListener('change', function(event) {
//Trigger the gmo-campaign-list block from the gmo-campaign-header
sendGmoCampaignListBlockEvent();
});

//Status List
const statusResponse = await graphqlQueryNameList('getStatusList');
const statuses = statusResponse.data.programList.items;

// Extract unique statuses
const uniqueStatuses = Array.from(new Set(statuses.map(item => item.status)));
let dropdownContent = document.getElementById('dropdownStatusOptions');
// Clear existing options
dropdownContent.innerHTML = '';
// Append new options
uniqueStatuses.forEach((status, index) => {
// Create a new anchor element for each status
var anchor = document.createElement('a');
anchor.href = "#";
anchor.id = "option" + (index + 1); // increment index for 1-based id
//anchor.dataset.value = "option" + (index + 1);
anchor.dataset.value = status;
anchor.dataset.type = "status";
anchor.className = "dropoption";
anchor.textContent = status; // using the status as the text
// Append to the dropdown
dropdownContent.appendChild(anchor);
});

//Product List
const productResponse = await graphqlQueryNameList('getProductList');
const products = productResponse.data.programList.items;

// Extract unique statuses
const uniqueProducts = Array.from(new Set(products.map(item => item.productOffering)));
let dropdownProductContent = document.getElementById('dropdownProductOptions');
// Clear existing options
dropdownProductContent.innerHTML = '';
// Append new options
uniqueProducts.forEach((product, index) => {
// Create a new anchor element for each status
var anchor = document.createElement('a');
anchor.href = "#";
anchor.id = "option" + (index + 1); // increment index for 1-based id
//anchor.dataset.value = "option" + (index + 1);
anchor.dataset.value = product;
anchor.dataset.type = "productOffering";//field in graphQL
anchor.className = "dropoption";
anchor.textContent = product; // using the status as the text
// Append to the dropdown
dropdownProductContent.appendChild(anchor);
});

//End product dropdown

document.querySelectorAll('.dropdown-button').forEach((button) => {
button.addEventListener('click', (event) => {
toggleDropdown(event.target);
Expand All @@ -108,6 +178,8 @@ export default async function decorate(block) {
document.querySelectorAll('.dropoption').forEach((button) => {
button.addEventListener('click', (event) => {
toggleOption(event.target.dataset.value, event.target.dataset.type);
//Closes the dropdown list
toggleDropdown(event.target);
});
});
document.querySelector('.reset-filters').addEventListener('click', () => {
Expand Down Expand Up @@ -160,16 +232,25 @@ function handleSelectedFilter(option) {
} else {
filterTagRoot.removeChild(document.querySelector(`.selected-filter[data-value='${filterValue}'][data-type='${filterType}']`));
}

//Trigger the gmo-campaign-list block from the gmo-campaign-header
sendGmoCampaignListBlockEvent();
}

function resetAllFilters() {
//Clear the campaignName search field
const searchInput = document.getElementById('campaign-search');
searchInput.value = '';

const selectedFilters = document.querySelectorAll('.dropoption.selected');
selectedFilters.forEach((element) => {
element.classList.toggle('selected');
})
const filterTagRoot = document.querySelector('.selected-filters-list');
filterTagRoot.replaceChildren();
checkResetBtn();
//Trigger the gmo-campaign-list block from the gmo-campaign-header
sendGmoCampaignListBlockEvent();
}

function checkResetBtn() {
Expand All @@ -181,3 +262,8 @@ function checkResetBtn() {
resetFiltersBtn.classList.add('inactive');
}
}

function sendGmoCampaignListBlockEvent() {
const blockEvent = new CustomEvent('gmoCampaignListBlock');
document.dispatchEvent(blockEvent);
}
Loading

0 comments on commit 27e2467

Please sign in to comment.