"use client"; import { useCallback, useEffect, useMemo, useState } from "react"; import { PageHead } from "../../../_ui/page-head"; import { CoverArt } from "../../../_ui/cover-art"; import { AlbumModal } from "../../../_ui/album-modal"; import { categoryOf, TAB_ORDER, type Category } from "../../../_ui/categories"; import { toast } from "../../../_ui/toast"; type Release = { rgMbid: string; album: string; primaryType: string | null; secondaryTypes: string[]; firstReleaseDate: string | null; monitored: boolean; have: boolean; }; type Preview = { artistName: string; followed: boolean; releases: Release[] }; export function PreviewClient({ mbid, initialName }: { mbid: string; initialName: string }) { const [data, setData] = useState(null); const [followed, setFollowed] = useState(false); const [error, setError] = useState(false); const [tab, setTab] = useState<"All" | Category>("Albums"); const [wanted, setWanted] = useState>(new Set()); const [open, setOpen] = useState(null); const load = useCallback(async () => { setError(false); const qs = new URLSearchParams({ all: "true" }); if (initialName) qs.set("name", initialName); const res = await fetch(`/api/discover/preview/${mbid}?${qs.toString()}`); if (!res.ok) { setError(true); return; } const d: Preview = await res.json(); setData(d); setFollowed(d.followed); }, [mbid, initialName]); useEffect(() => { load(); }, [load]); const name = data?.artistName || initialName; async function follow() { const res = await fetch("/api/artists", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ mbid, name }), }); if (res.ok || res.status === 409) { setFollowed(true); toast(`Following ${name}`); } } async function want(r: Release) { const res = await fetch("/api/discover/want", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ rgMbid: r.rgMbid, artistMbid: mbid, artistName: name, album: r.album, primaryType: r.primaryType, secondaryTypes: r.secondaryTypes, firstReleaseDate: r.firstReleaseDate, }), }); if (res.ok) { setWanted((s) => new Set(s).add(r.rgMbid)); toast(`Added ${r.album}`); } } const counts = useMemo(() => { const c: Record = {}; data?.releases.forEach((r) => { c[categoryOf(r)] = (c[categoryOf(r)] ?? 0) + 1; }); return c; }, [data]); function chipFor(r: Release) { if (r.have) return In library; if (r.monitored || wanted.has(r.rgMbid)) return Wanted; return null; } if (error) return (

Couldn’t load this artist.{" "}

); if (!data) return

Loading…

; const tabs: ("All" | Category)[] = ["All", ...TAB_ORDER.filter((t) => counts[t])]; const visible = tab === "All" ? data.releases : data.releases.filter((r) => categoryOf(r) === tab); return (
{followed ? ( Following ) : ( )} MusicBrainz ↗
{tabs.map((t) => ( ))}
    {visible.map((r) => { const owned = r.have || r.monitored || wanted.has(r.rgMbid); return (
  • {chipFor(r)}
  • ); })}
{open ? ( setOpen(null)} album={{ rgMbid: open.rgMbid, album: open.album, artist: name, year: open.firstReleaseDate?.slice(0, 4) ?? null, type: open.primaryType, artistMbid: mbid, }} status={chipFor(open)} actions={ open.have || open.monitored || wanted.has(open.rgMbid) ? null : ( ) } /> ) : null}
); }