118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
'use client'
|
|
|
|
import { PlaylistCard } from '@/components/PlaylistCard'
|
|
import { CreatePlaylistModal, CreatePlaylistData } from '@/components/CreatePlaylistModal'
|
|
import { useState, useEffect } from 'react'
|
|
|
|
export default function PlaylistsPage() {
|
|
const [playlists, setPlaylists] = useState<any[]>([])
|
|
const [isModalOpen, setIsModalOpen] = useState(false)
|
|
const [isCreating, setIsCreating] = useState(false)
|
|
const [loading, setLoading] = useState(true)
|
|
|
|
useEffect(() => {
|
|
fetchPlaylists()
|
|
}, [])
|
|
|
|
const fetchPlaylists = async () => {
|
|
try {
|
|
const res = await fetch('/api/playlists')
|
|
if (res.ok) {
|
|
const data = await res.json()
|
|
setPlaylists(data.playlists || [])
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to fetch playlists:', error)
|
|
} finally {
|
|
setLoading(false)
|
|
}
|
|
}
|
|
|
|
const handleCreatePlaylist = async (data: CreatePlaylistData) => {
|
|
setIsCreating(true)
|
|
try {
|
|
const res = await fetch('/api/playlists', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({
|
|
name: data.title,
|
|
description: data.description,
|
|
isPublic: data.isPublic,
|
|
}),
|
|
})
|
|
|
|
if (res.ok) {
|
|
const result = await res.json()
|
|
setPlaylists([result.playlist, ...playlists])
|
|
setIsModalOpen(false)
|
|
}
|
|
} catch (error) {
|
|
console.error('Failed to create playlist:', error)
|
|
} finally {
|
|
setIsCreating(false)
|
|
}
|
|
}
|
|
|
|
return (
|
|
<main className="min-h-screen bg-zinc-950">
|
|
<div className="max-w-7xl mx-auto px-4 py-8">
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between mb-8">
|
|
<div>
|
|
<h1 className="text-4xl font-bold text-white mb-4">My Playlists</h1>
|
|
<p className="text-xl text-zinc-400">
|
|
Create and manage your music collections
|
|
</p>
|
|
</div>
|
|
<button
|
|
onClick={() => setIsModalOpen(true)}
|
|
className="px-6 py-3 bg-emerald-600 hover:bg-emerald-700 text-white font-semibold rounded-lg transition-colors"
|
|
>
|
|
Create Playlist
|
|
</button>
|
|
</div>
|
|
|
|
{/* Playlists Grid */}
|
|
{loading ? (
|
|
<div className="text-center py-16">
|
|
<p className="text-zinc-400">Loading playlists...</p>
|
|
</div>
|
|
) : playlists.length > 0 ? (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
|
|
{playlists.map((playlist) => (
|
|
<PlaylistCard
|
|
key={playlist.id}
|
|
id={playlist.id}
|
|
title={playlist.name}
|
|
description={playlist.description}
|
|
coverUrl={playlist.coverUrl}
|
|
songCount={playlist.songs?.length || playlist._count?.songs || 0}
|
|
isPublic={playlist.isPublic}
|
|
/>
|
|
))}
|
|
</div>
|
|
) : (
|
|
<div className="text-center py-16">
|
|
<p className="text-xl text-zinc-400 mb-4">You don't have any playlists yet</p>
|
|
<p className="text-zinc-500 mb-6">Create your first playlist to start organizing your music</p>
|
|
<button
|
|
onClick={() => setIsModalOpen(true)}
|
|
className="px-6 py-3 bg-emerald-600 hover:bg-emerald-700 text-white font-semibold rounded-lg transition-colors"
|
|
>
|
|
Create Your First Playlist
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Create Playlist Modal */}
|
|
<CreatePlaylistModal
|
|
isOpen={isModalOpen}
|
|
onClose={() => setIsModalOpen(false)}
|
|
onSubmit={handleCreatePlaylist}
|
|
isLoading={isCreating}
|
|
/>
|
|
</main>
|
|
)
|
|
}
|