From 85964bfdedbc82a57c7902636bea9c29de1f6fc8 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Wed, 19 Jul 2023 17:14:00 -0700 Subject: [PATCH] Update playlist list implementation --- .../components/playlist-detail-content.tsx | 13 ++-- .../components/playlist-list-content.tsx | 8 +- .../components/playlist-list-grid-view.tsx | 24 +++--- .../playlist-list-header-filters.tsx | 31 +++++--- .../components/playlist-list-header.tsx | 15 ++-- .../components/playlist-list-table-view.tsx | 74 +++---------------- .../playlists/routes/playlist-list-route.tsx | 33 +++++---- src/renderer/store/list.store.ts | 9 --- 8 files changed, 77 insertions(+), 130 deletions(-) diff --git a/src/renderer/features/playlists/components/playlist-detail-content.tsx b/src/renderer/features/playlists/components/playlist-detail-content.tsx index a84df4f3..56555979 100644 --- a/src/renderer/features/playlists/components/playlist-detail-content.tsx +++ b/src/renderer/features/playlists/components/playlist-detail-content.tsx @@ -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(() => { diff --git a/src/renderer/features/playlists/components/playlist-list-content.tsx b/src/renderer/features/playlists/components/playlist-list-content.tsx index 8120ad64..ed40b04d 100644 --- a/src/renderer/features/playlists/components/playlist-list-content.tsx +++ b/src/renderer/features/playlists/components/playlist-list-content.tsx @@ -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 ( }> diff --git a/src/renderer/features/playlists/components/playlist-list-grid-view.tsx b/src/renderer/features/playlists/components/playlist-list-grid-view.tsx index 33efebc2..5c612f17 100644 --- a/src/renderer/features/playlists/components/playlist-list-grid-view.tsx +++ b/src/renderer/features/playlists/components/playlist-list-grid-view.tsx @@ -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 ( diff --git a/src/renderer/features/playlists/components/playlist-list-header-filters.tsx b/src/renderer/features/playlists/components/playlist-list-header-filters.tsx index d82a37b0..0e73c40e 100644 --- a/src/renderer/features/playlists/components/playlist-list-header-filters.tsx +++ b/src/renderer/features/playlists/components/playlist-list-header-filters.tsx @@ -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) => { if (!e.currentTarget?.value) return; setDisplayType({ data: e.currentTarget.value as ListDisplayType, key: pageKey }); }, - [setDisplayType], + [pageKey, setDisplayType], ); const handleTableColumns = (values: TableColumn[]) => { diff --git a/src/renderer/features/playlists/components/playlist-list-header.tsx b/src/renderer/features/playlists/components/playlist-list-header.tsx index daa8457a..07467b81 100644 --- a/src/renderer/features/playlists/components/playlist-list-header.tsx +++ b/src/renderer/features/playlists/components/playlist-list-header.tsx @@ -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; @@ -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({ diff --git a/src/renderer/features/playlists/components/playlist-list-table-view.tsx b/src/renderer/features/playlists/components/playlist-list-table-view.tsx index 5c8666f0..648a60b2 100644 --- a/src/renderer/features/playlists/components/playlist-list-table-view.tsx +++ b/src/renderer/features/playlists/components/playlist-list-table-view.tsx @@ -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 - > = 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>( - { - 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 ( diff --git a/src/renderer/features/playlists/routes/playlist-list-route.tsx b/src/renderer/features/playlists/routes/playlist-list-route.tsx index 07286c9f..00c46c12 100644 --- a/src/renderer/features/playlists/routes/playlist-list-route.tsx +++ b/src/renderer/features/playlists/routes/playlist-list-route.tsx @@ -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(null); const tableRef = useRef(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 ( - - + + + + ); }; diff --git a/src/renderer/store/list.store.ts b/src/renderer/store/list.store.ts index 654b3ecd..b00a9e21 100644 --- a/src/renderer/store/list.store.ts +++ b/src/renderer/store/list.store.ts @@ -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);