The code powering m.abunchtell.com https://m.abunchtell.com
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 

170 行
6.0 KiB

  1. import React from 'react';
  2. import PropTypes from 'prop-types';
  3. import ImmutablePropTypes from 'react-immutable-proptypes';
  4. import StatusContainer from '../../../containers/status_container';
  5. import AccountContainer from '../../../containers/account_container';
  6. import { injectIntl, FormattedMessage } from 'react-intl';
  7. import Permalink from '../../../components/permalink';
  8. import ImmutablePureComponent from 'react-immutable-pure-component';
  9. import { HotKeys } from 'react-hotkeys';
  10. const notificationForScreenReader = (intl, message, timestamp) => {
  11. const output = [message];
  12. output.push(intl.formatDate(timestamp, { hour: '2-digit', minute: '2-digit', month: 'short', day: 'numeric' }));
  13. return output.join(', ');
  14. };
  15. export default @injectIntl
  16. class Notification extends ImmutablePureComponent {
  17. static contextTypes = {
  18. router: PropTypes.object,
  19. };
  20. static propTypes = {
  21. notification: ImmutablePropTypes.map.isRequired,
  22. hidden: PropTypes.bool,
  23. onMoveUp: PropTypes.func.isRequired,
  24. onMoveDown: PropTypes.func.isRequired,
  25. onMention: PropTypes.func.isRequired,
  26. intl: PropTypes.object.isRequired,
  27. };
  28. handleMoveUp = () => {
  29. const { notification, onMoveUp } = this.props;
  30. onMoveUp(notification.get('id'));
  31. }
  32. handleMoveDown = () => {
  33. const { notification, onMoveDown } = this.props;
  34. onMoveDown(notification.get('id'));
  35. }
  36. handleOpen = () => {
  37. const { notification } = this.props;
  38. if (notification.get('status')) {
  39. this.context.router.history.push(`/statuses/${notification.get('status')}`);
  40. } else {
  41. this.handleOpenProfile();
  42. }
  43. }
  44. handleOpenProfile = () => {
  45. const { notification } = this.props;
  46. this.context.router.history.push(`/accounts/${notification.getIn(['account', 'id'])}`);
  47. }
  48. handleMention = e => {
  49. e.preventDefault();
  50. const { notification, onMention } = this.props;
  51. onMention(notification.get('account'), this.context.router.history);
  52. }
  53. getHandlers () {
  54. return {
  55. moveUp: this.handleMoveUp,
  56. moveDown: this.handleMoveDown,
  57. open: this.handleOpen,
  58. openProfile: this.handleOpenProfile,
  59. mention: this.handleMention,
  60. reply: this.handleMention,
  61. };
  62. }
  63. renderFollow (notification, account, link) {
  64. const { intl } = this.props;
  65. return (
  66. <HotKeys handlers={this.getHandlers()}>
  67. <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'))}>
  68. <div className='notification__message'>
  69. <div className='notification__favourite-icon-wrapper'>
  70. <i className='fas fa-fw fa-user-plus' />
  71. </div>
  72. <FormattedMessage id='notification.follow' defaultMessage='{name} followed you' values={{ name: link }} />
  73. </div>
  74. <AccountContainer id={account.get('id')} withNote={false} hidden={this.props.hidden} />
  75. </div>
  76. </HotKeys>
  77. );
  78. }
  79. renderMention (notification) {
  80. return (
  81. <StatusContainer
  82. id={notification.get('status')}
  83. withDismiss
  84. hidden={this.props.hidden}
  85. onMoveDown={this.handleMoveDown}
  86. onMoveUp={this.handleMoveUp}
  87. contextType='notifications'
  88. />
  89. );
  90. }
  91. renderFavourite (notification, link) {
  92. const { intl } = this.props;
  93. return (
  94. <HotKeys handlers={this.getHandlers()}>
  95. <div className='notification notification-favourite focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.favourite', defaultMessage: '{name} favourited your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
  96. <div className='notification__message'>
  97. <div className='notification__favourite-icon-wrapper'>
  98. <i className='fas fa-fw fa-star star-icon' />
  99. </div>
  100. <FormattedMessage id='notification.favourite' defaultMessage='{name} favourited your status' values={{ name: link }} />
  101. </div>
  102. <StatusContainer id={notification.get('status')} account={notification.get('account')} muted withDismiss hidden={!!this.props.hidden} />
  103. </div>
  104. </HotKeys>
  105. );
  106. }
  107. renderReblog (notification, link) {
  108. const { intl } = this.props;
  109. return (
  110. <HotKeys handlers={this.getHandlers()}>
  111. <div className='notification notification-reblog focusable' tabIndex='0' aria-label={notificationForScreenReader(intl, intl.formatMessage({ id: 'notification.reblog', defaultMessage: '{name} boosted your status' }, { name: notification.getIn(['account', 'acct']) }), notification.get('created_at'))}>
  112. <div className='notification__message'>
  113. <div className='notification__favourite-icon-wrapper'>
  114. <i className='fas fa-fw fa-retweet' />
  115. </div>
  116. <FormattedMessage id='notification.reblog' defaultMessage='{name} boosted your status' values={{ name: link }} />
  117. </div>
  118. <StatusContainer id={notification.get('status')} account={notification.get('account')} muted withDismiss hidden={this.props.hidden} />
  119. </div>
  120. </HotKeys>
  121. );
  122. }
  123. render () {
  124. const { notification } = this.props;
  125. const account = notification.get('account');
  126. const displayNameHtml = { __html: account.get('display_name_html') };
  127. const link = <bdi><Permalink className='notification__display-name' href={account.get('url')} title={account.get('acct')} to={`/accounts/${account.get('id')}`} dangerouslySetInnerHTML={displayNameHtml} /></bdi>;
  128. switch(notification.get('type')) {
  129. case 'follow':
  130. return this.renderFollow(notification, account, link);
  131. case 'mention':
  132. return this.renderMention(notification);
  133. case 'favourite':
  134. return this.renderFavourite(notification, link);
  135. case 'reblog':
  136. return this.renderReblog(notification, link);
  137. }
  138. return null;
  139. }
  140. }