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