Overview
The LastPodcast component provides a focused view of the latest podcast episode, accessible via the /ultimo-episodio route. It displays the most recent episode with full interaction capabilities including playback, episode management, downloads, and YouTube video integration.
Purpose
This component serves as a quick access point for users who want to immediately listen to or view the newest episode without browsing the full episode list. It automatically displays songs[0] from the podcast state, which is the most recent episode.
Props
Callback function to trigger audio playbackSignature: (podcast: PodcastObject) => void
Features
Automatic Latest Episode Display
src/components/LastPodcast/LastPodcast.jsx
const { songs } = useSelector((state) => state.podcast);
const podcast = songs[0]; // Always displays the first (latest) episode
The component automatically selects the first episode from the fetched episodes array, which represents the most recently published episode.
Full Episode Management
LastPodcast includes all the episode management features available in PodcastDetail:
- Favorites - Toggle favorite status with heart icon
- Listen Later - Add to listen later queue
- Mark as Completed - Track completed episodes
- Playback Tracking - Resume from last position
- Episode Status - Visual indicators for started/completed episodes
YouTube Integration
src/components/LastPodcast/LastPodcast.jsx
useEffect(() => {
const fetchYoutubeVideo = async () => {
if (podcast) {
const response = await fetch(
`https://www.googleapis.com/youtube/v3/search?part=snippet&q=${encodeURIComponent(
podcast.title
)}&key=${YT_API_KEY}&channelId=${CHANNEL_ID}&type=video&maxResults=1`
);
const data = await response.json();
if (data.items && data.items.length > 0) {
setYoutubeVideoId(data.items[0].id.videoId);
}
}
};
fetchYoutubeVideo();
}, [podcast]);
Automatically searches for and displays the corresponding YouTube video for the latest episode.
Download Support
Full download functionality with progress tracking:
src/components/LastPodcast/LastPodcast.jsx
const { isLoading, progress, isCancelled, handleDownload, cancelDownload } = useDownload();
// Download button with progress
<motion.button
onClick={() => handleDownload(podcast.audio, podcast.title)}
>
{isLoading ? (
<>
<FidgetSpinner />
<span>Descargando {progress}%</span>
<Close onClick={cancelDownload} />
</>
) : (
<>
<Download />
Descargar
</>
)}
</motion.button>
Share Functionality
Native Web Share API integration:
src/components/LastPodcast/LastPodcast.jsx
const handleShareClick = async () => {
if (navigator.share) {
await navigator.share({
title: podcast.title,
text: podcast.description,
url: window.location.href
});
}
};
Redux Integration
The component connects to multiple Redux slices:
src/components/LastPodcast/LastPodcast.jsx
// State selectors
const { songs, listenedEpisodes, completedEpisodes, favoriteEpisodes, listenLaterEpisodes } =
useSelector((state) => state.podcast);
const { currentPodcast, isPlaying } = useSelector((state) => state.player);
const { playbackTimes } = useSelector((state) => state.audioTime);
// Actions dispatched
dispatch(togglePlay());
dispatch(toggleFavorite(podcast));
dispatch(toggleListenLater(podcast));
dispatch(markAsCompleted(podcast.title));
dispatch(removeFromCompleted(podcast.title));
dispatch(removePlaybackTime(podcast.title));
Visual Features
const BootstrapTooltip = styled(({ className, ...props }) => (
<Tooltip {...props} arrow classes={{ popper: className }} />
))(({ theme }) => ({
[`& .${tooltipClasses.arrow}`]: {
color: "#14D993"
},
[`& .${tooltipClasses.tooltip}`]: {
backgroundColor: "#14DB93",
color: "#000000",
fontSize: "14px",
fontWeight: "bold"
}
}));
Framer Motion Animations
- Logo hover animation - Scales to 1.16x and rotates 45° with spring physics
- Icon hover animation - Scales to 1.1x on hover
- Page transition - Fades in with y-axis translation
- Button interactions - Scale animations on tap
User Interactions
Playback Controls
- Play/Pause - Toggles audio playback for the latest episode
- Status tracking - Displays “Reproduciendo” (Playing), “Completado” (Completed), “Empezado” (Started), or “No Empezado” (Not Started)
Confirmation Dialogs
Critical actions like removing playback progress or completed status trigger confirmation toasts:
const showConfirmToast = (message, onConfirm) => {
toast.custom((t) => (
<div className={styles.confirmToast}>
<div className={styles.confirmHeader}>
<Warning />
<h3>Confirmar Acción</h3>
</div>
<p>{message}</p>
<div className={styles.confirmButtons}>
<button onClick={() => { toast.dismiss(t.id); onConfirm(); }}>
Confirmar
</button>
<button onClick={() => toast.dismiss(t.id)}>
Cancelar
</button>
</div>
</div>
), { duration: Infinity });
};
Navigation
The component includes a back button to return to the main episode list:
<Link to="/" className={styles.backButton}>
<motion.div whileHover="hover">
<motion.div variants={logoVariants}>
<ArrowBack />
</motion.div>
<span>Volver</span>
</motion.div>
</Link>
SEO
Includes dynamic helmet meta tags for the latest episode:
<Helmet>
<title>{podcast.title} - Nadie Sabe Nada Podcast</title>
</Helmet>
Use Cases
- Quick access - Users can immediately play the newest episode
- Episode preview - See details about the latest release
- Direct sharing - Share the latest episode link
- Featured content - Highlight the most recent episode prominently
The LastPodcast component is functionally very similar to PodcastDetail but is specifically designed to always show the most recent episode, making it ideal for homepage features or quick access navigation.