Skip to content

Commit dab62ef

Browse files
ahtesham-quraishAhtesham Quraish
andauthored
fix: improvements article listing page and home page (#2963)
* fix: improvements article listing page and home page --------- Co-authored-by: Ahtesham Quraish <ahtesham.quraish@A006-01455.local>
1 parent d61cfda commit dab62ef

18 files changed

Lines changed: 201 additions & 66 deletions

File tree

articles/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def get_url(self):
5959
Return the relative URL for this article.
6060
"""
6161
if self.slug:
62-
return f"/articles/{self.slug}"
62+
return f"/news/{self.slug}"
6363
return None
6464

6565

articles/models_test.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def test_get_url_with_slug(self, _mock_queue_purge, _mock_queue_list): # noqa:
2626
user=user,
2727
)
2828

29-
assert article.get_url() == f"/articles/{article.slug}"
29+
assert article.get_url() == f"/news/{article.slug}"
3030

3131
def test_get_url_without_slug(self, _mock_queue_purge, _mock_queue_list): # noqa: PT019
3232
"""Test that get_url returns None for an article without a slug"""
@@ -56,8 +56,8 @@ def test_get_url_with_different_slugs(self, _mock_queue_purge, _mock_queue_list)
5656
user=user,
5757
)
5858

59-
assert article1.get_url() == f"/articles/{article1.slug}"
60-
assert article2.get_url() == f"/articles/{article2.slug}"
59+
assert article1.get_url() == f"/news/{article1.slug}"
60+
assert article2.get_url() == f"/news/{article2.slug}"
6161
assert article1.get_url() != article2.get_url()
6262

6363
def test_slug_generation_on_publish(self, _mock_queue_purge, _mock_queue_list): # noqa: PT019
@@ -80,4 +80,4 @@ def test_slug_generation_on_publish(self, _mock_queue_purge, _mock_queue_list):
8080
# Now should have a slug
8181
assert article.slug is not None
8282
assert article.slug == "test-article-title"
83-
assert article.get_url() == "/articles/test-article-title"
83+
assert article.get_url() == "/news/test-article-title"

articles/tasks.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ def queue_fastly_purge_articles_list():
7272
log.info("Purging articles list page from the Fastly cache...")
7373

7474
# Purge the articles API endpoint
75-
articles_url = "/articles"
75+
articles_url = "/news"
7676

7777
resp = call_fastly_purge_api(articles_url)
7878

articles/tasks_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def test_call_fastly_purge_api_no_token(self, mock_request, mock_fastly_response
8080
"""Test API call without auth token - skips in dev"""
8181
mock_request.return_value = mock_fastly_response
8282

83-
result = call_fastly_purge_api("/api/v1/articles/test/")
83+
result = call_fastly_purge_api("/api/v1/news/test/")
8484

8585
# Should skip purge when API key is empty (dev environment)
8686
assert result == {"status": "ok", "skipped": True}
@@ -98,7 +98,7 @@ def test_call_fastly_purge_api_error(
9898
"""Test Fastly API error response"""
9999
mock_request.return_value = mock_fastly_error_response
100100

101-
result = call_fastly_purge_api("/api/v1/articles/test/")
101+
result = call_fastly_purge_api("/api/v1/news/test/")
102102

103103
assert result is False
104104

frontends/main/src/app-pages/Articles/ArticleBanner.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ interface ArticleBannerProps {
6161
const ArticleBanner: React.FC<ArticleBannerProps> = ({
6262
title,
6363
description,
64-
currentBreadcrumb = "MIT Stories",
64+
currentBreadcrumb = "MIT News",
6565
backgroundUrl = DEFAULT_BACKGROUND_IMAGE_URL,
6666
className,
6767
}) => {

frontends/main/src/app-pages/Articles/ArticleListingPage.test.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,16 @@ describe("ArticleListingPage", () => {
4444
setupAPI(0)
4545
renderWithProviders(<ArticleListingPage />)
4646

47-
await screen.findByText("No Articles Available")
47+
await screen.findByText("No News Available")
4848

4949
expect(
5050
screen.getByText(
51-
"There are no articles to display at this time. Please check back later.",
51+
"There are no news to display at this time. Please check back later.",
5252
),
5353
).toBeInTheDocument()
5454
})
5555

56-
test("displays main story and grid stories on desktop", async () => {
56+
test("displays main news and grid stories on desktop", async () => {
5757
const news = setupAPI(21)
5858
renderWithProviders(<ArticleListingPage />)
5959

@@ -132,11 +132,13 @@ describe("ArticleListingPage", () => {
132132
expect(screen.queryByRole("progressbar")).not.toBeInTheDocument()
133133
})
134134

135-
// Find links by article title
136-
const titleLinks = screen.getAllByRole("link", {
137-
name: news.results[0].title,
138-
})
139-
expect(titleLinks[0]).toHaveAttribute("href", news.results[0].url)
135+
// Verify links exist with correct hrefs
136+
const allLinks = screen.getAllByRole("link")
137+
const firstArticleLink = allLinks.find(
138+
(link) => link.getAttribute("href") === news.results[0].url,
139+
)
140+
expect(firstArticleLink).toBeInTheDocument()
141+
expect(firstArticleLink).toHaveAttribute("href", news.results[0].url)
140142
})
141143

142144
test("displays article summaries with HTML stripped", async () => {
@@ -300,7 +302,7 @@ describe("ArticleListingPage", () => {
300302
setupAPI(0)
301303
renderWithProviders(<ArticleListingPage />)
302304

303-
await screen.findByText("No Articles Available")
305+
await screen.findByText("No News Available")
304306

305307
expect(screen.queryByRole("navigation")).not.toBeInTheDocument()
306308
})

frontends/main/src/app-pages/Articles/ArticleListingPage.tsx

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ const MainStoryCard = styled.div`
7373
border-top: 4px solid #a31f34;
7474
border-radius: 10px;
7575
76+
&:hover {
77+
h2 {
78+
text-decoration: underline;
79+
}
80+
}
81+
7682
${theme.breakpoints.down("sm")} {
7783
flex-direction: column;
7884
gap: 0;
@@ -203,11 +209,21 @@ const StoryCard = styled.div`
203209
flex-direction: row;
204210
gap: 24px;
205211
background: white;
206-
border: 1px solid ${theme.custom.colors.lightGray2};
207212
border-radius: 8px;
208213
padding: 16px 16px 16px 24px;
209214
overflow: hidden;
210215
216+
&:hover {
217+
border-radius: 8px;
218+
border: 1px solid ${theme.custom.colors.lightGray2};
219+
background: ${theme.custom.colors.white};
220+
box-shadow: 0 8px 20px 0 rgb(120 147 172 / 10%);
221+
222+
h2 {
223+
color: ${theme.custom.colors.red};
224+
}
225+
}
226+
211227
${theme.breakpoints.down("sm")} {
212228
flex-direction: row;
213229
gap: 12px;
@@ -216,6 +232,12 @@ const StoryCard = styled.div`
216232
border: none;
217233
border-bottom: 1px solid ${theme.custom.colors.lightGray2};
218234
border-radius: 0;
235+
236+
&:hover {
237+
border: none;
238+
border-bottom: 1px solid ${theme.custom.colors.lightGray2};
239+
box-shadow: none;
240+
}
219241
}
220242
`
221243

@@ -469,15 +491,18 @@ const MainStory: React.FC<{ item: NewsFeedItem }> = ({ item }) => {
469491
<MainStoryCard>
470492
<MainStoryImage>
471493
{item.image?.url && !imageError && (
472-
<Image
473-
src={item.image.url}
474-
alt={item.image.alt || item.title}
475-
fill
476-
style={{ objectFit: "cover" }}
477-
onError={() => setImageError(true)}
478-
/>
494+
<Link href={item.url}>
495+
<Image
496+
src={item.image.url}
497+
alt={item.image.alt || item.title}
498+
fill
499+
style={{ objectFit: "cover" }}
500+
onError={() => setImageError(true)}
501+
/>
502+
</Link>
479503
)}
480504
</MainStoryImage>
505+
481506
<MainStoryContent>
482507
<MainStoryContentContainer>
483508
<MainStoryTitle>
@@ -590,9 +615,9 @@ const ArticleListingPage: React.FC = () => {
590615
</LoadingContainer>
591616
) : stories.length === 0 ? (
592617
<EmptyState>
593-
<Typography variant="h4">No Articles Available</Typography>
618+
<Typography variant="h4">No News Available</Typography>
594619
<Typography variant="body1" color="textSecondary">
595-
There are no articles to display at this time. Please check back
620+
There are no news to display at this time. Please check back
596621
later.
597622
</Typography>
598623
</EmptyState>
@@ -628,7 +653,7 @@ const ArticleListingPage: React.FC = () => {
628653
{/* Grid Section: Other articles */}
629654
{gridStories.length > 0 ? (
630655
<GridContainer>
631-
<Grid2 container rowSpacing="8px" component={PlainList}>
656+
<Grid2 container rowSpacing="16px" component={PlainList}>
632657
{gridStories.map((item) => (
633658
<Grid2 key={item.id} size={12} component="li">
634659
<RegularStory item={item as NewsFeedItem} />

frontends/main/src/app-pages/HomePage/HomePage.test.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ describe("Home Page News and Events", () => {
191191
let section
192192
await waitFor(() => {
193193
section = screen
194-
.getAllByRole("heading", { name: "Stories" })!
194+
.getAllByRole("heading", { name: "News" })!
195195
.at(0)!
196196
.closest("section")!
197197
})
@@ -356,10 +356,10 @@ test("Headings", async () => {
356356
...media.results.map((result) => ({ level: 3, name: result.title })),
357357
{ level: 2, name: "Browse by Topic" },
358358
{ level: 2, name: "From Our Community" },
359-
{ level: 2, name: "MIT Stories & Events" },
360-
{ level: 3, name: "Stories" },
359+
{ level: 2, name: "MIT News & Events" },
360+
{ level: 3, name: "News" },
361361
{ level: 3, name: "Events" },
362-
{ level: 3, name: "Stories" },
362+
{ level: 3, name: "News" },
363363
{ level: 3, name: "Events" },
364364
])
365365
})

frontends/main/src/app-pages/HomePage/NewsEventsSection.tsx

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ const MobileContent = styled.div`
5454
margin: 40px 0;
5555
`
5656

57-
const StoriesContainer = styled.section`
57+
const NewsContainer = styled.section`
5858
display: flex;
5959
flex-direction: column;
6060
align-items: flex-start;
@@ -86,7 +86,7 @@ const StoryCard = styled(Card)<{ mobile: boolean }>`
8686
${({ mobile }) => (mobile ? "width: 274px" : "")}
8787
`
8888

89-
const StoriesSlider = styled.div`
89+
const NewsSlider = styled.div`
9090
display: flex;
9191
align-items: flex-start;
9292
gap: 16px;
@@ -240,7 +240,7 @@ const NewsEventsSection: React.FC = () => {
240240
return null
241241
}
242242

243-
const stories = news.results.slice(0, 6)
243+
const newsList = news.results.slice(0, 6)
244244

245245
const EventCards = events.results.map((item) => (
246246
<EventCard key={item.id} forwardClicksToLink>
@@ -270,7 +270,7 @@ const NewsEventsSection: React.FC = () => {
270270
return (
271271
<Section>
272272
<Title component="h2" variant="h2">
273-
MIT Stories & Events
273+
MIT News & Events
274274
</Title>
275275
<StrapLine>
276276
See what's happening in the world of learning with the latest news,
@@ -280,22 +280,22 @@ const NewsEventsSection: React.FC = () => {
280280
<MobileContent>
281281
<MobileContainer>
282282
<Typography component="h3" variant="h4">
283-
Stories
283+
News
284284
</Typography>
285285

286-
<StoriesSlider>
287-
{stories.map((item) => (
286+
<NewsSlider>
287+
{newsList.map((item) => (
288288
<Story
289289
key={item.id}
290290
mobile={true}
291291
item={item as NewsFeedItem}
292292
/>
293293
))}
294-
</StoriesSlider>
294+
</NewsSlider>
295295
{showArticleList && (
296296
<HeadingContainer>
297-
<SeeAllButton href="/articles/" size="large" responsive>
298-
See all stories
297+
<SeeAllButton href="/news/" size="large" responsive>
298+
See all news
299299
</SeeAllButton>
300300
</HeadingContainer>
301301
)}
@@ -311,12 +311,12 @@ const NewsEventsSection: React.FC = () => {
311311
<AboveMdOnly>
312312
<Container>
313313
<Content>
314-
<StoriesContainer>
314+
<NewsContainer>
315315
<Typography component="h3" variant="h4">
316-
Stories
316+
News
317317
</Typography>
318318
<Grid2 container columnSpacing="24px" rowSpacing="28px">
319-
{stories.map((item, index) => (
319+
{newsList.map((item, index) => (
320320
<Grid2
321321
key={item.id}
322322
size={{ xs: 12, sm: 12, md: 6, lg: 4, xl: 4 }}
@@ -333,12 +333,12 @@ const NewsEventsSection: React.FC = () => {
333333
</Grid2>
334334
{showArticleList && (
335335
<HeadingContainer>
336-
<SeeAllButton href="/articles/" size="large" responsive>
337-
See all stories
336+
<SeeAllButton href="/news/" size="large" responsive>
337+
See all news
338338
</SeeAllButton>
339339
</HeadingContainer>
340340
)}
341-
</StoriesContainer>
341+
</NewsContainer>
342342
<EventsContainer>
343343
<Typography component="h3" variant="h4">
344344
Events

frontends/main/src/app/articles/[slugOrId]/edit/page.tsx renamed to frontends/main/src/app/news/[slugOrId]/edit/page.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import React from "react"
22
import { ArticleEditPage } from "@/app-pages/Articles/ArticleEditPage"
33

4-
const Page: React.FC<PageProps<"/articles/[slugOrId]/edit">> = async (
5-
props,
6-
) => {
4+
const Page: React.FC<PageProps<"/news/[slugOrId]/edit">> = async (props) => {
75
const { slugOrId } = await props.params
86

97
return <ArticleEditPage articleId={slugOrId} />

0 commit comments

Comments
 (0)