2017-05-03 03:04:16 +03:00
import React from 'react' ;
2016-11-20 20:39:18 +02:00
import { connect } from 'react-redux' ;
2017-04-21 21:05:35 +03:00
import PropTypes from 'prop-types' ;
2016-11-20 20:39:18 +02:00
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import Column from '../ui/components/column' ;
2017-02-21 01:10:49 +02:00
import { expandNotifications , clearNotifications , scrollTopNotifications } from '../../actions/notifications' ;
2016-11-20 20:39:18 +02:00
import NotificationContainer from './containers/notification_container' ;
import { ScrollContainer } from 'react-router-scroll' ;
2017-02-18 03:37:59 +02:00
import { defineMessages , injectIntl , FormattedMessage } from 'react-intl' ;
2017-01-02 15:09:57 +02:00
import ColumnSettingsContainer from './containers/column_settings_container' ;
import { createSelector } from 'reselect' ;
import Immutable from 'immutable' ;
2017-01-30 19:04:15 +02:00
import LoadMore from '../../components/load_more' ;
2017-02-07 01:06:40 +02:00
import ClearColumnButton from './components/clear_column_button' ;
2017-04-23 05:39:50 +03:00
import { openModal } from '../../actions/modal' ;
2016-11-20 20:39:18 +02:00
const messages = defineMessages ( {
2017-03-02 20:24:12 +02:00
title : { id : 'column.notifications' , defaultMessage : 'Notifications' } ,
2017-04-23 05:39:50 +03:00
clearMessage : { id : 'notifications.clear_confirmation' , defaultMessage : 'Are you sure you want to permanently clear all your notifications?' } ,
clearConfirm : { id : 'notifications.clear' , defaultMessage : 'Clear notifications' }
2016-11-20 20:39:18 +02:00
} ) ;
2017-01-02 15:09:57 +02:00
const getNotifications = createSelector ( [
2017-01-09 15:00:55 +02:00
state => Immutable . List ( state . getIn ( [ 'settings' , 'notifications' , 'shows' ] ) . filter ( item => ! item ) . keys ( ) ) ,
2017-01-02 15:09:57 +02:00
state => state . getIn ( [ 'notifications' , 'items' ] )
] , ( excludedTypes , notifications ) => notifications . filterNot ( item => excludedTypes . includes ( item . get ( 'type' ) ) ) ) ;
2016-11-20 20:39:18 +02:00
const mapStateToProps = state => ( {
2017-01-26 05:30:40 +02:00
notifications : getNotifications ( state ) ,
2017-02-21 01:10:49 +02:00
isLoading : state . getIn ( [ 'notifications' , 'isLoading' ] , true ) ,
isUnread : state . getIn ( [ 'notifications' , 'unread' ] ) > 0
2016-11-20 20:39:18 +02:00
} ) ;
2017-04-21 21:05:35 +03:00
class Notifications extends React . PureComponent {
2016-11-20 20:39:18 +02:00
2017-04-21 21:05:35 +03: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 20:39:18 +02:00
handleScroll ( e ) {
const { scrollTop , scrollHeight , clientHeight } = e . target ;
2017-01-26 05:30:40 +02:00
const offset = scrollHeight - scrollTop - clientHeight ;
2017-01-30 19:04:15 +02:00
this . _oldScrollPosition = scrollHeight - scrollTop ;
2016-11-20 20:39:18 +02:00
2017-01-26 05:30:40 +02:00
if ( 250 > offset && ! this . props . isLoading ) {
2016-11-20 20:39:18 +02:00
this . props . dispatch ( expandNotifications ( ) ) ;
2017-02-21 01:10:49 +02:00
} else if ( scrollTop < 100 ) {
this . props . dispatch ( scrollTopNotifications ( true ) ) ;
} else {
this . props . dispatch ( scrollTopNotifications ( false ) ) ;
2016-11-20 20:39:18 +02:00
}
2017-04-21 21:05:35 +03:00
}
2016-11-20 20:39:18 +02:00
2017-01-30 19:04:15 +02: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 21:05:35 +03:00
}
2017-01-30 19:04:15 +02:00
handleLoadMore ( e ) {
e . preventDefault ( ) ;
this . props . dispatch ( expandNotifications ( ) ) ;
2017-04-21 21:05:35 +03:00
}
2017-01-30 19:04:15 +02:00
2017-02-07 01:06:40 +02:00
handleClear ( ) {
2017-04-23 05:39:50 +03:00
const { dispatch , intl } = this . props ;
dispatch ( openModal ( 'CONFIRM' , {
message : intl . formatMessage ( messages . clearMessage ) ,
confirm : intl . formatMessage ( messages . clearConfirm ) ,
onConfirm : ( ) => dispatch ( clearNotifications ( ) )
} ) ) ;
2017-04-21 21:05:35 +03:00
}
2017-02-07 01:06:40 +02:00
2017-01-30 19:04:15 +02:00
setRef ( c ) {
this . node = c ;
2017-04-21 21:05:35 +03:00
}
2017-01-30 19:04:15 +02:00
2016-11-20 20:39:18 +02:00
render ( ) {
2017-04-24 05:49:08 +03:00
const { intl , notifications , shouldUpdateScroll , isLoading , isUnread } = this . props ;
2017-01-30 19:04:15 +02:00
2017-02-18 03:37:59 +02:00
let loadMore = '' ;
let scrollableArea = '' ;
2017-02-21 01:10:49 +02:00
let unread = '' ;
2017-01-30 19:04:15 +02:00
if ( ! isLoading && notifications . size > 0 ) {
loadMore = < LoadMore onClick = { this . handleLoadMore } / > ;
}
2016-11-21 11:03:55 +02:00
2017-02-21 01:10:49 +02:00
if ( isUnread ) {
unread = < div className = 'notifications__unread-indicator' / > ;
}
2017-02-18 03:37:59 +02:00
if ( isLoading || notifications . size > 0 ) {
scrollableArea = (
< div className = 'scrollable' onScroll = { this . handleScroll } ref = { this . setRef } >
2017-02-21 01:10:49 +02:00
{ unread }
2017-02-18 03:37:59 +02:00
< div >
{ notifications . map ( item => < NotificationContainer key = { item . get ( 'id' ) } notification = { item } accountId = { item . get ( 'account' ) } / > ) }
{ loadMore }
< / d i v >
2016-11-21 11:03:55 +02:00
< / d i v >
2017-02-18 03:37:59 +02: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." / >
< / d i v >
) ;
}
2016-11-21 11:03:55 +02:00
2017-04-24 05:49:08 +03:00
return (
< Column icon = 'bell' active = { isUnread } heading = { intl . formatMessage ( messages . title ) } >
< ColumnSettingsContainer / >
< ClearColumnButton onClick = { this . handleClear } / >
< ScrollContainer scrollKey = 'notifications' shouldUpdateScroll = { shouldUpdateScroll } >
2016-11-21 11:03:55 +02:00
{ scrollableArea }
2017-04-24 05:49:08 +03:00
< / S c r o l l C o n t a i n e r >
< / C o l u m n >
) ;
2016-11-20 20:39:18 +02:00
}
2017-04-21 21:05:35 +03:00
}
Notifications . propTypes = {
notifications : ImmutablePropTypes . list . isRequired ,
dispatch : PropTypes . func . isRequired ,
2017-04-24 05:49:08 +03:00
shouldUpdateScroll : PropTypes . func ,
2017-04-21 21:05:35 +03:00
intl : PropTypes . object . isRequired ,
isLoading : PropTypes . bool ,
isUnread : PropTypes . bool
} ;
Notifications . defaultProps = {
trackScroll : true
} ;
2016-11-20 20:39:18 +02:00
export default connect ( mapStateToProps ) ( injectIntl ( Notifications ) ) ;