import { throttle } from 'lodash'; import React, { useCallback, useEffect, useMemo, useRef, useState, } from 'react'; import { useSelector } from 'react-redux'; import { FixedSizeList as List, ListChildComponentProps } from 'react-window'; import TextInput from 'Components/Form/TextInput'; import Button from 'Components/Link/Button'; import ModalBody from 'Components/Modal/ModalBody'; import ModalContent from 'Components/Modal/ModalContent'; import ModalFooter from 'Components/Modal/ModalFooter'; import ModalHeader from 'Components/Modal/ModalHeader'; import Scroller from 'Components/Scroller/Scroller'; import Column from 'Components/Table/Column'; import VirtualTableRowButton from 'Components/Table/VirtualTableRowButton'; import { scrollDirections } from 'Helpers/Props'; import Series from 'Series/Series'; import createAllSeriesSelector from 'Store/Selectors/createAllSeriesSelector'; import dimensions from 'Styles/Variables/dimensions'; import sortByProp from 'Utilities/Array/sortByProp'; import translate from 'Utilities/String/translate'; import SelectSeriesModalTableHeader from './SelectSeriesModalTableHeader'; import SelectSeriesRow from './SelectSeriesRow'; import styles from './SelectSeriesModalContent.css'; const columns = [ { name: 'title', label: () => translate('Title'), isVisible: true, }, { name: 'year', label: () => translate('Year'), isVisible: true, }, { name: 'tvdbId', label: () => translate('TvdbId'), isVisible: true, }, { name: 'imdbId', label: () => translate('ImdbId'), isVisible: true, }, ]; const bodyPadding = parseInt(dimensions.pageContentBodyPadding); interface SelectSeriesModalContentProps { modalTitle: string; onSeriesSelect(series: Series): void; onModalClose(): void; } interface RowItemData { items: Series[]; columns: Column[]; onSeriesSelect(seriesId: number): void; } const Row: React.FC> = ({ index, style, data, }) => { const { items, columns, onSeriesSelect } = data; if (index >= items.length) { return null; } const series = items[index]; return ( onSeriesSelect(series.id)} > ); }; function SelectSeriesModalContent(props: SelectSeriesModalContentProps) { const { modalTitle, onSeriesSelect, onModalClose } = props; const listRef = useRef>(null); const scrollerRef = useRef(null); const allSeries: Series[] = useSelector(createAllSeriesSelector()); const [filter, setFilter] = useState(''); const [size, setSize] = useState({ width: 0, height: 0 }); const windowHeight = window.innerHeight; useEffect(() => { const current = scrollerRef?.current as HTMLElement; if (current) { const width = current.clientWidth; const height = current.clientHeight; const padding = bodyPadding - 5; setSize({ width: width - padding * 2, height: height + padding, }); } }, [windowHeight, scrollerRef]); useEffect(() => { const currentScrollerRef = scrollerRef.current as HTMLElement; const currentScrollListener = currentScrollerRef; const handleScroll = throttle(() => { const { offsetTop = 0 } = currentScrollerRef; const scrollTop = currentScrollerRef.scrollTop - offsetTop; listRef.current?.scrollTo(scrollTop); }, 10); currentScrollListener.addEventListener('scroll', handleScroll); return () => { handleScroll.cancel(); if (currentScrollListener) { currentScrollListener.removeEventListener('scroll', handleScroll); } }; }, [listRef, scrollerRef]); const onFilterChange = useCallback( ({ value }: { value: string }) => { setFilter(value); }, [setFilter] ); const onSeriesSelectWrapper = useCallback( (seriesId: number) => { const series = allSeries.find((s) => s.id === seriesId) as Series; onSeriesSelect(series); }, [allSeries, onSeriesSelect] ); const sortedSeries = useMemo( () => [...allSeries].sort(sortByProp('sortTitle')), [allSeries] ); const items = useMemo( () => sortedSeries.filter( (item) => item.title.toLowerCase().includes(filter.toLowerCase()) || item.tvdbId.toString().includes(filter) || item.imdbId?.includes(filter) ), [sortedSeries, filter] ); return ( {modalTitle} - Select Series ref={listRef} style={{ width: '100%', height: '100%', overflow: 'none', }} width={size.width} height={size.height} itemCount={items.length} itemSize={38} itemData={{ items, columns, onSeriesSelect: onSeriesSelectWrapper, }} > {Row} ); } export default SelectSeriesModalContent;