import { CellContextMenuEvent, ColDef } 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 { useQueryClient } from '@tanstack/react-query'; import { sortBy } from 'lodash'; 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'; import styled from 'styled-components'; import { api } from '/@/renderer/api'; import { queryKeys } from '/@/renderer/api/query-keys'; import { LibraryItem, SortOrder, UserListQuery, UserListSort } from '/@/renderer/api/types'; import { Button, ConfirmModal, DropdownMenu, getColumnDefs, MotionGroup, toast, useFixedTableHeader, VirtualTable, } from '/@/renderer/components'; import { openContextMenu } from '/@/renderer/features/context-menu'; import { SONG_CONTEXT_MENU_ITEMS } from '/@/renderer/features/context-menu/context-menu-items'; import { usePlayQueueAdd } from '/@/renderer/features/player'; import { UpdatePlaylistForm } from '/@/renderer/features/playlists/components/update-playlist-form'; import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/delete-playlist-mutation'; import { usePlaylistDetail } from '/@/renderer/features/playlists/queries/playlist-detail-query'; 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 { usePlayButtonBehavior } from '/@/renderer/store/settings.store'; import { Play } from '/@/renderer/types'; const ContentContainer = styled.div` display: flex; flex-direction: column; max-width: 1920px; padding: 1rem 2rem 5rem; overflow: hidden; .ag-theme-alpine-dark { --ag-header-background-color: rgba(0, 0, 0, 0%); } `; interface PlaylistDetailContentProps { tableRef: MutableRefObject; } export const PlaylistDetailContent = ({ tableRef }: PlaylistDetailContentProps) => { 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( { id: playlistId, limit: 50, startIndex: 0, }, { cacheTime: 0, keepPreviousData: false }, ); const handleLoadMore = () => { playlistSongsQueryInfinite.fetchNextPage(); }; const columnDefs: ColDef[] = useMemo( () => getColumnDefs(page.table.columns).filter((c) => c.colId !== 'album' && c.colId !== 'artist'), [page.table.columns], ); const defaultColumnDefs: ColDef = useMemo(() => { return { lockPinned: true, lockVisible: true, resizable: true, }; }, []); const handleContextMenu = (e: CellContextMenuEvent) => { if (!e.event) return; const clickEvent = e.event as MouseEvent; clickEvent.preventDefault(); const selectedNodes = e.api.getSelectedNodes(); const selectedIds = selectedNodes.map((node) => node.data.id); let selectedRows = sortBy(selectedNodes, ['rowIndex']).map((node) => node.data); if (!selectedIds.includes(e.data.id)) { e.api.deselectAll(); e.node.setSelected(true); selectedRows = [e.data]; } openContextMenu({ data: selectedRows, menuItems: SONG_CONTEXT_MENU_ITEMS, type: LibraryItem.SONG, xPos: clickEvent.clientX, yPos: clickEvent.clientY, }); }; const playlistSongData = useMemo( () => playlistSongsQueryInfinite.data?.pages.flatMap((p) => p.items), [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 ( 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(); }} /> ); };