2020-08-17 21:07:16 +01:00
import React from 'react'
2020-08-17 21:59:29 +01:00
import PropTypes from 'prop-types'
2020-08-17 21:39:25 +01:00
import { connect } from 'react-redux'
2020-06-10 22:44:38 +01:00
import { withRouter } from 'react-router-dom'
2020-03-04 03:45:16 +00:00
import ImmutablePropTypes from 'react-immutable-proptypes'
import ImmutablePureComponent from 'react-immutable-pure-component'
2020-05-21 20:37:40 +01:00
import { FormattedMessage } from 'react-intl'
2020-04-08 02:06:59 +01:00
import debounce from 'lodash.debounce'
2020-06-10 22:44:38 +01:00
import throttle from 'lodash.throttle'
2019-08-13 16:54:29 +01:00
import {
expandNotifications ,
scrollTopNotifications ,
dequeueNotifications ,
2020-06-10 22:44:38 +01:00
forceDequeueNotifications ,
2020-04-24 04:17:27 +01:00
} from '../actions/notifications'
2020-10-30 04:33:50 +00:00
import {
TIMELINE _INJECTION _FEATURED _GROUPS ,
TIMELINE _INJECTION _GROUP _CATEGORIES ,
TIMELINE _INJECTION _USER _SUGGESTIONS ,
} from '../constants'
2020-04-24 04:17:27 +01:00
import NotificationContainer from '../containers/notification_container'
import ScrollableList from '../components/scrollable_list'
2020-05-21 20:37:40 +01:00
import TimelineQueueButtonHeader from '../components/timeline_queue_button_header'
import Block from '../components/block'
2020-06-13 02:52:26 +01:00
import Account from '../components/account'
2020-07-28 21:11:51 +01:00
import NotificationPlaceholder from '../components/placeholder/notification_placeholder'
2020-10-30 04:33:50 +00:00
import TimelineInjectionRoot from '../components/timeline_injections/timeline_injection_root'
2019-08-13 16:54:29 +01:00
class Notifications extends ImmutablePureComponent {
2020-07-16 05:01:49 +01:00
state = {
changedTabs : false ,
}
2020-05-21 20:37:40 +01:00
componentWillUnmount ( ) {
2020-03-04 03:45:16 +00:00
this . handleLoadOlder . cancel ( )
this . handleScrollToTop . cancel ( )
this . handleScroll . cancel ( )
2020-06-10 22:44:38 +01:00
this . props . onScrollTopNotifications ( false )
2019-08-13 16:54:29 +01:00
}
componentDidMount ( ) {
2020-03-04 03:45:16 +00:00
this . handleDequeueNotifications ( )
2020-06-10 22:44:38 +01:00
this . props . onScrollTopNotifications ( true )
2019-08-13 16:54:29 +01:00
}
2020-07-16 05:01:49 +01:00
componentDidUpdate ( prevProps , prevState ) {
2020-06-10 22:44:38 +01: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-16 05:01:49 +01: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 22:44:38 +01:00
}
handleReload = throttle ( ( ) => {
this . props . onExpandNotifications ( )
} , 5000 )
2019-08-13 16:54:29 +01:00
handleLoadOlder = debounce ( ( ) => {
2020-03-04 03:45:16 +00:00
const last = this . props . notifications . last ( )
2020-06-10 22:44:38 +01:00
this . props . onExpandNotifications ( { maxId : last && last . get ( 'id' ) } )
2020-03-04 03:45:16 +00:00
} , 300 , { leading : true } )
2019-08-13 16:54:29 +01:00
handleScrollToTop = debounce ( ( ) => {
2020-06-10 22:44:38 +01:00
this . props . onScrollTopNotifications ( true )
2020-03-04 03:45:16 +00:00
} , 100 )
2019-08-13 16:54:29 +01:00
handleScroll = debounce ( ( ) => {
2020-06-10 22:44:38 +01:00
this . props . onScrollTopNotifications ( false )
2020-03-04 03:45:16 +00:00
} , 100 )
2019-08-13 16:54:29 +01:00
handleDequeueNotifications = ( ) => {
2020-06-10 22:44:38 +01:00
this . props . onDequeueNotifications ( )
2020-03-04 03:45:16 +00:00
}
2019-08-13 16:54:29 +01:00
2020-05-21 20:37:40 +01:00
render ( ) {
2020-03-04 03:45:16 +00:00
const {
2020-10-30 04:33:50 +00:00
notifications ,
2020-05-21 20:37:40 +01:00
sortedNotifications ,
2020-03-04 03:45:16 +00:00
isLoading ,
hasMore ,
2020-05-21 20:37:40 +01:00
totalQueuedNotificationsCount ,
2020-06-13 02:52:26 +01:00
selectedFilter ,
2020-03-04 03:45:16 +00:00
} = this . props
2020-07-16 05:01:49 +01:00
const { changedTabs } = this . state
2020-03-04 03:45:16 +00:00
let scrollableContent = null
2020-10-30 04:33:50 +00:00
let emptyContent = [ ]
const canShowEmptyContent = ! scrollableContent && ! isLoading && notifications . size === 0 && selectedFilter === 'all'
2019-08-13 16:54:29 +01:00
2020-07-29 21:40:47 +01:00
if ( isLoading && this . scrollableContent && ! changedTabs ) {
2020-03-04 03:45:16 +00:00
scrollableContent = this . scrollableContent
2020-07-29 21:40:47 +01:00
} else if ( ( sortedNotifications . size > 0 || hasMore ) && selectedFilter !== 'follow' && ! changedTabs ) {
2020-05-21 20:37:40 +01:00
scrollableContent = sortedNotifications . map ( ( item , index ) => (
2019-08-13 16:54:29 +01:00
< NotificationContainer
2020-03-04 03:45:16 +00:00
key = { ` notification- ${ index } ` }
2019-08-13 16:54:29 +01:00
notification = { item }
/ >
2020-03-04 03:45:16 +00:00
) )
2020-07-29 21:40:47 +01:00
} else if ( ( sortedNotifications . size > 0 || hasMore ) && selectedFilter === 'follow' && ! changedTabs ) {
2020-06-13 02:52:26 +01:00
const followNotifications = [ ]
sortedNotifications . forEach ( ( block ) => {
2020-06-13 03:01:13 +01:00
if ( block ) {
const followBlock = block . get ( 'follow' )
if ( followBlock && followBlock . size > 0 ) {
followBlock . forEach ( ( item ) => {
followNotifications . push ( item )
} )
}
}
2020-06-13 02:52:26 +01:00
} )
scrollableContent = followNotifications . map ( ( item , index ) => {
return (
< Account
compact
withBio
key = { ` account- ${ index } ` }
id = { item . get ( 'account' ) }
/ >
)
} )
2019-08-13 16:54:29 +01:00
}
2020-10-30 04:33:50 +00:00
if ( canShowEmptyContent ) {
emptyContent = [
< TimelineInjectionRoot type = { TIMELINE _INJECTION _USER _SUGGESTIONS } key = 'empty-injection-0' / > ,
< TimelineInjectionRoot type = { TIMELINE _INJECTION _FEATURED _GROUPS } key = 'empty-injection-1' / > ,
< TimelineInjectionRoot type = { TIMELINE _INJECTION _USER _SUGGESTIONS } props = { { suggestionType : 'verified' } } key = 'empty-injection-2' / > ,
< TimelineInjectionRoot type = { TIMELINE _INJECTION _GROUP _CATEGORIES } key = 'empty-injection-3' / > ,
]
}
2020-03-04 03:45:16 +00:00
this . scrollableContent = scrollableContent
2019-08-13 16:54:29 +01:00
return (
2020-08-17 21:07:16 +01:00
< React . Fragment >
2020-03-02 22:26:25 +00:00
< TimelineQueueButtonHeader
onClick = { this . handleDequeueNotifications }
count = { totalQueuedNotificationsCount }
itemType = 'notification'
/ >
2020-03-04 03:45:16 +00:00
< Block >
< ScrollableList
scrollKey = 'notifications'
isLoading = { isLoading }
2020-07-29 21:53:02 +01:00
showLoading = { isLoading && sortedNotifications . size === 0 || changedTabs }
2020-03-04 03:45:16 +00: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 21:11:51 +01:00
placeholderComponent = { NotificationPlaceholder }
placeholderCount = { 3 }
2020-03-04 03:45:16 +00:00
>
2020-05-21 20:37:40 +01:00
{ scrollableContent }
2020-03-04 03:45:16 +00:00
< / S c r o l l a b l e L i s t >
< / B l o c k >
2020-10-30 04:33:50 +00:00
{
canShowEmptyContent &&
< div className = { [ _s . d , _s . mt15 , _s . w100PC ] . join ( ' ' ) } >
{ emptyContent }
< / d i v >
}
2020-08-17 21:07:16 +01:00
< / R e a c t . F r a g m e n t >
2020-03-02 22:26:25 +00:00
)
2019-08-13 16:54:29 +01:00
}
}
2020-08-19 01:22:15 +01: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 ) )