Skip to content

Commit 5705de3

Browse files
authored
feat: add /highlights page with channel navigation (#5857)
1 parent cc57247 commit 5705de3

23 files changed

Lines changed: 931 additions & 1620 deletions

packages/shared/src/components/Feed.spec.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ describe('Feed logged in', () => {
428428
await waitForNock();
429429
expect(await screen.findByText('Happening Now')).toBeInTheDocument();
430430
expect(screen.getByText('The first highlight')).toBeInTheDocument();
431-
expect(screen.getByLabelText('Read all highlights')).toBeInTheDocument();
431+
expect(screen.getByText('Read all')).toBeInTheDocument();
432432
});
433433

434434
it('should keep feedV2 highlights in the response order', async () => {

packages/shared/src/components/FeedItemComponent.tsx

Lines changed: 37 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { ReactElement } from 'react';
22
import React from 'react';
3-
import { useQueryClient } from '@tanstack/react-query';
43
import type { AdSquadItem, FeedItem } from '../hooks/useFeed';
54
import { isBoostedPostAd, isBoostedSquadAd } from '../hooks/useFeed';
65
import { PlaceholderGrid } from './cards/placeholder/PlaceholderGrid';
@@ -56,13 +55,7 @@ import { OtherFeedPage } from '../lib/query';
5655
import { isSourceSquadOrMachine } from '../graphql/sources';
5756
import { HighlightGrid } from './cards/highlight/HighlightGrid';
5857
import { HighlightList } from './cards/highlight/HighlightList';
59-
import {
60-
getHighlightIdsKey,
61-
getHighlightIds,
62-
MAJOR_HEADLINES_MAX_FIRST,
63-
majorHeadlinesQueryOptions,
64-
} from '../graphql/highlights';
65-
import { HighlightPostModal } from './modals/HighlightPostModal';
58+
import { getHighlightIds, getHighlightIdsKey } from '../graphql/highlights';
6659

6760
export type FeedItemComponentProps = {
6861
item: FeedItem;
@@ -271,10 +264,6 @@ function FeedItemComponent({
271264
disableAdRefresh,
272265
}: FeedItemComponentProps): ReactElement | null {
273266
const { logEvent } = useLogContext();
274-
const queryClient = useQueryClient();
275-
const [selectedHighlightId, setSelectedHighlightId] = React.useState<
276-
string | null
277-
>(null);
278267
const inViewRef = useLogImpression(
279268
item,
280269
index,
@@ -294,90 +283,44 @@ function FeedItemComponent({
294283
? HighlightList
295284
: HighlightGrid;
296285
const highlightIds = getHighlightIds(item.highlights);
297-
const openHighlightModal = (highlightId: string): void => {
298-
queryClient
299-
.fetchQuery(
300-
majorHeadlinesQueryOptions({ first: MAJOR_HEADLINES_MAX_FIRST }),
301-
)
302-
.catch(() => undefined)
303-
.finally(() => setSelectedHighlightId(highlightId));
304-
};
305286

306287
return (
307-
<>
308-
<HighlightTag
309-
ref={inViewRef}
310-
highlights={item.highlights}
311-
onReadAllClick={() => {
312-
const [firstHighlight] = item.highlights;
313-
314-
if (!firstHighlight) {
315-
return;
316-
}
317-
318-
logEvent(
319-
feedHighlightsLogEvent(LogEvent.Click, {
320-
columns: virtualizedNumCards,
321-
column,
322-
row,
323-
feedName,
324-
ranking,
325-
action: 'read_all_click',
326-
count: item.highlights.length,
327-
highlightIds,
328-
feedMeta: item.feedMeta,
329-
}),
330-
);
331-
332-
openHighlightModal(firstHighlight.id);
333-
}}
334-
onHighlightClick={(highlight, position) => {
335-
logEvent(
336-
feedHighlightsLogEvent(LogEvent.Click, {
337-
columns: virtualizedNumCards,
338-
column,
339-
row,
340-
feedName,
341-
ranking,
342-
action: 'highlight_click',
343-
position,
344-
count: item.highlights.length,
345-
clickedHighlight: highlight,
346-
highlightIds,
347-
feedMeta: item.feedMeta,
348-
}),
349-
);
350-
351-
openHighlightModal(highlight.id);
352-
}}
353-
/>
354-
<HighlightPostModal
355-
isOpen={!!selectedHighlightId}
356-
selectedHighlightId={selectedHighlightId}
357-
highlights={item.highlights}
358-
onRequestClose={() => setSelectedHighlightId(null)}
359-
onHighlightClick={(highlight, position, modalHighlights) => {
360-
logEvent(
361-
feedHighlightsLogEvent(LogEvent.Click, {
362-
columns: virtualizedNumCards,
363-
column,
364-
row,
365-
feedName,
366-
ranking,
367-
action: 'modal_highlight_click',
368-
position,
369-
count: modalHighlights.length,
370-
clickedHighlight: highlight,
371-
highlightIds: getHighlightIds(modalHighlights),
372-
feedMeta: item.feedMeta,
373-
}),
374-
);
375-
}}
376-
onSelectHighlight={(highlight) => {
377-
setSelectedHighlightId(highlight.id);
378-
}}
379-
/>
380-
</>
288+
<HighlightTag
289+
ref={inViewRef}
290+
highlights={item.highlights}
291+
onReadAllClick={() => {
292+
logEvent(
293+
feedHighlightsLogEvent(LogEvent.Click, {
294+
columns: virtualizedNumCards,
295+
column,
296+
row,
297+
feedName,
298+
ranking,
299+
action: 'read_all_click',
300+
count: item.highlights.length,
301+
highlightIds,
302+
feedMeta: item.feedMeta,
303+
}),
304+
);
305+
}}
306+
onHighlightClick={(highlight, position) => {
307+
logEvent(
308+
feedHighlightsLogEvent(LogEvent.Click, {
309+
columns: virtualizedNumCards,
310+
column,
311+
row,
312+
feedName,
313+
ranking,
314+
action: 'highlight_click',
315+
position,
316+
count: item.highlights.length,
317+
clickedHighlight: highlight,
318+
highlightIds,
319+
feedMeta: item.feedMeta,
320+
}),
321+
);
322+
}}
323+
/>
381324
);
382325
}
383326

packages/shared/src/components/cards/highlight/HighlightCards.spec.tsx

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import userEvent from '@testing-library/user-event';
44
import { HighlightGrid } from './HighlightGrid';
55
import { HighlightList } from './HighlightList';
66

7+
jest.mock('../../../lib/constants', () => ({
8+
webappUrl: '/',
9+
}));
10+
711
const highlights = [
812
{
913
id: 'highlight-1',
@@ -28,7 +32,31 @@ const highlights = [
2832
];
2933

3034
describe('Highlight cards', () => {
31-
it('should render the grid card and trigger highlight actions', async () => {
35+
it('should render the grid card with highlight links', () => {
36+
render(<HighlightGrid highlights={highlights} />);
37+
38+
expect(screen.getByText('Happening Now')).toBeInTheDocument();
39+
expect(screen.getByText('The first highlight')).toBeInTheDocument();
40+
expect(screen.getByText('The second highlight')).toBeInTheDocument();
41+
expect(screen.getByText('Read all')).toBeInTheDocument();
42+
expect(
43+
screen.getByRole('link', { name: /the first highlight/i }),
44+
).toHaveAttribute('href', '/highlights?highlight=highlight-1');
45+
expect(screen.getByLabelText('Read all highlights')).toHaveAttribute(
46+
'href',
47+
'/highlights?highlight=highlight-1',
48+
);
49+
});
50+
51+
it('should render the list card with highlight links', () => {
52+
render(<HighlightList highlights={highlights} />);
53+
54+
expect(screen.getByText('The first highlight')).toBeInTheDocument();
55+
expect(screen.getByText('The second highlight')).toBeInTheDocument();
56+
expect(screen.getByText('Read all')).toBeInTheDocument();
57+
});
58+
59+
it('should trigger the highlight callbacks without blocking navigation', async () => {
3260
const onHighlightClick = jest.fn();
3361
const onReadAllClick = jest.fn();
3462

@@ -40,21 +68,12 @@ describe('Highlight cards', () => {
4068
/>,
4169
);
4270

43-
expect(screen.getByText('Happening Now')).toBeInTheDocument();
44-
4571
await userEvent.click(
46-
screen.getByRole('button', { name: /the first highlight/i }),
72+
screen.getByRole('link', { name: /the first highlight/i }),
4773
);
4874
await userEvent.click(screen.getByLabelText('Read all highlights'));
4975

5076
expect(onHighlightClick).toHaveBeenCalledWith(highlights[0], 1);
5177
expect(onReadAllClick).toHaveBeenCalledTimes(1);
5278
});
53-
54-
it('should render the list card', () => {
55-
render(<HighlightList highlights={highlights} />);
56-
57-
expect(screen.getByText('The second highlight')).toBeInTheDocument();
58-
expect(screen.getByLabelText('Read all highlights')).toBeInTheDocument();
59-
});
6079
});

packages/shared/src/components/cards/highlight/HighlightGrid.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
import type { ReactElement, Ref } from 'react';
22
import React, { forwardRef } from 'react';
3-
import classNames from 'classnames';
43
import { Card } from '../common/Card';
54
import type { HighlightCardProps } from './common';
6-
import {
7-
getHighlightCardContainerHandlers,
8-
HighlightCardContent,
9-
} from './common';
5+
import { HighlightCardContent } from './common';
106

117
export const HighlightGrid = forwardRef(function HighlightGrid(
128
{ highlights, onHighlightClick, onReadAllClick }: HighlightCardProps,
@@ -16,14 +12,7 @@ export const HighlightGrid = forwardRef(function HighlightGrid(
1612
<Card
1713
ref={ref}
1814
data-testid="highlightItem"
19-
role={onReadAllClick ? 'button' : undefined}
20-
tabIndex={onReadAllClick ? 0 : undefined}
21-
aria-label={onReadAllClick ? 'Open highlights card' : undefined}
22-
{...getHighlightCardContainerHandlers(onReadAllClick)}
23-
className={classNames(
24-
'group flex h-full flex-col overflow-hidden !bg-surface-float hover:!bg-surface-float',
25-
onReadAllClick && 'cursor-pointer',
26-
)}
15+
className="group flex h-full flex-col overflow-hidden !bg-surface-float hover:!bg-surface-float"
2716
>
2817
<HighlightCardContent
2918
highlights={highlights}

packages/shared/src/components/cards/highlight/HighlightList.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
import type { ReactElement, Ref } from 'react';
22
import React, { forwardRef } from 'react';
3-
import classNames from 'classnames';
43
import { ListCard } from '../common/list/ListCard';
54
import type { HighlightCardProps } from './common';
6-
import {
7-
getHighlightCardContainerHandlers,
8-
HighlightCardContent,
9-
} from './common';
5+
import { HighlightCardContent } from './common';
106

117
export const HighlightList = forwardRef(function HighlightList(
128
{ highlights, onHighlightClick, onReadAllClick }: HighlightCardProps,
@@ -16,14 +12,7 @@ export const HighlightList = forwardRef(function HighlightList(
1612
<ListCard
1713
ref={ref}
1814
data-testid="highlightItem"
19-
role={onReadAllClick ? 'button' : undefined}
20-
tabIndex={onReadAllClick ? 0 : undefined}
21-
aria-label={onReadAllClick ? 'Open highlights card' : undefined}
22-
{...getHighlightCardContainerHandlers(onReadAllClick)}
23-
className={classNames(
24-
'group overflow-hidden !border-0 !border-t !border-border-subtlest-tertiary !bg-gradient-to-b !from-surface-float !to-background-default !px-4 !py-6',
25-
onReadAllClick && 'cursor-pointer',
26-
)}
15+
className="group overflow-hidden !border-0 !border-t !border-border-subtlest-tertiary !bg-gradient-to-b !from-surface-float !to-background-default !px-4 !py-6"
2716
>
2817
<HighlightCardContent
2918
highlights={highlights}

0 commit comments

Comments
 (0)