mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 16:05:18 +00:00
fixed useTrackReaction & usePlaylistReaction mutation bugs... handleSpotifyError bug fixed
This commit is contained in:
parent
5a1da660a1
commit
2d42bbd23d
@ -5,10 +5,11 @@ import { QueryCacheKeys } from "../conf";
|
|||||||
import playerContext from "../context/playerContext";
|
import playerContext from "../context/playerContext";
|
||||||
import useSpotifyInfiniteQuery from "../hooks/useSpotifyInfiniteQuery";
|
import useSpotifyInfiniteQuery from "../hooks/useSpotifyInfiniteQuery";
|
||||||
import useSpotifyQuery from "../hooks/useSpotifyQuery";
|
import useSpotifyQuery from "../hooks/useSpotifyQuery";
|
||||||
|
import { GenreView } from "./PlaylistGenreView";
|
||||||
import { PlaylistSimpleControls, TrackTableIndex } from "./PlaylistView";
|
import { PlaylistSimpleControls, TrackTableIndex } from "./PlaylistView";
|
||||||
import PlaceholderApplet from "./shared/PlaceholderApplet";
|
import PlaceholderApplet from "./shared/PlaceholderApplet";
|
||||||
import PlaylistCard from "./shared/PlaylistCard";
|
import PlaylistCard from "./shared/PlaylistCard";
|
||||||
import { TrackButton } from "./shared/TrackButton";
|
import { TrackButton, TrackButtonPlaylistObject } from "./shared/TrackButton";
|
||||||
import { TabMenuItem } from "./TabMenu";
|
import { TabMenuItem } from "./TabMenu";
|
||||||
|
|
||||||
function Library() {
|
function Library() {
|
||||||
@ -32,21 +33,36 @@ function Library() {
|
|||||||
export default Library;
|
export default Library;
|
||||||
|
|
||||||
function UserPlaylists() {
|
function UserPlaylists() {
|
||||||
const { data: userPlaylists, isError, isLoading, refetch } = useSpotifyQuery<SpotifyApi.PlaylistObjectSimplified[]>(QueryCacheKeys.userPlaylists, (spotifyApi) =>
|
const { data: userPagedPlaylists, isError, isLoading, refetch, isFetchingNextPage, hasNextPage, fetchNextPage } = useSpotifyInfiniteQuery<SpotifyApi.ListOfUsersPlaylistsResponse>(
|
||||||
spotifyApi.getUserPlaylists().then((userPlaylists) => {
|
QueryCacheKeys.userPlaylists,
|
||||||
return userPlaylists.body.items;
|
(spotifyApi, { pageParam }) =>
|
||||||
})
|
spotifyApi.getUserPlaylists({ limit: 20, offset: pageParam }).then((userPlaylists) => {
|
||||||
|
return userPlaylists.body;
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
getNextPageParam(lastPage) {
|
||||||
|
if (lastPage.next) {
|
||||||
|
return lastPage.offset + lastPage.limit;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const userPlaylists = userPagedPlaylists?.pages
|
||||||
|
?.map((playlist) => playlist.items)
|
||||||
|
.filter(Boolean)
|
||||||
|
.flat(1) as SpotifyApi.PlaylistObjectSimplified[];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollArea style="flex: 1; border: none;">
|
<GenreView
|
||||||
<View style="flex: 1; flex-direction: 'row'; flex-wrap: 'wrap'; justify-content: 'space-evenly'; width: 330px; align-items: 'center';">
|
heading="User Playlists"
|
||||||
<PlaceholderApplet error={isError} loading={isLoading} message="Failed querying spotify" reload={refetch} />
|
isError={isError}
|
||||||
{userPlaylists?.map((playlist, index) => (
|
isLoading={isLoading}
|
||||||
<PlaylistCard key={index + playlist.id} playlist={playlist} />
|
playlists={userPlaylists ?? []}
|
||||||
))}
|
isLoadable={!isFetchingNextPage}
|
||||||
</View>
|
refetch={refetch}
|
||||||
</ScrollArea>
|
loadMore={hasNextPage ? ()=>fetchNextPage() : undefined}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,19 +96,11 @@ function UserSavedTracks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const playlist: SpotifyApi.PlaylistObjectFull = {
|
const playlist: TrackButtonPlaylistObject = {
|
||||||
collaborative: false,
|
collaborative: false,
|
||||||
description: "User Playlist",
|
description: "User Playlist",
|
||||||
tracks: {
|
tracks: {
|
||||||
items: [userTracks ?? []].map(
|
items: userTracks ?? [],
|
||||||
(userTrack) =>
|
|
||||||
(({
|
|
||||||
...userTrack,
|
|
||||||
added_by: "Me",
|
|
||||||
is_local: false,
|
|
||||||
added_at: Date.now(),
|
|
||||||
} as unknown) as SpotifyApi.PlaylistTrackObject)
|
|
||||||
),
|
|
||||||
limit: 20,
|
limit: 20,
|
||||||
href: "",
|
href: "",
|
||||||
next: "",
|
next: "",
|
||||||
@ -101,10 +109,9 @@ function UserSavedTracks() {
|
|||||||
total: 20,
|
total: 20,
|
||||||
},
|
},
|
||||||
external_urls: { spotify: "" },
|
external_urls: { spotify: "" },
|
||||||
followers: { href: null, total: 2 },
|
|
||||||
href: "",
|
href: "",
|
||||||
id: userSavedPlaylistId,
|
id: userSavedPlaylistId,
|
||||||
images: [],
|
images: [{ url: "https://facebook.com/img.jpeg" }],
|
||||||
name: "User saved track",
|
name: "User saved track",
|
||||||
owner: { external_urls: { spotify: "" }, href: "", id: "Me", type: "user", uri: "spotify:user:me", display_name: "User", followers: { href: null, total: 0 } },
|
owner: { external_urls: { spotify: "" }, href: "", id: "Me", type: "user", uri: "spotify:user:me", display_name: "User", followers: { href: null, total: 0 } },
|
||||||
public: false,
|
public: false,
|
||||||
|
@ -5,26 +5,27 @@ import playerContext from "../../context/playerContext";
|
|||||||
import { msToMinAndSec } from "../../helpers/msToMin:sec";
|
import { msToMinAndSec } from "../../helpers/msToMin:sec";
|
||||||
import useTrackReaction from "../../hooks/useTrackReaction";
|
import useTrackReaction from "../../hooks/useTrackReaction";
|
||||||
import { heart, heartRegular, pause, play } from "../../icons";
|
import { heart, heartRegular, pause, play } from "../../icons";
|
||||||
import { audioPlayer } from "../Player";
|
|
||||||
import IconButton from "./IconButton";
|
import IconButton from "./IconButton";
|
||||||
|
|
||||||
|
export interface TrackButtonPlaylistObject extends SpotifyApi.PlaylistBaseObject {
|
||||||
|
follower?: SpotifyApi.FollowersObject;
|
||||||
|
tracks: SpotifyApi.PagingObject<SpotifyApi.SavedTrackObject | SpotifyApi.PlaylistTrackObject>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface TrackButtonProps {
|
export interface TrackButtonProps {
|
||||||
track: SpotifyApi.TrackObjectFull;
|
track: SpotifyApi.TrackObjectFull;
|
||||||
playlist?: SpotifyApi.PlaylistObjectFull;
|
playlist?: TrackButtonPlaylistObject;
|
||||||
index: number;
|
index: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TrackButton: FC<TrackButtonProps> = ({ track, index, playlist }) => {
|
export const TrackButton: FC<TrackButtonProps> = ({ track, index, playlist }) => {
|
||||||
const { reactToTrack, isFavorite } = useTrackReaction();
|
const { reactToTrack, isFavorite } = useTrackReaction();
|
||||||
const { currentPlaylist, setCurrentPlaylist, setCurrentTrack, currentTrack } = useContext(playerContext);
|
const { currentPlaylist, setCurrentPlaylist, setCurrentTrack, currentTrack } = useContext(playerContext);
|
||||||
const handlePlaylistPlayPause = (index?: number) => {
|
const handlePlaylistPlayPause = (index: number) => {
|
||||||
if (currentPlaylist?.id !== playlist?.id && playlist?.tracks) {
|
if (playlist && currentPlaylist?.id !== playlist.id) {
|
||||||
setCurrentPlaylist({ id: playlist.id, name: playlist.name, thumbnail: playlist.images[0].url, tracks: playlist.tracks.items });
|
const globalPlaylistObj = { id: playlist.id, name: playlist.name, thumbnail: playlist.images[0].url, tracks: playlist.tracks.items };
|
||||||
setCurrentTrack(playlist.tracks.items[index ?? 0].track);
|
setCurrentPlaylist(globalPlaylistObj);
|
||||||
} else {
|
setCurrentTrack(playlist.tracks.items[index].track);
|
||||||
audioPlayer.stop().catch((error) => console.error("Failed to stop audio player: ", error));
|
|
||||||
setCurrentTrack(undefined);
|
|
||||||
setCurrentPlaylist(undefined);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -36,7 +37,7 @@ export const TrackButton: FC<TrackButtonProps> = ({ track, index, playlist }) =>
|
|||||||
const active = (currentPlaylist?.id === playlist?.id && currentTrack?.id === track.id) || currentTrack?.id === track.id;
|
const active = (currentPlaylist?.id === playlist?.id && currentTrack?.id === track.id) || currentTrack?.id === track.id;
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
id={active?"active":"track-button"}
|
id={active ? "active" : "track-button"}
|
||||||
styleSheet={trackButtonStyle}
|
styleSheet={trackButtonStyle}
|
||||||
on={{
|
on={{
|
||||||
MouseButtonRelease(native: any) {
|
MouseButtonRelease(native: any) {
|
||||||
|
@ -1,21 +1,44 @@
|
|||||||
import { useQueryClient } from "react-query";
|
import { InfiniteData, useQueryClient } from "react-query";
|
||||||
import { QueryCacheKeys } from "../conf";
|
import { QueryCacheKeys } from "../conf";
|
||||||
|
import useSpotifyInfiniteQuery from "./useSpotifyInfiniteQuery";
|
||||||
import useSpotifyMutation from "./useSpotifyMutation";
|
import useSpotifyMutation from "./useSpotifyMutation";
|
||||||
import useSpotifyQuery from "./useSpotifyQuery";
|
|
||||||
|
|
||||||
function usePlaylistReaction() {
|
function usePlaylistReaction() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const { data: favoritePlaylists } = useSpotifyQuery<SpotifyApi.PlaylistObjectSimplified[]>(QueryCacheKeys.userPlaylists, (spotifyApi) =>
|
const { data: favoritePagedPlaylists } = useSpotifyInfiniteQuery<SpotifyApi.ListOfUsersPlaylistsResponse>(QueryCacheKeys.userPlaylists, (spotifyApi, { pageParam }) =>
|
||||||
spotifyApi.getUserPlaylists().then((userPlaylists) => userPlaylists.body.items)
|
spotifyApi.getUserPlaylists({ limit: 20, offset: pageParam }).then((userPlaylists) => {
|
||||||
|
return userPlaylists.body;
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
const favoritePlaylists = favoritePagedPlaylists?.pages
|
||||||
|
.map((playlist) => playlist.items)
|
||||||
|
.filter(Boolean)
|
||||||
|
.flat(1) as SpotifyApi.PlaylistObjectSimplified[];
|
||||||
|
|
||||||
|
function updateFunction(playlist: SpotifyApi.PlaylistObjectSimplified, old?: InfiniteData<SpotifyApi.ListOfUsersPlaylistsResponse>): InfiniteData<SpotifyApi.ListOfUsersPlaylistsResponse> {
|
||||||
|
const obj: typeof old = {
|
||||||
|
pageParams: old?.pageParams ?? [],
|
||||||
|
pages:
|
||||||
|
old?.pages.map(
|
||||||
|
(oldPage, index): SpotifyApi.ListOfUsersPlaylistsResponse => {
|
||||||
|
const isPlaylistFavorite = isFavorite(playlist.id);
|
||||||
|
if (index === 0 && !isPlaylistFavorite) {
|
||||||
|
return { ...oldPage, items: [...oldPage.items, playlist] };
|
||||||
|
} else if (isPlaylistFavorite) {
|
||||||
|
return { ...oldPage, items: oldPage.items.filter((oldPlaylist) => oldPlaylist.id !== playlist.id) };
|
||||||
|
}
|
||||||
|
return oldPage;
|
||||||
|
}
|
||||||
|
) ?? [],
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
const { mutate: reactToPlaylist } = useSpotifyMutation<{}, SpotifyApi.PlaylistObjectSimplified>(
|
const { mutate: reactToPlaylist } = useSpotifyMutation<{}, SpotifyApi.PlaylistObjectSimplified>(
|
||||||
(spotifyApi, { id }) => spotifyApi[isFavorite(id) ? "unfollowPlaylist" : "followPlaylist"](id).then((res) => res.body),
|
(spotifyApi, { id }) => spotifyApi[isFavorite(id) ? "unfollowPlaylist" : "followPlaylist"](id).then((res) => res.body),
|
||||||
{
|
{
|
||||||
onSuccess(_, playlist) {
|
onSuccess(_, playlist) {
|
||||||
queryClient.setQueryData<SpotifyApi.PlaylistObjectSimplified[]>(
|
queryClient.setQueryData<InfiniteData<SpotifyApi.ListOfUsersPlaylistsResponse>>(QueryCacheKeys.userPlaylists, (old) => updateFunction(playlist, old));
|
||||||
QueryCacheKeys.userPlaylists,
|
|
||||||
isFavorite(playlist.id) ? (old) => (old ?? []).filter((oldPlaylist) => oldPlaylist.id !== playlist.id) : (old) => [...(old ?? []), playlist]
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -7,17 +7,23 @@ import showError from "../helpers/showError";
|
|||||||
function useSpotifyApiError(spotifyApi: SpotifyWebApi) {
|
function useSpotifyApiError(spotifyApi: SpotifyWebApi) {
|
||||||
const { setAccess_token, isLoggedIn } = useContext(authContext);
|
const { setAccess_token, isLoggedIn } = useContext(authContext);
|
||||||
return async (error: any | Error | TypeError) => {
|
return async (error: any | Error | TypeError) => {
|
||||||
if ((error.message === "Unauthorized" && error.status === 401 && isLoggedIn) || (error.body.error.message === "No token provided" && error.body.error.status===401)) {
|
const isUnauthorized = error.message === "Unauthorized";
|
||||||
|
const status401 = error.status === 401;
|
||||||
|
const bodyStatus401 = error.body.error.status === 401;
|
||||||
|
const noToken = error.body.error.message === "No token provided";
|
||||||
|
const expiredToken = error.body.error.message === "The access token expired";
|
||||||
|
if ((isUnauthorized && isLoggedIn && status401) || ((noToken || expiredToken) && bodyStatus401)) {
|
||||||
try {
|
try {
|
||||||
console.log(chalk.bgYellow.blackBright("Refreshing Access token"))
|
console.log(chalk.bgYellow.blackBright("Refreshing Access token"));
|
||||||
const { body:{access_token: refreshedAccessToken}} = await spotifyApi.refreshAccessToken();
|
const {
|
||||||
|
body: { access_token: refreshedAccessToken },
|
||||||
|
} = await spotifyApi.refreshAccessToken();
|
||||||
setAccess_token(refreshedAccessToken);
|
setAccess_token(refreshedAccessToken);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(error, "[Authorization Failure]: ")
|
showError(error, "[Authorization Failure]: ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default useSpotifyApiError;
|
export default useSpotifyApiError;
|
@ -1,8 +1,7 @@
|
|||||||
import { useQueryClient } from "react-query";
|
import { InfiniteData, useQueryClient } from "react-query";
|
||||||
import { QueryCacheKeys } from "../conf";
|
import { QueryCacheKeys } from "../conf";
|
||||||
import useSpotifyInfiniteQuery from "./useSpotifyInfiniteQuery";
|
import useSpotifyInfiniteQuery from "./useSpotifyInfiniteQuery";
|
||||||
import useSpotifyMutation from "./useSpotifyMutation";
|
import useSpotifyMutation from "./useSpotifyMutation";
|
||||||
import useSpotifyQuery from "./useSpotifyQuery";
|
|
||||||
|
|
||||||
function useTrackReaction() {
|
function useTrackReaction() {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
@ -13,14 +12,31 @@ function useTrackReaction() {
|
|||||||
?.map((page) => page.items)
|
?.map((page) => page.items)
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.flat(1) as SpotifyApi.SavedTrackObject[] | undefined;
|
.flat(1) as SpotifyApi.SavedTrackObject[] | undefined;
|
||||||
|
|
||||||
|
function updateFunction(track: SpotifyApi.SavedTrackObject, old?: InfiniteData<SpotifyApi.UsersSavedTracksResponse>): InfiniteData<SpotifyApi.UsersSavedTracksResponse> {
|
||||||
|
const obj: typeof old = {
|
||||||
|
pageParams: old?.pageParams ?? [],
|
||||||
|
pages:
|
||||||
|
old?.pages.map(
|
||||||
|
(oldPage, index): SpotifyApi.UsersSavedTracksResponse => {
|
||||||
|
const isTrackFavorite = isFavorite(track.track.id);
|
||||||
|
if (index === 0 && !isTrackFavorite) {
|
||||||
|
return { ...oldPage, items: [...oldPage.items, track] };
|
||||||
|
} else if (isTrackFavorite) {
|
||||||
|
return { ...oldPage, items: oldPage.items.filter((oldTrack) => oldTrack.track.id !== track.track.id) };
|
||||||
|
}
|
||||||
|
return oldPage;
|
||||||
|
}
|
||||||
|
) ?? [],
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
const { mutate: reactToTrack } = useSpotifyMutation<{}, SpotifyApi.SavedTrackObject>(
|
const { mutate: reactToTrack } = useSpotifyMutation<{}, SpotifyApi.SavedTrackObject>(
|
||||||
(spotifyApi, { track }) => spotifyApi[isFavorite(track.id) ? "removeFromMySavedTracks" : "addToMySavedTracks"]([track.id]).then((res) => res.body),
|
(spotifyApi, { track }) => spotifyApi[isFavorite(track.id) ? "removeFromMySavedTracks" : "addToMySavedTracks"]([track.id]).then((res) => res.body),
|
||||||
{
|
{
|
||||||
onSuccess(_, track) {
|
onSuccess(_, track) {
|
||||||
queryClient.setQueryData<SpotifyApi.SavedTrackObject[]>(
|
queryClient.setQueryData<InfiniteData<SpotifyApi.UsersSavedTracksResponse>>(QueryCacheKeys.userSavedTracks, (old) => updateFunction(track, old));
|
||||||
QueryCacheKeys.userSavedTracks,
|
|
||||||
isFavorite(track.track.id) ? (old) => (old ?? []).filter((oldTrack) => oldTrack.track.id !== track.track.id) : (old) => [...(old ?? []), track]
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user