103 lines
3.3 KiB
TypeScript
103 lines
3.3 KiB
TypeScript
import { PlaylistHeader } from '@/components/PlaylistHeader'
|
|
import { TrackList } from '@/components/TrackList'
|
|
|
|
interface PageProps {
|
|
params: Promise<{ id: string }>
|
|
}
|
|
|
|
async function getPlaylist(id: string) {
|
|
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/playlists/${id}`, {
|
|
cache: 'no-store',
|
|
})
|
|
if (!res.ok) throw new Error('Playlist not found')
|
|
const data = await res.json()
|
|
return data.playlist
|
|
}
|
|
|
|
export default async function PlaylistPage({ params }: PageProps) {
|
|
const { id } = await params
|
|
const playlist = await getPlaylist(id)
|
|
|
|
// Calculate total duration from songs
|
|
const totalDuration = playlist.songs?.reduce((acc: number, item: any) => {
|
|
const song = item.song || item
|
|
return acc + (song.duration || 0)
|
|
}, 0) || 0
|
|
|
|
// Transform playlist songs for TrackList
|
|
const tracks = playlist.songs?.map((item: any, index: number) => {
|
|
const song = item.song || item
|
|
return {
|
|
id: song.id,
|
|
title: song.title,
|
|
artistName: song.artist?.name || 'Unknown Artist',
|
|
duration: song.duration || 0,
|
|
plays: song.plays,
|
|
position: item.position || index + 1
|
|
}
|
|
}) || []
|
|
|
|
return (
|
|
<main className="min-h-screen bg-zinc-950">
|
|
<PlaylistHeader
|
|
title={playlist.name}
|
|
description={playlist.description}
|
|
coverUrl={playlist.coverUrl}
|
|
ownerName={playlist.user?.displayName || playlist.user?.username || 'Unknown'}
|
|
isPublic={playlist.isPublic}
|
|
songCount={playlist.songs?.length || 0}
|
|
duration={totalDuration}
|
|
/>
|
|
|
|
<div className="max-w-7xl mx-auto px-4 py-8">
|
|
{/* Track List */}
|
|
{tracks.length > 0 ? (
|
|
<section className="mb-8">
|
|
<TrackList tracks={tracks} showPosition />
|
|
</section>
|
|
) : (
|
|
<div className="text-center py-16">
|
|
<p className="text-xl text-zinc-400 mb-4">This playlist is empty</p>
|
|
<p className="text-zinc-500">Add some songs to get started</p>
|
|
</div>
|
|
)}
|
|
|
|
{/* Playlist Info */}
|
|
{playlist.description && (
|
|
<section className="mt-12">
|
|
<h3 className="text-lg font-semibold text-white mb-2">Description</h3>
|
|
<p className="text-zinc-300 leading-relaxed max-w-3xl">
|
|
{playlist.description}
|
|
</p>
|
|
</section>
|
|
)}
|
|
|
|
<section className="grid grid-cols-1 md:grid-cols-3 gap-8 mt-8 text-zinc-300">
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-white mb-2">Created</h3>
|
|
<p>{new Date(playlist.createdAt).toLocaleDateString('en-US', {
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
})}</p>
|
|
</div>
|
|
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-white mb-2">Songs</h3>
|
|
<p>{playlist.songs?.length || 0} tracks</p>
|
|
</div>
|
|
|
|
{playlist.songs && playlist.songs.length > 0 && (
|
|
<div>
|
|
<h3 className="text-lg font-semibold text-white mb-2">Total Duration</h3>
|
|
<p>
|
|
{Math.floor(playlist.songs.reduce((acc: number, song: any) => acc + song.duration, 0) / 60)} minutes
|
|
</p>
|
|
</div>
|
|
)}
|
|
</section>
|
|
</div>
|
|
</main>
|
|
)
|
|
}
|