diff --git a/src/renderer/components/virtual-table/hooks/use-virtual-table.ts b/src/renderer/components/virtual-table/hooks/use-virtual-table.ts index 7319ec59..e4673dde 100644 --- a/src/renderer/components/virtual-table/hooks/use-virtual-table.ts +++ b/src/renderer/components/virtual-table/hooks/use-virtual-table.ts @@ -20,8 +20,9 @@ import { getColumnDefs, VirtualTableProps } from '/@/renderer/components/virtual import { SetContextMenuItems, useHandleTableContextMenu } from '/@/renderer/features/context-menu'; import { AppRoute } from '/@/renderer/router/routes'; import { useListStoreActions } from '/@/renderer/store'; -import { ListDisplayType, ServerListItem } from '/@/renderer/types'; -import { useListStoreByKey } from '../../../store/list.store'; +import { ListDisplayType, ServerListItem, TablePagination } from '/@/renderer/types'; +import { useSearchParams } from 'react-router-dom'; +import { ListKey, useListStoreByKey } from '../../../store/list.store'; export type AgGridFetchFn = ( args: { filter: TFilter; limit: number; startIndex: number }, @@ -31,6 +32,7 @@ export type AgGridFetchFn = ( interface UseAgGridProps { contextMenu: SetContextMenuItems; customFilters?: Partial; + isSearchParams?: boolean; itemCount?: number; itemType: LibraryItem; pageKey: string; @@ -46,11 +48,26 @@ export const useVirtualTable = ({ contextMenu, itemCount, customFilters, + isSearchParams, }: UseAgGridProps) => { const queryClient = useQueryClient(); const navigate = useNavigate(); const { setTable, setTablePagination } = useListStoreActions(); const properties = useListStoreByKey({ filter: customFilters, key: pageKey }); + const [searchParams, setSearchParams] = useSearchParams(); + + const scrollOffset = searchParams.get('scrollOffset'); + const pagination = useMemo(() => { + return { + currentPage: Number(searchParams.get('currentPage')), + itemsPerPage: Number(searchParams.get('itemsPerPage')), + totalItems: Number(searchParams.get('totalItems')), + totalPages: Number(searchParams.get('totalPages')), + }; + }, [searchParams]); + + const initialTableIndex = + Number(isSearchParams ? scrollOffset : properties.table.scrollOffset) || 0; const isPaginationEnabled = properties.display === ListDisplayType.TABLE_PAGINATED; @@ -149,16 +166,26 @@ export const useVirtualTable = ({ }; params.api.setDatasource(dataSource); - params.api.ensureIndexVisible(properties.table.scrollOffset || 0, 'top'); + params.api.ensureIndexVisible(initialTableIndex, 'top'); }, - [ - properties.table.scrollOffset, - properties.filter, - queryKeyFn, - server, - queryClient, - queryFn, - ], + [initialTableIndex, queryKeyFn, server, properties.filter, queryClient, queryFn], + ); + + const setParamsTablePagination = useCallback( + (args: { data: Partial; key: ListKey }) => { + const { data } = args; + + setSearchParams( + { + ...(data.currentPage && { currentPage: String(data.currentPage) }), + ...(data.itemsPerPage && { itemsPerPage: String(data.itemsPerPage) }), + ...(data.totalItems && { totalItems: String(data.totalItems) }), + ...(data.totalPages && { totalPages: String(data.totalPages) }), + }, + { replace: true }, + ); + }, + [setSearchParams], ); const onPaginationChanged = useCallback( @@ -175,21 +202,34 @@ export const useVirtualTable = ({ console.log(err); } - setTablePagination({ - data: { - itemsPerPage: event.api.paginationGetPageSize(), - totalItems: event.api.paginationGetRowCount(), - totalPages: event.api.paginationGetTotalPages() + 1, - }, - key: pageKey, - }); + if (isSearchParams) { + setSearchParams( + { + itemsPerPage: String(event.api.paginationGetPageSize()), + totalItems: String(event.api.paginationGetRowCount()), + totalPages: String(event.api.paginationGetTotalPages() + 1), + }, + { replace: true }, + ); + } else { + setTablePagination({ + data: { + itemsPerPage: event.api.paginationGetPageSize(), + totalItems: event.api.paginationGetRowCount(), + totalPages: event.api.paginationGetTotalPages() + 1, + }, + key: pageKey, + }); + } }, [ isPaginationEnabled, - setTablePagination, - pageKey, + isSearchParams, properties.table.pagination.currentPage, properties.table.pagination.itemsPerPage, + setSearchParams, + setTablePagination, + pageKey, ], ); @@ -223,7 +263,12 @@ export const useVirtualTable = ({ const onBodyScrollEnd = (e: BodyScrollEvent) => { const scrollOffset = Number((e.top / properties.table.rowHeight).toFixed(0)); - setTable({ data: { scrollOffset }, key: pageKey }); + + if (isSearchParams) { + setSearchParams({ scrollOffset: String(scrollOffset) }, { replace: true }); + } else { + setTable({ data: { scrollOffset }, key: pageKey }); + } }; const onCellContextMenu = useHandleTableContextMenu(itemType, contextMenu); @@ -245,8 +290,8 @@ export const useVirtualTable = ({ paginationProps: isPaginationEnabled ? { pageKey, - pagination: properties.table.pagination, - setPagination: setTablePagination, + pagination: isSearchParams ? pagination : properties.table.pagination, + setPagination: isSearchParams ? setParamsTablePagination : setTablePagination, } : undefined, rowBuffer: 20, @@ -256,11 +301,14 @@ export const useVirtualTable = ({ }; }, [ isPaginationEnabled, + isSearchParams, itemCount, pageKey, + pagination, properties.table.autoFit, properties.table.pagination, properties.table.rowHeight, + setParamsTablePagination, setTablePagination, ]); diff --git a/src/renderer/features/albums/components/album-list-grid-view.tsx b/src/renderer/features/albums/components/album-list-grid-view.tsx index 218af715..f10cc0bc 100644 --- a/src/renderer/features/albums/components/album-list-grid-view.tsx +++ b/src/renderer/features/albums/components/album-list-grid-view.tsx @@ -1,5 +1,6 @@ import { QueryKey, useQueryClient } from '@tanstack/react-query'; import { useCallback, useMemo } from 'react'; +import { useSearchParams } from 'react-router-dom'; import AutoSizer from 'react-virtualized-auto-sizer'; import { ListOnScrollProps } from 'react-window'; import { controller } from '/@/renderer/api/controller'; @@ -27,10 +28,14 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => { const queryClient = useQueryClient(); const server = useCurrentServer(); const handlePlayQueueAdd = usePlayQueueAdd(); - const { pageKey, customFilters } = useListContext(); + const { pageKey, customFilters, id } = useListContext(); const { grid, display, filter } = useListStoreByKey({ key: pageKey }); const { setGrid } = useListStoreActions(); + const [searchParams, setSearchParams] = useSearchParams(); + const scrollOffset = searchParams.get('scrollOffset'); + const initialScrollOffset = Number(id ? scrollOffset : grid?.scrollOffset) || 0; + const createFavoriteMutation = useCreateFavorite({}); const deleteFavoriteMutation = useDeleteFavorite({}); @@ -124,9 +129,13 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => { const handleGridScroll = useCallback( (e: ListOnScrollProps) => { - setGrid({ data: { scrollOffset: e.scrollOffset }, key: pageKey }); + if (id) { + setSearchParams({ scrollOffset: String(e.scrollOffset) }); + } else { + setGrid({ data: { scrollOffset: e.scrollOffset }, key: pageKey }); + } }, - [pageKey, setGrid], + [id, pageKey, setGrid, setSearchParams], ); const fetchInitialData = useCallback(() => { @@ -207,7 +216,7 @@ export const AlbumListGridView = ({ gridRef, itemCount }: any) => { handleFavorite={handleFavorite} handlePlayQueueAdd={handlePlayQueueAdd} height={height} - initialScrollOffset={grid?.scrollOffset || 0} + initialScrollOffset={initialScrollOffset} itemCount={itemCount || 0} itemGap={20} itemSize={grid?.itemsPerRow || 5} diff --git a/src/renderer/features/albums/components/album-list-table-view.tsx b/src/renderer/features/albums/components/album-list-table-view.tsx index ecbf3f8f..9ddb90db 100644 --- a/src/renderer/features/albums/components/album-list-table-view.tsx +++ b/src/renderer/features/albums/components/album-list-table-view.tsx @@ -8,11 +8,12 @@ import { useCurrentServer } from '/@/renderer/store'; export const AlbumListTableView = ({ tableRef, itemCount }: any) => { const server = useCurrentServer(); - const { pageKey, customFilters } = useListContext(); + const { pageKey, customFilters, id } = useListContext(); const tableProps = useVirtualTable({ contextMenu: ALBUM_CONTEXT_MENU_ITEMS, customFilters, + isSearchParams: Boolean(id), itemCount, itemType: LibraryItem.ALBUM, pageKey, diff --git a/src/renderer/features/songs/components/song-list-table-view.tsx b/src/renderer/features/songs/components/song-list-table-view.tsx index f23ed4eb..36ad27b4 100644 --- a/src/renderer/features/songs/components/song-list-table-view.tsx +++ b/src/renderer/features/songs/components/song-list-table-view.tsx @@ -17,13 +17,14 @@ interface SongListTableViewProps { export const SongListTableView = ({ tableRef, itemCount }: SongListTableViewProps) => { const server = useCurrentServer(); - const { pageKey, handlePlay, customFilters } = useListContext(); + const { pageKey, id, handlePlay, customFilters } = useListContext(); const { rowClassRules } = useCurrentSongRowStyles({ tableRef }); const tableProps = useVirtualTable({ contextMenu: SONG_CONTEXT_MENU_ITEMS, customFilters, + isSearchParams: Boolean(id), itemCount, itemType: LibraryItem.SONG, pageKey,