diff --git a/blocks/events/events.css b/blocks/events/events.css
new file mode 100644
index 0000000..b30da2d
--- /dev/null
+++ b/blocks/events/events.css
@@ -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);
+}
\ No newline at end of file
diff --git a/blocks/events/events.js b/blocks/events/events.js
new file mode 100644
index 0000000..875eee4
--- /dev/null
+++ b/blocks/events/events.js
@@ -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);
+ }
+}
diff --git a/head.html b/head.html
index 01ba501..3b7b98f 100644
--- a/head.html
+++ b/head.html
@@ -8,3 +8,4 @@
+
diff --git a/scripts/dom-builder.js b/scripts/dom-builder.js
index 4253cef..da06b26 100644
--- a/scripts/dom-builder.js
+++ b/scripts/dom-builder.js
@@ -86,3 +86,9 @@ export function tr(...items) { return domEl('tr', ...items); }
export function td(...items) { return domEl('td', ...items); }
export function th(...items) { return domEl('th', ...items); }
export function time(...items) { return domEl('time', ...items); }
+
+export function checkbox(attributes, labelContent) {
+ const checkboxInput = input({ type: 'checkbox', ...attributes });
+ const labelElement = label(labelContent, checkboxInput);
+ return div(labelElement);
+}
diff --git a/scripts/scripts.js b/scripts/scripts.js
index b35546e..58c29f2 100644
--- a/scripts/scripts.js
+++ b/scripts/scripts.js
@@ -340,6 +340,22 @@ function correctUTMFlow() {
}
}
+export function formatDateRange(startdate, enddate) {
+ const options = { month: 'short', day: '2-digit', year: 'numeric' };
+ const formattedStartDate = new Date(Number(startdate) * 1000).toLocaleDateString('en-us', options);
+ const formattedEndDate = new Date(Number(enddate) * 1000).toLocaleDateString('en-us', options);
+ const startYear = new Date(formattedStartDate).getFullYear();
+ const endYear = new Date(formattedEndDate).getFullYear();
+ const differentYear = startYear !== endYear;
+ let dateRangeString;
+ if (differentYear) {
+ dateRangeString = `${formattedStartDate} - ${formattedEndDate}`;
+ } else {
+ dateRangeString = `${(formattedStartDate).split(',')[0]} - ${formattedEndDate}`;
+ }
+ return dateRangeString;
+}
+
async function loadPage() {
await loadEager(document);
await loadLazy(document);
diff --git a/styles/list.css b/styles/list.css
new file mode 100644
index 0000000..4bd9744
--- /dev/null
+++ b/styles/list.css
@@ -0,0 +1,258 @@
+.list {
+ padding-top: 67px;
+}
+
+.list > * {
+ font-size: 18px;
+ text-align: left;
+}
+
+.list .event-title {
+ font-size: 36px;
+ padding-top: 6px;
+ margin-top: 0;
+ line-height: 0.8;
+ border-bottom: 2px solid #ccc;
+}
+
+/* panel */
+.list > .filter > .panel-title {
+ font-size: 20px;
+ font-weight: bold;
+ margin: 0;
+ padding: 8px 0 22px;
+ border-bottom: 2px solid #ccc;
+}
+
+/* filters */
+.list > .filter > .select {
+ border-bottom: 2px solid #ccc;
+ padding: 10px 0 16px;
+}
+
+.list > .filter > .select > .dropdown-toggle {
+ cursor: pointer;
+ position: relative;
+ padding: 15px 35px 16px 1px;
+ text-align: left;
+ font-weight: bold;
+ height: 56px;
+ width: 100%;
+ max-width: unset;
+ background: none;
+ color: unset;
+ transition-duration: 0.3s;
+}
+
+.list > .filter > .select.open > .dropdown-toggle,
+.list > .filter > .select > .dropdown-toggle:hover {
+ color: #adb3b7;
+}
+
+
+.list > .filter > .select > .dropdown-menu > p > a {
+ color: unset;
+ text-decoration: none;
+}
+
+.list > .filter > p > a {
+ font-weight: bold;
+}
+
+.list > .filter > p > a:hover {
+ text-decoration: none;
+}
+
+/* entries */
+.list > .items > .item {
+ height: auto;
+ max-width: 100%;
+ border-bottom: 2px solid #ccc;
+ padding: 37px 0 40px;
+}
+
+.list > .items > .item:last-of-type {
+ padding-bottom: 22px;
+}
+
+.list > .items > .item > .content,
+.list > .items > .item > .image {
+ width: 100%;
+ height: auto;
+}
+
+.list > .items > .item > .content {
+ padding-left: 30px;
+}
+
+.list > .items > .item > .content > p > .title {
+ font-size: 20px;
+ font-weight: bold;
+ line-height: 1.1;
+ margin-top: 15px;
+ margin-bottom:12px;
+ color: unset;
+ text-decoration: none;
+}
+
+ul.keyword-list {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+
+ul li {
+ padding: 0 !important;
+}
+
+ul.keyword-list li {
+ display: inline-block;
+ margin-right: 10px;
+ position: relative;
+ font-size: 18px;
+ vertical-align: middle;
+}
+
+ul.keyword-list li:not(:last-of-type)::after {
+ content: '|';
+ display: inline-block;
+ margin-left: 10px;
+}
+
+
+.list > .items > .item > .content > .cite {
+ padding: 0 !important;
+ font-size: 14px;
+ font-style: normal;
+ font-weight: 600;
+ color: #333;
+}
+
+.list > .items > .item > .image {
+ padding-right: 15px;
+}
+
+.list > .items > .item > .image img {
+ max-width: 100%;
+ height: 100%;
+ vertical-align: middle;
+ border: 0;
+ aspect-ratio: 16 / 16;
+}
+
+/* Styles for pagination */
+.list > .pagination {
+flex: 100%;
+margin-top: 30px;
+text-align: center;
+}
+
+.list > .pagination button {
+padding: 5px 10px;
+margin: 0 3px;
+background-color: #fff;
+color: black;
+border: none;
+cursor: pointer;
+}
+
+.list > .pagination button:hover {
+background-color: #fff;
+}
+
+.list > .pagination > .pager-item.active {
+border: 2px solid #007bff;
+color: #007bff;
+background-color: #fff;
+
+}
+
+.list > .pagination > .pager-item:disabled {
+opacity: 0.5;
+cursor: not-allowed;
+}
+
+@media (max-width: 991px) {
+ .main.section.events-container {
+ padding-top: 20px;
+ padding-bottom: 20px;
+ }
+}
+
+@media only screen and (max-width: 767px) {
+ .list > .items > .item > .content {
+ margin-top: 15px;
+ }
+
+ .list > .items > .item > .image {
+ padding-left: 15px;
+ }
+}
+
+@media (min-width: 769px) {
+ .list {
+ display: flex;
+ flex-flow: wrap;
+ flex-direction: row;
+ }
+
+ .list > .items > .item {
+ display: flex;
+ flex-direction: row;
+ padding: 37px 0 20px;
+ }
+
+ .list > .items > .item > .content {
+ flex: 66.67%;
+ margin-bottom: 20px;
+ }
+
+ .list > .items > .item > .content > .cite {
+ margin-top: 1px;
+ }
+
+ .list > .items > .item > .image {
+ flex: 40%;
+ margin-bottom: 20px;
+ }
+
+ .list > .filter {
+ width: 100%;
+ }
+
+ .list > .filter > .select {
+ max-width: 259px;
+ }
+}
+
+@media (min-width: 992px) {
+ .list > .filter {
+ width: 25%;
+ padding-right: 15px;
+ }
+
+ .list > .items {
+ width: 75%;
+ }
+
+ .list > .items > .item {
+ margin-left: 6px;
+ }
+
+ .list > .items > .item:first-of-type {
+ padding-top: 20px;
+ }
+
+ .list > .items > .item > .content {
+ width: 66.67%;
+ padding-left: 15px;
+ }
+
+ .list > .items > .item > image {
+ width: 33.33%;
+ }
+
+ .list > .filter > .panel-title {
+ max-width: 259px;
+ }
+}