Skip to content

[copilot] Front end build for new topic discovery component#13927

Open
Nabeel1276 wants to merge 23 commits intolatestfrom
WS-2397-front-end-build-for-new-topic-discovery-component
Open

[copilot] Front end build for new topic discovery component#13927
Nabeel1276 wants to merge 23 commits intolatestfrom
WS-2397-front-end-build-for-new-topic-discovery-component

Conversation

@Nabeel1276
Copy link
Copy Markdown
Contributor

Resolves JIRA: https://bbc.atlassian.net/browse/WS-2397

Summary

A very high-level summary of easily-reproducible changes that can be understood by non-devs, and why these changes where made.

Code changes

  • List key code changes that have been made.

Testing

  1. List the steps required to test this PR.

Useful Links

Copilot AI review requested due to automatic review settings April 17, 2026 14:02
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new TopicDiscovery UI component to render topic-based related content using a tabbed interface, reusing existing curation promo/grid building blocks in Simorgh.

Changes:

  • Introduces TopicDiscovery component, styles, and data/types to render a tabbed related-content section.
  • Adds a ScrollableTabs subcomponent for horizontally scrollable, keyboard-navigable tabs with scroll controls.
  • Adds Storybook stories and fixtures for local development/visual testing.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/app/components/TopicDiscovery/types.ts Adds TypeScript types for topic discovery payloads.
src/app/components/TopicDiscovery/index.tsx Implements the main TopicDiscovery section, tab state, and mapping items to curation summaries.
src/app/components/TopicDiscovery/index.styles.ts Emotion styles for the TopicDiscovery section layout.
src/app/components/TopicDiscovery/index.stories.tsx Storybook stories for default, single-topic, and empty states.
src/app/components/TopicDiscovery/fixtures.ts Fixture data for Storybook/dev testing.
src/app/components/TopicDiscovery/ScrollableTabs/index.tsx Implements scrollable tab UI with overflow detection and keyboard interaction.
src/app/components/TopicDiscovery/ScrollableTabs/index.styles.ts Emotion styles for ScrollableTabs and scroll buttons.

Comment on lines +23 to +26
title: item.title,
link: item.link,
imageUrl: item.imageUrl.replace('{width}', String(DEFAULT_IMAGE_WIDTH)),
imageAlt: item.imageAlt,
Comment on lines +28 to +34
mediaType: item.type === 'article' ? undefined : item.type,
description: item.description,
firstPublished: item.firstPublished,
lastPublished: item.lastPublished,
isLive: item.isLive,
duration: item.duration,
isPortraitImage: item.isPortraitImage,
});
};

const handleKeyDown = (event: React.KeyboardEvent) => {
Comment on lines +142 to +152
<button
type="button"
css={styles.scrollButton}
onClick={() => scroll('end')}
disabled={!canScrollEnd}
aria-hidden="true"
tabIndex={-1}
data-testid="scroll-end"
>
<Chevron orientation={ChevronOrientation.FORWARD} dir={dir} />
</button>
Comment on lines +41 to +51
const validTopics = topicDiscovery.topics.filter(
topic => topic.items && topic.items.length > 0,
);

const [activeTabId, setActiveTabId] = useState(validTopics[0]?.topicId ?? '');

if (validTopics.length === 0) return null;

const activeTopic = validTopics.find(topic => topic.topicId === activeTabId);

if (!activeTopic) return null;
Comment on lines +37 to +84
const TopicDiscovery = ({
topicDiscovery,
headingText,
}: TopicDiscoveryProps) => {
const validTopics = topicDiscovery.topics.filter(
topic => topic.items && topic.items.length > 0,
);

const [activeTabId, setActiveTabId] = useState(validTopics[0]?.topicId ?? '');

if (validTopics.length === 0) return null;

const activeTopic = validTopics.find(topic => topic.topicId === activeTabId);

if (!activeTopic) return null;

const tabs = validTopics.map(topic => ({
id: topic.topicId,
label: topic.topicName,
}));

const summaries = activeTopic.items.map(mapItemToSummary);

return (
<section css={styles.section} data-testid="topic-discovery">
<h2 id={HEADING_ID} css={styles.heading}>
{headingText}
</h2>
<ScrollableTabs
tabs={tabs}
activeTabId={activeTabId}
onTabChange={setActiveTabId}
labelledBy={HEADING_ID}
/>
<div
role="tabpanel"
id={`tabpanel-${activeTabId}`}
aria-labelledby={`tab-${activeTabId}`}
css={styles.tabPanel}
>
<CurationGrid
summaries={summaries}
eventTrackingData={eventTrackingData}
/>
</div>
</section>
);
};
Comment on lines +101 to +110
<button
type="button"
css={styles.scrollButton}
onClick={() => scroll('start')}
disabled={!canScrollStart}
aria-hidden="true"
tabIndex={-1}
data-testid="scroll-start"
>
<Chevron orientation={ChevronOrientation.BACKWARD} dir={dir} />
aria-labelledby={labelledBy}
css={styles.tabList}
onKeyDown={handleKeyDown}
tabIndex={0}
Comment on lines +128 to +133
id={`tab-${tab.id}`}
data-tab-id={tab.id}
aria-selected={isActive}
aria-controls={`tabpanel-${tab.id}`}
tabIndex={isActive ? 0 : -1}
css={[styles.tab, isActive && styles.tabActive]}
@Nabeel1276 Nabeel1276 self-assigned this Apr 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants