generated from adobe/aem-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #305 from hlxsites/feature/event-page-implementation
Feature/event page implementation
- Loading branch information
Showing
6 changed files
with
648 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
* { | ||
box-sizing: border-box; | ||
} | ||
|
||
main .section > div { | ||
margin: 0 auto; | ||
padding: 0 15px; | ||
} | ||
|
||
.section.events-container .events-wrapper { | ||
padding-top: 0; | ||
} | ||
|
||
.events .list .filter .select .dropdown-menu.open { | ||
max-height: initial; | ||
} | ||
|
||
.events .list .filter .select.open .dropdown-toggle, | ||
.events .list .filter .select .dropdown-toggle:hover { | ||
color: inherit; | ||
} | ||
|
||
.events label { | ||
display: block; | ||
padding: 0 0 0 37px; | ||
margin: 0 0 20px; | ||
position: relative; | ||
cursor: pointer; | ||
} | ||
|
||
.events input[type="checkbox"].filter-item { | ||
display: none; | ||
} | ||
|
||
.events label span::before { | ||
content: ""; | ||
width: 18px; | ||
height: 18px; | ||
position: absolute; | ||
left: 9px; | ||
background: none; | ||
border: 2px solid #adb3b7; | ||
} | ||
|
||
.events input[type="checkbox"].filter-item:checked+span::before { | ||
background-color: var(--primary-color); | ||
border-color: var(--primary-color); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,319 @@ | ||
import { createOptimizedPicture, capitalizeWords, toClassName } from '../../scripts/aem.js'; | ||
import { | ||
div, a, p, ul, li, article, span, | ||
label, input, h2, | ||
h3, | ||
nav, | ||
button, | ||
} from '../../scripts/dom-builder.js'; | ||
import { formatDateRange } from '../../scripts/scripts.js'; | ||
|
||
const REGIONS = [ | ||
'Europe', | ||
'North America', | ||
]; | ||
|
||
const TYPES = [ | ||
'Conference', | ||
'Events', | ||
'Webinar', | ||
]; | ||
|
||
async function fetchPostData() { | ||
try { | ||
const response = await fetch('/query-index.json'); | ||
const jsonData = await response.json(); | ||
return jsonData.data; | ||
} catch (error) { | ||
return []; | ||
} | ||
} | ||
|
||
let currentPageNumber = 1; | ||
const itemsPerPage = 10; | ||
|
||
// Function to sort events based on their start dates | ||
function sortEventsByDate(events) { | ||
// Sort events based on their start dates | ||
events.sort((dateA, dateB) => { | ||
// Convert start dates to Date objects for comparison | ||
const dateAnew = new Date(dateA.startdate * 1000); | ||
const dateBnew = new Date(dateB.startdate * 1000); | ||
|
||
// Compare dates | ||
if (dateAnew < dateBnew) { | ||
return -1; // dateA comes before dateB | ||
} if (dateAnew > dateBnew) { | ||
return 1; // dateA comes after dateB | ||
} | ||
return 0; // dates are equal | ||
}); | ||
|
||
return events; | ||
} | ||
|
||
// Function to separate events based on current date and class parameter | ||
function separateEventsByDate(events, currentDate, classParameter) { | ||
const futureEvents = []; | ||
const archivedEvents = []; | ||
events.forEach((event) => { | ||
const startDate = new Date(event.startdate * 1000); | ||
const endDate = new Date(event.enddate * 1000); | ||
|
||
if (startDate > currentDate || endDate > currentDate) { | ||
futureEvents.push(event); | ||
} else if (endDate < currentDate) { | ||
archivedEvents.push(event); | ||
} | ||
}); | ||
|
||
return classParameter === 'future' ? futureEvents : archivedEvents; | ||
} | ||
|
||
async function generateEventDetails(articles) { | ||
const articleElements = articles.map((art) => { | ||
let date = ''; | ||
if (art.startdate && art.enddate) { | ||
const endDate = new Date(art.enddate * 1000).toLocaleDateString('en-Us', { month: 'short', day: '2-digit', year: 'numeric' }); | ||
const eventDate = art.startdate === art.enddate | ||
? endDate : formatDateRange(art.startdate, art.enddate); | ||
date = (art.eventtime !== '') ? `${eventDate} ${art.eventtime}` : eventDate; | ||
} | ||
return article( | ||
{ class: 'item' }, | ||
div( | ||
{ class: 'image' }, | ||
a({ | ||
href: art.path, | ||
title: art.title, | ||
}, createOptimizedPicture(art.image, art.title)), | ||
), | ||
div( | ||
{ class: 'content' }, | ||
date ? p({ class: 'cite' }, date) : '', | ||
p( | ||
a({ | ||
class: 'title', | ||
title: art.title, | ||
href: art.path, | ||
}, capitalizeWords(art.title)), | ||
), | ||
ul( | ||
{ class: 'keyword-list' }, | ||
li({ class: 'item' }, art.type), | ||
li({ class: 'item' }, art.address !== art.region ? art.address : art.region), | ||
(art.address !== art.region ? li({ class: 'item' }, art.region) : ''), | ||
), | ||
), | ||
); | ||
}); | ||
return articleElements; | ||
} | ||
|
||
// Function to update the events displayed based on filtering | ||
function updateEvents(events) { | ||
// Clear the existing event list | ||
const itemsContainer = document.querySelector('.items'); | ||
itemsContainer.innerHTML = ''; | ||
|
||
// Generate and append new event details | ||
generateEventDetails(events).then((eventContent) => { | ||
const pageTitle = document.title; | ||
itemsContainer.appendChild(h2({ class: 'event-title' }, pageTitle)); | ||
if (eventContent.length === 0) { | ||
const noEventsMesage = h3({ class: 'no-result' }, 'No Events Found'); | ||
itemsContainer.appendChild(noEventsMesage); | ||
} else { | ||
eventContent.forEach((element) => { | ||
itemsContainer.appendChild(element); | ||
}); | ||
} | ||
}); | ||
} | ||
|
||
// Event listener function to handle checkbox changes | ||
function handleCheckboxChange(event, eventData) { | ||
const checkedCheckboxes = document.querySelectorAll('.filter-item:checked'); | ||
const selectedOptions = Array.from(checkedCheckboxes) | ||
.map((checkbox) => checkbox.nextSibling.textContent); | ||
let filteredEvents; | ||
// Filter events based on selected options | ||
const eventTypes = []; | ||
const regions = []; | ||
|
||
if (selectedOptions.length > 0) { | ||
selectedOptions.forEach((option) => { | ||
if (eventData.some((data) => data.type === option)) { | ||
eventTypes.push(option); | ||
} else if (eventData.some((data) => data.region === option)) { | ||
regions.push(option); | ||
} | ||
}); | ||
|
||
if (eventTypes.length > 0 && regions.length === 0) { | ||
filteredEvents = eventData.filter((data) => eventTypes.includes(data.type)); | ||
} else if (eventTypes.length === 0 && regions.length > 0) { | ||
filteredEvents = eventData.filter((data) => regions.includes(data.region)); | ||
} else { | ||
filteredEvents = eventData.filter((data) => eventTypes | ||
.includes(data.type) && regions.includes(data.region)); | ||
} | ||
} else { | ||
filteredEvents = eventData; | ||
} | ||
updateEvents(filteredEvents); | ||
const paginationContainer = document.querySelector('.pagination'); | ||
if (filteredEvents.length <= itemsPerPage) { | ||
paginationContainer.style.display = 'none'; | ||
} else { | ||
paginationContainer.style.display = 'block'; | ||
} | ||
} | ||
|
||
function createEventsDropdown(eventName, options) { | ||
const container = div({ class: 'select' }); | ||
container.setAttribute('name', eventName); | ||
|
||
const btn = div({ | ||
type: 'button', | ||
class: 'dropdown-toggle', | ||
value: '', | ||
}, eventName); | ||
// btn.addEventListener('click', toggleFilter, false); | ||
container.append(btn); | ||
|
||
const dropDown = div({ class: 'dropdown-menu' }); | ||
options.forEach((option) => { | ||
const fieldName = toClassName(option.toString()); | ||
dropDown.append(label( | ||
{ for: fieldName }, | ||
input({ | ||
type: 'checkbox', | ||
name: fieldName, | ||
id: fieldName, | ||
class: 'filter-item', | ||
}), | ||
span(option), | ||
)); | ||
}); | ||
container.append(dropDown); | ||
|
||
return container; | ||
} | ||
|
||
function createLink(text, currentPage) { | ||
const linkHref = currentPage === 'events' ? '/about-us/archived-events' : '/about-us/events'; | ||
const link = p(a({ href: linkHref, title: text }, text)); | ||
return link; | ||
} | ||
|
||
async function buildSidePanel(currentPage, eventData) { | ||
const sidePanel = div({ class: 'filter' }); | ||
const panelTitle = p({ class: 'panel-title' }, 'Filter By:'); | ||
|
||
// Dropdowns | ||
const eventTypeDropdown = createEventsDropdown('Event Type', TYPES); | ||
const regionDropdown = createEventsDropdown('Region', REGIONS); | ||
|
||
// Append dropdowns to filter div | ||
const linkText = currentPage === 'events' ? 'Archived Events' : 'Upcoming Events'; | ||
const link = createLink(linkText, currentPage); | ||
|
||
// Append filter div to side panel | ||
sidePanel.appendChild(panelTitle); | ||
sidePanel.appendChild(eventTypeDropdown); | ||
sidePanel.appendChild(regionDropdown); | ||
sidePanel.appendChild(link); | ||
|
||
const checkboxes = sidePanel.querySelectorAll('.select .dropdown-menu .filter-item'); | ||
checkboxes.forEach((checkbox) => { | ||
checkbox.addEventListener('change', (event) => { | ||
handleCheckboxChange(event, eventData); | ||
}); | ||
}); | ||
|
||
return sidePanel; | ||
} | ||
|
||
function updatePaginationButtons(currentPage) { | ||
document.querySelectorAll('.pagination .pager-item').forEach((data) => { | ||
data.classList.remove('active'); | ||
if (parseInt(data.textContent, 10) === currentPage) { | ||
data.classList.add('active'); | ||
} | ||
}); | ||
} | ||
|
||
function displayPage(page, events) { | ||
const startIndex = (page - 1) * itemsPerPage; | ||
const endIndex = startIndex + itemsPerPage; | ||
const currentPageEvents = events.slice(startIndex, endIndex); | ||
updateEvents(currentPageEvents); | ||
} | ||
|
||
function handlePagination(page, events) { | ||
currentPageNumber = page; | ||
displayPage(currentPageNumber, events); // Update UI with new page | ||
} | ||
|
||
function generatePaginationButtons(totalPages, currentPage, events) { | ||
const paginationContainer = nav({ class: 'pagination' }); | ||
for (let i = 1; i <= totalPages; i += 1) { | ||
const pageButton = button({ class: 'pager-item' }, i); | ||
if (i === currentPage) { | ||
pageButton.classList.add('active'); | ||
} | ||
pageButton.addEventListener('click', () => { | ||
handlePagination(i, events); | ||
updatePaginationButtons(i); | ||
}); | ||
paginationContainer.appendChild(pageButton); | ||
} | ||
return paginationContainer; | ||
} | ||
|
||
function getTotalPages(events) { | ||
return Math.ceil(events.length / itemsPerPage); | ||
} | ||
|
||
export default async function decorate(block) { | ||
const outerBlock = document.querySelector('.section'); | ||
outerBlock.classList.add('outer'); | ||
const postData = await fetchPostData(); | ||
const page = window.location.pathname.includes('/events'); | ||
const currentPage = page ? 'events' : 'archived-events'; | ||
const filteredResults = postData.filter((item) => /events\/.*$/.test(item.path.toLowerCase())); | ||
const sortedEvents = sortEventsByDate(filteredResults); | ||
const currentDate = new Date(); | ||
const classParameter = document.querySelector('.events.future') ? 'future' : 'archive'; | ||
const eventsToshow = separateEventsByDate(sortedEvents, currentDate, classParameter); | ||
const itemsContainer = div({ class: 'items' }); | ||
|
||
const eventContent = await generateEventDetails(eventsToshow); | ||
const sidePanel = await buildSidePanel(currentPage, eventsToshow); | ||
|
||
const wrapper = div({ class: 'list' }); | ||
const pageTitle = document.title; | ||
const title = h2({ class: 'event-title' }, pageTitle); | ||
itemsContainer.append(title); | ||
wrapper.appendChild(sidePanel); | ||
if (eventContent && eventContent.length > 0) { | ||
eventContent.forEach((element) => { | ||
itemsContainer.appendChild(element); | ||
}); | ||
} else { | ||
const noEventMessage = currentPage === 'events' ? 'No Upcoming Events' : 'No Archived Events'; | ||
const noResults = h3({ class: 'no-result' }, noEventMessage); | ||
itemsContainer.appendChild(noResults); | ||
block.appendChild(itemsContainer); | ||
} | ||
|
||
wrapper.appendChild(itemsContainer); | ||
block.appendChild(wrapper); | ||
if (eventsToshow.length > itemsPerPage) { | ||
const totalPages = getTotalPages(eventsToshow); | ||
wrapper.appendChild(generatePaginationButtons(totalPages, currentPageNumber, eventsToshow)); | ||
|
||
displayPage(currentPageNumber, eventsToshow); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.