diff --git a/packages/shared/src/components/post/focus/CommunitySentimentBreakdown.spec.tsx b/packages/shared/src/components/post/focus/CommunitySentimentBreakdown.spec.tsx index d404e4cddd..c499496d41 100644 --- a/packages/shared/src/components/post/focus/CommunitySentimentBreakdown.spec.tsx +++ b/packages/shared/src/components/post/focus/CommunitySentimentBreakdown.spec.tsx @@ -92,6 +92,54 @@ describe('CommunitySentimentBreakdown', () => { ).toBeInTheDocument(); }); + it('keeps a source row when another thread from the same provider has no comments', () => { + render( + , + ); + + expect(screen.queryByText('Hacker News')).not.toBeInTheDocument(); + expect(screen.getByText('Lobsters')).toBeInTheDocument(); + expect(screen.getByText('Skeptical')).toBeInTheDocument(); + expect(screen.getByText('12 points ยท 5 comments')).toBeInTheDocument(); + }); + it('keeps the source lean when comments are available', () => { render( = { hn: 'hackernews', + newsycombinatorcom: 'hackernews', twitter: 'x', + xcom: 'x', }; const normalizeProvider = (source: string): string => { @@ -48,6 +50,16 @@ const providerLabel = (source: string): string => const formatDiscussionCount = (value: number): string => largeNumberFormat(value)?.toLowerCase() ?? `${value}`; +const normalizeDiscussionUrl = (url: string): string => { + try { + const parsedUrl = new URL(url); + parsedUrl.hash = ''; + return parsedUrl.toString(); + } catch { + return url; + } +}; + const SourceBadge = ({ source, className, @@ -247,17 +259,48 @@ export const CommunitySentimentBreakdown = ({ }): ReactElement => { const { pros, cons, bySource, discussions } = data; - const discussionByProvider = new Map( - discussions?.map((discussion) => [ - normalizeProvider(discussion.provider), - discussion, - ]), - ); - const sourcesWithComments = bySource.filter((item) => { - const discussion = discussionByProvider.get(normalizeProvider(item.source)); - return discussion?.commentsCount !== 0; + const discussionsByProvider = new Map< + string, + CommunitySentimentDiscussion[] + >(); + const discussionsByUrl = new Map(); + + discussions?.forEach((discussion) => { + const provider = normalizeProvider(discussion.provider); + const providerDiscussions = discussionsByProvider.get(provider) ?? []; + providerDiscussions.push(discussion); + discussionsByProvider.set(provider, providerDiscussions); + + const url = normalizeDiscussionUrl(discussion.url); + const urlDiscussions = discussionsByUrl.get(url) ?? []; + urlDiscussions.push(discussion); + discussionsByUrl.set(url, urlDiscussions); }); + const getSourceDiscussions = ( + item: SourceSentiment, + ): CommunitySentimentDiscussion[] => { + const urlDiscussions = item.url + ? discussionsByUrl.get(normalizeDiscussionUrl(item.url)) + : undefined; + + return ( + urlDiscussions ?? + discussionsByProvider.get(normalizeProvider(item.source)) ?? + [] + ); + }; + const sourceRows = bySource + .map((item) => { + const sourceDiscussions = getSourceDiscussions(item); + const discussion = + sourceDiscussions.find(({ commentsCount }) => commentsCount > 0) ?? + sourceDiscussions[0]; + + return { item, discussion }; + }) + .filter(({ discussion }) => discussion?.commentsCount !== 0); + return (
{(pros.length > 0 || cons.length > 0) && ( @@ -271,17 +314,15 @@ export const CommunitySentimentBreakdown = ({
)} - {sourcesWithComments.length > 0 && ( + {sourceRows.length > 0 && (
By community
- {sourcesWithComments.map((item) => ( + {sourceRows.map(({ item, discussion }) => ( ))}