From 99e53f4d2981a04d9fa9d3c214c2600b97acf99f Mon Sep 17 00:00:00 2001 From: Svetlana Kazarian Date: Fri, 28 Aug 2026 15:24:58 -0500 Subject: [PATCH] [MWPW-205908] Add empty states and fix count visibility for speakers/products --- .../event-featured-products.js | 12 +++++++--- .../blocks/event-speakers/event-speakers.css | 6 +++++ .../blocks/event-speakers/event-speakers.js | 13 ++++++++--- .../event-featured-products.test.js | 22 +++++++++++++++--- .../event-speakers/event-speakers.test.js | 23 ++++++++++++++++--- 5 files changed, 64 insertions(+), 12 deletions(-) diff --git a/event-libs/v1/c2/blocks/event-featured-products/event-featured-products.js b/event-libs/v1/c2/blocks/event-featured-products/event-featured-products.js index a4512de9..df338c54 100644 --- a/event-libs/v1/c2/blocks/event-featured-products/event-featured-products.js +++ b/event-libs/v1/c2/blocks/event-featured-products/event-featured-products.js @@ -32,10 +32,16 @@ export default async function init(el) { const products = getAttrValues('Product').map((v) => v.label).filter(Boolean); el.replaceChildren(); if (background) el.style.background = background; - if (!products.length) return; + if (!products.length) { + el.remove(); + return; + } - const title = createTag('h2', { class: 'featured-products-title' }, 'Featured products '); - title.append(createTag('span', { class: 'featured-products-count' }, `(${products.length})`)); + const showCount = products.length > VISIBLE_LIMIT; + const title = createTag('h2', { class: 'featured-products-title' }, showCount ? 'Featured products ' : 'Featured products'); + if (showCount) { + title.append(createTag('span', { class: 'featured-products-count' }, `(${products.length})`)); + } el.append(title); const list = createTag('ul', { class: 'featured-products-list' }); diff --git a/event-libs/v1/c2/blocks/event-speakers/event-speakers.css b/event-libs/v1/c2/blocks/event-speakers/event-speakers.css index 04d340ad..0b99b2b8 100644 --- a/event-libs/v1/c2/blocks/event-speakers/event-speakers.css +++ b/event-libs/v1/c2/blocks/event-speakers/event-speakers.css @@ -22,6 +22,12 @@ font-weight: 400; } +.speakers-empty { + margin: 0; + color: var(--s2a-color-gray-1000, #000); + font-size: var(--s2a-font-size-16, 1rem); +} + .speakers-list { display: flex; flex-direction: column; diff --git a/event-libs/v1/c2/blocks/event-speakers/event-speakers.js b/event-libs/v1/c2/blocks/event-speakers/event-speakers.js index 255fe275..c21f4385 100644 --- a/event-libs/v1/c2/blocks/event-speakers/event-speakers.js +++ b/event-libs/v1/c2/blocks/event-speakers/event-speakers.js @@ -37,10 +37,17 @@ export default async function init(el) { const speakers = getJsonMetadata('speakers', []); el.replaceChildren(); if (background) el.style.background = background; - if (!Array.isArray(speakers) || !speakers.length) return; + if (!Array.isArray(speakers) || !speakers.length) { + el.append(createTag('h2', { class: 'speakers-title' }, 'Speakers')); + el.append(createTag('p', { class: 'speakers-empty' }, 'No speakers available for this session')); + return; + } - const title = createTag('h2', { class: 'speakers-title' }, 'Speakers '); - title.append(createTag('span', { class: 'speakers-count' }, `(${speakers.length})`)); + const showCount = speakers.length > VISIBLE_LIMIT; + const title = createTag('h2', { class: 'speakers-title' }, showCount ? 'Speakers ' : 'Speakers'); + if (showCount) { + title.append(createTag('span', { class: 'speakers-count' }, `(${speakers.length})`)); + } el.append(title); const list = createTag('ul', { class: 'speakers-list' }); diff --git a/test/unit/c2/blocks/event-featured-products/event-featured-products.test.js b/test/unit/c2/blocks/event-featured-products/event-featured-products.test.js index cb64de30..4f0a9c05 100644 --- a/test/unit/c2/blocks/event-featured-products/event-featured-products.test.js +++ b/test/unit/c2/blocks/event-featured-products/event-featured-products.test.js @@ -52,7 +52,7 @@ describe('Featured Products', () => { setProducts(['Photoshop', 'Illustrator', 'Fresco']); const el = block(); await init(el); - expect(el.querySelector('.featured-products-title').textContent).to.equal('Featured products (3)'); + expect(el.querySelector('.featured-products-title').textContent).to.equal('Featured products'); const names = [...el.querySelectorAll('.featured-product-name')].map((n) => n.textContent); expect(names).to.deep.equal(['Photoshop', 'Illustrator', 'Fresco']); }); @@ -101,11 +101,27 @@ describe('Featured Products', () => { expect(toggle.textContent).to.equal('Show less'); }); - it('renders nothing when there are no products', async () => { + it('omits the count at the visible limit and shows it just above', async () => { + let el = block(); + setProducts(Array.from({ length: 6 }, (_, i) => `Product ${i}`)); + await init(el); + expect(el.querySelector('.featured-products-title').textContent).to.equal('Featured products'); + expect(el.querySelector('.featured-products-count')).to.be.null; + + el = block(); + setProducts(Array.from({ length: 7 }, (_, i) => `Product ${i}`)); + await init(el); + expect(el.querySelector('.featured-products-count').textContent).to.equal('(7)'); + }); + + it('removes the block entirely when there are no products', async () => { setProducts([]); const el = block(); + const parent = document.createElement('div'); + parent.append(el); await init(el); - expect(el.children).to.have.lengthOf(0); + expect(el.parentNode).to.be.null; + expect(parent.children).to.have.lengthOf(0); }); it('applies an authored Background row as the block background and removes the row', async () => { diff --git a/test/unit/c2/blocks/event-speakers/event-speakers.test.js b/test/unit/c2/blocks/event-speakers/event-speakers.test.js index efae8863..dab65f43 100644 --- a/test/unit/c2/blocks/event-speakers/event-speakers.test.js +++ b/test/unit/c2/blocks/event-speakers/event-speakers.test.js @@ -34,7 +34,7 @@ describe('Speakers', () => { ]); const el = block(); await init(el); - expect(el.querySelector('.speakers-title').textContent).to.equal('Speakers (2)'); + expect(el.querySelector('.speakers-title').textContent).to.equal('Speakers'); const rows = [...el.querySelectorAll('.speaker')]; expect(rows).to.have.lengthOf(2); expect(rows[0].querySelector('.speaker-name').textContent).to.equal('Shantanu Narayen'); @@ -79,12 +79,29 @@ describe('Speakers', () => { expect(el.classList.contains('is-expanded')).to.be.true; expect(toggle.textContent).to.equal('Show less'); }); + + it('omits the count at the visible limit and shows it just above', async () => { + const atLimit = Array.from({ length: 5 }, (_, i) => ({ firstName: 'S', lastName: `${i}` })); + let el = block(); + setSpeakers(atLimit); + await init(el); + expect(el.querySelector('.speakers-title').textContent).to.equal('Speakers'); + expect(el.querySelector('.speakers-count')).to.be.null; + + const overLimit = Array.from({ length: 6 }, (_, i) => ({ firstName: 'S', lastName: `${i}` })); + el = block(); + setSpeakers(overLimit); + await init(el); + expect(el.querySelector('.speakers-count').textContent).to.equal('(6)'); + }); - it('renders nothing when there are no speakers', async () => { + it('renders an empty state when there are no speakers', async () => { setSpeakers([]); const el = block(); await init(el); - expect(el.children).to.have.lengthOf(0); + expect(el.querySelector('.speakers-title').textContent).to.equal('Speakers'); + expect(el.querySelector('.speakers-empty').textContent).to.equal('No speakers available for this session'); + expect(el.children).to.have.lengthOf(2); }); it('applies an authored Background row as the block background', async () => {