diff --git a/frontend/src/pages/ArtistDetails/components/ArtistDetailsSimilar.jsx b/frontend/src/pages/ArtistDetails/components/ArtistDetailsSimilar.jsx index 375fdda..531654f 100644 --- a/frontend/src/pages/ArtistDetails/components/ArtistDetailsSimilar.jsx +++ b/frontend/src/pages/ArtistDetails/components/ArtistDetailsSimilar.jsx @@ -1,6 +1,14 @@ +import { useEffect, useMemo, useState } from "react"; import PropTypes from "prop-types"; -import { Loader, ChevronLeft, ChevronRight } from "lucide-react"; +import { Loader, ChevronLeft, ChevronRight, CheckCircle2 } from "lucide-react"; import ArtistImage from "../../../components/ArtistImage"; +import { + lookupArtistsInLibraryBatch, + readLibraryLookupCache, +} from "../../../utils/api"; + +const getArtistId = (artist) => + artist?.id || artist?.mbid || artist?.foreignArtistId; export function ArtistDetailsSimilar({ loadingSimilar, @@ -8,6 +16,36 @@ export function ArtistDetailsSimilar({ similarArtistsScrollRef, onArtistClick, }) { + const [libraryLookup, setLibraryLookup] = useState({}); + const artistIds = useMemo( + () => similarArtists.map(getArtistId).filter(Boolean), + [similarArtists], + ); + + useEffect(() => { + const cached = readLibraryLookupCache(artistIds); + setLibraryLookup(cached); + const missing = artistIds.filter((id) => cached[id] === undefined); + if (missing.length === 0) return; + let cancelled = false; + const fetchLookup = async () => { + try { + const lookup = await lookupArtistsInLibraryBatch(missing); + if (!cancelled && lookup) { + setLibraryLookup((prev) => ({ ...prev, ...lookup })); + } + } catch { + if (!cancelled) { + setLibraryLookup((prev) => ({ ...prev })); + } + } + }; + fetchLookup(); + return () => { + cancelled = true; + }; + }, [artistIds]); + if (!loadingSimilar && similarArtists.length === 0) return null; return ( @@ -59,40 +97,48 @@ export function ArtistDetailsSimilar({ msOverflowStyle: "none", }} > - {similarArtists.map((similar) => ( -