feishin/src/renderer/features/songs/components/song-list-header.tsx

150 lines
4.8 KiB
TypeScript
Raw Normal View History

2022-12-27 13:52:50 -08:00
import type { IDatasource } from '@ag-grid-community/core';
import type { AgGridReact as AgGridReactType } from '@ag-grid-community/react/lib/agGridReact';
2022-12-28 01:23:54 -08:00
import { Flex, Group, Stack } from '@mantine/core';
2022-12-27 13:52:50 -08:00
import debounce from 'lodash/debounce';
2023-02-05 22:41:47 -08:00
import { ChangeEvent, MutableRefObject, useCallback } from 'react';
2022-12-27 13:52:50 -08:00
import { api } from '/@/renderer/api';
import { queryKeys } from '/@/renderer/api/query-keys';
2023-02-05 22:41:47 -08:00
import { LibraryItem, SongListQuery } from '/@/renderer/api/types';
import { PageHeader, Paper, SearchInput, SpinnerIcon } from '/@/renderer/components';
import { usePlayQueueAdd } from '/@/renderer/features/player';
2023-02-05 22:41:47 -08:00
import { LibraryHeaderBar } from '/@/renderer/features/shared';
import { SongListHeaderFilters } from '/@/renderer/features/songs/components/song-list-header-filters';
2022-12-27 13:52:50 -08:00
import { useContainerQuery } from '/@/renderer/hooks';
import { queryClient } from '/@/renderer/lib/react-query';
import {
SongListFilter,
useCurrentServer,
useSetSongFilters,
useSetSongTablePagination,
useSongListStore,
} from '/@/renderer/store';
2023-02-05 22:41:47 -08:00
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
import { Play } from '/@/renderer/types';
2022-12-19 15:59:14 -08:00
2022-12-27 13:52:50 -08:00
interface SongListHeaderProps {
2023-01-15 20:39:43 -08:00
customFilters?: Partial<SongListFilter>;
itemCount?: number;
2022-12-27 13:52:50 -08:00
tableRef: MutableRefObject<AgGridReactType | null>;
2023-01-15 20:39:43 -08:00
title?: string;
2022-12-27 13:52:50 -08:00
}
2023-01-15 20:39:43 -08:00
export const SongListHeader = ({
customFilters,
title,
itemCount,
tableRef,
}: SongListHeaderProps) => {
2022-12-19 15:59:14 -08:00
const server = useCurrentServer();
2022-12-27 13:52:50 -08:00
const page = useSongListStore();
const setFilter = useSetSongFilters();
2022-12-28 01:23:54 -08:00
const setPagination = useSetSongTablePagination();
const handlePlayQueueAdd = usePlayQueueAdd();
2022-12-27 13:52:50 -08:00
const cq = useContainerQuery();
const handleFilterChange = useCallback(
async (filters?: SongListFilter) => {
const dataSource: IDatasource = {
getRows: async (params) => {
const limit = params.endRow - params.startRow;
const startIndex = params.startRow;
const pageFilters = filters || page.filter;
2023-01-15 20:39:43 -08:00
const query: SongListQuery = {
2022-12-27 13:52:50 -08:00
limit,
startIndex,
...pageFilters,
2023-01-15 20:39:43 -08:00
...customFilters,
};
const queryKey = queryKeys.songs.list(server?.id || '', query);
2022-12-27 13:52:50 -08:00
const songsRes = await queryClient.fetchQuery(
queryKey,
async ({ signal }) =>
api.controller.getSongList({
2023-01-15 20:39:43 -08:00
query,
server,
signal,
}),
{ cacheTime: 1000 * 60 * 1 },
2022-12-27 13:52:50 -08:00
);
2022-12-19 15:59:14 -08:00
2022-12-27 13:52:50 -08:00
const songs = api.normalize.songList(songsRes, server);
params.successCallback(songs?.items || [], songsRes?.totalRecordCount || 0);
2022-12-27 13:52:50 -08:00
},
rowCount: undefined,
};
tableRef.current?.api.setDatasource(dataSource);
tableRef.current?.api.purgeInfiniteCache();
tableRef.current?.api.ensureIndexVisible(0, 'top');
2022-12-28 01:23:54 -08:00
setPagination({ currentPage: 0 });
2022-12-27 13:52:50 -08:00
},
2023-01-15 20:39:43 -08:00
[customFilters, page.filter, server, setPagination, tableRef],
2022-12-19 15:59:14 -08:00
);
2022-12-27 13:52:50 -08:00
const handleSearch = debounce((e: ChangeEvent<HTMLInputElement>) => {
const previousSearchTerm = page.filter.searchTerm;
const searchTerm = e.target.value === '' ? undefined : e.target.value;
const updatedFilters = setFilter({ searchTerm });
if (previousSearchTerm !== searchTerm) handleFilterChange(updatedFilters);
2022-12-27 13:52:50 -08:00
}, 500);
2023-02-05 22:41:47 -08:00
const playButtonBehavior = usePlayButtonBehavior();
const handlePlay = async (play: Play) => {
if (!itemCount || itemCount === 0) return;
const query: SongListQuery = { startIndex: 0, ...page.filter, ...customFilters };
handlePlayQueueAdd?.({
byItemType: {
id: query,
type: LibraryItem.SONG,
},
play,
});
};
2022-12-19 15:59:14 -08:00
return (
2023-02-05 22:41:47 -08:00
<Stack
ref={cq.ref}
spacing={0}
>
<PageHeader backgroundColor="var(--titlebar-bg)">
2022-12-27 13:52:50 -08:00
<Flex
2023-02-05 22:41:47 -08:00
justify="space-between"
w="100%"
2022-12-19 15:59:14 -08:00
>
2023-02-05 22:41:47 -08:00
<LibraryHeaderBar>
<LibraryHeaderBar.PlayButton onClick={() => handlePlay(playButtonBehavior)} />
<LibraryHeaderBar.Title>{title || 'Tracks'}</LibraryHeaderBar.Title>
2023-02-05 22:41:47 -08:00
<Paper
fw="600"
px="1rem"
py="0.3rem"
radius="sm"
>
{itemCount === null || itemCount === undefined ? <SpinnerIcon /> : itemCount}
</Paper>
</LibraryHeaderBar>
<Group>
<SearchInput
defaultValue={page.filter.searchTerm}
openedWidth={cq.isMd ? 250 : cq.isSm ? 200 : 150}
onChange={handleSearch}
/>
</Group>
2022-12-27 13:52:50 -08:00
</Flex>
2023-02-05 22:41:47 -08:00
</PageHeader>
2023-02-06 02:17:47 -08:00
<Paper p="1rem">
2023-02-05 22:41:47 -08:00
<SongListHeaderFilters
customFilters={customFilters}
itemCount={itemCount}
tableRef={tableRef}
/>
</Paper>
</Stack>
2022-12-19 15:59:14 -08:00
);
};