2020-08-17 15:07:16 -05:00
import React from 'react'
2020-08-17 15:59:29 -05:00
import PropTypes from 'prop-types'
2020-08-17 15:39:25 -05:00
import { connect } from 'react-redux'
2020-06-10 17:44:38 -04:00
import { withRouter } from 'react-router-dom'
2020-03-03 22:45:16 -05:00
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
2020-05-21 15:37:40 -04:00
import { FormattedMessage } from 'react-intl'
2020-04-07 21:06:59 -04:00
import debounce from 'lodash.debounce'
2020-06-10 17:44:38 -04:00
import throttle from 'lodash.throttle'
2019-08-13 11:54:29 -04:00
import {
expandNotifications ,
scrollTopNotifications ,
dequeueNotifications ,
2020-06-10 17:44:38 -04:00
forceDequeueNotifications ,
2020-04-23 23:17:27 -04:00
} from '../actions/notifications'
import NotificationContainer from '../containers/notification_container'
import ScrollableList from '../components/scrollable_list'
2020-05-21 15:37:40 -04:00
import TimelineQueueButtonHeader from '../components/timeline_queue_button_header'
import Block from '../components/block'
2020-06-12 21:52:26 -04:00
import Account from '../components/account'
2020-07-28 15:11:51 -05:00
import NotificationPlaceholder from '../components/placeholder/notification_placeholder'
2019-08-13 11:54:29 -04:00
class Notifications extends ImmutablePureComponent {
2020-07-15 23:01:49 -05:00
state = {
changedTabs : false ,
}
2020-05-21 15:37:40 -04:00
componentWillUnmount ( ) {
2020-03-03 22:45:16 -05:00
this . handleLoadOlder . cancel ( )
this . handleScrollToTop . cancel ( )
this . handleScroll . cancel ( )
2020-06-10 17:44:38 -04:00
this . props . onScrollTopNotifications ( false )
2019-08-13 11:54:29 -04:00
}
componentDidMount ( ) {
2020-03-03 22:45:16 -05:00
this . handleDequeueNotifications ( )
2020-06-10 17:44:38 -04:00
this . props . onScrollTopNotifications ( true )
2019-08-13 11:54:29 -04:00
}
2020-07-15 23:01:49 -05:00
componentDidUpdate ( prevProps , prevState ) {
2020-06-10 17:44:38 -04:00
//Check if clicked on "notifications" button, if so, reload
if ( prevProps . location . key !== this . props . location . key &&
prevProps . location . pathname === '/notifications' &&
this . props . location . pathname === '/notifications' ) {
this . handleReload ( )
}
2020-07-15 23:01:49 -05:00
if ( prevProps . selectedFilter !== this . props . selectedFilter ) {
this . setState ( { changedTabs : true } )
}
if ( prevProps . selectedFilter === this . props . selectedFilter && prevState . changedTabs ) {
this . setState ( { changedTabs : false } )
}
2020-06-10 17:44:38 -04:00
}
handleReload = throttle ( ( ) => {
this . props . onExpandNotifications ( )
} , 5000 )
2019-08-13 11:54:29 -04:00
handleLoadOlder = debounce ( ( ) => {
2020-03-03 22:45:16 -05:00
const last = this . props . notifications . last ( )
2020-06-10 17:44:38 -04:00
this . props . onExpandNotifications ( { maxId : last && last . get ( 'id' ) } )
2020-03-03 22:45:16 -05:00
} , 300 , { leading : true } )
2019-08-13 11:54:29 -04:00
handleScrollToTop = debounce ( ( ) => {
2020-06-10 17:44:38 -04:00
this . props . onScrollTopNotifications ( true )
2020-03-03 22:45:16 -05:00
} , 100 )
2019-08-13 11:54:29 -04:00
handleScroll = debounce ( ( ) => {
2020-06-10 17:44:38 -04:00
this . props . onScrollTopNotifications ( false )
2020-03-03 22:45:16 -05:00
} , 100 )
2019-08-13 11:54:29 -04:00
handleDequeueNotifications = ( ) => {
2020-06-10 17:44:38 -04:00
this . props . onDequeueNotifications ( )
2020-03-03 22:45:16 -05:00
}
2019-08-13 11:54:29 -04:00
2020-05-21 15:37:40 -04:00
render ( ) {
2020-03-03 22:45:16 -05:00
const {
2020-05-21 15:37:40 -04:00
sortedNotifications ,
2020-03-03 22:45:16 -05:00
isLoading ,
hasMore ,
2020-05-21 15:37:40 -04:00
totalQueuedNotificationsCount ,
2020-06-12 21:52:26 -04:00
selectedFilter ,
2020-03-03 22:45:16 -05:00
} = this . props
2020-07-15 23:01:49 -05:00
const { changedTabs } = this . state
2020-03-03 22:45:16 -05:00
let scrollableContent = null
2019-08-13 11:54:29 -04:00
2020-07-29 15:40:47 -05:00
if ( isLoading && this . scrollableContent && ! changedTabs ) {
2020-03-03 22:45:16 -05:00
scrollableContent = this . scrollableContent
2020-07-29 15:40:47 -05:00
} else if ( ( sortedNotifications . size > 0 || hasMore ) && selectedFilter !== 'follow' && ! changedTabs ) {
2020-05-21 15:37:40 -04:00
scrollableContent = sortedNotifications . map ( ( item , index ) => (
2019-08-13 11:54:29 -04:00
< NotificationContainer
2020-03-03 22:45:16 -05:00
key = { ` notification- ${ index } ` }
2019-08-13 11:54:29 -04:00
notification = { item }
/ >
2020-03-03 22:45:16 -05:00
) )
2020-07-29 15:40:47 -05:00
} else if ( ( sortedNotifications . size > 0 || hasMore ) && selectedFilter === 'follow' && ! changedTabs ) {
2020-06-12 21:52:26 -04:00
const followNotifications = [ ]
sortedNotifications . forEach ( ( block ) => {
2020-06-12 22:01:13 -04:00
if ( block ) {
const followBlock = block . get ( 'follow' )
if ( followBlock && followBlock . size > 0 ) {
followBlock . forEach ( ( item ) => {
followNotifications . push ( item )
} )
}
}
2020-06-12 21:52:26 -04:00
} )
scrollableContent = followNotifications . map ( ( item , index ) => {
return (
< Account
compact
withBio
key = { ` account- ${ index } ` }
id = { item . get ( 'account' ) }
/ >
)
} )
2019-08-13 11:54:29 -04:00
}
2020-03-03 22:45:16 -05:00
this . scrollableContent = scrollableContent
2019-08-13 11:54:29 -04:00
return (
2020-08-17 15:07:16 -05:00
< React . Fragment >
2020-03-02 17:26:25 -05:00
< TimelineQueueButtonHeader
onClick = { this . handleDequeueNotifications }
count = { totalQueuedNotificationsCount }
itemType = 'notification'
/ >
2020-03-03 22:45:16 -05:00
< Block >
< ScrollableList
scrollKey = 'notifications'
isLoading = { isLoading }
2020-07-29 15:53:02 -05:00
showLoading = { isLoading && sortedNotifications . size === 0 || changedTabs }
2020-03-03 22:45:16 -05:00
hasMore = { hasMore }
emptyMessage = { < FormattedMessage id = 'empty_column.notifications' defaultMessage = "You don't have any notifications yet. Interact with others to start the conversation." / > }
onLoadMore = { this . handleLoadOlder }
onScrollToTop = { this . handleScrollToTop }
onScroll = { this . handleScroll }
2020-07-28 15:11:51 -05:00
placeholderComponent = { NotificationPlaceholder }
placeholderCount = { 3 }
2020-03-03 22:45:16 -05:00
>
2020-05-21 15:37:40 -04:00
{ scrollableContent }
2020-03-03 22:45:16 -05:00
< / S c r o l l a b l e L i s t >
< / B l o c k >
2020-08-17 15:07:16 -05:00
< / R e a c t . F r a g m e n t >
2020-03-02 17:26:25 -05:00
)
2019-08-13 11:54:29 -04:00
}
}
2020-08-18 19:22:15 -05:00
const mapStateToProps = ( state ) => ( {
notifications : state . getIn ( [ 'notifications' , 'items' ] ) ,
sortedNotifications : state . getIn ( [ 'notifications' , 'sortedItems' ] ) ,
isLoading : state . getIn ( [ 'notifications' , 'isLoading' ] , true ) ,
hasMore : state . getIn ( [ 'notifications' , 'hasMore' ] ) ,
totalQueuedNotificationsCount : state . getIn ( [ 'notifications' , 'totalQueuedNotificationsCount' ] , 0 ) ,
selectedFilter : state . getIn ( [ 'notifications' , 'filter' , 'active' ] ) ,
} )
const mapDispatchToProps = ( dispatch ) => ( {
onDequeueNotifications ( ) {
dispatch ( dequeueNotifications ( ) )
} ,
onExpandNotifications ( options ) {
if ( ! options ) dispatch ( forceDequeueNotifications ( ) )
dispatch ( expandNotifications ( options ) )
} ,
onScrollTopNotifications ( top ) {
dispatch ( scrollTopNotifications ( top ) )
} ,
} )
Notifications . propTypes = {
hasMore : PropTypes . bool ,
isLoading : PropTypes . bool ,
notifications : ImmutablePropTypes . list . isRequired ,
onDequeueNotifications : PropTypes . func . isRequired ,
onExpandNotifications : PropTypes . func . isRequired ,
onScrollTopNotifications : PropTypes . func . isRequired ,
sortedNotifications : ImmutablePropTypes . list . isRequired ,
totalQueuedNotificationsCount : PropTypes . number ,
selectedFilter : PropTypes . string . isRequired ,
}
export default withRouter ( connect ( mapStateToProps , mapDispatchToProps ) ( Notifications ) )