2016-11-20 19:39:18 +01:00
import { connect } from 'react-redux' ;
2017-04-21 20:05:35 +02:00
import PropTypes from 'prop-types' ;
2016-11-20 19:39:18 +01:00
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import Column from '../ui/components/column' ;
2017-02-21 00:10:49 +01:00
import { expandNotifications , clearNotifications , scrollTopNotifications } from '../../actions/notifications' ;
2016-11-20 19:39:18 +01:00
import NotificationContainer from './containers/notification_container' ;
import { ScrollContainer } from 'react-router-scroll' ;
2017-02-18 02:37:59 +01:00
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
2017-01-02 14:09:57 +01:00
import ColumnSettingsContainer from './containers/column_settings_container' ;
import { createSelector } from 'reselect' ;
import Immutable from 'immutable' ;
2017-01-30 18:04:15 +01:00
import LoadMore from '../../components/load_more' ;
2017-02-07 00:06:40 +01:00
import ClearColumnButton from './components/clear_column_button' ;
2016-11-20 19:39:18 +01:00
const messages = defineMessages ( {
2017-03-02 19:24:12 +01:00
title : { id : 'column.notifications' , defaultMessage : 'Notifications' } ,
2017-03-02 19:25:11 +01:00
confirm : { id : 'notifications.clear_confirmation' , defaultMessage : 'Are you sure you want to clear all your notifications?' }
2016-11-20 19:39:18 +01:00
} ) ;
2017-01-02 14:09:57 +01:00
const getNotifications = createSelector ( [
2017-01-09 14:00:55 +01:00
state => Immutable . List ( state . getIn ( [ 'settings' , 'notifications' , 'shows' ] ) . filter ( item => ! item ) . keys ( ) ) ,
2017-01-02 14:09:57 +01:00
state => state . getIn ( [ 'notifications' , 'items' ] )
] , ( excludedTypes , notifications ) => notifications . filterNot ( item => excludedTypes . includes ( item . get ( 'type' ) ) ) ) ;
2016-11-20 19:39:18 +01:00
const mapStateToProps = state => ( {
2017-01-26 04:30:40 +01:00
notifications : getNotifications ( state ) ,
2017-02-21 00:10:49 +01:00
isLoading : state . getIn ( [ 'notifications' , 'isLoading' ] , true ) ,
isUnread : state . getIn ( [ 'notifications' , 'unread' ] ) > 0
2016-11-20 19:39:18 +01:00
} ) ;
2017-04-21 20:05:35 +02:00
class Notifications extends React . PureComponent {
2016-11-20 19:39:18 +01:00
2017-04-21 20:05:35 +02:00
constructor ( props , context ) {
super ( props , context ) ;
this . handleScroll = this . handleScroll . bind ( this ) ;
this . handleLoadMore = this . handleLoadMore . bind ( this ) ;
this . handleClear = this . handleClear . bind ( this ) ;
this . setRef = this . setRef . bind ( this ) ;
}
2016-11-20 19:39:18 +01:00
handleScroll ( e ) {
const { scrollTop , scrollHeight , clientHeight } = e . target ;
2017-01-26 04:30:40 +01:00
const offset = scrollHeight - scrollTop - clientHeight ;
2017-01-30 18:04:15 +01:00
this . _oldScrollPosition = scrollHeight - scrollTop ;
2016-11-20 19:39:18 +01:00
2017-01-26 04:30:40 +01:00
if ( 250 > offset && ! this . props . isLoading ) {
2016-11-20 19:39:18 +01:00
this . props . dispatch ( expandNotifications ( ) ) ;
2017-02-21 00:10:49 +01:00
} else if ( scrollTop < 100 ) {
this . props . dispatch ( scrollTopNotifications ( true ) ) ;
} else {
this . props . dispatch ( scrollTopNotifications ( false ) ) ;
2016-11-20 19:39:18 +01:00
}
2017-04-21 20:05:35 +02:00
}
2016-11-20 19:39:18 +01:00
2017-01-30 18:04:15 +01:00
componentDidUpdate ( prevProps ) {
if ( this . node . scrollTop > 0 && ( prevProps . notifications . size < this . props . notifications . size && prevProps . notifications . first ( ) !== this . props . notifications . first ( ) && ! ! this . _oldScrollPosition ) ) {
this . node . scrollTop = this . node . scrollHeight - this . _oldScrollPosition ;
}
2017-04-21 20:05:35 +02:00
}
2017-01-30 18:04:15 +01:00
handleLoadMore ( e ) {
e . preventDefault ( ) ;
this . props . dispatch ( expandNotifications ( ) ) ;
2017-04-21 20:05:35 +02:00
}
2017-01-30 18:04:15 +01:00
2017-02-07 00:06:40 +01:00
handleClear ( ) {
2017-03-02 19:24:12 +01:00
if ( window . confirm ( this . props . intl . formatMessage ( messages . confirm ) ) ) {
this . props . dispatch ( clearNotifications ( ) ) ;
}
2017-04-21 20:05:35 +02:00
}
2017-02-07 00:06:40 +01:00
2017-01-30 18:04:15 +01:00
setRef ( c ) {
this . node = c ;
2017-04-21 20:05:35 +02:00
}
2017-01-30 18:04:15 +01:00
2016-11-20 19:39:18 +01:00
render ( ) {
2017-02-21 00:10:49 +01:00
const { intl , notifications , trackScroll , isLoading , isUnread } = this . props ;
2017-01-30 18:04:15 +01:00
2017-02-18 02:37:59 +01:00
let loadMore = '' ;
let scrollableArea = '' ;
2017-02-21 00:10:49 +01:00
let unread = '' ;
2017-01-30 18:04:15 +01:00
if ( ! isLoading && notifications . size > 0 ) {
loadMore = < LoadMore onClick = { this . handleLoadMore } / > ;
}
2016-11-21 10:03:55 +01:00
2017-02-21 00:10:49 +01:00
if ( isUnread ) {
unread = < div className = 'notifications__unread-indicator' / > ;
}
2017-02-18 02:37:59 +01:00
if ( isLoading || notifications . size > 0 ) {
scrollableArea = (
< div className = 'scrollable' onScroll = { this . handleScroll } ref = { this . setRef } >
2017-02-21 00:10:49 +01:00
{ unread }
2017-02-18 02:37:59 +01:00
< div >
{ notifications . map ( item => < NotificationContainer key = { item . get ( 'id' ) } notification = { item } accountId = { item . get ( 'account' ) } / > ) }
{ loadMore }
< / div >
2016-11-21 10:03:55 +01:00
< / div >
2017-02-18 02:37:59 +01:00
) ;
} else {
scrollableArea = (
< div className = 'empty-column-indicator' ref = { this . setRef } >
< FormattedMessage id = 'empty_column.notifications' defaultMessage = "You don't have any notifications yet. Interact with others to start the conversation." / >
< / div >
) ;
}
2016-11-21 10:03:55 +01:00
if ( trackScroll ) {
return (
2017-02-21 00:10:49 +01:00
< Column icon = 'bell' active = { isUnread } heading = { intl . formatMessage ( messages . title ) } >
2017-01-24 13:04:12 +01:00
< ColumnSettingsContainer / >
2017-02-07 00:06:40 +01:00
< ClearColumnButton onClick = { this . handleClear } / >
2016-11-21 10:03:55 +01:00
< ScrollContainer scrollKey = 'notifications' >
{ scrollableArea }
< / ScrollContainer >
< / Column >
) ;
} else {
return (
2017-02-21 00:10:49 +01:00
< Column icon = 'bell' active = { isUnread } heading = { intl . formatMessage ( messages . title ) } >
2017-01-02 14:09:57 +01:00
< ColumnSettingsContainer / >
2017-02-07 00:06:40 +01:00
< ClearColumnButton onClick = { this . handleClear } / >
2016-11-21 10:03:55 +01:00
{ scrollableArea }
< / Column >
) ;
}
2016-11-20 19:39:18 +01:00
}
2017-04-21 20:05:35 +02:00
}
Notifications . propTypes = {
notifications : ImmutablePropTypes . list . isRequired ,
dispatch : PropTypes . func . isRequired ,
trackScroll : PropTypes . bool ,
intl : PropTypes . object . isRequired ,
isLoading : PropTypes . bool ,
isUnread : PropTypes . bool
} ;
Notifications . defaultProps = {
trackScroll : true
} ;
2016-11-20 19:39:18 +01:00
export default connect ( mapStateToProps ) ( injectIntl ( Notifications ) ) ;