artists.ts 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import { AxiosInstance, AxiosResponse } from 'axios';
  2. import { useCallback, useEffect, useState } from 'react';
  3. import { Song } from '../../types/songs';
  4. import { getApiUrl } from '../../utils/url';
  5. import { useRequestCallback } from '../request';
  6. type ArtistsResponse = {
  7. artists: string[];
  8. };
  9. const emptyArtists: string[] = [];
  10. export function useArtists(): ArtistsResponse & {
  11. fetching: boolean;
  12. } {
  13. const sendRequest = useCallback(
  14. (axios: AxiosInstance): Promise<AxiosResponse<ArtistsResponse>> =>
  15. axios.get(`${getApiUrl()}/artists`),
  16. [],
  17. );
  18. const [onFetch, response, fetching] = useRequestCallback<void, ArtistsResponse>({
  19. sendRequest,
  20. });
  21. useEffect(onFetch, [onFetch]);
  22. return { artists: response?.artists ?? emptyArtists, fetching };
  23. }
  24. type ArtistDependencyResponse<K extends string, T> = { artist: string } & { [key in K]: T[] };
  25. function useArtistDependency<K extends string, T>(
  26. key: K,
  27. artist: string,
  28. pause: boolean,
  29. ): [ArtistDependencyResponse<K, T> | null, boolean] {
  30. const sendRequest = useCallback(
  31. (axios: AxiosInstance, query: string): Promise<AxiosResponse<ArtistDependencyResponse<K, T>>> =>
  32. axios.get(`${getApiUrl()}/${key}?artist=${encodeURIComponent(query)}`),
  33. [key],
  34. );
  35. const [onFetch, response, fetching] = useRequestCallback<string, ArtistDependencyResponse<K, T>>({
  36. sendRequest,
  37. });
  38. const [hasLoadedByArtist, setHasLoadedByArtist] = useState<Record<string, boolean>>({});
  39. const hasLoadedThisArtist = !!hasLoadedByArtist[artist];
  40. useEffect(() => {
  41. if (!pause && !hasLoadedThisArtist) {
  42. onFetch(artist);
  43. }
  44. }, [onFetch, pause, hasLoadedThisArtist, artist]);
  45. useEffect(() => {
  46. if (response) {
  47. setHasLoadedByArtist((last) => ({ ...last, [response.artist]: true }));
  48. }
  49. }, [response]);
  50. return [response, fetching];
  51. }
  52. export function useArtistsAlbumsAndSongs(
  53. artist: string,
  54. pauseAlbums: boolean,
  55. pauseSongs: boolean,
  56. ): {
  57. albums: ArtistDependencyResponse<'albums', string> | null;
  58. songs: ArtistDependencyResponse<'songs', Song> | null;
  59. fetchingAlbums: boolean;
  60. fetchingSongs: boolean;
  61. } {
  62. const [albums, fetchingAlbums] = useArtistDependency<'albums', string>(
  63. 'albums',
  64. artist,
  65. pauseAlbums,
  66. );
  67. const [songs, fetchingSongs] = useArtistDependency<'songs', Song>('songs', artist, pauseSongs);
  68. return {
  69. albums,
  70. songs,
  71. fetchingAlbums,
  72. fetchingSongs,
  73. };
  74. }