2020-03-27 13:59:38 -07:00
import React from 'react' ;
import PropTypes from 'prop-types' ;
import ImmutablePropTypes from 'react-immutable-proptypes' ;
import StatusContainer from '../../../containers/status_container' ;
import AccountContainer from '../../../containers/account_container' ;
import { injectIntl , FormattedMessage } from 'react-intl' ;
import Permalink from '../../../components/permalink' ;
import ImmutablePureComponent from 'react-immutable-pure-component' ;
import { HotKeys } from 'react-hotkeys' ;
2021-03-29 11:35:30 -07:00
import FollowRequestContainer from '../containers/follow_request_container' ;
2020-05-28 15:52:07 -07:00
import Icon from 'soapbox/components/icon' ;
import emojify from 'soapbox/features/emoji/emoji' ;
2021-03-29 11:35:30 -07:00
import classNames from 'classnames' ;
2020-03-27 13:59:38 -07:00
const notificationForScreenReader = ( intl , message , timestamp ) => {
const output = [ message ] ;
output . push ( intl . formatDate ( timestamp , { hour : '2-digit' , minute : '2-digit' , month : 'short' , day : 'numeric' } ) ) ;
return output . join ( ', ' ) ;
} ;
export default @ injectIntl
class Notification extends ImmutablePureComponent {
static contextTypes = {
router : PropTypes . object ,
} ;
static propTypes = {
notification : ImmutablePropTypes . map . isRequired ,
hidden : PropTypes . bool ,
onMoveUp : PropTypes . func . isRequired ,
onMoveDown : PropTypes . func . isRequired ,
onMention : PropTypes . func . isRequired ,
onFavourite : PropTypes . func . isRequired ,
onReblog : PropTypes . func . isRequired ,
onToggleHidden : PropTypes . func . isRequired ,
status : ImmutablePropTypes . map ,
intl : PropTypes . object . isRequired ,
getScrollPosition : PropTypes . func ,
updateScrollBottom : PropTypes . func ,
cacheMediaWidth : PropTypes . func ,
cachedMediaWidth : PropTypes . number ,
} ;
handleMoveUp = ( ) => {
const { notification , onMoveUp } = this . props ;
onMoveUp ( notification . get ( 'id' ) ) ;
}
handleMoveDown = ( ) => {
const { notification , onMoveDown } = this . props ;
onMoveDown ( notification . get ( 'id' ) ) ;
}
handleOpen = ( ) => {
const { notification } = this . props ;
if ( notification . get ( 'status' ) ) {
this . context . router . history . push ( ` /@ ${ notification . getIn ( [ 'account' , 'acct' ] ) } /posts/ ${ notification . get ( 'status' ) } ` ) ;
} else {
this . handleOpenProfile ( ) ;
}
}
handleOpenProfile = ( ) => {
const { notification } = this . props ;
this . context . router . history . push ( ` /@ ${ notification . getIn ( [ 'account' , 'acct' ] ) } ` ) ;
}
handleMention = e => {
e . preventDefault ( ) ;
const { notification , onMention } = this . props ;
onMention ( notification . get ( 'account' ) , this . context . router . history ) ;
}
handleHotkeyFavourite = ( ) => {
const { status } = this . props ;
if ( status ) this . props . onFavourite ( status ) ;
}
handleHotkeyBoost = e => {
const { status } = this . props ;
if ( status ) this . props . onReblog ( status , e ) ;
}
handleHotkeyToggleHidden = ( ) => {
const { status } = this . props ;
if ( status ) this . props . onToggleHidden ( status ) ;
}
2020-04-14 14:47:35 -07:00
getHandlers ( ) {
2020-03-27 13:59:38 -07:00
return {
reply : this . handleMention ,
favourite : this . handleHotkeyFavourite ,
boost : this . handleHotkeyBoost ,
mention : this . handleMention ,
open : this . handleOpen ,
openProfile : this . handleOpenProfile ,
moveUp : this . handleMoveUp ,
moveDown : this . handleMoveDown ,
toggleHidden : this . handleHotkeyToggleHidden ,
} ;
}
2020-04-14 14:47:35 -07:00
renderFollow ( notification , account , link ) {
2020-03-27 13:59:38 -07:00
const { intl } = this . props ;
return (
< HotKeys handlers = { this . getHandlers ( ) } >
< div className = 'notification notification-follow focusable' tabIndex = '0' aria - label = { notificationForScreenReader ( intl , intl . formatMessage ( { id : 'notification.follow' , defaultMessage : '{name} followed you' } , { name : account . get ( 'acct' ) } ) , notification . get ( 'created_at' ) ) } >
< div className = 'notification__message' >
< div className = 'notification__favourite-icon-wrapper' >
< Icon id = 'user-plus' fixedWidth / >
< / d i v >
< span title = { notification . get ( 'created_at' ) } >
< FormattedMessage id = 'notification.follow' defaultMessage = '{name} followed you' values = { { name : link } } / >
< / s p a n >
< / d i v >
< AccountContainer id = { account . get ( 'id' ) } withNote = { false } hidden = { this . props . hidden } / >
< / d i v >
< / H o t K e y s >
) ;
}
2021-03-29 11:35:30 -07:00
renderFollowRequest ( notification , account , link ) {
const { intl , unread } = this . props ;
return (
< HotKeys handlers = { this . getHandlers ( ) } >
< div className = { classNames ( 'notification notification-follow-request focusable' , { unread } ) } tabIndex = '0' aria - label = { notificationForScreenReader ( intl , intl . formatMessage ( { id : 'notification.follow_request' , defaultMessage : '{name} has requested to follow you' } , { name : account . get ( 'acct' ) } ) , notification . get ( 'created_at' ) ) } >
< div className = 'notification__message' >
< div className = 'notification__favourite-icon-wrapper' >
< Icon id = 'user' fixedWidth / >
< / d i v >
< span title = { notification . get ( 'created_at' ) } >
< FormattedMessage id = 'notification.follow_request' defaultMessage = '{name} has requested to follow you' values = { { name : link } } / >
< / s p a n >
< / d i v >
< FollowRequestContainer id = { account . get ( 'id' ) } withNote = { false } hidden = { this . props . hidden } / >
< / d i v >
< / H o t K e y s >
) ;
}
2020-04-14 14:47:35 -07:00
renderMention ( notification ) {
2020-03-27 13:59:38 -07:00
return (
< StatusContainer
id = { notification . get ( 'status' ) }
withDismiss
hidden = { this . props . hidden }
onMoveDown = { this . handleMoveDown }
onMoveUp = { this . handleMoveUp }
contextType = 'notifications'
getScrollPosition = { this . props . getScrollPosition }
updateScrollBottom = { this . props . updateScrollBottom }
cachedMediaWidth = { this . props . cachedMediaWidth }
cacheMediaWidth = { this . props . cacheMediaWidth }
/ >
) ;
}
2020-08-24 17:51:24 -07:00
renderChatMention ( notification , link ) {
const { intl } = this . props ;
return (
< HotKeys handlers = { this . getHandlers ( ) } >
< div className = 'notification notification-chat-mention focusable' tabIndex = '0' aria - label = { notificationForScreenReader ( intl , intl . formatMessage ( { id : 'notification.chat_mention' , defaultMessage : '{name} sent you a message' } , { name : notification . getIn ( [ 'account' , 'acct' ] ) } ) , notification . get ( 'created_at' ) ) } >
< div className = 'notification__message' >
< div className = 'notification__favourite-icon-wrapper' >
2020-08-27 12:33:03 -07:00
< Icon id = 'comment' fixedWidth / >
2020-08-24 17:51:24 -07:00
< / d i v >
< span title = { notification . get ( 'created_at' ) } >
< FormattedMessage id = 'notification.chat_mention' defaultMessage = '{name} sent you a message' values = { { name : link } } / >
< / s p a n >
< / d i v >
< / d i v >
2020-08-27 12:33:03 -07:00
< div className = 'chat-message' >
< span
className = 'chat-message__bubble'
dangerouslySetInnerHTML = { { _ _html : emojify ( notification . getIn ( [ 'chat_message' , 'content' ] ) ) } }
/ >
< / d i v >
2020-08-24 17:51:24 -07:00
< / H o t K e y s >
) ;
}
2020-05-20 16:01:37 -07:00
renderEmojiReact ( notification , link ) {
const { intl } = this . props ;
return (
< HotKeys handlers = { this . getHandlers ( ) } >
2021-04-09 12:46:23 -07:00
< div className = 'notification notification-emoji-react focusable' tabIndex = '0' aria - label = { notificationForScreenReader ( intl , intl . formatMessage ( { id : 'notification.pleroma:emoji_reaction' , defaultMessage : '{name} reacted to your post' } , { name : notification . getIn ( [ 'account' , 'acct' ] ) } ) , notification . get ( 'created_at' ) ) } >
2020-05-20 16:01:37 -07:00
< div className = 'notification__message' >
< div className = 'notification__favourite-icon-wrapper' >
< span dangerouslySetInnerHTML = { { _ _html : emojify ( emojify ( notification . get ( 'emoji' ) ) ) } } / >
< / d i v >
< span title = { notification . get ( 'created_at' ) } >
2021-04-09 12:46:23 -07:00
< FormattedMessage id = 'notification.pleroma:emoji_reaction' defaultMessage = '{name} reacted to your post' values = { { name : link } } / >
2020-05-20 16:01:37 -07:00
< / s p a n >
< / d i v >
< StatusContainer
id = { notification . get ( 'status' ) }
account = { notification . get ( 'account' ) }
muted
withDismiss
hidden = { ! ! this . props . hidden }
getScrollPosition = { this . props . getScrollPosition }
updateScrollBottom = { this . props . updateScrollBottom }
cachedMediaWidth = { this . props . cachedMediaWidth }
cacheMediaWidth = { this . props . cacheMediaWidth }
/ >
< / d i v >
< / H o t K e y s >
) ;
}
2020-04-14 14:47:35 -07:00
renderFavourite ( notification , link ) {
2020-03-27 13:59:38 -07:00
const { intl } = this . props ;
return (
< HotKeys handlers = { this . getHandlers ( ) } >
2020-05-21 17:01:41 -07:00
< div className = 'notification notification-favourite focusable' tabIndex = '0' aria - label = { notificationForScreenReader ( intl , intl . formatMessage ( { id : 'notification.favourite' , defaultMessage : '{name} liked your post' } , { name : notification . getIn ( [ 'account' , 'acct' ] ) } ) , notification . get ( 'created_at' ) ) } >
2020-03-27 13:59:38 -07:00
< div className = 'notification__message' >
< div className = 'notification__favourite-icon-wrapper' >
2020-05-20 16:01:37 -07:00
< Icon id = 'thumbs-up' className = 'star-icon' fixedWidth / >
2020-03-27 13:59:38 -07:00
< / d i v >
< span title = { notification . get ( 'created_at' ) } >
2020-05-21 17:01:41 -07:00
< FormattedMessage id = 'notification.favourite' defaultMessage = '{name} liked your post' values = { { name : link } } / >
2020-03-27 13:59:38 -07:00
< / s p a n >
< / d i v >
< StatusContainer
id = { notification . get ( 'status' ) }
account = { notification . get ( 'account' ) }
muted
withDismiss
hidden = { ! ! this . props . hidden }
getScrollPosition = { this . props . getScrollPosition }
updateScrollBottom = { this . props . updateScrollBottom }
cachedMediaWidth = { this . props . cachedMediaWidth }
cacheMediaWidth = { this . props . cacheMediaWidth }
/ >
< / d i v >
< / H o t K e y s >
) ;
}
2020-04-14 14:47:35 -07:00
renderReblog ( notification , link ) {
2020-03-27 13:59:38 -07:00
const { intl } = this . props ;
return (
< HotKeys handlers = { this . getHandlers ( ) } >
< div className = 'notification notification-reblog focusable' tabIndex = '0' aria - label = { notificationForScreenReader ( intl , intl . formatMessage ( { id : 'notification.reblog' , defaultMessage : '{name} reposted your post' } , { name : notification . getIn ( [ 'account' , 'acct' ] ) } ) , notification . get ( 'created_at' ) ) } >
< div className = 'notification__message' >
< div className = 'notification__favourite-icon-wrapper' >
< Icon id = 'retweet' fixedWidth / >
< / d i v >
< span title = { notification . get ( 'created_at' ) } >
< FormattedMessage id = 'notification.reblog' defaultMessage = '{name} reposted your post' values = { { name : link } } / >
< / s p a n >
< / d i v >
< StatusContainer
id = { notification . get ( 'status' ) }
account = { notification . get ( 'account' ) }
muted
withDismiss
hidden = { this . props . hidden }
getScrollPosition = { this . props . getScrollPosition }
updateScrollBottom = { this . props . updateScrollBottom }
cachedMediaWidth = { this . props . cachedMediaWidth }
cacheMediaWidth = { this . props . cacheMediaWidth }
/ >
< / d i v >
< / H o t K e y s >
) ;
}
2020-04-14 14:47:35 -07:00
renderPoll ( notification ) {
2020-03-27 13:59:38 -07:00
const { intl } = this . props ;
return (
< HotKeys handlers = { this . getHandlers ( ) } >
< div className = 'notification notification-poll focusable' tabIndex = '0' aria - label = { notificationForScreenReader ( intl , intl . formatMessage ( { id : 'notification.poll' , defaultMessage : 'A poll you have voted in has ended' } ) , notification . get ( 'created_at' ) ) } >
< div className = 'notification__message' >
< div className = 'notification__favourite-icon-wrapper' >
< Icon id = 'tasks' fixedWidth / >
< / d i v >
< span title = { notification . get ( 'created_at' ) } >
< FormattedMessage id = 'notification.poll' defaultMessage = 'A poll you have voted in has ended' / >
< / s p a n >
< / d i v >
< StatusContainer
id = { notification . get ( 'status' ) }
account = { notification . get ( 'account' ) }
muted
withDismiss
hidden = { this . props . hidden }
getScrollPosition = { this . props . getScrollPosition }
updateScrollBottom = { this . props . updateScrollBottom }
cachedMediaWidth = { this . props . cachedMediaWidth }
cacheMediaWidth = { this . props . cacheMediaWidth }
/ >
< / d i v >
< / H o t K e y s >
) ;
}
2020-04-14 14:47:35 -07:00
render ( ) {
2020-03-27 13:59:38 -07:00
const { notification } = this . props ;
const account = notification . get ( 'account' ) ;
const displayNameHtml = { _ _html : account . get ( 'display_name_html' ) } ;
const link = < bdi > < Permalink className = 'notification__display-name' href = { ` /@ ${ account . get ( 'acct' ) } ` } title = { account . get ( 'acct' ) } to = { ` /@ ${ account . get ( 'acct' ) } ` } dangerouslySetInnerHTML = { displayNameHtml } / > < / b d i > ;
switch ( notification . get ( 'type' ) ) {
case 'follow' :
return this . renderFollow ( notification , account , link ) ;
2021-03-29 11:35:30 -07:00
case 'follow_request' :
return this . renderFollowRequest ( notification , account , link ) ;
2020-03-27 13:59:38 -07:00
case 'mention' :
return this . renderMention ( notification ) ;
case 'favourite' :
return this . renderFavourite ( notification , link ) ;
case 'reblog' :
return this . renderReblog ( notification , link ) ;
case 'poll' :
return this . renderPoll ( notification ) ;
2020-05-20 16:01:37 -07:00
case 'pleroma:emoji_reaction' :
return this . renderEmojiReact ( notification , link ) ;
2020-08-24 17:51:24 -07:00
case 'pleroma:chat_mention' :
2020-08-27 12:33:03 -07:00
return this . renderChatMention ( notification , link ) ;
2020-03-27 13:59:38 -07:00
}
return null ;
}
}