All files / Rindu/components/VirtualizedList TracksList.tsx

16.21% Statements 6/37
0% Branches 0/17
0% Functions 0/9
18.75% Lines 6/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 11219x       19x 19x 19x     19x         19x                                                                                                                                                                                                  
import { ReactElement, useCallback, useState } from "react";
 
import { IndexRange } from "react-virtualized";
 
import VirtualizedList from "./VirtualizedList";
import CardTrack, { CardType } from "components/CardTrack";
import { useSpotify } from "hooks";
 
import { ITrack } from "types/spotify";
import { getIdFromUri, mapPlaylistItems } from "utils";
import {
  checkTracksInLibrary,
  getMyLikedSongs,
  getTracksFromPlaylist,
} from "utils/spotifyCalls";
 
interface Props {
  type: CardType;
  initialTracksInLibrary: boolean[] | null;
  isLibrary?: boolean;
  isGeneratedPlaylist?: boolean;
}
 
export function TracksList({
  isGeneratedPlaylist,
  isLibrary,
  type,
  initialTracksInLibrary,
}: Readonly<Props>): ReactElement {
  const { allTracks, pageDetails, setAllTracks } = useSpotify();
  const [tracksInLibrary, setTracksInLibrary] = useState<boolean[] | null>(
    initialTracksInLibrary
  );
 
  const spliceTracks = useCallback(
    <T,>(allTracks: T[] | null, newTracks: T[], position: number): T[] => {
      Iif (!allTracks) {
        return [...newTracks];
      }
      const tracks = [...allTracks];
      tracks.splice(position, 50, ...newTracks);
      return tracks;
    },
    []
  );
 
  const addTracksToPlaylists = useCallback(
    (
      tracks: ITrack[],
      tracksInLibrary: boolean[] | null,
      position: number
    ): void => {
      setAllTracks((allTracks) => spliceTracks(allTracks, tracks, position));
 
      Iif (!tracksInLibrary) return;
 
      setTracksInLibrary((allTracks) =>
        spliceTracks(allTracks, tracksInLibrary, position)
      );
    },
    [setAllTracks, spliceTracks]
  );
 
  const isItemLoaded = useCallback(
    (index: number) => {
      return !!allTracks?.[index]?.name;
    },
    [allTracks]
  );
 
  const loadMoreRows = useCallback(
    async ({ startIndex }: IndexRange) => {
      Iif (isGeneratedPlaylist) return;
      const data = isLibrary
        ? await getMyLikedSongs(50, startIndex)
        : await getTracksFromPlaylist(
            getIdFromUri(pageDetails?.uri, "id") ?? "",
            startIndex
          );
      const items = data?.items;
      const tracks = mapPlaylistItems(items, startIndex);
      Iif (!tracks) return;
      const trackIds = tracks.map((track) => track.id ?? "");
      const tracksInLibrary = await checkTracksInLibrary(trackIds);
      addTracksToPlaylists(tracks, tracksInLibrary, startIndex);
    },
    [addTracksToPlaylists, isGeneratedPlaylist, isLibrary, pageDetails?.uri]
  );
 
  return (
    <VirtualizedList
      items={allTracks}
      totalItems={pageDetails?.tracks?.total ?? allTracks?.length ?? 0}
      itemHeight={65}
      loadMoreItems={loadMoreRows}
      isItemLoaded={isItemLoaded}
      renderItem={({ key, style, item: track }) => (
        <CardTrack
          key={key}
          style={style}
          track={track}
          playlistUri={pageDetails?.uri ?? ""}
          isTrackInLibrary={tracksInLibrary?.[track?.position ?? -1]}
          isSingleTrack={isGeneratedPlaylist}
          type={type}
          position={track?.position}
        />
      )}
    />
  );
}