import { useSuspenseQuery } from '@tanstack/react-query'; import clsx from 'clsx'; import formatDuration from 'format-duration'; import { motion } from 'motion/react'; import { Fragment, Suspense, useCallback, useRef } from 'react'; import styles from './expanded-album-list-item.module.css'; import { getDraggedItems } from '/@/renderer/components/item-list/helpers/get-dragged-items'; import { useDefaultItemListControls } from '/@/renderer/components/item-list/helpers/item-list-controls'; import { ItemListStateActions, ItemListStateItem, useItemListState, } from '/@/renderer/components/item-list/helpers/item-list-state'; import { ItemListItem } from '/@/renderer/components/item-list/types'; import { albumQueries } from '/@/renderer/features/albums/api/album-api'; import { useFastAverageColor } from '/@/renderer/hooks'; import { useDragDrop } from '/@/renderer/hooks/use-drag-drop'; import { ActionIcon } from '/@/shared/components/action-icon/action-icon'; import { Group } from '/@/shared/components/group/group'; import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area'; import { Separator } from '/@/shared/components/separator/separator'; import { Spinner } from '/@/shared/components/spinner/spinner'; import { TextTitle } from '/@/shared/components/text-title/text-title'; import { Text } from '/@/shared/components/text/text'; import { useMergedRef } from '/@/shared/hooks/use-merged-ref'; import { LibraryItem, Song } from '/@/shared/types/domain-types'; import { DragOperation, DragTarget, DragTargetMap } from '/@/shared/types/drag-and-drop'; interface AlbumTracksTableProps { isDark?: boolean; serverId: string; songs?: Array<{ discNumber: number; duration: number; id: string; name: string; trackNumber: number; }>; } interface ExpandedAlbumListItemProps { internalState?: ItemListStateActions; item: ItemListStateItem; } interface TrackRowProps { controls: ReturnType; internalState: ItemListStateActions; serverId: string; song: NonNullable[0]; } const TrackRow = ({ controls, internalState, serverId, song }: TrackRowProps) => { const rowId = internalState.extractRowId(song); const isSelected = rowId ? internalState.isSelected(rowId) : false; const songWithMetadata = { ...song, _serverId: serverId, itemType: LibraryItem.SONG, } as unknown as ItemListItem; const { isDraggedOver, isDragging: isDraggingLocal, ref: dragRef, } = useDragDrop({ drag: { getId: () => { const draggedItems = getDraggedItems( songWithMetadata as unknown as Song, internalState, ); return draggedItems.map((draggedItem) => draggedItem.id); }, getItem: () => { const draggedItems = getDraggedItems( songWithMetadata as unknown as Song, internalState, ); return draggedItems; }, itemType: LibraryItem.SONG, onDragStart: () => { const draggedItems = getDraggedItems( songWithMetadata as unknown as Song, internalState, ); internalState.setDragging(draggedItems); }, onDrop: () => { internalState.setDragging([]); }, operation: [DragOperation.ADD], target: DragTargetMap[LibraryItem.SONG] || DragTarget.GENERIC, }, isEnabled: true, }); const isDragging = internalState.isDragging(song.id) || isDraggingLocal; const containerRef = useRef(null); const mergedRef = useMergedRef(containerRef, dragRef); return ( controls.onClick?.({ event: e, internalState, item: songWithMetadata, itemType: LibraryItem.SONG, }) } ref={mergedRef} size="sm" > {song.discNumber} - {song.trackNumber} {song.name} {formatDuration(song.duration)} ); }; const AlbumTracksTable = ({ isDark, serverId, songs }: AlbumTracksTableProps) => { const getDataFn = useCallback(() => songs || [], [songs]); const extractRowId = useCallback((item: unknown) => { if (item && typeof item === 'object' && 'id' in item) { return (item as { id: string }).id; } return undefined; }, []); const internalState = useItemListState(getDataFn, extractRowId); const controls = useDefaultItemListControls(); return (
{songs?.map((song) => ( ))}
); }; export const ExpandedAlbumListItem = ({ internalState, item }: ExpandedAlbumListItemProps) => { const { data, isLoading } = useSuspenseQuery( albumQueries.detail({ query: { id: item.id }, serverId: item._serverId, }), ); const color = useFastAverageColor({ algorithm: 'sqrt', id: item.id, src: data?.imageUrl, srcLoaded: true, }); if (color.isLoading) { return null; } return ( {isLoading && (
)}
{data?.name} {internalState && ( { const rowId = internalState.extractRowId(item); if (rowId) { internalState.clearExpanded(); } }} radius="50%" size="sm" variant="default" /> )}
{data?.albumArtists.map((artist, index) => ( {artist.name} {index < data?.albumArtists.length - 1 && } ))}
); };