2016-11-20 13:39:18 -05:00
import { connect } from 'react-redux' ;
import PureRenderMixin from 'react-addons-pure-render-mixin' ;
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import Column from '../ui/components/column' ;
2017-02-20 18:10:49 -05:00
import { expandNotifications , clearNotifications , scrollTopNotifications } from '../../actions/notifications' ;
2016-11-20 13:39:18 -05:00
import NotificationContainer from './containers/notification_container' ;
import { ScrollContainer } from 'react-router-scroll' ;
2017-02-17 20:37:59 -05:00
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
2017-01-02 08:09:57 -05:00
import ColumnSettingsContainer from './containers/column_settings_container' ;
import { createSelector } from 'reselect' ;
import Immutable from 'immutable' ;
2017-01-30 12:04:15 -05:00
import LoadMore from '../../components/load_more' ;
2017-02-06 18:06:40 -05:00
import ClearColumnButton from './components/clear_column_button' ;
2016-11-20 13:39:18 -05:00
const messages = defineMessages ( {
title : { id : 'column.notifications' , defaultMessage : 'Notifications' }
} ) ;
2017-01-02 08:09:57 -05:00
const getNotifications = createSelector ( [
2017-01-09 08:00:55 -05:00
state => Immutable . List ( state . getIn ( [ 'settings' , 'notifications' , 'shows' ] ) . filter ( item => ! item ) . keys ( ) ) ,
2017-01-02 08:09:57 -05:00
state => state . getIn ( [ 'notifications' , 'items' ] )
] , ( excludedTypes , notifications ) => notifications . filterNot ( item => excludedTypes . includes ( item . get ( 'type' ) ) ) ) ;
2016-11-20 13:39:18 -05:00
const mapStateToProps = state => ( {
2017-01-25 22:30:40 -05:00
notifications : getNotifications ( state ) ,
2017-02-20 18:10:49 -05:00
isLoading : state . getIn ( [ 'notifications' , 'isLoading' ] , true ) ,
isUnread : state . getIn ( [ 'notifications' , 'unread' ] ) > 0
2016-11-20 13:39:18 -05:00
} ) ;
const Notifications = React . createClass ( {
propTypes : {
notifications : ImmutablePropTypes . list . isRequired ,
2016-11-21 04:03:55 -05:00
dispatch : React . PropTypes . func . isRequired ,
2017-01-02 08:09:57 -05:00
trackScroll : React . PropTypes . bool ,
2017-01-25 22:30:40 -05:00
intl : React . PropTypes . object . isRequired ,
2017-02-20 18:10:49 -05:00
isLoading : React . PropTypes . bool ,
isUnread : React . PropTypes . bool
2016-11-20 13:39:18 -05:00
} ,
2016-12-13 07:42:10 -05:00
getDefaultProps ( ) {
return {
trackScroll : true
} ;
} ,
2016-11-20 13:39:18 -05:00
mixins : [ PureRenderMixin ] ,
handleScroll ( e ) {
const { scrollTop , scrollHeight , clientHeight } = e . target ;
2017-01-25 22:30:40 -05:00
const offset = scrollHeight - scrollTop - clientHeight ;
2017-01-30 12:04:15 -05:00
this . _oldScrollPosition = scrollHeight - scrollTop ;
2016-11-20 13:39:18 -05:00
2017-01-25 22:30:40 -05:00
if ( 250 > offset && ! this . props . isLoading ) {
2016-11-20 13:39:18 -05:00
this . props . dispatch ( expandNotifications ( ) ) ;
2017-02-20 18:10:49 -05:00
} else if ( scrollTop < 100 ) {
this . props . dispatch ( scrollTopNotifications ( true ) ) ;
} else {
this . props . dispatch ( scrollTopNotifications ( false ) ) ;
2016-11-20 13:39:18 -05:00
}
} ,
2017-01-30 12:04:15 -05: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 ;
}
} ,
handleLoadMore ( e ) {
e . preventDefault ( ) ;
this . props . dispatch ( expandNotifications ( ) ) ;
} ,
2017-02-06 18:06:40 -05:00
handleClear ( ) {
this . props . dispatch ( clearNotifications ( ) ) ;
} ,
2017-01-30 12:04:15 -05:00
setRef ( c ) {
this . node = c ;
} ,
2016-11-20 13:39:18 -05:00
render ( ) {
2017-02-20 18:10:49 -05:00
const { intl , notifications , trackScroll , isLoading , isUnread } = this . props ;
2017-01-30 12:04:15 -05:00
2017-02-17 20:37:59 -05:00
let loadMore = '' ;
let scrollableArea = '' ;
2017-02-20 18:10:49 -05:00
let unread = '' ;
2017-01-30 12:04:15 -05:00
if ( ! isLoading && notifications . size > 0 ) {
loadMore = < LoadMore onClick = { this . handleLoadMore } / > ;
}
2016-11-21 04:03:55 -05:00
2017-02-20 18:10:49 -05:00
if ( isUnread ) {
unread = < div className = 'notifications__unread-indicator' / > ;
}
2017-02-17 20:37:59 -05:00
if ( isLoading || notifications . size > 0 ) {
scrollableArea = (
< div className = 'scrollable' onScroll = { this . handleScroll } ref = { this . setRef } >
2017-02-20 18:10:49 -05:00
{ unread }
2017-02-17 20:37:59 -05:00
< div >
{ notifications . map ( item => < NotificationContainer key = { item . get ( 'id' ) } notification = { item } accountId = { item . get ( 'account' ) } / > ) }
{ loadMore }
< / div >
2016-11-21 04:03:55 -05:00
< / div >
2017-02-17 20:37:59 -05: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 04:03:55 -05:00
if ( trackScroll ) {
return (
2017-02-20 18:10:49 -05:00
< Column icon = 'bell' active = { isUnread } heading = { intl . formatMessage ( messages . title ) } >
2017-01-24 07:04:12 -05:00
< ColumnSettingsContainer / >
2017-02-06 18:06:40 -05:00
< ClearColumnButton onClick = { this . handleClear } / >
2016-11-21 04:03:55 -05:00
< ScrollContainer scrollKey = 'notifications' >
{ scrollableArea }
< / ScrollContainer >
< / Column >
) ;
} else {
return (
2017-02-20 18:10:49 -05:00
< Column icon = 'bell' active = { isUnread } heading = { intl . formatMessage ( messages . title ) } >
2017-01-02 08:09:57 -05:00
< ColumnSettingsContainer / >
2017-02-06 18:06:40 -05:00
< ClearColumnButton onClick = { this . handleClear } / >
2016-11-21 04:03:55 -05:00
{ scrollableArea }
< / Column >
) ;
}
2016-11-20 13:39:18 -05:00
}
} ) ;
export default connect ( mapStateToProps ) ( injectIntl ( Notifications ) ) ;