mirror of
https://github.com/ershisan99/podcaster.git
synced 2025-12-18 12:33:48 +00:00
chore: refactor to take advantage of routing instead of rendering the same component twice
This commit is contained in:
53
src/components/podcast-episodes-list.tsx
Normal file
53
src/components/podcast-episodes-list.tsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { Link, useParams } from "react-router-dom";
|
||||||
|
import { usePodcastEpisodesQuery } from "../services/podcasts/podcast.hooks";
|
||||||
|
|
||||||
|
export function PodcastEpisodesList() {
|
||||||
|
const { podcastId } = useParams<{ podcastId: string }>();
|
||||||
|
const { data: episodesData } = usePodcastEpisodesQuery(podcastId);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>Episodes: {episodesData?.podcast.trackCount}</div>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Release Date</th>
|
||||||
|
<th>Duration</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{episodesData?.episodes?.map((episode) => {
|
||||||
|
const formattedDate = formatDate(episode.releaseDate);
|
||||||
|
const formattedDuration = formatDuration(episode.durationSeconds);
|
||||||
|
const url = `/podcast/${podcastId}/episode/${episode.id}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<tr key={episode.id}>
|
||||||
|
<td>
|
||||||
|
<Link to={url}>{episode.title}</Link>
|
||||||
|
</td>
|
||||||
|
<td>{formattedDate}</td>
|
||||||
|
<td>{formattedDuration}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDuration(duration?: number) {
|
||||||
|
if (!duration) {
|
||||||
|
return "N/A";
|
||||||
|
}
|
||||||
|
const minutes = Math.floor(duration / 60);
|
||||||
|
const seconds = Math.floor(duration % 60);
|
||||||
|
return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDate(date: string) {
|
||||||
|
return new Date(date).toLocaleDateString();
|
||||||
|
}
|
||||||
@@ -5,12 +5,12 @@ type Props = {
|
|||||||
imageURL: string;
|
imageURL: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PodcastInfoCard = ({
|
export function PodcastInfoCard({
|
||||||
title,
|
title,
|
||||||
author,
|
author,
|
||||||
description,
|
description,
|
||||||
imageURL,
|
imageURL,
|
||||||
}: Props) => {
|
}: Props) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
@@ -19,4 +19,4 @@ export const PodcastInfoCard = ({
|
|||||||
<p>{description}</p>
|
<p>{description}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|||||||
@@ -1,3 +1,26 @@
|
|||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { usePodcastEpisodesQuery } from "../services/podcasts/podcast.hooks";
|
||||||
|
|
||||||
export function Episode() {
|
export function Episode() {
|
||||||
return <h1>Episode page</h1>;
|
const { podcastId, episodeId } = useParams<{
|
||||||
|
podcastId: string;
|
||||||
|
episodeId: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const { data: episodesData } = usePodcastEpisodesQuery(podcastId);
|
||||||
|
|
||||||
|
const episode = episodesData?.episodes.find(
|
||||||
|
(episode) => episode.id.toString() === episodeId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>{episode?.description}</div>
|
||||||
|
<div>
|
||||||
|
<audio controls src={episode?.audioUrl}>
|
||||||
|
Audio is not supported by your browser
|
||||||
|
</audio>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Link, useParams } from "react-router-dom";
|
import { Outlet, useParams } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
usePodcastEpisodesQuery,
|
usePodcastEpisodesQuery,
|
||||||
useTopPodcastsQuery,
|
useTopPodcastsQuery,
|
||||||
@@ -26,7 +26,7 @@ export function Podcast() {
|
|||||||
if (!podcast) {
|
if (!podcast) {
|
||||||
return <h1>Podcast not found</h1>;
|
return <h1>Podcast not found</h1>;
|
||||||
}
|
}
|
||||||
// TODO: break into smaller components
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PodcastInfoCard
|
<PodcastInfoCard
|
||||||
@@ -35,48 +35,7 @@ export function Podcast() {
|
|||||||
description={podcast.description}
|
description={podcast.description}
|
||||||
imageURL={episodesData?.podcast.images.large ?? ""}
|
imageURL={episodesData?.podcast.images.large ?? ""}
|
||||||
/>
|
/>
|
||||||
<div>Episodes: {episodesData?.podcast.trackCount}</div>
|
<Outlet />
|
||||||
<div>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Title</th>
|
|
||||||
<th>Release Date</th>
|
|
||||||
<th>Duration</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{episodesData?.episodes?.map((episode) => {
|
|
||||||
const formattedDate = formatDate(episode.releaseDate);
|
|
||||||
const formattedDuration = formatDuration(episode.durationSeconds);
|
|
||||||
const url = `/podcast/${podcastId}/episode/${episode.id}`;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<tr key={episode.id}>
|
|
||||||
<td>
|
|
||||||
<Link to={url}>{episode.title}</Link>
|
|
||||||
</td>
|
|
||||||
<td>{formattedDate}</td>
|
|
||||||
<td>{formattedDuration}</td>
|
|
||||||
</tr>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDuration(duration?: number) {
|
|
||||||
if (!duration) {
|
|
||||||
return "N/A";
|
|
||||||
}
|
|
||||||
const minutes = Math.floor(duration / 60);
|
|
||||||
const seconds = Math.floor(duration % 60);
|
|
||||||
return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDate(date: string) {
|
|
||||||
return new Date(date).toLocaleDateString();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
|||||||
import { Home } from "./pages/home";
|
import { Home } from "./pages/home";
|
||||||
import { Podcast } from "./pages/podcast";
|
import { Podcast } from "./pages/podcast";
|
||||||
import { Episode } from "./pages/episode";
|
import { Episode } from "./pages/episode";
|
||||||
|
import { PodcastEpisodesList } from "./components/podcast-episodes-list";
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{
|
{
|
||||||
@@ -9,12 +10,18 @@ const router = createBrowserRouter([
|
|||||||
element: <Home />,
|
element: <Home />,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "/podcast/:podcastId",
|
path: "/podcast",
|
||||||
element: <Podcast />,
|
element: <Podcast />,
|
||||||
},
|
children: [
|
||||||
{
|
{
|
||||||
path: "/podcast/:podcastId/episode/:episodeId",
|
path: ":podcastId",
|
||||||
element: <Episode />,
|
element: <PodcastEpisodesList />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ":podcastId/episode/:episodeId",
|
||||||
|
element: <Episode />,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class PodcastsService {
|
|||||||
const response: GetEpisodesResponse = await this.fetchWithoutCors(
|
const response: GetEpisodesResponse = await this.fetchWithoutCors(
|
||||||
url.toString(),
|
url.toString(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let podcast: PodcastExtraDTO = {} as PodcastExtraDTO;
|
let podcast: PodcastExtraDTO = {} as PodcastExtraDTO;
|
||||||
const episodes: EpisodeDto[] = [];
|
const episodes: EpisodeDto[] = [];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user