diff --git a/src/apps/experimental/components/AppToolbar/userViews/UserViewNav.tsx b/src/apps/experimental/components/AppToolbar/userViews/UserViewNav.tsx index 1c3a22ca20..b3599e3128 100644 --- a/src/apps/experimental/components/AppToolbar/userViews/UserViewNav.tsx +++ b/src/apps/experimental/components/AppToolbar/userViews/UserViewNav.tsx @@ -1,4 +1,5 @@ import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; +import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type'; import ArrowDropDown from '@mui/icons-material/ArrowDropDown'; import Favorite from '@mui/icons-material/Favorite'; @@ -11,7 +12,8 @@ import { Link, useLocation, useSearchParams } from 'react-router-dom'; import LibraryIcon from 'apps/experimental/components/LibraryIcon'; import { MetaView } from 'apps/experimental/constants/metaView'; -import { isLibraryPath } from 'apps/experimental/features/libraries/utils/path'; +import { useAncestors } from 'apps/experimental/features/libraries/hooks/api/useAncestors'; +import { isDetailsPath, isLibraryPath } from 'apps/experimental/features/libraries/utils/path'; import { appRouter } from 'components/router/appRouter'; import { useApi } from 'hooks/useApi'; import useCurrentTab from 'hooks/useCurrentTab'; @@ -37,7 +39,7 @@ const getCurrentUserView = ( collectionType: string | null, tab: number ) => { - const isUserViewPath = isLibraryPath(pathname) || [HOME_PATH, LIST_PATH].includes(pathname); + const isUserViewPath = isDetailsPath(pathname) || isLibraryPath(pathname) || [HOME_PATH, LIST_PATH].includes(pathname); if (!isUserViewPath) return undefined; if (collectionType === CollectionType.Livetv) { @@ -55,6 +57,7 @@ const getCurrentUserView = ( const UserViewNav = () => { const location = useLocation(); const [ searchParams ] = useSearchParams(); + const itemId = searchParams.get('id') || undefined; const libraryId = searchParams.get('topParentId') || searchParams.get('parentId'); const collectionType = searchParams.get('collectionType'); const { activeTab } = useCurrentTab(); @@ -78,6 +81,14 @@ const UserViewNav = () => { isPending } = useUserViews(user?.Id); + const { + data: ancestors + } = useAncestors({ itemId }); + + const ancestorLibraryId = useMemo(() => { + return ancestors?.find(ancestor => ancestor.Type === BaseItemKind.CollectionFolder)?.Id || null; + }, [ ancestors ]); + const primaryViews = useMemo(() => ( userViews?.Items?.slice(0, maxViews) ), [ maxViews, userViews ]); @@ -98,8 +109,8 @@ const UserViewNav = () => { }, []); const currentUserView = useMemo(() => ( - getCurrentUserView(userViews?.Items, location.pathname, libraryId, collectionType, activeTab) - ), [ activeTab, collectionType, libraryId, location.pathname, userViews ]); + getCurrentUserView(userViews?.Items, location.pathname, libraryId || ancestorLibraryId, collectionType, activeTab) + ), [ activeTab, collectionType, libraryId, ancestorLibraryId, location.pathname, userViews ]); if (isPending) return null; diff --git a/src/apps/experimental/features/libraries/hooks/api/useAncestors.ts b/src/apps/experimental/features/libraries/hooks/api/useAncestors.ts new file mode 100644 index 0000000000..09563aa3a2 --- /dev/null +++ b/src/apps/experimental/features/libraries/hooks/api/useAncestors.ts @@ -0,0 +1,41 @@ +import type { Api } from '@jellyfin/sdk/lib/api'; +import type { LibraryApiGetAncestorsRequest } from '@jellyfin/sdk/lib/generated-client/api/library-api'; +import { getLibraryApi } from '@jellyfin/sdk/lib/utils/api/library-api'; +import { queryOptions, useQuery } from '@tanstack/react-query'; +import type { AxiosRequestConfig } from 'axios'; + +import { useApi } from 'hooks/useApi'; + +interface AncestorsParams { + itemId?: string; + userId?: string; +} + +const fetchAncestors = async ( + api: Api, + params: LibraryApiGetAncestorsRequest, + options?: AxiosRequestConfig +) => { + const response = await getLibraryApi(api).getAncestors(params, options); + return response.data; +}; + +/** Query options for fetching the hierarchy of ancestors of a given item. */ +export const getAncestorsQuery = ( + api?: Api, + params?: AncestorsParams +) => queryOptions({ + queryKey: [ 'Items', params?.itemId, 'Ancestors' ], + queryFn: ({ signal }) => fetchAncestors(api!, params as LibraryApiGetAncestorsRequest, { signal }), + staleTime: Infinity, // Ancestors are unlikely to change + enabled: !!api && !!params?.itemId +}); + +/** Hook to fetch the hierarchy of ancestors of a given item. */ +export const useAncestors = ( + params: AncestorsParams +) => { + const apiContext = useApi(); + const { api } = apiContext; + return useQuery(getAncestorsQuery(api, params)); +}; diff --git a/src/apps/experimental/features/libraries/utils/path.ts b/src/apps/experimental/features/libraries/utils/path.ts index a187b29010..5a632eef57 100644 --- a/src/apps/experimental/features/libraries/utils/path.ts +++ b/src/apps/experimental/features/libraries/utils/path.ts @@ -2,6 +2,13 @@ import * as userSettings from 'scripts/settings/userSettings'; import { LibraryRoutes } from '../constants/libraryRoutes'; +/** + * Utility function to check if a path is a details path. + */ +export const isDetailsPath = (path: string) => ( + path === '/details' +); + /** * Utility function to check if a path is a library path. */