import _ from 'lodash'; import PropTypes from 'prop-types'; import React, { Component } from 'react'; import ReactDOM from 'react-dom'; import Measure from 'react-measure'; import { Grid, WindowScroller } from 'react-virtualized'; import hasDifferentItems from 'Utilities/Object/hasDifferentItems'; import dimensions from 'Styles/Variables/dimensions'; import { sortDirections } from 'Helpers/Props'; import ArtistIndexItemConnector from 'Artist/Index/ArtistIndexItemConnector'; import ArtistIndexOverview from './ArtistIndexOverview'; import styles from './ArtistIndexOverviews.css'; // Poster container dimensions const columnPadding = parseInt(dimensions.artistIndexColumnPadding); const columnPaddingSmallScreen = parseInt(dimensions.artistIndexColumnPaddingSmallScreen); const progressBarHeight = parseInt(dimensions.progressBarSmallHeight); const detailedProgressBarHeight = parseInt(dimensions.progressBarMediumHeight); function calculatePosterWidth(posterSize, isSmallScreen) { const maxiumPosterWidth = isSmallScreen ? 192 : 202; if (posterSize === 'large') { return maxiumPosterWidth; } if (posterSize === 'medium') { return Math.floor(maxiumPosterWidth * 0.75); } return Math.floor(maxiumPosterWidth * 0.5); } function calculateRowHeight(posterHeight, sortKey, isSmallScreen, overviewOptions) { const { detailedProgressBar } = overviewOptions; const heights = [ posterHeight, detailedProgressBar ? detailedProgressBarHeight : progressBarHeight, isSmallScreen ? columnPaddingSmallScreen : columnPadding ]; return heights.reduce((acc, height) => acc + height, 0); } function calculatePosterHeight(posterWidth) { return posterWidth; } class ArtistIndexOverviews extends Component { // // Lifecycle constructor(props, context) { super(props, context); this.state = { width: 0, columnCount: 1, posterWidth: 238, posterHeight: 238, rowHeight: calculateRowHeight(238, null, props.isSmallScreen, {}) }; this._isInitialized = false; this._grid = null; } componentDidMount() { this._contentBodyNode = ReactDOM.findDOMNode(this.props.contentBody); } componentDidUpdate(prevProps) { const { items, filterKey, filterValue, sortKey, sortDirection, overviewOptions } = this.props; const itemsChanged = hasDifferentItems(prevProps.items, items); const overviewOptionsChanged = !_.isMatch(prevProps.overviewOptions, overviewOptions); if ( prevProps.sortKey !== sortKey || prevProps.overviewOptions !== overviewOptions || itemsChanged ) { this.calculateGrid(); } if ( prevProps.filterKey !== filterKey || prevProps.filterValue !== filterValue || prevProps.sortKey !== sortKey || prevProps.sortDirection !== sortDirection || itemsChanged || overviewOptionsChanged ) { this._grid.recomputeGridSize(); } } // // Control scrollToFirstCharacter(character) { const items = this.props.items; const { rowHeight } = this.state; const index = _.findIndex(items, (item) => { const firstCharacter = item.sortTitle.charAt(0); if (character === '#') { return !isNaN(firstCharacter); } return firstCharacter === character; }); if (index != null) { const scrollTop = rowHeight * index; this.props.onScroll({ scrollTop }); } } setGridRef = (ref) => { this._grid = ref; } calculateGrid = (width = this.state.width, isSmallScreen) => { const { sortKey, overviewOptions } = this.props; const posterWidth = calculatePosterWidth(overviewOptions.size, isSmallScreen); const posterHeight = calculatePosterHeight(posterWidth); const rowHeight = calculateRowHeight(posterHeight, sortKey, isSmallScreen, overviewOptions); this.setState({ width, posterWidth, posterHeight, rowHeight }); } cellRenderer = ({ key, rowIndex, style }) => { const { items, sortKey, overviewOptions, showRelativeDates, shortDateFormat, timeFormat, isSmallScreen } = this.props; const { posterWidth, posterHeight, rowHeight } = this.state; const artist = items[rowIndex]; if (!artist) { return null; } return ( ); } // // Listeners onMeasure = ({ width }) => { this.calculateGrid(width, this.props.isSmallScreen); } onSectionRendered = () => { if (!this._isInitialized && this._contentBodyNode) { this.props.onRender(); this._isInitialized = true; } } // // Render render() { const { items, scrollTop, isSmallScreen, onScroll } = this.props; const { width, rowHeight } = this.state; return ( {({ height, isScrolling }) => { return ( ); } } ); } } ArtistIndexOverviews.propTypes = { items: PropTypes.arrayOf(PropTypes.object).isRequired, filterKey: PropTypes.string, filterValue: PropTypes.oneOfType([PropTypes.bool, PropTypes.number, PropTypes.string]), sortKey: PropTypes.string, sortDirection: PropTypes.oneOf(sortDirections.all), overviewOptions: PropTypes.object.isRequired, scrollTop: PropTypes.number.isRequired, contentBody: PropTypes.object.isRequired, showRelativeDates: PropTypes.bool.isRequired, shortDateFormat: PropTypes.string.isRequired, isSmallScreen: PropTypes.bool.isRequired, timeFormat: PropTypes.string.isRequired, onRender: PropTypes.func.isRequired, onScroll: PropTypes.func.isRequired }; export default ArtistIndexOverviews;