Teal.fm frontend powered by slices.network tealfm-slices.wisp.place
tealfm slices
at main 2.7 kB view raw
1import { graphql, useLazyLoadQuery } from "react-relay"; 2import { useParams } from "react-router-dom"; 3import type { ProfileTopArtistsQuery } from "./__generated__/ProfileTopArtistsQuery.graphql"; 4import { useDateRangeFilter } from "./useDateRangeFilter"; 5import ArtistItem from "./ArtistItem"; 6import { useMemo } from "react"; 7 8export default function ProfileTopArtists() { 9 const { handle, period } = useParams<{ handle: string; period?: string }>(); 10 const dateRangeVariables = useDateRangeFilter(period); 11 12 const queryVariables = useMemo(() => { 13 return { 14 where: { 15 ...dateRangeVariables.where, 16 actorHandle: { eq: handle }, 17 }, 18 }; 19 }, [handle, dateRangeVariables]); 20 21 const data = useLazyLoadQuery<ProfileTopArtistsQuery>( 22 graphql` 23 query ProfileTopArtistsQuery($where: FmTealAlphaFeedPlayWhereInput) { 24 fmTealAlphaFeedPlaysAggregated( 25 groupBy: [{ field: artists }] 26 orderBy: { count: desc } 27 limit: 50 28 where: $where 29 ) { 30 artists 31 count 32 } 33 } 34 `, 35 queryVariables, 36 { fetchKey: `${handle}-${period || "all"}`, fetchPolicy: "store-or-network" } 37 ); 38 39 const processedArtists = useMemo(() => { 40 const artistCounts: { [key: string]: number } = {}; 41 42 (data.fmTealAlphaFeedPlaysAggregated || []).forEach((row) => { 43 if (!row.artists) return; 44 45 let names: string[] = []; 46 47 try { 48 const parsed = typeof row.artists === 'string' ? JSON.parse(row.artists) : row.artists; 49 50 if (Array.isArray(parsed)) { 51 names = parsed.map((a: { artistName: string }) => a.artistName.trim()); 52 } else if (typeof parsed === 'string') { 53 names = parsed.split(',').map(s => s.trim()); 54 } 55 } catch (e) { 56 if (typeof row.artists === 'string') { 57 names = row.artists.split(',').map(s => s.trim()); 58 } 59 } 60 61 names.forEach(name => { 62 if (name) { 63 artistCounts[name] = (artistCounts[name] || 0) + row.count; 64 } 65 }); 66 }); 67 68 return Object.entries(artistCounts) 69 .map(([name, count]) => ({ artists: name, count })) 70 .sort((a, b) => b.count - a.count) 71 .slice(0, 10); 72 }, [data.fmTealAlphaFeedPlaysAggregated]); 73 74 const maxCount = processedArtists.length > 0 ? processedArtists[0].count : 0; 75 76 return ( 77 <div className="space-y-1"> 78 {processedArtists.map((artist, index) => ( 79 <ArtistItem 80 key={`${artist.artists}-${index}`} 81 artists={artist.artists || "Unknown Artist"} 82 count={artist.count} 83 rank={index + 1} 84 maxCount={maxCount} 85 /> 86 ))} 87 </div> 88 ); 89}