import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact'; import { closeAllModals, openModal } from '@mantine/modals'; import { motion } from 'motion/react'; import { useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath, useNavigate, useParams } from 'react-router'; import { useHandlePlayQueueAdd } from '/@/renderer/features/player/hooks/use-handle-playqueue-add'; import { PlaylistDetailSongListContent } from '/@/renderer/features/playlists/components/playlist-detail-song-list-content'; import { PlaylistDetailSongListHeader } from '/@/renderer/features/playlists/components/playlist-detail-song-list-header'; import { PlaylistQueryBuilder } from '/@/renderer/features/playlists/components/playlist-query-builder'; import { SaveAsPlaylistForm } from '/@/renderer/features/playlists/components/save-as-playlist-form'; import { useCreatePlaylist } from '/@/renderer/features/playlists/mutations/create-playlist-mutation'; import { useDeletePlaylist } from '/@/renderer/features/playlists/mutations/delete-playlist-mutation'; import { usePlaylistDetail } from '/@/renderer/features/playlists/queries/playlist-detail-query'; import { usePlaylistSongList } from '/@/renderer/features/playlists/queries/playlist-song-list-query'; import { AnimatedPage } from '/@/renderer/features/shared'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer, usePlaylistDetailStore } from '/@/renderer/store'; import { searchSongs } from '/@/renderer/utils/search-songs'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { Box } from '/@/shared/components/box/box'; import { Group } from '/@/shared/components/group/group'; import { Text } from '/@/shared/components/text/text'; import { toast } from '/@/shared/components/toast/toast'; import { ServerType, SongListSort, SortOrder, sortSongList } from '/@/shared/types/domain-types'; import { Play } from '/@/shared/types/types'; const PlaylistDetailSongListRoute = () => { const { t } = useTranslation(); const navigate = useNavigate(); const tableRef = useRef(null); const { playlistId } = useParams() as { playlistId: string }; const server = useCurrentServer(); const handlePlayQueueAdd = useHandlePlayQueueAdd(); const detailQuery = usePlaylistDetail({ query: { id: playlistId }, serverId: server?.id }); const createPlaylistMutation = useCreatePlaylist({}); const deletePlaylistMutation = useDeletePlaylist({}); const handleSave = ( filter: Record, extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, ) => { const rules = { ...filter, limit: extraFilters.limit || undefined, order: extraFilters.sortOrder || 'desc', sort: extraFilters.sortBy || 'dateAdded', }; if (!detailQuery?.data) return; createPlaylistMutation.mutate( { body: { _custom: { navidrome: { owner: detailQuery?.data?.owner || '', ownerId: detailQuery?.data?.ownerId || '', rules, sync: detailQuery?.data?.sync || false, }, }, comment: detailQuery?.data?.description || '', name: detailQuery?.data?.name, public: detailQuery?.data?.public || false, }, serverId: detailQuery?.data?.serverId, }, { onSuccess: (data) => { toast.success({ message: 'Playlist has been saved' }); navigate( generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: data?.id || '', }), { replace: true, }, ); deletePlaylistMutation.mutate({ query: { id: playlistId }, serverId: detailQuery?.data?.serverId, }); }, }, ); }; const handleSaveAs = ( filter: Record, extraFilters: { limit?: number; sortBy?: string; sortOrder?: string }, ) => { openModal({ children: ( navigate( generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: data?.id || '', }), ) } serverId={detailQuery?.data?.serverId} /> ), title: t('common.saveAs', { postProcess: 'sentenceCase' }), }); }; const isSmartPlaylist = !detailQuery?.isLoading && detailQuery?.data?.rules && server?.type === ServerType.NAVIDROME; const [showQueryBuilder, setShowQueryBuilder] = useState(false); const [isQueryBuilderExpanded, setIsQueryBuilderExpanded] = useState(false); const handleToggleExpand = () => { setIsQueryBuilderExpanded((prev) => !prev); }; const handleToggleShowQueryBuilder = () => { setShowQueryBuilder((prev) => !prev); setIsQueryBuilderExpanded(true); }; const page = usePlaylistDetailStore(); const playlistSongs = usePlaylistSongList({ query: { id: playlistId, }, serverId: server?.id, }); const filterSortedSongs = useMemo(() => { let items = playlistSongs.data?.items; if (items) { const searchTerm = page?.table.id[playlistId]?.filter?.searchTerm; if (searchTerm) { items = searchSongs(items, searchTerm); } const sortBy = page?.table.id[playlistId]?.filter?.sortBy || SongListSort.ID; const sortOrder = page?.table.id[playlistId]?.filter?.sortOrder || SortOrder.ASC; return sortSongList(items, sortBy, sortOrder); } else { return []; } }, [playlistSongs.data?.items, page?.table.id, playlistId]); const itemCount = typeof playlistSongs.data?.totalRecordCount === 'number' ? filterSortedSongs.length : undefined; const handlePlay = (play: Play) => { handlePlayQueueAdd?.({ byData: filterSortedSongs, playType: play, }); }; return ( {(isSmartPlaylist || showQueryBuilder) && ( {t('form.queryEditor.title', { postProcess: 'titleCase' })} {isQueryBuilderExpanded && ( )} )} ); }; export default PlaylistDetailSongListRoute;