feat(web): Follow button + clickable artist in album modals
AlbumModal showed the artist name as static text — no way to follow the artist or jump to them. Adds a Follow affordance (todo #13): - AlbumInfo gains optional `artistMbid`. When present, the modal title links the artist name to /discover/artist/{mbid} and shows a Follow/Following button that reflects live follow state. - Follow state fetched via a new lightweight GET /api/artists?mbid= check (avoids pulling the full watched list + discography); Follow reuses POST /api/artists. Non-ok POST surfaces a toast (also chips at todo #14). - Wired artistMbid in the three discovery contexts where following is valuable: Discover, Discover artist preview, and Last.fm. Library/discography callers pass none (already-followed artists) so the button stays hidden — graceful. web 152 tests (the ?mbid= follow-state check asserted), tsc + build clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,10 @@ import { GET, POST } from "./route";
|
||||
const mockBrowse = vi.mocked(browseReleaseGroups);
|
||||
afterEach(() => mockBrowse.mockReset());
|
||||
|
||||
function listReq(qs = "") {
|
||||
return new Request(`http://localhost/api/artists${qs}`);
|
||||
}
|
||||
|
||||
function postReq(body: unknown) {
|
||||
return new Request("http://localhost/api/artists", {
|
||||
method: "POST",
|
||||
@@ -52,7 +56,7 @@ describe("artists collection API", () => {
|
||||
// mark the one release as monitored + have, to exercise the counts
|
||||
await prisma.monitoredRelease.updateMany({ where: { artistMbid: "a1" }, data: { monitored: true, currentQualityClass: 2 } });
|
||||
|
||||
const res = await GET();
|
||||
const res = await GET(listReq());
|
||||
expect(res.status).toBe(200);
|
||||
const a = (await res.json()).artists[0];
|
||||
expect(a).toMatchObject({ mbid: "a1", name: "John Mayer", releaseCount: 1, monitoredCount: 1, haveCount: 1 });
|
||||
@@ -72,11 +76,17 @@ describe("artists collection API", () => {
|
||||
},
|
||||
});
|
||||
|
||||
const before = (await (await GET()).json()).artists.find((a: { mbid: string }) => a.mbid === "a2");
|
||||
const before = (await (await GET(listReq())).json()).artists.find((a: { mbid: string }) => a.mbid === "a2");
|
||||
expect(before).toMatchObject({ showAllTypes: false, releaseCount: 1, monitoredCount: 1, haveCount: 1 });
|
||||
|
||||
await prisma.watchedArtist.update({ where: { mbid: "a2" }, data: { showAllTypes: true } });
|
||||
const after = (await (await GET()).json()).artists.find((a: { mbid: string }) => a.mbid === "a2");
|
||||
const after = (await (await GET(listReq())).json()).artists.find((a: { mbid: string }) => a.mbid === "a2");
|
||||
expect(after).toMatchObject({ showAllTypes: true, releaseCount: 2, monitoredCount: 2, haveCount: 2 });
|
||||
});
|
||||
|
||||
it("GET ?mbid= returns the follow state for a single artist", async () => {
|
||||
await prisma.watchedArtist.create({ data: { mbid: "followed-1", name: "Followed" } });
|
||||
expect((await (await GET(listReq("?mbid=followed-1"))).json()).followed).toBe(true);
|
||||
expect((await (await GET(listReq("?mbid=nope"))).json()).followed).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user