diff --git a/src/renderer/features/albums/components/album-detail-content.tsx b/src/renderer/features/albums/components/album-detail-content.tsx index 59db77ba..ce8de7ad 100644 --- a/src/renderer/features/albums/components/album-detail-content.tsx +++ b/src/renderer/features/albums/components/album-detail-content.tsx @@ -5,11 +5,12 @@ import { getColumnDefs, GridCarousel, TextTitle, + useFixedTableHeader, VirtualTable, } from '/@/renderer/components'; import { CellContextMenuEvent, ColDef } from '@ag-grid-community/core'; import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; -import { Group, Stack } from '@mantine/core'; +import { Box, Group, Stack } from '@mantine/core'; import { useSetState } from '@mantine/hooks'; import sortBy from 'lodash/sortBy'; import { RiHeartLine, RiMoreFill } from 'react-icons/ri'; @@ -29,19 +30,16 @@ import { AlbumListSort, LibraryItem, SortOrder } from '/@/renderer/api/types'; import { usePlayQueueAdd } from '/@/renderer/features/player'; const ContentContainer = styled.div` + position: relative; display: flex; flex-direction: column; max-width: 1920px; - padding: 1rem 2rem; + padding: 1rem 2rem 5rem; overflow: hidden; .ag-theme-alpine-dark { --ag-header-background-color: rgba(0, 0, 0, 0%); } - - .ag-header-container { - z-index: 1000; - } `; interface AlbumDetailContentProps { @@ -170,9 +168,13 @@ export const AlbumDetailContent = ({ tableRef }: AlbumDetailContentProps) => { }); }; + const { intersectRef, tableContainerRef } = useFixedTableHeader(); + return ( { - data.data.id} - rowData={detailQuery.data?.songs} - rowHeight={60} - rowSelection="multiple" - onCellContextMenu={handleContextMenu} - onGridReady={(params) => { - params.api.setDomLayout('autoHeight'); - params.api.sizeColumnsToFit(); - }} - onGridSizeChanged={(params) => { - params.api.sizeColumnsToFit(); - }} - /> + + data.data.id} + rowData={detailQuery.data?.songs} + rowHeight={60} + rowSelection="multiple" + onCellContextMenu={handleContextMenu} + onGridReady={(params) => { + params.api.setDomLayout('autoHeight'); + params.api.sizeColumnsToFit(); + }} + onGridSizeChanged={(params) => { + params.api.sizeColumnsToFit(); + }} + /> + { + const navigate = useNavigate(); const { playlistId } = useParams() as { playlistId: string }; const page = useSongListStore(); + const handlePlayQueueAdd = usePlayQueueAdd(); + const detailQuery = usePlaylistDetail({ id: playlistId }); + const playButtonBehavior = usePlayButtonBehavior(); + const queryClient = useQueryClient(); + const server = useCurrentServer(); const playlistSongsQueryInfinite = usePlaylistSongListInfinite( { @@ -44,7 +67,7 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps) limit: 50, startIndex: 0, }, - { keepPreviousData: false }, + { cacheTime: 0, keepPreviousData: false }, ); const handleLoadMore = () => { @@ -94,41 +117,178 @@ export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps) [playlistSongsQueryInfinite.data?.pages], ); + console.log('playlistSongData', playlistSongData); + + const { intersectRef, tableContainerRef } = useFixedTableHeader(); + + const deletePlaylistMutation = useDeletePlaylist(); + + const handleDeletePlaylist = () => { + deletePlaylistMutation.mutate( + { query: { id: playlistId } }, + { + onError: (err) => { + toast.error({ + message: err.message, + title: 'Error deleting playlist', + }); + }, + onSuccess: () => { + toast.success({ + message: `${detailQuery?.data?.name} was successfully deleted`, + title: 'Playlist deleted', + }); + closeAllModals(); + navigate(AppRoute.PLAYLISTS); + }, + }, + ); + }; + + const openDeletePlaylist = () => { + openModal({ + children: ( + + Are you sure you want to delete this playlist? + + ), + title: 'Delete playlist', + }); + }; + + const handlePlay = (playType?: Play) => { + handlePlayQueueAdd?.({ + byItemType: { + id: [playlistId], + type: LibraryItem.PLAYLIST, + }, + play: playType || playButtonBehavior, + }); + }; + + const openUpdatePlaylistModal = async () => { + const query: UserListQuery = { + sortBy: UserListSort.NAME, + sortOrder: SortOrder.ASC, + startIndex: 0, + }; + + const users = await queryClient.fetchQuery({ + queryFn: ({ signal }) => api.controller.getUserList({ query, server, signal }), + queryKey: queryKeys.users.list(server?.id || '', query), + }); + + const normalizedUsers = api.normalize.userList(users, server); + + openModal({ + children: ( + + ), + title: 'Edit playlist', + }); + }; + + const loadMoreRef = useRef(null); + return ( - data.data.uniqueId} - rowData={playlistSongData} - rowHeight={60} - rowSelection="multiple" - onCellContextMenu={handleContextMenu} - onGridReady={(params) => { - params.api.setDomLayout('autoHeight'); - params.api.sizeColumnsToFit(); - }} - onGridSizeChanged={(params) => { - params.api.sizeColumnsToFit(); - }} - /> + + handlePlay()} /> + + + + + + {PLAY_TYPES.filter((type) => type.play !== playButtonBehavior).map((type) => ( + handlePlay(type.play)} + > + {type.label} + + ))} + + Edit playlist + Delete playlist + + + + + + + data.data.id} + rowData={playlistSongData} + rowHeight={60} + rowSelection="multiple" + onCellContextMenu={handleContextMenu} + onGridReady={(params) => { + params.api.setDomLayout('autoHeight'); + params.api.sizeColumnsToFit(); + }} + onGridSizeChanged={(params) => { + params.api.sizeColumnsToFit(); + }} + /> + + - or - - + ); }; diff --git a/src/renderer/features/playlists/components/playlist-detail-header.tsx b/src/renderer/features/playlists/components/playlist-detail-header.tsx index 765fef3e..4d8b573c 100644 --- a/src/renderer/features/playlists/components/playlist-detail-header.tsx +++ b/src/renderer/features/playlists/components/playlist-detail-header.tsx @@ -1,24 +1,12 @@ import { forwardRef, Fragment, Ref } from 'react'; import { Group, Stack } from '@mantine/core'; -import { closeAllModals, openModal } from '@mantine/modals'; -import { useQueryClient } from '@tanstack/react-query'; -import { RiMoreFill } from 'react-icons/ri'; -import { generatePath, useNavigate, useParams } from 'react-router'; -import { Link } from 'react-router-dom'; -import { DropdownMenu, Button, ConfirmModal, toast, Text } from '/@/renderer/components'; -import { usePlayQueueAdd } from '/@/renderer/features/player'; -import { UpdatePlaylistForm } from './update-playlist-form'; -import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/delete-playlist-mutation'; +import { useParams } from 'react-router'; +import { Text } from '/@/renderer/components'; import { usePlaylistDetail } from '/@/renderer/features/playlists/queries/playlist-detail-query'; -import { LibraryHeader, PlayButton, PLAY_TYPES } from '/@/renderer/features/shared'; +import { LibraryHeader } from '/@/renderer/features/shared'; import { AppRoute } from '/@/renderer/router/routes'; -import { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; -import { Play } from '/@/renderer/types'; import { formatDurationString } from '/@/renderer/utils'; -import { UserListSort, SortOrder, UserListQuery, LibraryItem } from '/@/renderer/api/types'; -import { useCurrentServer } from '/@/renderer/store'; -import { api } from '/@/renderer/api'; -import { queryKeys } from '/@/renderer/api/query-keys'; +import { LibraryItem } from '/@/renderer/api/types'; interface PlaylistDetailHeaderProps { background: string; @@ -31,99 +19,8 @@ export const PlaylistDetailHeader = forwardRef( { background, imageUrl, imagePlaceholderUrl }: PlaylistDetailHeaderProps, ref: Ref, ) => { - const navigate = useNavigate(); - const queryClient = useQueryClient(); const { playlistId } = useParams() as { playlistId: string }; const detailQuery = usePlaylistDetail({ id: playlistId }); - const handlePlayQueueAdd = usePlayQueueAdd(); - const playButtonBehavior = usePlayButtonBehavior(); - const server = useCurrentServer(); - - const handlePlay = (playType?: Play) => { - handlePlayQueueAdd?.({ - byItemType: { - id: [playlistId], - type: LibraryItem.PLAYLIST, - }, - play: playType || playButtonBehavior, - }); - }; - - const openUpdatePlaylistModal = async () => { - const query: UserListQuery = { - sortBy: UserListSort.NAME, - sortOrder: SortOrder.ASC, - startIndex: 0, - }; - - const users = await queryClient.fetchQuery({ - queryFn: ({ signal }) => api.controller.getUserList({ query, server, signal }), - queryKey: queryKeys.users.list(server?.id || '', query), - }); - - const normalizedUsers = api.normalize.userList(users, server); - - openModal({ - children: ( - - ), - title: 'Edit playlist', - }); - }; - - const deletePlaylistMutation = useDeletePlaylist(); - - const handleDeletePlaylist = () => { - deletePlaylistMutation.mutate( - { query: { id: playlistId } }, - { - onError: (err) => { - toast.error({ - message: err.message, - title: 'Error deleting playlist', - }); - }, - onSuccess: () => { - toast.success({ - message: `${detailQuery?.data?.name} was successfully deleted`, - title: 'Playlist deleted', - }); - closeAllModals(); - navigate(AppRoute.PLAYLISTS); - }, - }, - ); - }; - - const openDeletePlaylist = () => { - openModal({ - children: ( - - Are you sure you want to delete this playlist? - - ), - title: 'Delete playlist', - }); - }; const metadataItems = [ { @@ -160,49 +57,6 @@ export const PlaylistDetailHeader = forwardRef( {detailQuery?.data?.description} - - - handlePlay()} /> - - - - - - {PLAY_TYPES.filter((type) => type.play !== playButtonBehavior).map((type) => ( - handlePlay(type.play)} - > - {type.label} - - ))} - - - Edit playlist - - Delete playlist - - - - - - ); },