import classNames from 'classnames'; import { useEffect, useMemo, type FunctionComponent } from 'react'; import { List, useListRef } from 'react-window'; import { useDebounce } from 'use-debounce'; import { useLatest } from 'hooks'; import { LOCALE_FEATURES } from 'i18n'; import { RESULTS_ITEM_HEIGHT } from 'parameters'; import { selectAreResultsOutdated, selectLocale, selectProcessedResults, selectSolveError, selectSolveIsLoading, useTranslate, useTypedSelector, } from 'state'; import { EmptyState } from '../EmptyState'; import { Loading } from '../Loading'; import { ResultsInput } from '../ResultsInput'; import { Header } from './Header'; import { Result } from './Result'; import styles from './Results.module.scss'; import { SolveButton } from './SolveButton'; import { type ResultCallbacks, type ResultData } from './types'; interface Props { callbacks: ResultCallbacks; className?: string; highlightedIndex?: number; } const IS_LOADING_DEBOUNCE = 100; export const Results: FunctionComponent = ({ callbacks, className, highlightedIndex }) => { const translate = useTranslate(); const locale = useTypedSelector(selectLocale); const { direction } = LOCALE_FEATURES[locale]; const results = useTypedSelector(selectProcessedResults); const isLoading = useTypedSelector(selectSolveIsLoading); const [isLoadingDebounced] = useDebounce(isLoading, IS_LOADING_DEBOUNCE); const isOutdated = useTypedSelector(selectAreResultsOutdated); const error = useTypedSelector(selectSolveError); const itemData = useMemo( () => ({ ...callbacks, highlightedIndex, results }), [callbacks, highlightedIndex, results], ); const listRef = useListRef(null); const scrollToIndex = typeof highlightedIndex === 'number' ? highlightedIndex : 0; const scrollToIndexRef = useLatest(scrollToIndex); const hasResults = typeof error === 'undefined' && typeof results !== 'undefined'; const showInput = hasResults && results.length > 0 && !isOutdated; useEffect(() => { // without setTimeout, the initial scrolling offset is calculated // incorrectly, as the list is not fully rendered by the browser yet const timeout = globalThis.setTimeout(() => { listRef.current?.scrollToRow({ align: 'center', behavior: 'instant', index: scrollToIndexRef.current, }); }, 0); return () => { globalThis.clearTimeout(timeout); }; }, [results, listRef, scrollToIndexRef]); return (
{typeof error !== 'undefined' && ( {error.message} )} {typeof error === 'undefined' && typeof results === 'undefined' && ( {translate('results.empty-state.uninitialized')} )} {hasResults && ( <> {isOutdated && ( {translate('results.empty-state.outdated')} )} {!isOutdated && results.length === 0 && ( {translate('results.empty-state.no-results')} )} {!isOutdated && results.length > 0 && (
)} )}
{showInput && } {isLoadingDebounced && }
); };