Dapps.jsx
1 import React from 'react' 2 import PropTypes from 'prop-types' 3 import { debounce } from 'debounce' 4 import DappList from '../../common/components/DappList' 5 import CategoryHeader from '../CategoryHeader' 6 import styles from './Dapps.module.scss' 7 import { headerElements, getYPosition } from './Dapps.utils' 8 9 class Dapps extends React.Component { 10 static scanHeaderPositions() { 11 const headerPositions = headerElements().map(element => ({ 12 id: element.id, 13 position: getYPosition(element), 14 })) 15 return headerPositions 16 } 17 18 constructor(props) { 19 super(props) 20 this.state = { 21 currentCategoryIndex: 0, 22 } 23 } 24 25 componentDidMount() { 26 this.boundScroll = debounce(this.handleScroll.bind(this), 1) 27 window.addEventListener('scroll', this.boundScroll) 28 this.fetchDapps() 29 } 30 31 componentDidUpdate() { 32 this.fetchDapps() 33 } 34 35 componentWillUnmount() { 36 window.removeEventListener('scroll', this.boundScroll) 37 } 38 39 onFetchByCategory(category) { 40 const { fetchByCategory } = this.props 41 fetchByCategory(category) 42 } 43 44 getCategories() { 45 const { dappsCategoryMap } = this.props 46 return [...dappsCategoryMap.keys()] 47 } 48 49 fetchDapps() { 50 const { dappsCategoryMap, fetchByCategory } = this.props 51 52 dappsCategoryMap.forEach((dappState, category) => { 53 if (dappState.canFetch() === false) return 54 if (dappState.items.length >= 1) return 55 fetchByCategory(category) 56 }) 57 } 58 59 handleScroll() { 60 const currentHeader = document.getElementById(this.currentCategory()) 61 const headerPositions = Dapps.scanHeaderPositions() 62 const categories = this.getCategories() 63 64 const newHeader = [...headerPositions] 65 .reverse() 66 .find(header => header.position < window.scrollY) 67 68 if (!newHeader) { 69 return this.setState({ currentCategoryIndex: 0 }) 70 } 71 72 if (newHeader.id === currentHeader.id) { 73 return false 74 } 75 76 const newIndex = categories.indexOf(newHeader.id) 77 78 return this.setState({ currentCategoryIndex: newIndex }) 79 } 80 81 currentCategory() { 82 const { currentCategoryIndex } = this.state 83 const categories = this.getCategories() 84 return categories[currentCategoryIndex] 85 } 86 87 isCurrentCategory(category) { 88 return category === this.currentCategory() 89 } 90 91 render() { 92 const { dappsCategoryMap } = this.props 93 const categories = this.getCategories() 94 95 return ( 96 <div className={styles.list}> 97 {categories.map(category => ( 98 <div key={category}> 99 <div id={category} className="category-header"> 100 <CategoryHeader 101 text={category} 102 active={this.isCurrentCategory(category)} 103 /> 104 </div> 105 <DappList dapps={dappsCategoryMap.get(category).items} /> 106 {dappsCategoryMap.get(category).canFetch() && ( 107 <div 108 className={styles.loadMore} 109 onClick={this.onFetchByCategory.bind(this, category)} 110 > 111 Load more dApps from {category}{' '} 112 </div> 113 )} 114 </div> 115 ))} 116 </div> 117 ) 118 } 119 } 120 121 // Dapps.propTypes = { 122 // categories: PropTypes.arrayOf( 123 // PropTypes.shape({ category: PropTypes.string, dapps: DappListModel }), 124 // ).isRequired, 125 // } 126 Dapps.propTypes = { 127 dappsCategoryMap: PropTypes.instanceOf(Map).isRequired, 128 fetchByCategory: PropTypes.func.isRequired, 129 } 130 131 export default Dapps