Update playlist list implementation

This commit is contained in:
jeffvli 2023-07-19 17:14:00 -07:00
parent 8b4a2d1ac0
commit 85964bfded
8 changed files with 77 additions and 130 deletions

View file

@ -1,8 +1,8 @@
import { MutableRefObject, useMemo, useRef } from 'react';
import { ColDef, RowDoubleClickedEvent } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Box, Group } from '@mantine/core';
import { closeAllModals, openModal } from '@mantine/modals';
import { MutableRefObject, useMemo, useRef } from 'react';
import { RiMoreFill } from 'react-icons/ri';
import { generatePath, useNavigate, useParams } from 'react-router';
import { Link } from 'react-router-dom';
@ -27,9 +27,10 @@ import { usePlaylistDetail } from '/@/renderer/features/playlists/queries/playli
import { usePlaylistSongListInfinite } from '/@/renderer/features/playlists/queries/playlist-song-list-query';
import { PlayButton, PLAY_TYPES } from '/@/renderer/features/shared';
import { AppRoute } from '/@/renderer/router/routes';
import { useCurrentServer, useSongListStore } from '/@/renderer/store';
import { useCurrentServer } from '/@/renderer/store';
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
import { Play } from '/@/renderer/types';
import { useListStoreByKey } from '../../../store/list.store';
const ContentContainer = styled.div`
position: relative;
@ -54,7 +55,7 @@ interface PlaylistDetailContentProps {
export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps) => {
const navigate = useNavigate();
const { playlistId } = useParams() as { playlistId: string };
const page = useSongListStore();
const { table } = useListStoreByKey({ key: LibraryItem.SONG });
const handlePlayQueueAdd = usePlayQueueAdd();
const server = useCurrentServer();
const detailQuery = usePlaylistDetail({ query: { id: playlistId }, serverId: server?.id });
@ -79,10 +80,8 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps)
const columnDefs: ColDef[] = useMemo(
() =>
getColumnDefs(page.table.columns).filter(
(c) => c.colId !== 'album' && c.colId !== 'artist',
),
[page.table.columns],
getColumnDefs(table.columns).filter((c) => c.colId !== 'album' && c.colId !== 'artist'),
[table.columns],
);
const contextMenuItems = useMemo(() => {

View file

@ -1,9 +1,10 @@
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { lazy, MutableRefObject, Suspense } from 'react';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { Spinner } from '/@/renderer/components';
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
import { usePlaylistListStore } from '/@/renderer/store';
import { ListDisplayType } from '/@/renderer/types';
import { useListContext } from '../../../context/list-context';
import { useListStoreByKey } from '../../../store/list.store';
const PlaylistListTableView = lazy(() =>
import('/@/renderer/features/playlists/components/playlist-list-table-view').then((module) => ({
@ -24,7 +25,8 @@ interface PlaylistListContentProps {
}
export const PlaylistListContent = ({ gridRef, tableRef, itemCount }: PlaylistListContentProps) => {
const { display } = usePlaylistListStore();
const { pageKey } = useListContext();
const { display } = useListStoreByKey({ key: pageKey });
return (
<Suspense fallback={<Spinner container />}>

View file

@ -2,7 +2,8 @@ import { useQueryClient } from '@tanstack/react-query';
import { MutableRefObject, useCallback, useMemo } from 'react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { ListOnScrollProps } from 'react-window';
import { usePlaylistGridStore, usePlaylistStoreActions } from '../../../store/playlist.store';
import { useListContext } from '../../../context/list-context';
import { useListStoreActions } from '../../../store/list.store';
import { controller } from '/@/renderer/api/controller';
import { queryKeys } from '/@/renderer/api/query-keys';
import { LibraryItem, Playlist, PlaylistListQuery, PlaylistListSort } from '/@/renderer/api/types';
@ -15,7 +16,7 @@ import {
import { usePlayQueueAdd } from '/@/renderer/features/player';
import { useCreateFavorite, useDeleteFavorite } from '/@/renderer/features/shared';
import { AppRoute } from '/@/renderer/router/routes';
import { useCurrentServer, useGeneralSettings, usePlaylistListStore } from '/@/renderer/store';
import { useCurrentServer, useGeneralSettings, useListStoreByKey } from '/@/renderer/store';
import { CardRow, ListDisplayType } from '/@/renderer/types';
interface PlaylistListGridViewProps {
@ -24,13 +25,12 @@ interface PlaylistListGridViewProps {
}
export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridViewProps) => {
const { pageKey } = useListContext();
const queryClient = useQueryClient();
const server = useCurrentServer();
const handlePlayQueueAdd = usePlayQueueAdd();
const { display } = usePlaylistListStore();
const grid = usePlaylistGridStore();
const { setGrid } = usePlaylistStoreActions();
const page = usePlaylistListStore();
const { display, grid, filter } = useListStoreByKey({ key: pageKey });
const { setGrid } = useListStoreActions();
const { defaultFullPlaylist } = useGeneralSettings();
const createFavoriteMutation = useCreateFavorite({});
@ -66,7 +66,7 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
? [PLAYLIST_CARD_ROWS.nameFull]
: [PLAYLIST_CARD_ROWS.name];
switch (page.filter.sortBy) {
switch (filter.sortBy) {
case PlaylistListSort.DURATION:
rows.push(PLAYLIST_CARD_ROWS.duration);
break;
@ -87,13 +87,13 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
}
return rows;
}, [defaultFullPlaylist, page.filter.sortBy]);
}, [defaultFullPlaylist, filter.sortBy]);
const handleGridScroll = useCallback(
(e: ListOnScrollProps) => {
setGrid({ data: { scrollOffset: e.scrollOffset } });
setGrid({ data: { scrollOffset: e.scrollOffset }, key: pageKey });
},
[setGrid],
[pageKey, setGrid],
);
const fetch = useCallback(
@ -105,7 +105,7 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
const query: PlaylistListQuery = {
limit: take,
startIndex: skip,
...page.filter,
...filter,
_custom: {},
};
@ -123,7 +123,7 @@ export const PlaylistListGridView = ({ gridRef, itemCount }: PlaylistListGridVie
return playlists;
},
[page.filter, queryClient, server],
[filter, queryClient, server],
);
return (

View file

@ -4,6 +4,8 @@ import { Divider, Flex, Group, Stack } from '@mantine/core';
import { useQueryClient } from '@tanstack/react-query';
import { ChangeEvent, MouseEvent, MutableRefObject, useCallback } from 'react';
import { RiMoreFill, RiRefreshLine, RiSettings3Fill } from 'react-icons/ri';
import { useListContext } from '../../../context/list-context';
import { useListStoreByKey } from '../../../store/list.store';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { LibraryItem, PlaylistListQuery, PlaylistListSort, SortOrder } from '/@/renderer/api/types';
@ -12,12 +14,7 @@ import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
import { PLAYLIST_TABLE_COLUMNS } from '/@/renderer/components/virtual-table';
import { OrderToggleButton } from '/@/renderer/features/shared';
import { useContainerQuery } from '/@/renderer/hooks';
import {
PlaylistListFilter,
useCurrentServer,
useListStoreActions,
usePlaylistListStore,
} from '/@/renderer/store';
import { PlaylistListFilter, useCurrentServer, useListStoreActions } from '/@/renderer/store';
import { ListDisplayType, TableColumn } from '/@/renderer/types';
const FILTERS = {
@ -45,12 +42,12 @@ export const PlaylistListHeaderFilters = ({
gridRef,
tableRef,
}: PlaylistListHeaderFiltersProps) => {
const pageKey = 'playlist';
const { pageKey } = useListContext();
const queryClient = useQueryClient();
const server = useCurrentServer();
const { setFilter, setTable, setTablePagination, setGrid, setDisplayType } =
useListStoreActions();
const { display, filter, table, grid } = usePlaylistListStore({ key: pageKey });
const { display, filter, table, grid } = useListStoreByKey({ key: pageKey });
const cq = useContainerQuery();
const isGrid = display === ListDisplayType.CARD || display === ListDisplayType.POSTER;
@ -146,7 +143,17 @@ export const PlaylistListHeaderFilters = ({
setTablePagination({ data: { currentPage: 0 }, key: pageKey });
}
},
[isGrid, gridRef, fetch, filter, tableRef, setTablePagination, server, queryClient],
[
isGrid,
gridRef,
fetch,
filter,
tableRef,
setTablePagination,
pageKey,
server,
queryClient,
],
);
const handleSetSortBy = useCallback(
@ -168,7 +175,7 @@ export const PlaylistListHeaderFilters = ({
handleFilterChange(updatedFilters);
},
[handleFilterChange, server?.type, setFilter],
[handleFilterChange, pageKey, server?.type, setFilter],
);
const handleToggleSortOrder = useCallback(() => {
@ -179,14 +186,14 @@ export const PlaylistListHeaderFilters = ({
key: pageKey,
}) as PlaylistListFilter;
handleFilterChange(updatedFilters);
}, [filter.sortOrder, handleFilterChange, setFilter]);
}, [filter.sortOrder, handleFilterChange, pageKey, setFilter]);
const handleSetViewType = useCallback(
(e: MouseEvent<HTMLButtonElement>) => {
if (!e.currentTarget?.value) return;
setDisplayType({ data: e.currentTarget.value as ListDisplayType, key: pageKey });
},
[setDisplayType],
[pageKey, setDisplayType],
);
const handleTableColumns = (values: TableColumn[]) => {

View file

@ -8,18 +8,14 @@ import { CreatePlaylistForm } from '/@/renderer/features/playlists/components/cr
import { PlaylistListHeaderFilters } from '/@/renderer/features/playlists/components/playlist-list-header-filters';
import { LibraryHeaderBar } from '/@/renderer/features/shared';
import { useContainerQuery } from '/@/renderer/hooks';
import {
PlaylistListFilter,
useCurrentServer,
useListStoreActions,
usePlaylistListFilter,
usePlaylistListStore,
} from '/@/renderer/store';
import { PlaylistListFilter, useCurrentServer, useListStoreActions } from '/@/renderer/store';
import { ListDisplayType, ServerType } from '/@/renderer/types';
import debounce from 'lodash/debounce';
import { RiFileAddFill } from 'react-icons/ri';
import { LibraryItem } from '/@/renderer/api/types';
import { useListFilterRefresh } from '../../../hooks/use-list-filter-refresh';
import { useListContext } from '/@/renderer/context/list-context';
import { useListStoreByKey } from '../../../store/list.store';
interface PlaylistListHeaderProps {
gridRef: MutableRefObject<VirtualInfiniteGridRef | null>;
@ -28,12 +24,11 @@ interface PlaylistListHeaderProps {
}
export const PlaylistListHeader = ({ itemCount, tableRef, gridRef }: PlaylistListHeaderProps) => {
const pageKey = 'playlist';
const { pageKey } = useListContext();
const cq = useContainerQuery();
const server = useCurrentServer();
const { setFilter, setTablePagination } = useListStoreActions();
const filter = usePlaylistListFilter({ key: pageKey });
const { display } = usePlaylistListStore({ key: pageKey });
const { display, filter } = useListStoreByKey({ key: pageKey });
const handleCreatePlaylistModal = () => {
openModal({

View file

@ -1,25 +1,13 @@
import { RowDoubleClickedEvent } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { useCallback } from 'react';
import { generatePath, useNavigate } from 'react-router';
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
import { LibraryItem, PlaylistListQuery, PlaylistListResponse } from '/@/renderer/api/types';
import { LibraryItem } from '/@/renderer/api/types';
import { VirtualGridAutoSizerContainer } from '/@/renderer/components/virtual-grid';
import { VirtualTable } from '/@/renderer/components/virtual-table';
import {
AgGridFetchFn,
useVirtualTable,
} from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
import { useVirtualTable } from '/@/renderer/components/virtual-table/hooks/use-virtual-table';
import { PLAYLIST_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items';
import { AppRoute } from '/@/renderer/router/routes';
import {
useCurrentServer,
useGeneralSettings,
useListStoreActions,
usePlaylistListFilter,
usePlaylistListStore,
} from '/@/renderer/store';
import { useCurrentServer, useGeneralSettings } from '/@/renderer/store';
interface PlaylistListTableViewProps {
itemCount?: number;
@ -30,36 +18,7 @@ export const PlaylistListTableView = ({ tableRef, itemCount }: PlaylistListTable
const navigate = useNavigate();
const server = useCurrentServer();
const { defaultFullPlaylist } = useGeneralSettings();
const { setTable, setTablePagination } = useListStoreActions();
const pageKey = 'playlist';
const filter = usePlaylistListFilter({ key: pageKey });
const listProperties = usePlaylistListStore({ key: pageKey });
console.log('listProperties :>> ', listProperties);
const fetchFn: AgGridFetchFn<
PlaylistListResponse,
Omit<PlaylistListQuery, 'startIndex'>
> = useCallback(
async ({ filter, limit, startIndex }, signal) => {
const res = api.controller.getPlaylistList({
apiClientProps: {
server,
signal,
},
query: {
...filter,
limit,
sortBy: filter.sortBy,
sortOrder: filter.sortOrder,
startIndex,
},
});
return res;
},
[server],
);
const handleRowDoubleClick = (e: RowDoubleClickedEvent) => {
if (!e.data) return;
@ -70,25 +29,14 @@ export const PlaylistListTableView = ({ tableRef, itemCount }: PlaylistListTable
}
};
const tableProps = useVirtualTable<PlaylistListResponse, Omit<PlaylistListQuery, 'startIndex'>>(
{
contextMenu: PLAYLIST_CONTEXT_MENU_ITEMS,
fetch: {
filter,
fn: fetchFn,
itemCount,
queryKey: queryKeys.playlists.list,
server,
},
itemCount,
itemType: LibraryItem.PLAYLIST,
pageKey,
properties: listProperties,
setTable,
setTablePagination,
tableRef,
},
);
const tableProps = useVirtualTable({
contextMenu: PLAYLIST_CONTEXT_MENU_ITEMS,
itemCount,
itemType: LibraryItem.PLAYLIST,
pageKey,
server,
tableRef,
});
return (
<VirtualGridAutoSizerContainer>

View file

@ -1,19 +1,22 @@
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
import { useRef } from 'react';
import { useParams } from 'react-router';
import { PlaylistListSort, SortOrder } from '/@/renderer/api/types';
import { VirtualInfiniteGridRef } from '/@/renderer/components/virtual-grid';
import { ListContext } from '/@/renderer/context/list-context';
import { PlaylistListContent } from '/@/renderer/features/playlists/components/playlist-list-content';
import { PlaylistListHeader } from '/@/renderer/features/playlists/components/playlist-list-header';
import { usePlaylistList } from '/@/renderer/features/playlists/queries/playlist-list-query';
import { AnimatedPage } from '/@/renderer/features/shared';
import { useCurrentServer, usePlaylistListFilter } from '/@/renderer/store';
import { useCurrentServer, useListStoreByKey } from '/@/renderer/store';
const PlaylistListRoute = () => {
const gridRef = useRef<VirtualInfiniteGridRef | null>(null);
const tableRef = useRef<AgGridReactType | null>(null);
const server = useCurrentServer();
const playlistListFilter = usePlaylistListFilter({ key: 'playlist' });
const { playlistId } = useParams();
const pageKey = 'playlist';
const { filter } = useListStoreByKey({ key: pageKey });
const itemCountCheck = usePlaylistList({
options: {
@ -21,7 +24,7 @@ const PlaylistListRoute = () => {
staleTime: 1000 * 60 * 60 * 2,
},
query: {
...playlistListFilter,
...filter,
limit: 1,
sortBy: PlaylistListSort.NAME,
sortOrder: SortOrder.ASC,
@ -37,16 +40,18 @@ const PlaylistListRoute = () => {
return (
<AnimatedPage>
<PlaylistListHeader
gridRef={gridRef}
itemCount={itemCount}
tableRef={tableRef}
/>
<PlaylistListContent
gridRef={gridRef}
itemCount={itemCount}
tableRef={tableRef}
/>
<ListContext.Provider value={{ id: playlistId, pageKey }}>
<PlaylistListHeader
gridRef={gridRef}
itemCount={itemCount}
tableRef={tableRef}
/>
<PlaylistListContent
gridRef={gridRef}
itemCount={itemCount}
tableRef={tableRef}
/>
</ListContext.Provider>
</AnimatedPage>
);
};

View file

@ -624,13 +624,4 @@ export const useAlbumArtistListFilter = (args: { id?: string; key?: string }) =>
}) as AlbumArtistListFilter;
}, shallow);
export const usePlaylistListFilter = (args: { id?: string; key?: string }) =>
useListStore((state) => {
return state._actions.getFilter({
id: args.id,
itemType: LibraryItem.PLAYLIST,
key: args.key,
}) as PlaylistListFilter;
}, shallow);
export const useListDetail = (key: string) => useListStore((state) => state.detail[key], shallow);