import { closeAllModals, openModal } from '@mantine/modals'; import { MouseEvent, useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { generatePath } from 'react-router'; import { Link } from 'react-router-dom'; import styles from './sidebar-playlist-list.module.css'; import { usePlayQueueAdd } from '/@/renderer/features/player'; import { CreatePlaylistForm, usePlaylistList } from '/@/renderer/features/playlists'; import { SidebarItem } from '/@/renderer/features/sidebar/components/sidebar-item'; import { AppRoute } from '/@/renderer/router/routes'; import { useCurrentServer } from '/@/renderer/store'; import { Accordion } from '/@/shared/components/accordion/accordion'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { ButtonProps } from '/@/shared/components/button/button'; import { Group } from '/@/shared/components/group/group'; import { Text } from '/@/shared/components/text/text'; import { LibraryItem, Playlist, PlaylistListSort, ServerType, SortOrder, } from '/@/shared/types/domain-types'; import { Play } from '/@/shared/types/types'; interface PlaylistRowButtonProps extends Omit { name: string; onPlay: (id: string, playType: Play.LAST | Play.NEXT | Play.NOW | Play.SHUFFLE) => void; to: string; } const PlaylistRowButton = ({ name, onPlay, to, ...props }: PlaylistRowButtonProps) => { const url = generatePath(AppRoute.PLAYLISTS_DETAIL_SONGS, { playlistId: to }); const [isHovered, setIsHovered] = useState(false); return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} > {name} {isHovered && ( )}
); }; const RowControls = ({ id, onPlay, }: { id: string; onPlay: (id: string, playType: Play) => void; }) => { const { t } = useTranslation(); return ( { if (!id) return; onPlay(id, Play.NOW); }} size="xs" tooltip={{ label: t('player.play', { postProcess: 'sentenceCase' }), openDelay: 500, }} variant="subtle" /> { if (!id) return; onPlay(id, Play.SHUFFLE); }} size="xs" tooltip={{ label: t('player.shuffle', { postProcess: 'sentenceCase' }), openDelay: 500, }} variant="subtle" /> { if (!id) return; onPlay(id, Play.LAST); }} size="xs" tooltip={{ label: t('player.addLast', { postProcess: 'sentenceCase' }), openDelay: 500, }} variant="subtle" /> { if (!id) return; onPlay(id, Play.NEXT); }} size="xs" tooltip={{ label: t('player.addNext', { postProcess: 'sentenceCase' }), openDelay: 500, }} variant="subtle" /> ); }; export const SidebarPlaylistList = () => { const handlePlayQueueAdd = usePlayQueueAdd(); const { t } = useTranslation(); const server = useCurrentServer(); const playlistsQuery = usePlaylistList({ query: { sortBy: PlaylistListSort.NAME, sortOrder: SortOrder.ASC, startIndex: 0, }, serverId: server?.id, }); const handlePlayPlaylist = useCallback( (id: string, playType: Play) => { handlePlayQueueAdd?.({ byItemType: { id: [id], type: LibraryItem.PLAYLIST, }, playType, }); }, [handlePlayQueueAdd], ); const data = playlistsQuery.data; const memoizedItemData = useMemo(() => { const base = { handlePlay: handlePlayPlaylist }; if (!server?.type || !server?.username || !data?.items) { return { ...base, items: data?.items }; } const owned: Array<[boolean, () => void] | Playlist> = []; for (const playlist of data.items) { owned.push(playlist); } return { ...base, items: owned }; }, [data?.items, handlePlayPlaylist, server?.type, server?.username]); const handleCreatePlaylistModal = (e: MouseEvent) => { e.stopPropagation(); openModal({ children: closeAllModals()} />, size: server?.type === ServerType?.NAVIDROME ? 'lg' : 'sm', title: t('form.createPlaylist.title', { postProcess: 'titleCase' }), }); }; return ( {t('page.sidebar.playlists', { postProcess: 'titleCase', })} e.stopPropagation()} size="xs" to={AppRoute.PLAYLISTS} tooltip={{ label: t('action.viewPlaylists', { postProcess: 'sentenceCase', }), openDelay: 500, }} variant="subtle" /> {memoizedItemData?.items?.map((item, index) => ( ))} ); }; export const SidebarSharedPlaylistList = () => { const handlePlayQueueAdd = usePlayQueueAdd(); const { t } = useTranslation(); const server = useCurrentServer(); const playlistsQuery = usePlaylistList({ query: { sortBy: PlaylistListSort.NAME, sortOrder: SortOrder.ASC, startIndex: 0, }, serverId: server?.id, }); const handlePlayPlaylist = useCallback( (id: string, playType: Play) => { handlePlayQueueAdd?.({ byItemType: { id: [id], type: LibraryItem.PLAYLIST, }, playType, }); }, [handlePlayQueueAdd], ); const data = playlistsQuery.data; const memoizedItemData = useMemo(() => { const base = { handlePlay: handlePlayPlaylist }; if (!server?.type || !server?.username || !data?.items) { return { ...base, items: data?.items }; } const shared: Playlist[] = []; for (const playlist of data.items) { if (playlist.owner && playlist.owner !== server.username) { shared.push(playlist); } } return { ...base, items: shared }; }, [data?.items, handlePlayPlaylist, server?.type, server?.username]); if (memoizedItemData?.items?.length === 0) { return null; } return ( {t('page.sidebar.shared', { postProcess: 'titleCase', })} {memoizedItemData?.items?.map((item, index) => ( ))} ); };