diff --git a/app/components/DiscoverTracks/ArtistType.tsx b/app/components/DiscoverTracks/ArtistType.tsx index fa085f2..119b8e2 100644 --- a/app/components/DiscoverTracks/ArtistType.tsx +++ b/app/components/DiscoverTracks/ArtistType.tsx @@ -66,8 +66,8 @@ const ArtistType = () => { {artistArray.map((value, index) => ( -
handleArtistDelete(e, index)}> @@ -77,7 +77,7 @@ const ArtistType = () => { icon='iconoir:cancel' className='text-lightest w-4 h-4' /> -
+ ))}
)} diff --git a/app/components/DiscoverTracks/ChangeType.tsx b/app/components/DiscoverTracks/ChangeType.tsx index e867e7e..4e15b55 100644 --- a/app/components/DiscoverTracks/ChangeType.tsx +++ b/app/components/DiscoverTracks/ChangeType.tsx @@ -9,20 +9,20 @@ const ChangeType = () => { return (
-

setType('artist')} className={`${ type === 'artist' ? 'bg-brand text-lightest' : 'text-darkest' } w-1/2 text-center text-fsm py-1 rounded-l cursor-pointer`}> Artist -

-

+

); }; diff --git a/app/components/DiscoverTracks/SubmitButtion.tsx b/app/components/DiscoverTracks/SubmitButtion.tsx index 00b992a..5cb91ee 100644 --- a/app/components/DiscoverTracks/SubmitButtion.tsx +++ b/app/components/DiscoverTracks/SubmitButtion.tsx @@ -1,16 +1,17 @@ 'use client'; import { - addTracksToPlayList, - createPlayList, - getAllTracksInAPlaylist, -} from '@/app/lib/spotify'; -import { + addToUrl, extractPlaylistId, getAllTracks, getEveryAlbum, isValidPlaylistLink, } from '@/app/lib/utils'; +import { + addTracksToPlayList, + createPlayList, + getAllTracksInAPlaylist, +} from '@/app/lib/spotify'; import { GoogleGenerativeAI } from '@google/generative-ai'; import React from 'react'; @@ -61,7 +62,7 @@ const SubmitButtion = () => { setLoadingMessage(`Getting the list of new artists`); const result = await model.generateContent(prompt); - ``; + const response = await result.response; const text = response.text(); @@ -71,7 +72,7 @@ const SubmitButtion = () => { const finalList = lastPart ? lastPart.split(', ') : []; - finalList.length > 20 ? (finalList.length = 20) : null; + finalList.length > 20 && (finalList.length = 20); setLoadingMessage(`Getting the albums of each artist`); const albums = await getEveryAlbum(finalList); @@ -97,7 +98,10 @@ const SubmitButtion = () => { if (tracks === null) throw new Error('Track is empty'); addTracksToPlayList(tracks, playListID) - .then(() => setPlayListData({ link, name })) + .then(() => { + addToUrl('link', link.split('/').at(-1) as string); + setPlayListData({ link, name }); + }) .catch((err) => { return err; }); diff --git a/app/components/Header.tsx b/app/components/Header.tsx index a52be98..03da789 100644 --- a/app/components/Header.tsx +++ b/app/components/Header.tsx @@ -160,7 +160,7 @@ const Header = () => { SignOut )} -
{isDarkMode ? ( @@ -171,7 +171,7 @@ const Header = () => { className='w-3 h-4 sm:w-6 sm:h-6' /> )} -
+ ([]); + const { playListData } = useGeneralState(); const handleClick = () => { setOpenPlaylist(!openPlaylist); }; - const handleCheckboxChange = (id: string) => { - setSelectedTracksToRestore((prevSelectedTracks) => { - if (prevSelectedTracks.includes(id)) { - return prevSelectedTracks.filter((trackId) => trackId !== id); - } else { - return [...prevSelectedTracks, id]; - } - }); - }; - return ( <>
@@ -65,118 +42,10 @@ function OpenOnSpotify({ link }: { link: string }) {
- {openPlaylist && ( -
-
-
-

Edit Playlist Generated

- -
-
    - {showingTracks.map(({ id, name, artist, image }) => { - return ( -
  • -
    -
    - {name -
    -
    -

    {name}

    -

    - {artist.join(', ')} -

    -
    -
    - -
  • - ); - })} -
- {startedEditing && ( -
-
- - -
- {restoreOption && ( -
- {tracksDeleted.length > 0 && ( -
- - {selectedTracksToRestore.length > 0 && ( - - )} -
- )} -
- {tracksDeleted.map(({ name, id, artist }) => { - return ( - - ); - })} -
-
- )} -
- )} -
-
- )} + + {openPlaylist && } + ); }; diff --git a/app/components/OpenOnSpotify/DeleteOptions.tsx b/app/components/OpenOnSpotify/DeleteOptions.tsx new file mode 100644 index 0000000..d8c527b --- /dev/null +++ b/app/components/OpenOnSpotify/DeleteOptions.tsx @@ -0,0 +1,37 @@ +import { Icon } from '@iconify/react/dist/iconify.js'; +import { usePlaylistView } from '@/app/context/PlaylistViewContext'; + +type DeleteOptionsTypes = { + restoreOption: boolean; + toggleRestoreOption: () => void; +}; + +const DeleteOptions = ({ + restoreOption, + toggleRestoreOption, +}: DeleteOptionsTypes) => { + const { saveTracks, loading } = usePlaylistView(); + + return ( +
+ + +
+ ); +}; + +export default DeleteOptions; diff --git a/app/components/OpenOnSpotify/OpenPlaylist.tsx b/app/components/OpenOnSpotify/OpenPlaylist.tsx new file mode 100644 index 0000000..3e688f8 --- /dev/null +++ b/app/components/OpenOnSpotify/OpenPlaylist.tsx @@ -0,0 +1,27 @@ +import { Icon } from '@iconify/react/dist/iconify.js'; +import { PlaylistViewProvider } from '@/app/context/PlaylistViewContext'; +import StartedEditing from './StartedEditing'; +import TrackList from './TrackList'; + +const OpenPlaylist = ({ handleClick }: { handleClick: () => void }) => { + return ( + +
+
+
+

Edit Playlist Generated

+ + +
+ + +
+
+
+ ); +}; + +export default OpenPlaylist; diff --git a/app/components/OpenOnSpotify/RestoreOptions.tsx b/app/components/OpenOnSpotify/RestoreOptions.tsx new file mode 100644 index 0000000..65a4282 --- /dev/null +++ b/app/components/OpenOnSpotify/RestoreOptions.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { usePlaylistView } from '@/app/context/PlaylistViewContext'; + +type RestoreOptionsTypes = { + selectedTracksToRestore: string[]; + handleRestoreSelected: () => void; +}; + +const RestoreOptions = ({ + selectedTracksToRestore, + handleRestoreSelected, +}: RestoreOptionsTypes) => { + const { restoreAllTracks } = usePlaylistView(); + + return ( +
+ + {selectedTracksToRestore.length > 0 && ( + + )} +
+ ); +}; + +export default RestoreOptions; diff --git a/app/components/OpenOnSpotify/StartedEditing.tsx b/app/components/OpenOnSpotify/StartedEditing.tsx new file mode 100644 index 0000000..ab47a6c --- /dev/null +++ b/app/components/OpenOnSpotify/StartedEditing.tsx @@ -0,0 +1,62 @@ +import DeleteOptions from './DeleteOptions'; +import RestoreOptions from './RestoreOptions'; +import { usePlaylistView } from '@/app/context/PlaylistViewContext'; +import useRestoreSongs from '@/app/hooks/useRestoreSongs'; + +const StartedEditing = () => { + const { tracksDeleted, startedEditing } = usePlaylistView(); + const { + restoreOption, + toggleRestoreOption, + selectedTracksToRestore, + handleRestoreSelected, + handleCheckboxChange, + } = useRestoreSongs(); + + return ( + startedEditing && ( +
+ + {restoreOption && ( +
+ {tracksDeleted.length > 0 && ( + + )} +
+ {tracksDeleted.map(({ name, id, artist }) => { + return ( + + ); + })} +
+
+ )} +
+ ) + ); +}; + +export default StartedEditing; diff --git a/app/components/OpenOnSpotify/TrackList.tsx b/app/components/OpenOnSpotify/TrackList.tsx new file mode 100644 index 0000000..64a2a9b --- /dev/null +++ b/app/components/OpenOnSpotify/TrackList.tsx @@ -0,0 +1,16 @@ +import TrackListItem from './TrackListItem'; +import { usePlaylistView } from '@/app/context/PlaylistViewContext'; + +const TrackList = () => { + const { showingTracks } = usePlaylistView(); + + return ( + + ); +}; + +export default TrackList; diff --git a/app/components/OpenOnSpotify/TrackListItem.tsx b/app/components/OpenOnSpotify/TrackListItem.tsx new file mode 100644 index 0000000..b4feb69 --- /dev/null +++ b/app/components/OpenOnSpotify/TrackListItem.tsx @@ -0,0 +1,33 @@ +import { Icon } from '@iconify/react/dist/iconify.js'; +import Image from 'next/image'; +import { playlistSongDetails } from '@/app/types'; +import { usePlaylistView } from '@/app/context/PlaylistViewContext'; + +const TrackListItem = ({ item }: { item: playlistSongDetails }) => { + const { artist, id, name, image } = item; + const { deleteTrack } = usePlaylistView(); + + return ( +
  • +
    +
    + {name +
    +
    +

    {name}

    +

    + {artist.join(', ')} +

    +
    +
    + +
  • + ); +}; + +export default TrackListItem; diff --git a/app/components/ResultLink.tsx b/app/components/ResultLink.tsx index 84f3739..0db08c2 100644 --- a/app/components/ResultLink.tsx +++ b/app/components/ResultLink.tsx @@ -1,20 +1,30 @@ 'use client'; +import React, { useEffect } from 'react'; + import OpenOnSpotify from './OpenOnSpotify'; -import React from 'react'; +import { getFromUrl } from '../lib/utils'; import { useGeneralState } from '@/app/context/generalStateContext'; import { useLoading } from '@/app/context/loadingContext'; const ResultLink = () => { const { loading } = useLoading(); - const { playListData, errorMessages } = useGeneralState(); + const { playListData, errorMessages, setPlayListData } = useGeneralState(); + + useEffect(() => { + const link = getFromUrl('link'); + link && + setPlayListData({ + ...playListData, + link: 'https://open.spotify.com/playlist/' + link, + }); + }, []); + return ( !loading && (
    - {playListData.link.length !== 0 && playListData.name.length !== 0 ? ( - <> - - + {playListData.link.length !== 0 ? ( + ) : (

    {errorMessages.error !== null && errorMessages.error} diff --git a/app/components/TopTracks/ArtistInput.tsx b/app/components/TopTracks/ArtistInput.tsx index 427fe3f..43e738e 100644 --- a/app/components/TopTracks/ArtistInput.tsx +++ b/app/components/TopTracks/ArtistInput.tsx @@ -52,15 +52,15 @@ const ArtistInput = () => { {artistArray.map((value, index) => ( -

    handleArtistDelete(e, index)}> {value} -
    + ))} )} diff --git a/app/context/DiscoverTracks/typeContext.tsx b/app/context/DiscoverTracks/typeContext.tsx index c22f371..1b62aad 100644 --- a/app/context/DiscoverTracks/typeContext.tsx +++ b/app/context/DiscoverTracks/typeContext.tsx @@ -14,11 +14,16 @@ const TypeContext = createContext(undefined); const TypeProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [type, setType] = useState('artist'); - return ( - - {children} - - ); + const value = React.useMemo( + () => ({ + type, + setType, + }), + [type], + ); + return ( + {children} + ); }; const useType = (): TypeContextProps => { diff --git a/app/context/PlaylistViewContext.tsx b/app/context/PlaylistViewContext.tsx new file mode 100644 index 0000000..6498881 --- /dev/null +++ b/app/context/PlaylistViewContext.tsx @@ -0,0 +1,152 @@ +import React, { + createContext, + useCallback, + useContext, + useEffect, + useMemo, + useState, +} from 'react'; +import { + getAllTracksInAPlaylist, + removeTracksFromPlaylists, +} from '../lib/spotify'; +import { loadingType, playlistSongDetails } from '../types'; + +import { useGeneralState } from '../context/generalStateContext'; + +type PlaylistViewContextType = { + showingTracks: playlistSongDetails[]; + loading: loadingType; + startedEditing: boolean; + tracksDeleted: playlistSongDetails[]; + deleteTrack: (id: string) => void; + restoreAllTracks: () => void; + restoreSelectedTracks: (ids: string[]) => void; + saveTracks: () => void; +}; + +const PlaylistViewContext = createContext( + undefined, +); + +export const usePlaylistView = () => { + const context = useContext(PlaylistViewContext); + if (!context) { + throw new Error( + 'usePlaylistView must be used within a PlaylistViewProvider', + ); + } + return context; +}; + +export const PlaylistViewProvider: React.FC<{ children: React.ReactNode }> = ({ + children, +}) => { + const { playListData } = useGeneralState(); + const link = playListData.link.split('/').at(-1) as string; + + const [loading, setLoading] = useState({ + isLoading: false, + message: null, + }); + const [startedEditing, setStartedEditing] = useState(false); + const [tracks, setTracks] = useState([]); + const [showingTracks, setShowingTracks] = useState([]); + const [tracksToRemove, setTracksToRemove] = useState<{ uri: string }[]>([]); + const [tracksDeleted, setTracksDeleted] = useState([]); + + useEffect(() => { + (async () => { + await getTracks(); + })(); + }, []); + + useEffect(() => { + if (showingTracks.length === 0) { + setShowingTracks(tracks); + } + }, [showingTracks, tracks]); + + const getTracks = useCallback(async () => { + const data = await getAllTracksInAPlaylist(link); + + console.log(data); + const tracks = data.map((item: any) => { + const track = item.track; + const image = track.album.images[1].url; + const artist = track.artists.map((subitem: any) => subitem.name); + return { id: track.id, name: track.name, artist, image }; + }); + + setTracks(tracks); + }, [link]); + + const deleteTrack = useCallback( + (id: string) => { + setStartedEditing(true); + setShowingTracks((prevTracks) => + prevTracks.filter((track) => track.id !== id), + ); + const deletingTrack = tracks.filter((track) => track.id === id)[0]; + + setTracksDeleted((prev) => [...prev, deletingTrack]); + setTracksToRemove((prev) => [...prev, { uri: 'spotify:track:' + id }]); + }, + [tracks], + ); + + const restoreAllTracks = useCallback(() => { + setShowingTracks(tracks); + setStartedEditing(false); + setTracksToRemove([]); + setTracksDeleted([]); + }, [tracks]); + + const restoreSelectedTracks = useCallback( + (ids: string[]) => { + const restoringTracks = tracks.filter((track) => ids.includes(track.id)); + const remainingDeletedTracks = tracksDeleted.filter( + (track) => !ids.includes(track.id), + ); + const TracksToRemove = tracksToRemove.filter( + (track) => !ids.includes(track.uri.split(':').at(-1) as string), + ); + + setTracksToRemove(TracksToRemove); + setTracksDeleted(remainingDeletedTracks); + setShowingTracks((prev) => [...prev, ...restoringTracks]); + }, + [tracks, tracksDeleted, tracksToRemove], + ); + + const saveTracks = useCallback(async () => { + setLoading({ isLoading: true, message: 'Deleting Tracks....' }); + await removeTracksFromPlaylists(link, tracksToRemove); + + await getTracks(); + setLoading({ isLoading: false, message: null }); + setTracksToRemove([]); + setTracksDeleted([]); + setStartedEditing(false); + }, [tracksToRemove]); + + const value = useMemo( + () => ({ + showingTracks, + loading, + startedEditing, + tracksDeleted, + deleteTrack, + restoreAllTracks, + saveTracks, + restoreSelectedTracks, + }), + [showingTracks, loading, startedEditing, tracksDeleted], + ); + + return ( + + {children} + + ); +}; diff --git a/app/context/authContext.tsx b/app/context/authContext.tsx index a92504c..dad04fb 100644 --- a/app/context/authContext.tsx +++ b/app/context/authContext.tsx @@ -1,6 +1,12 @@ 'use client'; -import React, { ReactNode, createContext, useContext, useState } from 'react'; +import React, { + ReactNode, + createContext, + useContext, + useMemo, + useState, +} from 'react'; interface AuthContextProps { isLoggedIn: boolean; @@ -34,12 +40,12 @@ export const AuthProvider: React.FC = ({ children }) => { setAuthInProgress(state); }; - return ( - - {children} - + const value = useMemo( + () => ({ isLoggedIn, logOut, logIn, isAuthInProgress, authInProgress }), + [isLoggedIn, isAuthInProgress], ); + + return {children}; }; export const useAuth = (): AuthContextProps => { diff --git a/app/context/generalStateContext.tsx b/app/context/generalStateContext.tsx index 3faa5e6..f4399a3 100644 --- a/app/context/generalStateContext.tsx +++ b/app/context/generalStateContext.tsx @@ -1,6 +1,12 @@ 'use client'; -import React, { ReactNode, createContext, useContext, useState } from 'react'; +import React, { + ReactNode, + createContext, + useContext, + useMemo, + useState, +} from 'react'; interface PlayListData { link: string; @@ -10,7 +16,7 @@ interface PlayListData { interface ErrorMessages { notCorrectSpotifyLink: boolean; notCorrectFormatForArtist: boolean; - error: null | any; + error: any; } interface GeneralStateContextProps { @@ -40,16 +46,20 @@ const GeneralStateProvider: React.FC<{ children: ReactNode }> = ({ error: null, }); + const value = useMemo( + () => ({ + playListData, + setPlayListData, + buttonClick, + setButtonClicked, + errorMessages, + setErrorMessages, + }), + [playListData, buttonClick, errorMessages], + ); + return ( - + {children} ); diff --git a/app/context/inputContext.tsx b/app/context/inputContext.tsx index 57a7fc4..997f762 100644 --- a/app/context/inputContext.tsx +++ b/app/context/inputContext.tsx @@ -5,6 +5,7 @@ import React, { RefObject, createContext, useContext, + useMemo, useRef, useState, } from 'react'; @@ -23,11 +24,13 @@ const InputProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [artistArray, setArtistArray] = useState([]); const spotifyPlaylist = useRef(null); + const value = useMemo( + () => ({ artistName, artistArray, setArtistArray, spotifyPlaylist }), + [artistArray, artistName, spotifyPlaylist], + ); + return ( - - {children} - + {children} ); }; diff --git a/app/context/loadingContext.tsx b/app/context/loadingContext.tsx index 5ae641f..d945cd4 100644 --- a/app/context/loadingContext.tsx +++ b/app/context/loadingContext.tsx @@ -1,6 +1,12 @@ 'use client'; -import React, { ReactNode, createContext, useContext, useState } from 'react'; +import React, { + ReactNode, + createContext, + useContext, + useMemo, + useState, +} from 'react'; interface LoadingContextProps { loading: boolean; @@ -17,11 +23,13 @@ const LoadingProvider: React.FC<{ children: ReactNode }> = ({ children }) => { const [loading, setLoading] = useState(false); const [loadingMessage, setLoadingMessage] = useState(null); + const value = useMemo( + () => ({ loading, setLoading, loadingMessage, setLoadingMessage }), + [loading, loadingMessage], + ); + return ( - - {children} - + {children} ); }; diff --git a/app/hooks/useRestoreSongs.tsx b/app/hooks/useRestoreSongs.tsx new file mode 100644 index 0000000..edbc455 --- /dev/null +++ b/app/hooks/useRestoreSongs.tsx @@ -0,0 +1,39 @@ +import { usePlaylistView } from '../context/PlaylistViewContext'; +import { useState } from 'react'; + +const useRestoreSongs = () => { + const { restoreSelectedTracks } = usePlaylistView(); + const [selectedTracksToRestore, setSelectedTracksToRestore] = useState< + string[] + >([]); + const [restoreOption, setRestoreOption] = useState(false); + + const handleCheckboxChange = (id: string) => { + setSelectedTracksToRestore((prevSelectedTracks) => { + if (prevSelectedTracks.includes(id)) { + return prevSelectedTracks.filter((trackId) => trackId !== id); + } else { + return [...prevSelectedTracks, id]; + } + }); + }; + + const handleRestoreSelected = () => { + restoreSelectedTracks(selectedTracksToRestore); + setSelectedTracksToRestore([]); + }; + + const toggleRestoreOption = () => { + setRestoreOption(!restoreOption); + }; + + return { + restoreOption, + selectedTracksToRestore, + handleCheckboxChange, + handleRestoreSelected, + toggleRestoreOption, + }; +}; + +export default useRestoreSongs; diff --git a/app/hooks/useViewPlaylist.tsx b/app/hooks/useViewPlaylist.tsx deleted file mode 100644 index b2dd342..0000000 --- a/app/hooks/useViewPlaylist.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import { - getAllTracksInAPlaylist, - removeTracksFromPlaylists, -} from '../lib/spotify'; -import { loadingType, playlistSongDetails } from '../types'; -import { useEffect, useState } from 'react'; - -const useViewPlaylist = ( - link: string, -): { - showingTracks: playlistSongDetails[]; - loading: loadingType; - startedEditing: boolean; - tracksDeleted: playlistSongDetails[]; - deleteTrack: (id: string) => void; - restoreAllTracks: () => void; - restoreSelectedTracks: (ids: string[]) => void; - saveTracks: () => void; -} => { - link = link.split('/').at(-1) as string; - - const [loading, setLoading] = useState({ - isLoading: false, - message: null, - }); - const [startedEditing, setStartedEditing] = useState(false); - const [tracks, setTracks] = useState([]); - const [showingTracks, setShowingTracks] = useState([]); - const [tracksToRemove, setTracksToRemove] = useState<{ uri: string }[]>([]); - const [tracksDeleted, setTracksDeleted] = useState([]); - - useEffect(() => { - (async () => { - await getTracks(); - })(); - }, []); - - useEffect(() => { - if (showingTracks.length === 0) { - setShowingTracks(tracks); - } - }, [tracks]); - - const getTracks = async () => { - const data = await getAllTracksInAPlaylist(link); - - const tracks = data.map((item: any) => { - const track = item.track; - const image = track.album.images[1].url; - const artist = track.artists.map((subitem: any) => subitem.name); - return { id: track.id, name: track.name, artist, image }; - }); - - setTracks(tracks); - }; - - const deleteTrack = (id: string) => { - setStartedEditing(true); - setShowingTracks((prevTracks) => - prevTracks.filter((track) => track.id !== id), - ); - const deletingTrack = tracks.filter((track) => track.id === id)[0]; - setTracksDeleted([...tracksDeleted, deletingTrack]); - setTracksToRemove([...tracksToRemove, { uri: 'spotify:track:' + id }]); - }; - - const restoreAllTracks = () => { - setShowingTracks(tracks); - setStartedEditing(false); - setTracksToRemove([]); - setTracksDeleted([]); - }; - - const restoreSelectedTracks = (ids: string[]) => { - const restoringTracks = tracks.filter((track) => ids.includes(track.id)); - const remainingDeletedTracks = tracksDeleted.filter( - (track) => !ids.includes(track.id), - ); - const TracksToRemove = tracksToRemove.filter((track) => - ids.includes(track.uri.split(':').at(-1) as string), - ); - - setTracksToRemove(TracksToRemove); - setTracksDeleted(remainingDeletedTracks); - setShowingTracks([...showingTracks, ...restoringTracks]); - }; - - const saveTracks = async () => { - setLoading({ isLoading: true, message: 'Deleting Tracks....' }); - removeTracksFromPlaylists(link, tracksToRemove); - - await getTracks(); - setLoading({ isLoading: false, message: null }); - setTracksToRemove([]); - setTracksDeleted([]); - setStartedEditing(false); - }; - - return { - showingTracks, - loading, - startedEditing, - deleteTrack, - restoreAllTracks, - saveTracks, - restoreSelectedTracks, - tracksDeleted, - }; -}; - -export default useViewPlaylist; diff --git a/app/lib/utils.ts b/app/lib/utils.ts index 912cd1b..0450e88 100644 --- a/app/lib/utils.ts +++ b/app/lib/utils.ts @@ -94,6 +94,17 @@ export const copyToClipboard = async (textToCopy: string) => { } }; +export const addToUrl = (key: string, value: string) => { + const searchParams = new URLSearchParams(window.location.search); + searchParams.set(key, value); + const newUrl = `${window.location.pathname}?${searchParams.toString()}`; + window.history.pushState({}, '', newUrl); +}; + +export const getFromUrl = (key: string) => { + const searchParams = new URLSearchParams(window.location.search); + return searchParams.get(key); +}; // export const getAllTracks = async (albums) => { // const getAlbumTracks = albums.map(getOneAlbumTrack) // const tracks = await Promise.all(getAlbumTracks);