Merge remote-tracking branch 'origin/refactor-components' into develop
This commit is contained in:
commit
1f33c01035
|
@ -7,12 +7,11 @@ import { Typography } from '@acid-info/lsd-react'
|
|||
import styled from '@emotion/styled'
|
||||
import ReactPlayer from 'react-player'
|
||||
import { LPE } from '../../types/lpe.types'
|
||||
import { convertSecToMinAndSec } from '@/utils/string.utils'
|
||||
|
||||
export const RenderEpisodeBlock = ({
|
||||
block,
|
||||
}: {
|
||||
block: LPE.Podcast.Document['transcription'][0]
|
||||
block: Extract<LPE.Post.ContentBlock, LPE.Post.TextBlock>
|
||||
hide?: boolean
|
||||
}) => {
|
||||
const isYoutubeRegex =
|
||||
|
@ -25,22 +24,12 @@ export const RenderEpisodeBlock = ({
|
|||
<ReactPlayer url={youtubeLink[0]} />
|
||||
) : (
|
||||
<TranscriptionItem>
|
||||
<TranscriptionData>
|
||||
{block?.start && (
|
||||
<Typography variant="body2" component={'p'}>
|
||||
{convertSecToMinAndSec(Number(block.start))}
|
||||
</Typography>
|
||||
)}
|
||||
<Typography variant="body2" component={'p'}>
|
||||
{block.speaker}
|
||||
</Typography>
|
||||
</TranscriptionData>
|
||||
<Transcript
|
||||
variant="body2"
|
||||
component={'p'}
|
||||
genericFontFamily="sans-serif"
|
||||
className={extractClassFromFirstTag(block.html) || ''}
|
||||
id={extractIdFromFirstTag(block.html) || `p-${block.start}`}
|
||||
id={extractIdFromFirstTag(block.html) || `p-${block.id}`}
|
||||
dangerouslySetInnerHTML={{ __html: extractInnerHtml(block.html) }}
|
||||
/>
|
||||
</TranscriptionItem>
|
||||
|
@ -58,10 +47,3 @@ const Transcript = styled(Typography)`
|
|||
line-height: var(--lsd-h6-lineHeight);
|
||||
}
|
||||
`
|
||||
|
||||
const TranscriptionData = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
margin-bottom: var(--lsd-body2-lineHeight);
|
||||
`
|
||||
|
|
|
@ -10,7 +10,8 @@ type Props = {
|
|||
|
||||
const EpisodeBlocks = ({ data }: Props) => {
|
||||
const [showMore, setShowMore] = useState(false)
|
||||
const blocks = data?.transcription
|
||||
|
||||
const blocks = data?.content as LPE.Post.TextBlock[]
|
||||
|
||||
return blocks?.length && showMore ? (
|
||||
<>
|
||||
|
|
|
@ -15,17 +15,20 @@ export default function EpisodeBody({ episode, relatedEpisodes }: Props) {
|
|||
const youtube = episode?.channels.find(
|
||||
(channel) => channel?.name === LPE.Podcast.ChannelNames.Youtube,
|
||||
)
|
||||
const simplecast = episode?.channels.find(
|
||||
(channel) => channel?.name === LPE.Podcast.ChannelNames.Simplecast,
|
||||
)
|
||||
|
||||
const channel = youtube ?? simplecast ?? null
|
||||
|
||||
const state = useHookstate(playerState)
|
||||
const duration = Math.round(state.value.duration / 60)
|
||||
|
||||
return (
|
||||
<EpisodeContainer>
|
||||
<EpisodeHeader
|
||||
{...episode}
|
||||
url={youtube?.url as string}
|
||||
duration={duration}
|
||||
/>
|
||||
{!!channel && (
|
||||
<EpisodeHeader {...episode} channel={channel} duration={duration} />
|
||||
)}
|
||||
<EpisodeTranscript episode={episode} />
|
||||
<EpisodeFooter episode={episode} relatedEpisodes={relatedEpisodes} />
|
||||
</EpisodeContainer>
|
||||
|
|
|
@ -13,10 +13,10 @@ type Props = {
|
|||
const EpisodeFooter = ({ episode, relatedEpisodes }: Props) => {
|
||||
const footnotes = useMemo(() => {
|
||||
return (
|
||||
episode.credits &&
|
||||
episode.credits
|
||||
.filter((b) => b.footnotes.length)
|
||||
.map((b) => b.footnotes)
|
||||
episode.content &&
|
||||
episode.content
|
||||
.filter((b) => (b as LPE.Post.TextBlock).footnotes.length)
|
||||
.map((b) => (b as LPE.Post.TextBlock).footnotes)
|
||||
.flat()
|
||||
)
|
||||
}, [episode])
|
||||
|
|
|
@ -3,6 +3,7 @@ import styled from '@emotion/styled'
|
|||
import { useState } from 'react'
|
||||
import { LPE } from '@/types/lpe.types'
|
||||
import { PostCard } from '@/components/PostCard'
|
||||
import { Grid, GridItem } from '@/components/Grid/Grid'
|
||||
|
||||
type props = {
|
||||
podcastSlug: string
|
||||
|
@ -25,26 +26,29 @@ const RelatedEpisodes = ({ podcastSlug, relatedEpisodes }: props) => {
|
|||
<Typography>More Episodes</Typography>
|
||||
<EpisodeCards>
|
||||
{relatedEpisodes.slice(0, showIndex).map((episode, idx: number) => (
|
||||
<PostCard
|
||||
key={'related-episode' + idx}
|
||||
contentType={LPE.PostTypes.Podcast}
|
||||
data={{
|
||||
authors: episode.authors,
|
||||
date: episode.publishedAt ? new Date(episode.publishedAt) : null,
|
||||
slug: episode.show?.slug
|
||||
? `${episode.show?.slug}/${episode.slug}`
|
||||
: `${podcastSlug}/${episode.slug}`,
|
||||
title: episode.title,
|
||||
coverImage: episode.coverImage,
|
||||
tags: episode.tags,
|
||||
podcastShowDetails: {
|
||||
<PostCardContainer className="w-8" key={'related-episode' + idx}>
|
||||
<PostCard
|
||||
contentType={LPE.PostTypes.Podcast}
|
||||
data={{
|
||||
authors: episode.authors,
|
||||
date: episode.publishedAt
|
||||
? new Date(episode.publishedAt)
|
||||
: null,
|
||||
slug: episode.show?.slug
|
||||
? `${episode.show?.slug}/${episode.slug}`
|
||||
: `${podcastSlug}/${episode.slug}`,
|
||||
title: episode.title,
|
||||
slug: `${episode.show?.slug}`,
|
||||
episodeNumber: episode.episodeNumber,
|
||||
podcast: episode.show as LPE.Podcast.Show,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
coverImage: episode.coverImage,
|
||||
tags: episode.tags,
|
||||
podcastShowDetails: {
|
||||
title: episode.title,
|
||||
slug: `${episode.show?.slug}`,
|
||||
episodeNumber: episode.episodeNumber,
|
||||
podcast: episode.show as LPE.Podcast.Show,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</PostCardContainer>
|
||||
))}
|
||||
</EpisodeCards>
|
||||
{relatedEpisodes?.length > 4 && (
|
||||
|
@ -64,11 +68,8 @@ const Container = styled.div`
|
|||
flex-direction: column;
|
||||
`
|
||||
|
||||
const EpisodeCards = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
const EpisodeCards = styled(Grid)`
|
||||
gap: 0 16px;
|
||||
flex-wrap: wrap;
|
||||
`
|
||||
|
||||
const ShowButton = styled(Button)`
|
||||
|
@ -76,4 +77,8 @@ const ShowButton = styled(Button)`
|
|||
margin-top: 24px;
|
||||
`
|
||||
|
||||
const PostCardContainer = styled(GridItem)`
|
||||
padding-top: 24px;
|
||||
`
|
||||
|
||||
export default RelatedEpisodes
|
||||
|
|
|
@ -8,24 +8,31 @@ import EpisodeStats from '../Episode.Stats'
|
|||
import EpisodePlayer from './Episode.Player'
|
||||
|
||||
export type EpisodeHeaderProps = LPE.Podcast.Document & {
|
||||
url: string
|
||||
channel: LPE.Podcast.Channel
|
||||
duration: number
|
||||
}
|
||||
|
||||
const EpisodeHeader = ({
|
||||
url,
|
||||
channel,
|
||||
title,
|
||||
description,
|
||||
publishedAt,
|
||||
tags,
|
||||
show,
|
||||
channels,
|
||||
duration,
|
||||
coverImage,
|
||||
}: EpisodeHeaderProps) => {
|
||||
const date = new Date(publishedAt)
|
||||
|
||||
return (
|
||||
<EpisodeHeaderContainer>
|
||||
<EpisodePlayer url={url} />
|
||||
<EpisodePlayer
|
||||
title={title}
|
||||
showTitle={show?.title ?? ''}
|
||||
channel={channel}
|
||||
coverImage={coverImage}
|
||||
/>
|
||||
<EpisodeStats date={date} duration={duration} />
|
||||
<EpisodeTitle variant="h1" genericFontFamily="serif" component="h1">
|
||||
{title}
|
||||
|
|
|
@ -3,33 +3,41 @@ import ReactPlayer from 'react-player'
|
|||
import { useHookstate } from '@hookstate/core'
|
||||
import { playerState } from '@/components/GlobalAudioPlayer/globalAudioPlayer.state'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { extractUUIDFromEpisode } from '@/utils/string.utils'
|
||||
import { getAudioSourceFromEpisode } from '@/utils/data.utils'
|
||||
import { episodeState } from '@/components/GlobalAudioPlayer/episode.state'
|
||||
import SimplecastPlayer from './Episode.SimplecastPlayer'
|
||||
import { LPE } from '@/types/lpe.types'
|
||||
|
||||
export type EpisodePlayerProps = {
|
||||
url: string
|
||||
channel: LPE.Podcast.Channel
|
||||
coverImage: LPE.Podcast.Document['coverImage']
|
||||
title: string
|
||||
showTitle: string
|
||||
}
|
||||
|
||||
const EpisodePlayer = ({ url }: EpisodePlayerProps) => {
|
||||
const EpisodePlayer = ({
|
||||
channel,
|
||||
coverImage,
|
||||
title,
|
||||
showTitle,
|
||||
}: EpisodePlayerProps) => {
|
||||
const state = useHookstate(playerState)
|
||||
const epState = useHookstate(episodeState)
|
||||
|
||||
const isYoutubeRegex =
|
||||
/(?:\/(?:embed|v|e)\/|\/watch\?v=|\/v\/|https?:\/\/(?:www\.)?youtu\.be\/)([^?&]+)/
|
||||
const isSimplecast = channel?.name === LPE.Podcast.ChannelNames.Simplecast
|
||||
|
||||
const youtubeLink = url.match(isYoutubeRegex) ?? []
|
||||
const url =
|
||||
channel?.name === LPE.Podcast.ChannelNames.Youtube
|
||||
? channel.url
|
||||
: (
|
||||
channel as Extract<
|
||||
LPE.Podcast.Channel,
|
||||
{ name: typeof LPE.Podcast.ChannelNames.Simplecast }
|
||||
>
|
||||
).data.audioFileUrl
|
||||
|
||||
const playerContainerRef = useRef<HTMLDivElement>(null)
|
||||
const playerRef = useRef<ReactPlayer>(null)
|
||||
|
||||
const isSimplecastRegex =
|
||||
/^https?:\/\/([a-zA-Z0-9-]+\.)*simplecast\.com\/[^?\s]+(\?[\s\S]*)?$/
|
||||
|
||||
const isSimplecast = isSimplecastRegex.test(url)
|
||||
const simplecastLink = url.match(isSimplecastRegex) ?? []
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
|
@ -52,40 +60,19 @@ const EpisodePlayer = ({ url }: EpisodePlayerProps) => {
|
|||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const episodeId = extractUUIDFromEpisode(simplecastLink[0] ?? '')
|
||||
epState.set({
|
||||
episodeId: 'aaa',
|
||||
title: title,
|
||||
podcast: showTitle,
|
||||
url: url,
|
||||
coverImage: coverImage ?? null,
|
||||
})
|
||||
|
||||
if (isSimplecast) {
|
||||
const getAudioSource = async () => {
|
||||
const response = await getAudioSourceFromEpisode(episodeId as string)
|
||||
|
||||
epState.set({
|
||||
episodeId: episodeId as string,
|
||||
title: response.title,
|
||||
podcast: response.podcast.title,
|
||||
url: response.ad_free_audio_file_url,
|
||||
thumbnail: response.image_url,
|
||||
})
|
||||
|
||||
state.set((prev) => ({
|
||||
...prev,
|
||||
url: response.ad_free_audio_file_url,
|
||||
}))
|
||||
}
|
||||
getAudioSource()
|
||||
} else {
|
||||
state.set((prev) => ({
|
||||
...prev,
|
||||
url,
|
||||
}))
|
||||
|
||||
const thumbnail = `https://img.youtube.com/vi/${youtubeLink[1]}/0.jpg`
|
||||
|
||||
epState.set((prev) => ({
|
||||
...prev,
|
||||
thumbnail: thumbnail,
|
||||
}))
|
||||
}
|
||||
}, [])
|
||||
state.set((prev) => ({
|
||||
...prev,
|
||||
url: url,
|
||||
}))
|
||||
}, [url, title, showTitle, coverImage])
|
||||
|
||||
useEffect(() => {
|
||||
if (!state.value.isEnabled) {
|
||||
|
@ -122,8 +109,9 @@ const EpisodePlayer = ({ url }: EpisodePlayerProps) => {
|
|||
{isSimplecast && (
|
||||
<SimplecastPlayer
|
||||
playerRef={playerRef}
|
||||
title={epState.value.title as string}
|
||||
thumbnail={epState.value.thumbnail as string}
|
||||
coverImage={
|
||||
epState.value.coverImage as LPE.Podcast.Document['coverImage']
|
||||
}
|
||||
handlePlay={handlePlay}
|
||||
handlePause={handlePause}
|
||||
/>
|
||||
|
|
|
@ -2,6 +2,7 @@ import { playerState } from '@/components/GlobalAudioPlayer/globalAudioPlayer.st
|
|||
import { PauseIcon } from '@/components/Icons/PauseIcon'
|
||||
import { PlayIcon } from '@/components/Icons/PlayIcon'
|
||||
import { VolumeIcon } from '@/components/Icons/VolumeIcon'
|
||||
import { LPE } from '@/types/lpe.types'
|
||||
import { convertSecToMinAndSec } from '@/utils/string.utils'
|
||||
import { Typography } from '@acid-info/lsd-react'
|
||||
import styled from '@emotion/styled'
|
||||
|
@ -11,16 +12,14 @@ import { useState } from 'react'
|
|||
|
||||
export type SimplecastPlayerProps = {
|
||||
playerRef: React.RefObject<any>
|
||||
title: string
|
||||
thumbnail: string
|
||||
coverImage: LPE.Podcast.Document['coverImage']
|
||||
handlePlay: (state: any) => void
|
||||
handlePause: (state: any) => void
|
||||
}
|
||||
|
||||
const SimplecastPlayer = ({
|
||||
playerRef,
|
||||
title,
|
||||
thumbnail,
|
||||
coverImage,
|
||||
handlePlay,
|
||||
handlePause,
|
||||
}: SimplecastPlayerProps) => {
|
||||
|
@ -52,9 +51,9 @@ const SimplecastPlayer = ({
|
|||
|
||||
return (
|
||||
<Container>
|
||||
{thumbnail && (
|
||||
{coverImage && (
|
||||
<ImageContainer>
|
||||
<Thumbnail src={thumbnail} alt={title} fill priority />
|
||||
<Thumbnail src={coverImage.url} alt={coverImage.alt} fill priority />
|
||||
</ImageContainer>
|
||||
)}
|
||||
<Controls>
|
||||
|
|
|
@ -183,10 +183,10 @@ export default function GlobalAudioPlayer() {
|
|||
onProgress={handleProgress}
|
||||
/>
|
||||
<RightMenu>
|
||||
{!!epState.value.thumbnail && (
|
||||
{!!epState.value.coverImage && (
|
||||
<Image
|
||||
src={epState.value.thumbnail}
|
||||
alt={epState.value.thumbnail}
|
||||
src={epState.value.coverImage.url}
|
||||
alt={epState.value.coverImage.alt}
|
||||
width={48}
|
||||
height={48}
|
||||
/>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { LPE } from '@/types/lpe.types'
|
||||
import { hookstate } from '@hookstate/core'
|
||||
|
||||
export type EpisodeState = {
|
||||
|
@ -5,7 +6,7 @@ export type EpisodeState = {
|
|||
title: string
|
||||
podcast: string
|
||||
url: string
|
||||
thumbnail: string
|
||||
coverImage: LPE.Post.ImageBlock | null
|
||||
}
|
||||
|
||||
export const defaultEpisodeState: EpisodeState = {
|
||||
|
@ -13,7 +14,7 @@ export const defaultEpisodeState: EpisodeState = {
|
|||
title: '',
|
||||
podcast: '',
|
||||
url: '',
|
||||
thumbnail: '',
|
||||
coverImage: null,
|
||||
}
|
||||
|
||||
export const episodeState =
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
import styled from '@emotion/styled'
|
||||
import { LPE } from '../../types/lpe.types'
|
||||
import { PostCard } from '@/components/PostCard/PostCard'
|
||||
import { Grid, GridItem } from '../Grid/Grid'
|
||||
|
||||
interface Props {
|
||||
header?: React.ReactNode
|
||||
episodes: LPE.Podcast.Document[]
|
||||
show?: LPE.Podcast.Show
|
||||
divider?: boolean
|
||||
isFeatured?: boolean
|
||||
}
|
||||
|
||||
export default function EpisodesList({
|
||||
|
@ -14,13 +16,18 @@ export default function EpisodesList({
|
|||
episodes,
|
||||
show,
|
||||
divider = false,
|
||||
isFeatured = false,
|
||||
}: Props) {
|
||||
return (
|
||||
<EpisodeListContainer>
|
||||
{header}
|
||||
<EpisodesContainer>
|
||||
{episodes.slice(0, 2).map((episode) => (
|
||||
<PostCardContainer key={episode.id} divider={divider}>
|
||||
{episodes.map((episode) => (
|
||||
<PostCardContainer
|
||||
key={episode.id}
|
||||
divider={divider}
|
||||
className={isFeatured ? 'w-8' : 'w-4'}
|
||||
>
|
||||
<PostCard
|
||||
contentType={LPE.PostTypes.Podcast}
|
||||
data={{
|
||||
|
@ -55,13 +62,12 @@ const EpisodeListContainer = styled.div`
|
|||
padding-top: 16px;
|
||||
`
|
||||
|
||||
const EpisodesContainer = styled.div`
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
const EpisodesContainer = styled(Grid)`
|
||||
gap: 36px 16px;
|
||||
`
|
||||
|
||||
const PostCardContainer = styled.div<{ divider: boolean }>`
|
||||
padding-top: 24px;
|
||||
const PostCardContainer = styled(GridItem)<{ divider: boolean }>`
|
||||
padding-block: 24px;
|
||||
border-top: ${({ divider }) =>
|
||||
divider ? '1px solid rgb(var(--lsd-border-primary))' : 'none'};
|
||||
`
|
||||
|
|
|
@ -23,7 +23,7 @@ export default function PodcastShowCard({
|
|||
<Container {...props}>
|
||||
<LogosCircleIcon width={73} height={73} />
|
||||
<ShowData>
|
||||
<Typography variant="h3">{show.title}</Typography>
|
||||
<Title variant="h3">{show.title}</Title>
|
||||
<PodcastHost show={show} />
|
||||
<Description variant="body2">{show.description}</Description>
|
||||
</ShowData>
|
||||
|
@ -35,7 +35,10 @@ const Container = styled.div`
|
|||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 68px;
|
||||
`
|
||||
|
||||
const Title = styled(Typography)`
|
||||
margin-bottom: 16px;
|
||||
`
|
||||
|
||||
const ShowData = styled.div`
|
||||
|
|
|
@ -4,6 +4,7 @@ import { Button, Typography } from '@acid-info/lsd-react'
|
|||
import Link from 'next/link'
|
||||
import PodcastHost from './Podcast.Host'
|
||||
import Image from 'next/image'
|
||||
import { Grid, GridItem } from '../Grid/Grid'
|
||||
|
||||
interface Props {
|
||||
shows: LPE.Podcast.Show[]
|
||||
|
@ -14,42 +15,48 @@ export default function PodcastsLists({ shows }: Props) {
|
|||
<PodcastListsContainer>
|
||||
{shows &&
|
||||
shows.map((show) => (
|
||||
<PodcastCard key={show.id}>
|
||||
<Image
|
||||
src={show.logo.url}
|
||||
width={56}
|
||||
height={56}
|
||||
alt={show.logo.alt}
|
||||
/>
|
||||
<Typography variant="h3">{show.title}</Typography>
|
||||
<Row>
|
||||
<PodcastHost show={show} />
|
||||
<Typography variant="body2">•</Typography>
|
||||
<Typography variant="body2">
|
||||
{show.numberOfEpisodes} EP
|
||||
</Typography>
|
||||
</Row>
|
||||
<Description variant="body2">{show.description}</Description>
|
||||
<Link href={`/podcasts/${show.slug}`}>
|
||||
<Button>Go to the show page</Button>
|
||||
</Link>
|
||||
</PodcastCard>
|
||||
<ShowCardContainer key={show.id} className="w-8">
|
||||
<ShowCard>
|
||||
<Image
|
||||
src={show.logo.url}
|
||||
width={56}
|
||||
height={56}
|
||||
alt={show.logo.alt}
|
||||
/>
|
||||
<Typography variant="h3">{show.title}</Typography>
|
||||
<Row>
|
||||
<PodcastHost show={show} />
|
||||
<Typography variant="body2">•</Typography>
|
||||
<Typography variant="body2">
|
||||
{show.numberOfEpisodes} EP
|
||||
</Typography>
|
||||
</Row>
|
||||
<Description variant="body2">{show.description}</Description>
|
||||
<Link href={`/podcasts/${show.slug}`}>
|
||||
<Button>Go to the show page</Button>
|
||||
</Link>
|
||||
</ShowCard>
|
||||
</ShowCardContainer>
|
||||
))}
|
||||
</PodcastListsContainer>
|
||||
)
|
||||
}
|
||||
|
||||
const PodcastListsContainer = styled.div`
|
||||
display: flex;
|
||||
const PodcastListsContainer = styled(Grid)`
|
||||
gap: 16px;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
flex-direction: column;
|
||||
}
|
||||
`
|
||||
|
||||
const PodcastCard = styled.div`
|
||||
const ShowCardContainer = styled(GridItem)``
|
||||
|
||||
const ShowCard = styled.div`
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
border: 1px solid rgb(var(--lsd-text-primary));
|
||||
width: 50%;
|
||||
`
|
||||
|
||||
const Row = styled.div`
|
||||
|
|
|
@ -22,11 +22,7 @@ const EpisodeContainer = (props: Props) => {
|
|||
)
|
||||
}
|
||||
|
||||
const EpisodeBodyContainer = styled(GridItem)`
|
||||
@media (min-width: 768px) and (max-width: 1200px) {
|
||||
grid-column: span 10 !important;
|
||||
}
|
||||
`
|
||||
const EpisodeBodyContainer = styled(GridItem)``
|
||||
|
||||
const EpisodeGrid = styled(Grid)`
|
||||
width: 100%;
|
||||
|
|
|
@ -2,10 +2,11 @@ import { Grid, GridItem } from '@/components/Grid/Grid'
|
|||
import styled from '@emotion/styled'
|
||||
import { LPE } from '../types/lpe.types'
|
||||
import EpisodesList from '@/components/Podcasts/Episodes.List'
|
||||
import { Typography } from '@acid-info/lsd-react'
|
||||
import { Button, Typography } from '@acid-info/lsd-react'
|
||||
import PodcastShowCard from '@/components/Podcasts/PodcastShowCard'
|
||||
import { PodcastType } from '@/components/PostCard/PostCard'
|
||||
import PodcastSection from '@/components/Podcasts/Podcast.Section'
|
||||
import { api } from '@/services/api.service'
|
||||
import { useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
show: LPE.Podcast.Show
|
||||
|
@ -15,30 +16,58 @@ interface Props {
|
|||
|
||||
const PodcastShowContainer = (props: Props) => {
|
||||
const { show, latestEpisodes, highlightedEpisodes } = props
|
||||
const [latest, setLatest] = useState(latestEpisodes)
|
||||
const [page, setPage] = useState(2)
|
||||
const [showSeeMore, setShowSeeMore] = useState(true)
|
||||
|
||||
const handleLoadMore = async () => {
|
||||
const response = await api.getLatestEpisodes({
|
||||
page: page,
|
||||
limit: 9,
|
||||
showSlug: show.slug,
|
||||
})
|
||||
|
||||
if (response.data.length === 0) {
|
||||
setShowSeeMore(false)
|
||||
return
|
||||
}
|
||||
|
||||
setLatest((prev) => [...prev, ...response.data])
|
||||
setPage((prev) => prev + 1)
|
||||
}
|
||||
|
||||
return (
|
||||
<PodcastsGrid>
|
||||
<PodcastsBodyContainer className={'w-16'}>
|
||||
<PodcastShowCard show={show} />
|
||||
|
||||
<PodcastSection>
|
||||
<EpisodesList
|
||||
header={<Typography variant="body2">All episodes</Typography>}
|
||||
episodes={highlightedEpisodes}
|
||||
show={show}
|
||||
/>
|
||||
</PodcastSection>
|
||||
|
||||
<EpisodesList episodes={latestEpisodes} divider={true} show={show} />
|
||||
</PodcastsBodyContainer>
|
||||
</PodcastsGrid>
|
||||
<>
|
||||
<PodcastsGrid>
|
||||
<PodcastsBodyContainer className={'w-16'}>
|
||||
<PodcastShowCard show={show} />
|
||||
<PodcastSection>
|
||||
<EpisodesList
|
||||
header={<Typography variant="body2">All episodes</Typography>}
|
||||
episodes={highlightedEpisodes}
|
||||
show={show}
|
||||
isFeatured={true}
|
||||
/>
|
||||
</PodcastSection>
|
||||
<EpisodesList episodes={latest} divider={true} show={show} />
|
||||
</PodcastsBodyContainer>
|
||||
</PodcastsGrid>
|
||||
{showSeeMore && (
|
||||
<SeeMoreButton onClick={handleLoadMore}>
|
||||
See more episodes
|
||||
</SeeMoreButton>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const PodcastsBodyContainer = styled(GridItem)`
|
||||
@media (min-width: 768px) and (max-width: 1200px) {
|
||||
grid-column: span 10 !important;
|
||||
}
|
||||
const PodcastsBodyContainer = styled(GridItem)``
|
||||
|
||||
const SeeMoreButton = styled(Button)`
|
||||
display: block;
|
||||
width: 236px;
|
||||
height: 40px;
|
||||
margin: 24px auto;
|
||||
`
|
||||
|
||||
const PodcastsGrid = styled(Grid)`
|
||||
|
|
|
@ -24,7 +24,12 @@ const PodcastsContainer = (props: Props) => {
|
|||
<PodcastSection>
|
||||
<EpisodesList
|
||||
header={<EpisodeListHeader>Latest Episodes</EpisodeListHeader>}
|
||||
episodes={highlightedEpisodes}
|
||||
episodes={highlightedEpisodes.slice(0, 2)}
|
||||
isFeatured={true}
|
||||
/>
|
||||
<EpisodesList
|
||||
episodes={highlightedEpisodes.slice(2)}
|
||||
divider={true}
|
||||
/>
|
||||
</PodcastSection>
|
||||
|
||||
|
@ -57,11 +62,7 @@ const PodcastsContainer = (props: Props) => {
|
|||
)
|
||||
}
|
||||
|
||||
const PodcastsBodyContainer = styled(GridItem)`
|
||||
@media (min-width: 768px) and (max-width: 1200px) {
|
||||
grid-column: span 10 !important;
|
||||
}
|
||||
`
|
||||
const PodcastsBodyContainer = styled(GridItem)``
|
||||
|
||||
const PodcastsGrid = styled(Grid)`
|
||||
width: 100%;
|
||||
|
|
|
@ -75,6 +75,7 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => {
|
|||
const { data: relatedArticles } = await unbodyApi.getRelatedArticles({
|
||||
id: data.id,
|
||||
})
|
||||
|
||||
const { data: articlesFromSameAuthors } =
|
||||
await unbodyApi.getArticlesFromSameAuthors(
|
||||
slug as string,
|
||||
|
|
|
@ -42,16 +42,25 @@ const EpisodePage = ({ episode, relatedEpisodes, errors }: EpisodeProps) => {
|
|||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const { data } = await unbodyApi.getPodcastShows({ populateEpisodes: true })
|
||||
|
||||
const paths = data.flatMap((show) => {
|
||||
return (
|
||||
show?.episodes &&
|
||||
show.episodes.map((episode) => {
|
||||
return {
|
||||
params: {
|
||||
showSlug: show.slug,
|
||||
epSlug: episode.slug,
|
||||
},
|
||||
}
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
return {
|
||||
paths: [
|
||||
{
|
||||
params: {
|
||||
showSlug: `hasing-it-out`,
|
||||
epSlug: `test-podcast-highlighted`,
|
||||
},
|
||||
},
|
||||
],
|
||||
fallback: true,
|
||||
paths: paths,
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,10 +47,19 @@ const PodcastShowPage = ({
|
|||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
// TODO : dynamic paths
|
||||
const { data } = await unbodyApi.getPodcastShows({ populateEpisodes: false })
|
||||
|
||||
const paths = data.map((show) => {
|
||||
return {
|
||||
params: {
|
||||
showSlug: show.slug,
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
paths: [{ params: { showSlug: `hashing-it-out` } }],
|
||||
fallback: true,
|
||||
paths: paths,
|
||||
fallback: false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +84,7 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => {
|
|||
await unbodyApi.getLatestEpisodes({
|
||||
showSlug: showSlug as string,
|
||||
page: 1,
|
||||
limit: 12,
|
||||
limit: 9,
|
||||
})
|
||||
|
||||
// TODO : error handling
|
||||
|
@ -83,7 +92,7 @@ export const getStaticProps = async ({ params }: GetStaticPropsContext) => {
|
|||
await unbodyApi.getHighlightedEpisodes({
|
||||
showSlug: showSlug as string,
|
||||
page: 1,
|
||||
limit: 9,
|
||||
limit: 2,
|
||||
})
|
||||
|
||||
return {
|
||||
|
|
Loading…
Reference in New Issue