From a1fb00bd9f9ed28f241ba68a309496a27a81dabb Mon Sep 17 00:00:00 2001 From: Ahtesham Quraish Date: Fri, 15 May 2026 15:57:00 +0500 Subject: [PATCH 1/2] fix: link the podcast episode to its detail page and fix the video count on collection page --- .../PodcastPage/PodcastDetailPage.tsx | 31 ++++++++++++++----- .../PodcastPage/PodcastEpisodeDetailPage.tsx | 7 ++++- .../VideoPlaylistCollectionPage.tsx | 10 +++--- 3 files changed, 34 insertions(+), 14 deletions(-) diff --git a/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx b/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx index 2e4eae2b0e..7e8cf1ec92 100644 --- a/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx +++ b/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx @@ -1,6 +1,8 @@ "use client" import React, { useState, useEffect, useRef } from "react" +import { notFound } from "next/navigation" +import { useRouter } from "next-nprogress-bar" import { Breadcrumbs, Typography, styled, useMediaQuery } from "ol-components" import type { Theme } from "ol-components" import { Button, ActionButton } from "@mitodl/smoot-design" @@ -15,12 +17,11 @@ import { ResourceTypeEnum } from "api/v1" import type { LearningResource } from "api/v1" import moment from "moment" import { formatDate } from "ol-utilities" -import { HOME } from "@/common/urls" +import { HOME, podcastEpisodePageView } from "@/common/urls" import PodcastContainer from "./PodcastContainer" import { useFeatureFlagsLoaded } from "@/common/useFeatureFlagsLoaded" import { useFeatureFlagEnabled } from "posthog-js/react" import { FeatureFlags } from "@/common/feature_flags" -import { notFound } from "next/navigation" const HeaderSection = styled.div(({ theme }) => ({ borderBottom: `1px solid ${theme.custom.colors.lightGray2}`, @@ -148,7 +149,7 @@ const EpisodesHeading = styled(Typography)(({ theme }) => ({ }, })) -const EpisodeList = styled.ul({ +const EpisodeList = styled.div({ listStyle: "none", margin: 0, padding: 0, @@ -156,9 +157,10 @@ const EpisodeList = styled.ul({ gridTemplateColumns: "1fr", }) -const EpisodeRow = styled("li", { +const EpisodeRow = styled("div", { shouldForwardProp: (prop) => prop !== "isEpisodePage", })<{ isEpisodePage?: boolean }>(({ theme, isEpisodePage }) => ({ + cursor: "pointer", margin: 0, display: "flex", flexDirection: "row", @@ -310,6 +312,7 @@ const PlayButton = styled(ActionButton, { export type EpisodeItemProps = { episode: LearningResource + href: string onPlayClick: (episode: LearningResource) => void onPauseClick?: () => void isPlaying: boolean @@ -319,12 +322,14 @@ export type EpisodeItemProps = { export const EpisodeItem: React.FC = ({ episode, + href, onPlayClick, onPauseClick, isPlaying, isPlayable, isEpisodePage = false, }) => { + const router = useRouter() const podcastEpisode = episode.resource_type === "podcast_episode" ? episode.podcast_episode : null @@ -339,10 +344,7 @@ export const EpisodeItem: React.FC = ({ const metaParts = [duration ? `${duration} min` : null, date].filter(Boolean) return ( - (isPlaying ? onPauseClick?.() : onPlayClick(episode))} - isEpisodePage={isEpisodePage} - > + router.push(href)} isEpisodePage={isEpisodePage}> {episode.title} @@ -364,6 +366,15 @@ export const EpisodeItem: React.FC = ({ aria-label={ isPlaying ? `Pause ${episode.title}` : `Play ${episode.title}` } + onClick={(e) => { + e.preventDefault() + e.stopPropagation() + if (isPlaying) { + onPauseClick?.() + } else { + onPlayClick(episode) + } + }} isPlaying={isPlaying} disabled={!isPlayable} variant="secondary" @@ -575,6 +586,10 @@ export const PodcastDetailPage: React.FC = ({ playerRef.current?.pause()} isPlaying={ diff --git a/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx b/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx index 4253e4df4a..5055177601 100644 --- a/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx +++ b/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx @@ -25,7 +25,7 @@ import { ResourceTypeEnum } from "api/v1" import type { LearningResource } from "api/v1" import moment from "moment" import { formatDate } from "ol-utilities" -import { HOME, podcastPageView } from "@/common/urls" +import { HOME, podcastPageView, podcastEpisodePageView } from "@/common/urls" import DOMPurify from "isomorphic-dompurify" import { EpisodeItem } from "./PodcastDetailPage" import PodcastContainer from "./PodcastContainer" @@ -354,6 +354,11 @@ export const PodcastEpisodeDetailPage: React.FC< page.results.map((rel) => rel.resource), @@ -117,7 +118,6 @@ const VideoPlaylistCollectionPage: React.FC< ) const playlistType = isOcwPlaylist(playlist) - const totalVideos = videos.length const totalVideoSeconds = videos.reduce((acc, video) => { const duration = video.video?.duration ?? "" const match = /PT(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?/.exec(duration) @@ -141,7 +141,7 @@ const VideoPlaylistCollectionPage: React.FC< {isLoading ? ( @@ -151,7 +151,7 @@ const VideoPlaylistCollectionPage: React.FC< video={videos[0]} href={getVideoHref(videos[0])} isSeries={playlistType} - totalVideos={totalVideos} + totalVideos={totalCount} totalTime={totalTime} /> ) : null} From 06ee46c78578698ebac70cadf5aa29494387b4a3 Mon Sep 17 00:00:00 2001 From: Ahtesham Quraish Date: Fri, 15 May 2026 16:47:10 +0500 Subject: [PATCH 2/2] fix spaces issues --- .../PodcastPage/PodcastDetailPage.tsx | 61 +++++++++++++------ .../PodcastPage/PodcastEpisodeDetailPage.tsx | 14 +++-- .../VideoPlaylistCollectionPage.tsx | 4 +- 3 files changed, 52 insertions(+), 27 deletions(-) diff --git a/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx b/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx index 7e8cf1ec92..d85ffe28a4 100644 --- a/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx +++ b/frontends/main/src/app-pages/PodcastPage/PodcastDetailPage.tsx @@ -122,8 +122,10 @@ const HeaderTextContent = styled.div({ /* ── Episodes list ── */ -const EpisodesSection = styled.div(({ theme }) => ({ - padding: "0 48px", +const EpisodesSection = styled("div", { + shouldForwardProp: (prop) => prop !== "hasMoreEpisodes", +})<{ hasMoreEpisodes?: boolean }>(({ theme, hasMoreEpisodes }) => ({ + padding: hasMoreEpisodes ? "0 48px" : "0 48px 40px 48px", [theme.breakpoints.down("sm")]: { padding: "0 0 48px", }, @@ -150,7 +152,6 @@ const EpisodesHeading = styled(Typography)(({ theme }) => ({ })) const EpisodeList = styled.div({ - listStyle: "none", margin: 0, padding: 0, display: "grid", @@ -184,6 +185,10 @@ const EpisodeRow = styled("div", { backgroundColor: theme.custom.colors.lightGray1, cursor: "pointer", }, + "&:focus-visible": { + outline: `2px solid ${theme.custom.colors.red}`, + outlineOffset: "-2px", + }, "&:hover .episode-title, &:focus-visible .episode-title": { color: theme.custom.colors.red, }, @@ -330,6 +335,10 @@ export const EpisodeItem: React.FC = ({ isEpisodePage = false, }) => { const router = useRouter() + + const handleRowNavigate = () => { + if (href) router.push(href) + } const podcastEpisode = episode.resource_type === "podcast_episode" ? episode.podcast_episode : null @@ -344,7 +353,18 @@ export const EpisodeItem: React.FC = ({ const metaParts = [duration ? `${duration} min` : null, date].filter(Boolean) return ( - router.push(href)} isEpisodePage={isEpisodePage}> + { + if (e.key === "Enter" || e.key === " ") { + e.preventDefault() + handleRowNavigate() + } + }} + role="link" + tabIndex={0} + isEpisodePage={isEpisodePage} + > {episode.title} @@ -577,26 +597,27 @@ export const PodcastDetailPage: React.FC = ({ - + Episodes {episodes && episodes.length > 0 && ( - + {episodes.map((episode) => ( - playerRef.current?.pause()} - isPlaying={ - playingEpisode?.id === episode.id && isAudioPlaying - } - isPlayable={Boolean(getEpisodeAudioUrl(episode))} - /> +
+ playerRef.current?.pause()} + isPlaying={ + playingEpisode?.id === episode.id && isAudioPlaying + } + isPlayable={Boolean(getEpisodeAudioUrl(episode))} + /> +
))}
)} diff --git a/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx b/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx index 5055177601..2f8805045a 100644 --- a/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx +++ b/frontends/main/src/app-pages/PodcastPage/PodcastEpisodeDetailPage.tsx @@ -47,9 +47,13 @@ const PageSection = styled.div(({ theme }) => ({ minHeight: "100vh", })) -const HeaderSection = styled.div(({ theme }) => ({ - borderBottom: `1px solid ${theme.custom.colors.lightGray2}`, - marginBottom: "64px", +const HeaderSection = styled("div", { + shouldForwardProp: (prop) => prop !== "hasEpisodes", +})<{ hasEpisodes?: boolean }>(({ theme, hasEpisodes }) => ({ + ...(hasEpisodes && { + borderBottom: `1px solid ${theme.custom.colors.lightGray2}`, + marginBottom: "64px", + }), paddingBottom: "64px", [theme.breakpoints.down("sm")]: { marginBottom: "24px", @@ -305,7 +309,7 @@ export const PodcastEpisodeDetailPage: React.FC< />
- + 0}> {podcast?.title && ( {podcast.title} @@ -357,7 +361,7 @@ export const PodcastEpisodeDetailPage: React.FC< href={ podcastId ? podcastEpisodePageView(String(episode.id), podcastId) - : "#" + : "" } isPlaying={ playingEpisode?.id === episode.id && isAudioPlaying diff --git a/frontends/main/src/app-pages/VideoPlaylistCollectionPage/VideoPlaylistCollectionPage.tsx b/frontends/main/src/app-pages/VideoPlaylistCollectionPage/VideoPlaylistCollectionPage.tsx index ddd2e96609..c1ce123c82 100644 --- a/frontends/main/src/app-pages/VideoPlaylistCollectionPage/VideoPlaylistCollectionPage.tsx +++ b/frontends/main/src/app-pages/VideoPlaylistCollectionPage/VideoPlaylistCollectionPage.tsx @@ -90,7 +90,7 @@ const VideoPlaylistCollectionPage: React.FC< learning_resource_id: playlistId, limit: VIDEOS_PAGE_SIZE, }) - console.log("itemsData", itemsData) + const { data: similarData, isLoading: similarLoading } = useQuery({ ...learningResourceQueries.vectorSimilar({ id: playlistId, @@ -99,7 +99,7 @@ const VideoPlaylistCollectionPage: React.FC< }), }) - if (showVideoPlaylistPage) { + if (!showVideoPlaylistPage) { return flagsLoaded ? notFound() : null }