/* eslint-disable no-plusplus */ import { useState, useCallback, useMemo } from 'react'; import { Group, Box, Slider } from '@mantine/core'; import { useDebouncedValue, useSetState, useToggle } from '@mantine/hooks'; import { useQueryClient } from '@tanstack/react-query'; import { AnimatePresence, motion } from 'framer-motion'; import throttle from 'lodash/throttle'; import { nanoid } from 'nanoid'; import { RiArrowDownSLine, RiDeleteBack2Fill, RiSettings2Fill, } from 'react-icons/ri'; import AutoSizer from 'react-virtualized-auto-sizer'; import { api } from '@/renderer/api'; import { AlbumSort } from '@/renderer/api/albums.api'; import { queryKeys } from '@/renderer/api/query-keys'; import { SortOrder } from '@/renderer/api/types'; import { Button, DropdownMenu, NumberInput, ScrollArea, Paper, Text, VirtualGridAutoSizerContainer, VirtualGridContainer, VirtualInfiniteGrid, } from '@/renderer/components'; import { AdvancedFilterGroup, AdvancedFilters, FilterGroupType, encodeAdvancedFiltersQuery, } from '@/renderer/features/albums/components/advanced-filters'; import { useAlbumList } from '@/renderer/features/albums/queries/use-album-list'; import { useServerList } from '@/renderer/features/servers'; import { AnimatedPage, useServerCredential } from '@/renderer/features/shared'; import { AppRoute } from '@/renderer/router/routes'; import { useAppStore, useAuthStore } from '@/renderer/store'; import { LibraryItem, CardDisplayType } from '@/renderer/types'; const FILTERS = [ { name: 'Title', value: AlbumSort.NAME }, { name: 'Date added', value: AlbumSort.DATE_ADDED }, { name: 'Date Added (remote)', value: AlbumSort.DATE_ADDED_REMOTE, }, { name: 'Release Date', value: AlbumSort.DATE_RELEASED }, { name: 'Year', value: AlbumSort.DATE_RELEASED_YEAR }, { name: 'Random', value: AlbumSort.RANDOM }, { name: 'Favorites', value: AlbumSort.FAVORITE }, { name: 'Rating', value: AlbumSort.RATING }, ]; const ORDER = [ { name: 'Ascending', value: SortOrder.ASC }, { name: 'Descending', value: SortOrder.DESC }, ]; const DEFAULT_ADVANCED_FILTERS = { group: [], rules: [ { field: '', operator: '', uniqueId: nanoid(), value: '', }, ], type: FilterGroupType.AND, uniqueId: nanoid(), }; export const AlbumListRoute = () => { const queryClient = useQueryClient(); const { serverToken, isImageTokenRequired } = useServerCredential(); const page = useAppStore((state) => state.albums); const setPage = useAppStore((state) => state.setPage); const serverId = useAuthStore((state) => state.currentServer?.id) || ''; const { data: servers } = useServerList({ enabled: true }); const [filters, setFilters] = useSetState({ orderBy: SortOrder.ASC, serverFolderId: [] as string[], sortBy: AlbumSort.NAME, }); const [isAdvFilter, toggleAdvFilter] = useToggle(); const [rawAdvFilters, setRawAdvFilters] = useState( DEFAULT_ADVANCED_FILTERS ); const [debouncedAdvFilters] = useDebouncedValue(rawAdvFilters, 500); const advancedFilters = useMemo(() => { if (!isAdvFilter) { return encodeAdvancedFiltersQuery(DEFAULT_ADVANCED_FILTERS); } return encodeAdvancedFiltersQuery(debouncedAdvFilters); }, [debouncedAdvFilters, isAdvFilter]); const handleResetAdvancedFilters = () => { setRawAdvFilters(DEFAULT_ADVANCED_FILTERS); }; const serverFolders = useMemo(() => { const server = servers?.data.find((server) => server.id === serverId); return server?.serverFolders; }, [serverId, servers]); const { data: albums } = useAlbumList({ advancedFilters, orderBy: filters.orderBy, serverFolderId: filters.serverFolderId, skip: 0, sortBy: filters.sortBy, take: 0, }); const fetch = useCallback( async ({ skip, take }: { skip: number; take: number }) => { const albums = await queryClient.fetchQuery( queryKeys.albums.list(serverId, { skip, take, ...filters, advancedFilters, }), async () => api.albums.getAlbumList( { serverId }, { skip, take, ...filters, advancedFilters } ) ); // * Adds server token if (isImageTokenRequired) { const data = albums.data.map((album) => { return { ...album, imageUrl: album.imageUrl && album.imageUrl + serverToken!, }; }); return { ...albums, data }; } return albums; }, [ advancedFilters, filters, isImageTokenRequired, queryClient, serverId, serverToken, ] ); const setSize = throttle( (e: number) => setPage('albums', { ...page, list: { ...page.list, size: e }, }), 200 ); return ( Albums {FILTERS.map((filter) => ( setFilters({ sortBy: filter.value })} > {filter.name} ))} toggleAdvFilter()} > Advanced Filters {ORDER.map((sort) => ( setFilters({ orderBy: sort.value })} > {sort.name} ))} {serverFolders?.map((folder) => ( { if (filters.serverFolderId.includes(folder.id)) { setFilters({ serverFolderId: filters.serverFolderId.filter( (id) => id !== folder.id ), }); } else { setFilters({ serverFolderId: [ ...filters.serverFolderId, folder.id, ], }); } }} > {folder.name} ))} setPage('albums', { ...page, list: { ...page.list, display: CardDisplayType.CARD, type: 'grid', }, }) } > Card setPage('albums', { ...page, list: { ...page.list, display: CardDisplayType.POSTER, type: 'grid', }, }) } > Poster setPage('albums', { ...page, list: { ...page.list, type: 'list', }, }) } > List {isAdvFilter && ( Advanced Filters )} {({ height, width }) => ( )} ); };