From e37482935899102508aa4ea8c8b62cd72551cf25 Mon Sep 17 00:00:00 2001 From: Amirmahdi Nourkazemi Date: Thu, 11 Jun 2026 12:00:39 +0330 Subject: [PATCH] feat: add playlist --- app/dashboard/music/tracks/page.tsx | 49 ++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/app/dashboard/music/tracks/page.tsx b/app/dashboard/music/tracks/page.tsx index c297704..b75c540 100644 --- a/app/dashboard/music/tracks/page.tsx +++ b/app/dashboard/music/tracks/page.tsx @@ -20,6 +20,14 @@ import { MediaPreview } from "@/components/MediaPreview"; import { ImagePicker } from "@/components/ImagePicker"; import { pickUrl, SOUND_KEYS, IMAGE_KEYS } from "@/lib/media"; +interface Playlist { + id: number; + name?: string; + // Some endpoints nest the playlist's sub-categories; key casing varies. + subcategories?: Playlist[]; + subCategories?: Playlist[]; +} + interface Track { id: number; title?: string; @@ -28,11 +36,12 @@ interface Track { type?: string; playlist_id?: number; image_id?: number | null; -} - -interface Playlist { - id: number; - name?: string; + // A track belongs to many playlists; the /music row embeds them as an array. + playlists?: Playlist[]; + // Sub-categories may also be embedded directly on the track (key casing varies). + subcategories?: Playlist[]; + subCategories?: Playlist[]; + sub_categories?: Playlist[]; } export default function MusicTracksPage() { @@ -56,6 +65,26 @@ export default function MusicTracksPage() { const [deleting, setDeleting] = useState(null); const [removing, setRemoving] = useState(false); + // A track belongs to many playlists — list their names. + function playlistName(r: Track): string { + const names = (r.playlists ?? []).map((p) => p.name).filter(Boolean); + return names.length ? (names as string[]).join("، ") : "—"; + } + + // Sub-categories may sit on the track directly or come through its playlists; + // key casing varies between endpoints, so gather from every shape. + function subCategoryNames(r: Track): string { + const subs: Playlist[] = [ + ...(r.subcategories ?? r.subCategories ?? r.sub_categories ?? []), + ...(r.playlists ?? []).flatMap( + (p) => p.subcategories ?? p.subCategories ?? [], + ), + ]; + const names = subs.map((s) => s.name).filter(Boolean) as string[]; + const unique = Array.from(new Set(names)); + return unique.length ? unique.join("، ") : "—"; + } + function resetForm() { setTitle(""); setArtist(""); @@ -163,6 +192,16 @@ export default function MusicTracksPage() { }, { key: "title", header: "عنوان" }, { key: "artist", header: "هنرمند", render: (r) => r.artist ?? "—" }, + { + key: "playlist", + header: "پلی‌لیست", + render: (r) => playlistName(r), + }, + { + key: "subcategory", + header: "زیر‌دسته", + render: (r) => subCategoryNames(r), + }, { key: "duration", header: "مدت زمان",