diff --git a/blocks/gmo-program-details/gmo-program-details.css b/blocks/gmo-program-details/gmo-program-details.css
index 9e6737d..9eca969 100644
--- a/blocks/gmo-program-details/gmo-program-details.css
+++ b/blocks/gmo-program-details/gmo-program-details.css
@@ -822,9 +822,14 @@ body {
font: normal normal normal 14px/21px Adobe Clean;
letter-spacing: 0px;
color: #0D66D0;
+ border: 1px solid #D3D3D3;
+ border-radius: 4px;
+ padding: 0 10px;
+ height: 24px;
+ line-height: 24px;
&:not(:last-child) {
- margin-right: 30px;
+ margin-right: 5px;
}
}
}
diff --git a/blocks/gmo-program-details/gmo-program-details.js b/blocks/gmo-program-details/gmo-program-details.js
index 736fedd..79a7dfb 100644
--- a/blocks/gmo-program-details/gmo-program-details.js
+++ b/blocks/gmo-program-details/gmo-program-details.js
@@ -107,7 +107,6 @@ export default async function decorate(block) {
div({ class: 'use-case-tag'}, 'Text to Image'),
div({ class: 'use-case-tag'}, 'Use Case 2'),
)
-
),
div(
{ id: 'deliverable-type', class: 'channel-scope-wrapper'},
@@ -282,17 +281,21 @@ async function addProgramStats(block) {
}
} else {
//programName and campaignName is null
+ const noDataBlock = div(
+ div(
+ { class: 'back-button' },
+ span({ class: 'icon icon-back' }),
+ span({ class: 'back-label' }, 'Back')
+ ),
+ div(
+ { class: 'main-body-wrapper' },
+ header,
+ div({ class: 'no-data-msg' }, 'No program data available.'),
+ ),
+ );
header.textContent = 'Unable to retrieve program information.';
- block.innerHTML = `
-
';
- } else {
- divopen = '
';
+ headerRowDiv.classList.add('subheader');
+ divOpen.classList.add('subheading');
}
- if (isInactive) headerRow.classList.add('inactive');
- headerRow.innerHTML = `
- ${divopen}
-
-
-
-
`;
- return headerRow;
+ headerRowDiv.appendChild(divOpen);
+ if (isInactive) headerRowDiv.classList.add('inactive');
+ return headerRowDiv;
}
-async function buildTableRow(deliverable, kpi, createHidden) {
+async function buildTableRow(deliverable, createHidden) {
//look up friendly name for deliverable type
const typeLabel = await lookupType(deliverable.deliverableType, 'deliverable-type');
- const dataRow = document.createElement('div');
- dataRow.classList.add('row', 'datarow');
- if (createHidden) dataRow.classList.add('inactive');
+ const assetLinks = createAssetLink(deliverable);
const status = (deliverable.deliverableStatusUpdate == null) ? "Not Available" : deliverable.deliverableStatusUpdate + "%";
const statusPct = (deliverable.deliverableStatusUpdate == null) ? "0%" : deliverable.deliverableStatusUpdate + "%";
- const assetLinks = createAssetLink(deliverable);
- dataRow.innerHTML = `
-
${checkBlankString(deliverable.deliverableName)}
-
${checkBlankString(typeLabel)}
-
-
- ${deliverable.reviewLink ? '
QA Files ': "Not Available"}
-
-
- ${assetLinks.outerHTML}
-
-
-
-
${dateFormat(deliverable.taskCompletionDate)}
- ${deliverable.previousTaskCompletionDate ? '
Revised from ' + deliverable.previousTaskCompletionDate + '
': ""}
-
-
${checkBlankString(deliverable.driver)}
- `;
- createPlatformString(deliverable.platforms, dataRow);
- return dataRow;
+
+ const dataRowDiv = div(
+ { class: 'row datarow' },
+ div({ class: 'property table-column column1 deliverable-name' }, checkBlankString(deliverable.deliverableName)),
+ div({ class: 'property table-column column2 deliverable-type' }, checkBlankString(typeLabel)),
+ div({ class: 'property table-column column3 platforms' }),
+ div(
+ { class: 'property table-column column4 qa-files' },
+ deliverable.reviewLink
+ ? a({ class: 'campaign-link', target: '_blank', href: deliverable.reviewLink }, 'QA Files')
+ : 'Not Available'
+ ),
+ div({ class: 'property table-column column5' }, assetLinks),
+ div(
+ { class: 'property table-column column7 justify-center' },
+ div(
+ { class: 'status-wrapper '},
+ div(
+ { class: 'status-heading' },
+ div({ class: 'status-label' }, 'Progress'),
+ div({ class: 'status-percent' }, status),
+ ),
+ div(
+ { class: 'status-bar-wrapper' },
+ div({ class: 'status-bar-underlay' }),
+ div({ class: 'status-bar', style: `width: ${statusPct}` }),
+ ),
+ )
+ ),
+ div({ class: 'property table-column column8 date-wrapper' },
+ div({ class: 'completion-date' }, dateFormat(deliverable.taskCompletionDate)),
+ deliverable.previousTaskCompletionDate
+ ? div({ class: 'revised-date' }, `Revised from ${deliverable.previousTaskCompletionDate}`)
+ : ''
+ ),
+ div({ class: 'property table-column column9' }, checkBlankString(deliverable.driver)),
+ );
+ if (createHidden) dataRowDiv.classList.add('inactive');
+ createPlatformString(deliverable.platforms, dataRowDiv);
+ return dataRowDiv;
}
async function createPlatformString(platforms, htmlElem) {
@@ -1075,6 +1072,24 @@ function parseCollectionName(rawString) {
}
}
+function parseProgramCollectionLink(collectionString) {
+ let collectionName, collectionLink;
+ const splitString = collectionString.split(';');
+ if (splitString.length > 1) {
+ collectionName = splitString[0];
+ collectionLink = splitString[1];
+ } else {
+ collectionName = 'Collection';
+ collectionLink = splitString[0];
+ }
+
+ const parsedCollection = {
+ 'name': collectionName,
+ 'link': collectionLink,
+ }
+ return parsedCollection;
+}
+
function parseCollectionLink(collectionString) {
let collectionName, collectionPlatform, collectionCategory, collectionLink;
const fullNameSplit = collectionString.split(';');
@@ -1099,7 +1114,6 @@ function parseCollectionLink(collectionString) {
'link': collectionLink,
'fullName': fullName
}
-
return parsedCollection;
}
@@ -1206,7 +1220,9 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
// get end of the view
viewEnd = getTimeBounds(calendarDeliverables, "end", endDateProp);
- if (!(isValidDate(viewEnd)) || viewEnd <= 0) {
+
+ // update- if viewEnd is before viewStart, ignore and set arbitrary viewStart+1 month end date
+ if (!(isValidDate(viewEnd)) || viewEnd <= 0 || viewEnd < viewStart) {
viewEnd = new Date(viewStart);
viewEnd.setMonth(viewStart.getMonth() + 1);
}
@@ -1244,6 +1260,14 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
contentWrapper.dataset.view = "year";
}
+ const contentWrapperDiv = div({ class: 'calendar-content-wrapper' });
+ if (type === 'quater') {
+ contentWrapperDiv.classList.add('quarter-view');
+ contentWrapperDiv.dataset.view = 'quarter';
+ } else {
+ contentWrapperDiv.dataset.vew = 'year';
+ }
+
var groupIndex = 1;
for (const group of uniqueGroups) {
const groupType = await lookupType(group, 'deliverable-type');
@@ -1285,9 +1309,7 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
const widthOfGroup = (endPosition - startPosition); // width of group = start position + (day duration)
// calculate the duration of the group as that helps set the width of its members
const groupDuration = Math.floor((latestEndDate.getTime() - earliestStartDate.getTime()) / (1000 * 60 * 60 * 24));
-
- const itemWrapper = document.createElement('div');
- itemWrapper.classList.add('group-content');
+ const itemWrapperDiv = div({ class: 'group-content' });
for (const item of matchedItems) {
const itemStartDate = (item[startDateProp]) ? new Date(item[startDateProp]) : viewStart;
@@ -1299,68 +1321,64 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
let daysDifference = Math.floor((itemStartDate.getTime() - earliestStartDate.getTime()) / (1000 * 60 * 60 * 24));
const startPctDiff = ((daysDifference / groupDuration) * 100).toFixed(2);
- let itemEl = document.createElement('div');
- itemEl.classList.add('item');
- itemEl.style.marginLeft = startPctDiff + '%';
// Find the corresponding color code from the taskStatusMappings array
const itemStatusMapping = await getTaskStatusMapping(item.taskStatus);
const { text: statusText = 'Unknown Status', 'color-code': colorCode = 'green' } = itemStatusMapping;
// Create a placeholder for the thumbnail
- itemEl.innerHTML = `
-
-
-
-
-
-
${item.deliverableName}
-
-
-
-
-
- ${itemEndDateStr ? '
End Date: ' + itemEndDateStr + '
' : ''}
-
-
-
- `;
- itemEl.style.width = itemDurationPct + '%';
+ const itemElDiv = div({ class: 'item', style: `margin-left: ${startPctDiff}%;width: ${itemDurationPct}%`},
+ div({ class: 'color-tab'}),
+ div(
+ { class: 'item-content' },
+ div(
+ { class: 'content-row' },
+ div(
+ { class: 'info' },
+ div({ class: 'thumbnail' }),
+ div({ class: 'name', title: item.deliverableName}, item.deliverableName),
+ div({ class: 'item-status', 'data-status': checkBlankString(item.taskStatus),
+ style: `background-color: #${colorCode}`, title: statusText,
+ }),
+ ),
+ ),
+ div(
+ { class: 'content-row bottom' },
+ itemEndDateStr
+ ? div({ class: 'start-date', title: `Task Planned End Date: ${itemEndDateStr}`}, `End Date: ${itemEndDateStr}`)
+ : '',
+ div(
+ { class: 'link' },
+ a({ href: item.reviewLink, target: '_blank' }, 'QA Files'),
+ )
+ )
+ )
+ );
// Call the new function to fetch and add the thumbnail, ensuring sequential execution
- await addThumbnailToItem(itemEl, item.programName, item.campaignName,item.deliverableType);
- itemWrapper.appendChild(itemEl);
-
+ await addThumbnailToItem(itemElDiv, item.programName, item.campaignName,item.deliverableType);
+ itemWrapperDiv.appendChild(itemElDiv);
};
- //await lookupType(category, 'deliverable-type');
- const groupEl = document.createElement('div');
- groupEl.classList.add('calendar-group', `color${groupIndex}`);
- groupEl.style.marginLeft = startPosition + '%';
- groupEl.style.width = widthOfGroup + '%';
- groupEl.innerHTML = `
-
- `;
- groupEl.appendChild(itemWrapper);
- groupEl.querySelectorAll('.group-controls').forEach((arrow) => {
+ const groupElDiv = div({ class: `calendar-group color${groupIndex}`,
+ style: `margin-left: ${startPosition}%;width: ${widthOfGroup}%`},
+ div({ class: 'group-header'},
+ div({ class: 'left-block' },
+ img({ src: '/icons/chevron-right.svg', class: 'group-expand group-controls inactive'}),
+ img({ src: '/icons/chevron-right.svg', class: 'group-collapse group-controls'}),
+ div({ class: 'group-heading', title: `${groupType}`}, groupType),
+ div({ class: 'group-count'}, matchedItems.length)
+ ),
+ div({ class: 'right-block' }),
+ ),
+ );
+
+ groupElDiv.appendChild(itemWrapperDiv);
+ groupElDiv.querySelectorAll('.group-controls').forEach((arrow) => {
arrow.addEventListener('click', showHideGroup);
});
- contentWrapper.appendChild(groupEl);
+ contentWrapper.appendChild(groupElDiv);
groupIndex = (groupIndex === 5) ? 1 : groupIndex + 1;
};
@@ -1368,19 +1386,13 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
block.querySelector('.calendar.tab').appendChild(calendarEl);
// populate "filter" dropdown
- const filterDropdown = document.createElement('div');
- filterDropdown.classList.add('filter-dropdown-content');
+ const filterDropdown = div({ class: 'filter-dropdown-content'});
const uniqueYears = getUniqueYears(calendarDeliverables);
- const yearOptionLabel = document.createElement('div');
- yearOptionLabel.classList.add('filter-label');
- yearOptionLabel.textContent = 'Year';
- const quarterOptionLabel = document.createElement('div');
- quarterOptionLabel.classList.add('filter-label');
- quarterOptionLabel.textContent = 'Quarter';
+ const yearOptionLabel = div({ class: 'filter-label' }, 'Year');
+ const quarterOptionLabel = div({ class: 'filter-label' }, 'Quarter');
filterDropdown.appendChild(yearOptionLabel);
// when choosing 'Quarter' the top left controls change to control the quarter in focus
- // its kind of a zoomed in view.
uniqueYears.forEach((year) => {
const yearOption = document.createElement('div');
yearOption.classList.add('filter-option');
@@ -1392,11 +1404,7 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
filterDropdown.appendChild(quarterOptionLabel);
const quarters = [ 1, 2, 3, 4 ];
quarters.forEach((quarter) => {
- const quarterOption = document.createElement('div');
- quarterOption.classList.add('filter-option');
- quarterOption.dataset.period = quarter;
- quarterOption.textContent = quarter;
- //quarterOption.addEventListener('click', filterDropdownSelection);
+ const quarterOption = div({ class: 'filter-option', 'data-period': quarter }, quarter);
quarterOption.addEventListener('click', (event) => filterDropdownSelection(event, viewStartYear, years.length));
filterDropdown.appendChild(quarterOption);
})
@@ -1416,13 +1424,15 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
const totalDaysInMonth = new Date((new Date(currentYear, currentMonth, 1)) - 1).getDate();
const percentOfMonth = (currentDate.getUTCDate() / totalDaysInMonth).toFixed(2) * 100;
const monthEl = block.querySelector(`.month-wrapper[data-year='${currentYear}'] .month[data-num='${currentMonth}']`);
- monthEl.classList.add('current');
- const lineEl = document.createElement('div');
- lineEl.classList.add('calendar-indicator');
- // use direct style for offset
- lineEl.style.marginRight = ((-2 * percentOfMonth) + 100) + '%';
- monthEl.appendChild(lineEl);
-
+
+ // account for view not including current date
+ if (monthEl) {
+ monthEl.classList.add('current');
+ // use direct style for line offset
+ const lineEl = div({ class: 'calendar-indicator', style: `margin-right: ${((-2 * percentOfMonth) + 100)}%` })
+ monthEl.appendChild(lineEl);
+ }
+
// close dropdown listener for clicks outside open dropdown
document.querySelector('.gmo-program-details.block').addEventListener('click', dismissDropdown);
block.querySelectorAll('.year-switch > .year-toggle').forEach((control) => {
@@ -1447,8 +1457,6 @@ async function buildCalendar(dataObj, block, type, mappingArray, period) {
});
}
-// calendar view supporting functions
-
// Helper function to get task status mapping
async function getTaskStatusMapping(taskStatus) {
const taskStatusArray = await taskStatusMappings;
@@ -1476,11 +1484,8 @@ async function addThumbnailToItem(itemEl, programName, campaignName, deliverable
// Use the cached or newly fetched imageObject
if (imageObject && imageObject.imageUrl) {
const thumbnailDiv = itemEl.querySelector('.thumbnail');
- const imgElement = document.createElement('img');
- imgElement.src = imageObject.imageUrl;
- imgElement.alt = imageObject.imageAltText;
- imgElement.loading = 'lazy';
- thumbnailDiv.appendChild(imgElement);
+ const imgEl = img({ src: imageObject.imageUrl, alt: imageObject.imageAltText, loading: 'lazy' });
+ thumbnailDiv.appendChild(imgEl);
} else {
console.error("Image Object does not have a valid imageUrl");
}
@@ -1657,49 +1662,63 @@ function calendarYears(startYear, endYear) {
}
function buildYearCal(years) {
- const calendarEl = document.createElement('div');
- calendarEl.classList.add('calendar-wrapper');
+ const calendarEl = div({ class: 'calendar-wrapper' });
if (years.length > 1) calendarEl.classList.add('multiyear');
- const backgroundEl = document.createElement('div');
- backgroundEl.classList.add('calendar-background');
- backgroundEl.style.width = (years.length * 100) + '%';
+ const backgroundEl = div({ class: 'calendar-background', style: `width: ${(years.length * 100)}%` });
years.forEach((year) => {
- const yearWrapper = document.createElement('div');
- yearWrapper.dataset.year = year;
- yearWrapper.classList.add('year-wrapper');
- yearWrapper.style.width = (100 / years.length) + '%';
- const calendarHeader = document.createElement('div');
- calendarHeader.classList.add('header-wrapper');
- const quartersHeader = document.createElement('div');
- quartersHeader.classList.add('quarter-header');
- quartersHeader.innerHTML = `
-
Q1 ${year}
-
Q2 ${year}
-
Q3 ${year}
-
Q4 ${year}
- `;
- calendarHeader.appendChild(quartersHeader);
-
- const monthsWrapper = document.createElement('div');
- monthsWrapper.classList.add('month-wrapper');
- monthsWrapper.dataset.year = year;
- monthsWrapper.innerHTML = `
-
-
-
-
-
-
-
-
-
-
-
-
- `;
- yearWrapper.appendChild(calendarHeader);
- yearWrapper.appendChild(monthsWrapper);
+ const yearWrapper = div(
+ { class: 'year-wrapper', style: `width: ${(100 / years.length)}%`, 'data-year': year },
+ div(
+ { class: 'header-wrapper' },
+ div(
+ { class: 'quarter-header' },
+ div({ class: 'quarter' }, `Q1 ${year}`),
+ div({ class: 'quarter' }, `Q2 ${year}`),
+ div({ class: 'quarter' }, `Q3 ${year}`),
+ div({ class: 'quarter' }, `Q4 ${year}`),
+ ),
+ ),
+ div(
+ { class: 'month-wrapper', 'data-year': year },
+ div({ class: 'month', 'data-num': '1'},
+ div({ class: 'label' }, 'Jan'),
+ ),
+ div({ class: 'month', 'data-num': '2'},
+ div({ class: 'label' }, 'Feb'),
+ ),
+ div({ class: 'month', 'data-num': '3'},
+ div({ class: 'label' }, 'Mar'),
+ ),
+ div({ class: 'month', 'data-num': '4'},
+ div({ class: 'label' }, 'Apr'),
+ ),
+ div({ class: 'month', 'data-num': '5'},
+ div({ class: 'label' }, 'May'),
+ ),
+ div({ class: 'month', 'data-num': '6'},
+ div({ class: 'label' }, 'Jun'),
+ ),
+ div({ class: 'month', 'data-num': '7'},
+ div({ class: 'label' }, 'Jul'),
+ ),
+ div({ class: 'month', 'data-num': '8'},
+ div({ class: 'label' }, 'Aug'),
+ ),
+ div({ class: 'month', 'data-num': '9'},
+ div({ class: 'label' }, 'Sep'),
+ ),
+ div({ class: 'month', 'data-num': '10'},
+ div({ class: 'label' }, 'Oct'),
+ ),
+ div({ class: 'month', 'data-num': '11'},
+ div({ class: 'label' }, 'Nov'),
+ ),
+ div({ class: 'month', 'data-num': '12'},
+ div({ class: 'label' }, 'Dec'),
+ ),
+ )
+ );
backgroundEl.appendChild(yearWrapper);
});
calendarEl.appendChild(backgroundEl);
@@ -1708,50 +1727,64 @@ function buildYearCal(years) {
function buildQuarterCal(years) {
- const calendarEl = document.createElement('div');
- calendarEl.classList.add('calendar-wrapper', 'quarter-view');
+ const calendarEl = div({ class: 'calendar-wrapper quarter-view' });
if (years.length > 1) calendarEl.classList.add('multiyear');
- const backgroundEl = document.createElement('div');
- backgroundEl.classList.add('calendar-background');
+
// this is wider for 'quarter' view- see equivalent in 'year' view.
- backgroundEl.style.width = (years.length * 300) + '%';
+ const backgroundEl = div({ class: 'calendar-background', style: `width: ${(years.length * 300)}%`});
years.forEach((year) => {
- const yearWrapper = document.createElement('div');
- yearWrapper.dataset.year = year;
- yearWrapper.classList.add('year-wrapper');
- yearWrapper.style.width = (100 / years.length) + '%';
- const calendarHeader = document.createElement('div');
- calendarHeader.classList.add('header-wrapper');
- const quartersHeader = document.createElement('div');
- quartersHeader.classList.add('quarter-header');
- quartersHeader.innerHTML = `
-
Fiscal Q1 ${year}
-
Fiscal Q2 ${year}
-
Fiscal Q3 ${year}
-
Fiscal Q4 ${year}
- `;
- calendarHeader.appendChild(quartersHeader);
-
- const monthsWrapper = document.createElement('div');
- monthsWrapper.classList.add('month-wrapper');
- monthsWrapper.dataset.year = year;
- monthsWrapper.innerHTML = `
-
-
-
-
-
-
-
-
-
-
-
-
- `;
- yearWrapper.appendChild(calendarHeader);
- yearWrapper.appendChild(monthsWrapper);
+ const yearWrapper = div(
+ { class: 'year-wrapper', style: `width: ${(100 / years.length)}%`, 'data-year': year },
+ div(
+ { class: 'header-wrapper' },
+ div(
+ { class: 'quarter-header' },
+ div({ class: 'quarter' }, `Fiscal Q1 ${year}`),
+ div({ class: 'quarter' }, `Fiscal Q2 ${year}`),
+ div({ class: 'quarter' }, `Fiscal Q3 ${year}`),
+ div({ class: 'quarter' }, `Fiscal Q4 ${year}`),
+ ),
+ ),
+ div({ class: 'month-wrapper', 'data-year': year },
+ div({ class: 'month', 'data-num': '12'},
+ div({ class: 'label' }, 'Dec Q1'),
+ ),
+ div({ class: 'month', 'data-num': '1'},
+ div({ class: 'label' }, 'Jan Q1'),
+ ),
+ div({ class: 'month', 'data-num': '2'},
+ div({ class: 'label' }, 'Feb Q1'),
+ ),
+ div({ class: 'month', 'data-num': '3'},
+ div({ class: 'label' }, 'Mar Q2'),
+ ),
+ div({ class: 'month', 'data-num': '4'},
+ div({ class: 'label' }, 'Apr Q2'),
+ ),
+ div({ class: 'month', 'data-num': '5'},
+ div({ class: 'label' }, 'May Q2'),
+ ),
+ div({ class: 'month', 'data-num': '6'},
+ div({ class: 'label' }, 'Jun Q3'),
+ ),
+ div({ class: 'month', 'data-num': '7'},
+ div({ class: 'label' }, 'Jul Q3'),
+ ),
+ div({ class: 'month', 'data-num': '8'},
+ div({ class: 'label' }, 'Aug Q3'),
+ ),
+ div({ class: 'month', 'data-num': '9'},
+ div({ class: 'label' }, 'Sep Q4'),
+ ),
+ div({ class: 'month', 'data-num': '10'},
+ div({ class: 'label' }, 'Oct Q4'),
+ ),
+ div({ class: 'month', 'data-num': '11'},
+ div({ class: 'label' }, 'Nov Q4'),
+ ),
+ )
+ );
backgroundEl.appendChild(yearWrapper);
});
calendarEl.appendChild(backgroundEl);
@@ -1811,4 +1844,4 @@ function calculateScroll(type, viewStartYear, displayYear, displayQuarter, numYe
function isValidDate(dateObj) {
return dateObj instanceof Date && !isNaN(dateObj);
-}
+}
\ No newline at end of file