From 3e5a8ac78dae25bbf10576b553888cf1ef607c60 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sat, 4 Apr 2026 22:25:21 -0700 Subject: [PATCH] re-add default suspense to album/artist routes --- .../albums/routes/album-detail-route.tsx | 19 ++++------- .../routes/dummy-album-detail-route.tsx | 6 ++-- ...rtist-detail-favorite-songs-list-route.tsx | 32 +++++++++---------- ...bum-artist-detail-top-songs-list-route.tsx | 7 ++-- .../components/playlist-query-editor.tsx | 5 +-- .../playlist-detail-song-list-route.tsx | 12 +++---- .../shared/components/animated-page.tsx | 2 +- src/renderer/layouts/default-layout.tsx | 8 +---- .../layouts/mobile-layout/mobile-layout.tsx | 7 ++-- 9 files changed, 42 insertions(+), 56 deletions(-) diff --git a/src/renderer/features/albums/routes/album-detail-route.tsx b/src/renderer/features/albums/routes/album-detail-route.tsx index 051b45e4c..4633f8879 100644 --- a/src/renderer/features/albums/routes/album-detail-route.tsx +++ b/src/renderer/features/albums/routes/album-detail-route.tsx @@ -1,6 +1,6 @@ -import { useQuery } from '@tanstack/react-query'; +import { useSuspenseQuery } from '@tanstack/react-query'; import { useRef } from 'react'; -import { useLocation, useParams } from 'react-router'; +import { useParams } from 'react-router'; import { useItemImageUrl } from '/@/renderer/components/item-image/item-image'; import { NativeScrollArea } from '/@/renderer/components/native-scroll-area/native-scroll-area'; @@ -16,7 +16,7 @@ import { LibraryContainer } from '/@/renderer/features/shared/components/library import { LibraryHeaderBar } from '/@/renderer/features/shared/components/library-header-bar'; import { PageErrorBoundary } from '/@/renderer/features/shared/components/page-error-boundary'; import { useFastAverageColor } from '/@/renderer/hooks'; -import { useAlbumBackground, useCurrentServer } from '/@/renderer/store'; +import { useAlbumBackground, useCurrentServerId } from '/@/renderer/store'; import { LibraryItem } from '/@/shared/types/domain-types'; const ALBUM_DETAIL_BG_FALLBACK = 'var(--theme-colors-foreground-muted)'; @@ -27,13 +27,10 @@ const AlbumDetailRoute = () => { const { albumBackground, albumBackgroundBlur } = useAlbumBackground(); const { albumId } = useParams() as { albumId: string }; - const server = useCurrentServer(); + const serverId = useCurrentServerId(); - const location = useLocation(); - - const detailQuery = useQuery({ - ...albumQueries.detail({ query: { id: albumId }, serverId: server?.id }), - placeholderData: location.state?.item, + const detailQuery = useSuspenseQuery({ + ...albumQueries.detail({ query: { id: albumId }, serverId }), }); const imageUrl = @@ -65,9 +62,7 @@ const AlbumDetailRoute = () => { itemType={LibraryItem.ALBUM} variant="default" /> - - {detailQuery?.data?.name} - + {detailQuery.data.name} ), offset: 200, diff --git a/src/renderer/features/albums/routes/dummy-album-detail-route.tsx b/src/renderer/features/albums/routes/dummy-album-detail-route.tsx index 828e7bb69..bf29f326d 100644 --- a/src/renderer/features/albums/routes/dummy-album-detail-route.tsx +++ b/src/renderer/features/albums/routes/dummy-album-detail-route.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query'; +import { useSuspenseQuery } from '@tanstack/react-query'; import { Fragment } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath, Link, useParams } from 'react-router'; @@ -39,7 +39,7 @@ const DummyAlbumDetailRoute = () => { const { albumId } = useParams() as { albumId: string }; const server = useCurrentServer(); const queryKey = queryKeys.songs.detail(server?.id || '', albumId); - const detailQuery = useQuery({ + const detailQuery = useSuspenseQuery({ queryFn: ({ signal }) => { return api.controller.getSongDetail({ apiClientProps: { serverId: server?.id || '', signal }, @@ -52,7 +52,7 @@ const DummyAlbumDetailRoute = () => { const { background, colorId } = useFastAverageColor({ id: albumId, src: detailQuery.data?.imageUrl, - srcLoaded: !detailQuery.isLoading, + srcLoaded: Boolean(detailQuery.data?.imageUrl), }); const { addToQueueByFetch } = usePlayer(); const playButtonBehavior = usePlayButtonBehavior(); diff --git a/src/renderer/features/artists/routes/album-artist-detail-favorite-songs-list-route.tsx b/src/renderer/features/artists/routes/album-artist-detail-favorite-songs-list-route.tsx index 280f89727..9758646f9 100644 --- a/src/renderer/features/artists/routes/album-artist-detail-favorite-songs-list-route.tsx +++ b/src/renderer/features/artists/routes/album-artist-detail-favorite-songs-list-route.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query'; +import { useSuspenseQueries } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useParams } from 'react-router'; @@ -35,20 +35,18 @@ const AlbumArtistDetailFavoriteSongsListRoute = () => { const server = useCurrentServer(); const pageKey = LibraryItem.SONG; - const detailQuery = useQuery( - artistsQueries.albumArtistDetail({ - query: { id: routeId }, - serverId: server?.id, - }), - ); - - const favoriteSongsQuery = useQuery( - artistsQueries.favoriteSongs({ - options: { enabled: !!detailQuery?.data?.name }, - query: { artistId: routeId }, - serverId: server?.id, - }), - ); + const [detailQuery, favoriteSongsQuery] = useSuspenseQueries({ + queries: [ + artistsQueries.albumArtistDetail({ + query: { id: routeId }, + serverId: server?.id, + }), + artistsQueries.favoriteSongs({ + query: { artistId: routeId }, + serverId: server?.id, + }), + ], + }); const songs = useMemo( () => favoriteSongsQuery?.data?.items || [], @@ -168,7 +166,7 @@ const AlbumArtistDetailFavoriteSongsListRoute = () => { ); }; -const AlbumArtistDetailTopSongsListRouteWithBoundary = () => { +const AlbumArtistDetailFavoriteSongsListRouteWithBoundary = () => { return ( @@ -176,4 +174,4 @@ const AlbumArtistDetailTopSongsListRouteWithBoundary = () => { ); }; -export default AlbumArtistDetailTopSongsListRouteWithBoundary; +export default AlbumArtistDetailFavoriteSongsListRouteWithBoundary; diff --git a/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx b/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx index 4ba014299..2c0753089 100644 --- a/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx +++ b/src/renderer/features/artists/routes/album-artist-detail-top-songs-list-route.tsx @@ -1,4 +1,4 @@ -import { useQuery } from '@tanstack/react-query'; +import { useSuspenseQuery } from '@tanstack/react-query'; import { useMemo } from 'react'; import { useParams } from 'react-router'; @@ -34,16 +34,15 @@ const AlbumArtistDetailTopSongsListRoute = () => { key: 'album-artist-top-songs-query-type', }); - const detailQuery = useQuery( + const detailQuery = useSuspenseQuery( artistsQueries.albumArtistDetail({ query: { id: routeId }, serverId: server?.id, }), ); - const topSongsQuery = useQuery( + const topSongsQuery = useSuspenseQuery( artistsQueries.topSongs({ - options: { enabled: !!detailQuery?.data?.name }, query: { artist: detailQuery?.data?.name || '', artistId: routeId, diff --git a/src/renderer/features/playlists/components/playlist-query-editor.tsx b/src/renderer/features/playlists/components/playlist-query-editor.tsx index bd1ff0560..a31a1537a 100644 --- a/src/renderer/features/playlists/components/playlist-query-editor.tsx +++ b/src/renderer/features/playlists/components/playlist-query-editor.tsx @@ -1,5 +1,6 @@ +import type { UseSuspenseQueryResult } from '@tanstack/react-query'; + import { closeAllModals, openModal } from '@mantine/modals'; -import { useQuery } from '@tanstack/react-query'; import { useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -25,7 +26,7 @@ import { toast } from '/@/shared/components/toast/toast'; import { SongListSort } from '/@/shared/types/domain-types'; export interface PlaylistQueryEditorProps { - detailQuery: ReturnType>; + detailQuery: UseSuspenseQueryResult; handleSave: ( filter: Record, extraFilters: { diff --git a/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx b/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx index 67e8e21cb..65a467c6b 100644 --- a/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx +++ b/src/renderer/features/playlists/routes/playlist-detail-song-list-route.tsx @@ -1,8 +1,8 @@ import { closeAllModals, openModal } from '@mantine/modals'; -import { useQuery } from '@tanstack/react-query'; +import { useSuspenseQuery } from '@tanstack/react-query'; import { Suspense, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { generatePath, useLocation, useNavigate, useParams } from 'react-router'; +import { generatePath, useNavigate, useParams } from 'react-router'; import { ListContext, useListContext } from '/@/renderer/context/list-context'; import { playlistsQueries } from '/@/renderer/features/playlists/api/playlists-api'; @@ -72,13 +72,11 @@ const PlaylistSongListFiltersSidebar = () => { const PlaylistDetailSongListRoute = () => { const { t } = useTranslation(); const navigate = useNavigate(); - const location = useLocation(); const { playlistId } = useParams() as { playlistId: string }; const server = useCurrentServer(); - const detailQuery = useQuery({ + const detailQuery = useSuspenseQuery({ ...playlistsQueries.detail({ query: { id: playlistId }, serverId: server?.id }), - placeholderData: location.state?.item, }); const deletePlaylistMutation = useDeletePlaylist({}); const updatePlaylistMutation = useUpdatePlaylist({}); @@ -212,9 +210,7 @@ const PlaylistDetailSongListRoute = () => { }; const isSmartPlaylist = Boolean( - !detailQuery?.isLoading && - detailQuery?.data?.rules && - server?.type === ServerType.NAVIDROME, + detailQuery?.data?.rules && server?.type === ServerType.NAVIDROME, ); const [showQueryBuilder, setShowQueryBuilder] = useState(false); diff --git a/src/renderer/features/shared/components/animated-page.tsx b/src/renderer/features/shared/components/animated-page.tsx index 3192379f2..b72ae2ddb 100644 --- a/src/renderer/features/shared/components/animated-page.tsx +++ b/src/renderer/features/shared/components/animated-page.tsx @@ -17,7 +17,7 @@ export const AnimatedPage = forwardRef( {children} diff --git a/src/renderer/layouts/default-layout.tsx b/src/renderer/layouts/default-layout.tsx index c3a5a20fa..520de2f4a 100644 --- a/src/renderer/layouts/default-layout.tsx +++ b/src/renderer/layouts/default-layout.tsx @@ -1,12 +1,12 @@ import clsx from 'clsx'; import isElectron from 'is-electron'; -import { lazy } from 'react'; import styles from './default-layout.module.css'; import { ContextMenuController } from '/@/renderer/features/context-menu/context-menu-controller'; import { MainContent } from '/@/renderer/layouts/default-layout/main-content'; import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar'; +import { WindowBar } from '/@/renderer/layouts/window-bar'; import { useSettingsStore, useWindowBarStyle } from '/@/renderer/store/settings.store'; import { Platform, PlayerType } from '/@/shared/types/types'; @@ -18,12 +18,6 @@ if (!isElectron()) { }); } -const WindowBar = lazy(() => - import('/@/renderer/layouts/window-bar').then((module) => ({ - default: module.WindowBar, - })), -); - interface DefaultLayoutProps { shell?: boolean; } diff --git a/src/renderer/layouts/mobile-layout/mobile-layout.tsx b/src/renderer/layouts/mobile-layout/mobile-layout.tsx index 7a99a2a0b..b08d694a3 100644 --- a/src/renderer/layouts/mobile-layout/mobile-layout.tsx +++ b/src/renderer/layouts/mobile-layout/mobile-layout.tsx @@ -1,6 +1,6 @@ import clsx from 'clsx'; import { AnimatePresence } from 'motion/react'; -import { lazy } from 'react'; +import { lazy, Suspense } from 'react'; import { Outlet } from 'react-router'; import styles from './mobile-layout.module.css'; @@ -13,6 +13,7 @@ import { PlayerBar } from '/@/renderer/layouts/default-layout/player-bar'; import { useFullScreenPlayerOverlayState, useWindowBarStyle } from '/@/renderer/store'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { Drawer } from '/@/shared/components/drawer/drawer'; +import { Spinner } from '/@/shared/components/spinner/spinner'; import { useDisclosure } from '/@/shared/hooks/use-disclosure'; import { Platform } from '/@/shared/types/types'; @@ -53,7 +54,9 @@ export const MobileLayout = ({ shell }: MobileLayoutProps) => { variant="subtle" />
- + }> + +