import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { SelectProvider } from 'App/SelectContext'; import ClientSideCollectionAppState from 'App/State/ClientSideCollectionAppState'; import IndexerAppState, { IndexerIndexAppState, } from 'App/State/IndexerAppState'; import { APP_INDEXER_SYNC } from 'Commands/commandNames'; import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import PageContent from 'Components/Page/PageContent'; import PageContentBody from 'Components/Page/PageContentBody'; import PageJumpBar from 'Components/Page/PageJumpBar'; import PageToolbar from 'Components/Page/Toolbar/PageToolbar'; import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton'; import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection'; import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator'; import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper'; import withScrollPosition from 'Components/withScrollPosition'; import { align, icons } from 'Helpers/Props'; import SortDirection from 'Helpers/Props/SortDirection'; import AddIndexerModal from 'Indexer/Add/AddIndexerModal'; import EditIndexerModalConnector from 'Indexer/Edit/EditIndexerModalConnector'; import NoIndexer from 'Indexer/NoIndexer'; import { executeCommand } from 'Store/Actions/commandActions'; import { cloneIndexer, fetchIndexers, testAllIndexers, } from 'Store/Actions/indexerActions'; import { setIndexerFilter, setIndexerSort, setIndexerTableOption, } from 'Store/Actions/indexerIndexActions'; import { fetchIndexerStatus } from 'Store/Actions/indexerStatusActions'; import scrollPositions from 'Store/scrollPositions'; import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector'; import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector'; import createIndexerClientSideCollectionItemsSelector from 'Store/Selectors/createIndexerClientSideCollectionItemsSelector'; import translate from 'Utilities/String/translate'; import IndexerIndexFooter from './IndexerIndexFooter'; import IndexerIndexFilterMenu from './Menus/IndexerIndexFilterMenu'; import IndexerIndexSortMenu from './Menus/IndexerIndexSortMenu'; import IndexerIndexSelectAllButton from './Select/IndexerIndexSelectAllButton'; import IndexerIndexSelectAllMenuItem from './Select/IndexerIndexSelectAllMenuItem'; import IndexerIndexSelectFooter from './Select/IndexerIndexSelectFooter'; import IndexerIndexSelectModeButton from './Select/IndexerIndexSelectModeButton'; import IndexerIndexSelectModeMenuItem from './Select/IndexerIndexSelectModeMenuItem'; import IndexerIndexTable from './Table/IndexerIndexTable'; import IndexerIndexTableOptions from './Table/IndexerIndexTableOptions'; import styles from './IndexerIndex.css'; const getViewComponent = () => IndexerIndexTable; interface IndexerIndexProps { initialScrollTop?: number; } const IndexerIndex = withScrollPosition((props: IndexerIndexProps) => { const { isFetching, isPopulated, isTestingAll, error, totalItems, items, columns, selectedFilterKey, filters, customFilters, sortKey, sortDirection, view, }: IndexerAppState & IndexerIndexAppState & ClientSideCollectionAppState = useSelector(createIndexerClientSideCollectionItemsSelector('indexerIndex')); const isSyncingIndexers = useSelector( createCommandExecutingSelector(APP_INDEXER_SYNC) ); const { isSmallScreen } = useSelector(createDimensionsSelector()); const dispatch = useDispatch(); const scrollerRef = useRef(null); const [isAddIndexerModalOpen, setIsAddIndexerModalOpen] = useState(false); const [isEditIndexerModalOpen, setIsEditIndexerModalOpen] = useState(false); const [jumpToCharacter, setJumpToCharacter] = useState( undefined ); const [isSelectMode, setIsSelectMode] = useState(false); useEffect(() => { dispatch(fetchIndexers()); dispatch(fetchIndexerStatus()); }, [dispatch]); const onAddIndexerPress = useCallback(() => { setIsAddIndexerModalOpen(true); }, [setIsAddIndexerModalOpen]); const onAddIndexerModalClose = useCallback(() => { setIsAddIndexerModalOpen(false); }, [setIsAddIndexerModalOpen]); const onEditIndexerPress = useCallback(() => { setIsEditIndexerModalOpen(true); }, [setIsEditIndexerModalOpen]); const onEditIndexerModalClose = useCallback(() => { setIsEditIndexerModalOpen(false); }, [setIsEditIndexerModalOpen]); const onCloneIndexerPress = useCallback( (id: number) => { dispatch(cloneIndexer({ id })); setIsEditIndexerModalOpen(true); }, [dispatch, setIsEditIndexerModalOpen] ); const onAppIndexerSyncPress = useCallback(() => { dispatch( executeCommand({ name: APP_INDEXER_SYNC, forceSync: true, }) ); }, [dispatch]); const onTestAllPress = useCallback(() => { dispatch(testAllIndexers()); }, [dispatch]); const onSelectModePress = useCallback(() => { setIsSelectMode(!isSelectMode); }, [isSelectMode, setIsSelectMode]); const onTableOptionChange = useCallback( (payload: unknown) => { dispatch(setIndexerTableOption(payload)); }, [dispatch] ); const onSortSelect = useCallback( (value: string) => { dispatch(setIndexerSort({ sortKey: value })); }, [dispatch] ); const onFilterSelect = useCallback( (value: string) => { dispatch(setIndexerFilter({ selectedFilterKey: value })); }, [dispatch] ); const onJumpBarItemPress = useCallback( (character: string) => { setJumpToCharacter(character); }, [setJumpToCharacter] ); const onScroll = useCallback( ({ scrollTop }: { scrollTop: number }) => { setJumpToCharacter(undefined); scrollPositions.indexerIndex = scrollTop; }, [setJumpToCharacter] ); const jumpBarItems = useMemo(() => { // Reset if not sorting by sortName if (sortKey !== 'sortName') { return { order: [], }; } const characters = items.reduce((acc: Record, item) => { let char = item.sortName.charAt(0); if (!isNaN(Number(char))) { char = '#'; } if (char in acc) { acc[char] = acc[char] + 1; } else { acc[char] = 1; } return acc; }, {}); const order = Object.keys(characters).sort(); // Reverse if sorting descending if (sortDirection === SortDirection.Descending) { order.reverse(); } return { characters, order, }; }, [items, sortKey, sortDirection]); const ViewComponent = useMemo(() => getViewComponent(), []); const isLoaded = !!(!error && isPopulated && items.length); const hasNoIndexer = !totalItems; return (
{isFetching && !isPopulated ? : null} {!isFetching && !!error ? (
{translate('UnableToLoadIndexers')}
) : null} {isLoaded ? (
) : null} {!error && isPopulated && !items.length ? ( ) : null}
{isLoaded && !!jumpBarItems.order.length ? ( ) : null}
{isSelectMode ? : null}
); }, 'indexerIndex'); export default IndexerIndex;