fediversion/frontend/components/profile/user-playlists-list.tsx
fullsizemalt 60456c4737
Some checks failed
Deploy Fediversion / deploy (push) Failing after 1s
feat(frontend): Enforce strict mode and refactor pages
2025-12-30 22:29:16 -08:00

94 lines
4.2 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import { Card, CardContent, CardHeader, CardTitle, CardDescription, CardFooter } from "@/components/ui/card"
import { ListMusic, Plus, PlayCircle, MoreHorizontal } from "lucide-react"
import Link from "next/link"
import { Button } from "@/components/ui/button"
import { getApiUrl } from "@/lib/api-config"
import { Skeleton } from "@/components/ui/skeleton"
import { Playlist } from "@/types/models"
export function UserPlaylistsList({ userId, isOwner = false }: { userId: number, isOwner?: boolean }) {
const [playlists, setPlaylists] = useState<Playlist[]>([])
const [loading, setLoading] = useState(true)
useEffect(() => {
const token = localStorage.getItem("token")
if (!token) return
// If isOwner, use /mine endpoint to see private playlists too
const endpoint = isOwner ? `${getApiUrl()}/playlists/mine` : `${getApiUrl()}/playlists?user_id=${userId}`
fetch(endpoint, {
headers: { Authorization: `Bearer ${token}` }
})
.then(res => res.json())
.then(data => setPlaylists(data))
.catch(err => console.error(err))
.finally(() => setLoading(false))
}, [userId, isOwner])
if (loading) {
return (
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{[1, 2, 3].map(i => (
<Skeleton key={i} className="h-40 w-full rounded-lg" />
))}
</div>
)
}
if (playlists.length === 0) {
return (
<div className="text-center py-12 border-2 border-dashed rounded-lg">
<ListMusic className="h-12 w-12 text-muted-foreground/30 mx-auto mb-4" />
<p className="text-muted-foreground font-medium">No playlists created yet</p>
{isOwner && (
<Button variant="outline" className="mt-4 gap-2">
<Plus className="h-4 w-4" /> Create Playlist
</Button>
)}
</div>
)
}
return (
<div className="space-y-4">
{isOwner && (
<div className="flex justify-end">
<Button size="sm" className="gap-2">
<Plus className="h-4 w-4" /> New Playlist
</Button>
</div>
)}
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{playlists.map((playlist) => (
<Link key={playlist.id} href={`/playlists/${playlist.id}`} className="group">
<Card className="h-full hover:border-primary/50 transition-colors cursor-pointer flex flex-col">
<CardHeader>
<div className="flex justify-between items-start gap-2">
<div className="bg-primary/10 p-2 rounded-md group-hover:bg-primary/20 transition-colors">
<ListMusic className="h-5 w-5 text-primary" />
</div>
{!playlist.is_public && (
<span className="text-[10px] uppercase font-bold tracking-wider bg-muted text-muted-foreground px-1.5 py-0.5 rounded">Private</span>
)}
</div>
<CardTitle className="mt-2 line-clamp-1">{playlist.name}</CardTitle>
<CardDescription className="line-clamp-2 min-h-[2.5em]">
{playlist.description || "No description"}
</CardDescription>
</CardHeader>
<CardFooter className="mt-auto pt-0 text-xs text-muted-foreground flex justify-between items-center">
<span>{playlist.performance_count} tracks</span>
<span>Updated {new Date(playlist.created_at).toLocaleDateString()}</span>
</CardFooter>
</Card>
</Link>
))}
</div>
</div>
)
}