You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ChatMessage.js 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // @flow
  2. import React from 'react';
  3. import { toArray } from 'react-emoji-render';
  4. import { translate } from '../../../base/i18n';
  5. import { Linkify } from '../../../base/react';
  6. import { MESSAGE_TYPE_LOCAL } from '../../constants';
  7. import AbstractChatMessage, {
  8. type Props
  9. } from '../AbstractChatMessage';
  10. import PrivateMessageButton from '../PrivateMessageButton';
  11. /**
  12. * Renders a single chat message.
  13. */
  14. class ChatMessage extends AbstractChatMessage<Props> {
  15. /**
  16. * Implements React's {@link Component#render()}.
  17. *
  18. * @inheritdoc
  19. * @returns {ReactElement}
  20. */
  21. render() {
  22. const { message, t } = this.props;
  23. const processedMessage = [];
  24. // content is an array of text and emoji components
  25. const content = toArray(this._getMessageText(), { className: 'smiley' });
  26. content.forEach(i => {
  27. if (typeof i === 'string') {
  28. processedMessage.push(<Linkify key = { i }>{ i }</Linkify>);
  29. } else {
  30. processedMessage.push(i);
  31. }
  32. });
  33. return (
  34. <div
  35. className = 'chatmessage-wrapper'
  36. tabIndex = { -1 }>
  37. <div className = { `chatmessage ${message.privateMessage ? 'privatemessage' : ''}` }>
  38. <div className = 'replywrapper'>
  39. <div className = 'messagecontent'>
  40. { this.props.showDisplayName && this._renderDisplayName() }
  41. <div className = 'usermessage'>
  42. <span className = 'sr-only'>
  43. { this.props.message.displayName === this.props.message.recipient
  44. ? t('chat.messageAccessibleTitleMe')
  45. : t('chat.messageAccessibleTitle',
  46. { user: this.props.message.displayName }) }
  47. </span>
  48. { processedMessage }
  49. </div>
  50. { message.privateMessage && this._renderPrivateNotice() }
  51. </div>
  52. { message.privateMessage && message.messageType !== MESSAGE_TYPE_LOCAL
  53. && (
  54. <div className = 'messageactions'>
  55. <PrivateMessageButton
  56. participantID = { message.id }
  57. reply = { true }
  58. showLabel = { false } />
  59. </div>
  60. ) }
  61. </div>
  62. </div>
  63. { this.props.showTimestamp && this._renderTimestamp() }
  64. </div>
  65. );
  66. }
  67. _getFormattedTimestamp: () => string;
  68. _getMessageText: () => string;
  69. _getPrivateNoticeMessage: () => string;
  70. /**
  71. * Renders the display name of the sender.
  72. *
  73. * @returns {React$Element<*>}
  74. */
  75. _renderDisplayName() {
  76. return (
  77. <div
  78. aria-hidden = { true }
  79. className = 'display-name'>
  80. { this.props.message.displayName }
  81. </div>
  82. );
  83. }
  84. /**
  85. * Renders the message privacy notice.
  86. *
  87. * @returns {React$Element<*>}
  88. */
  89. _renderPrivateNotice() {
  90. return (
  91. <div className = 'privatemessagenotice'>
  92. { this._getPrivateNoticeMessage() }
  93. </div>
  94. );
  95. }
  96. /**
  97. * Renders the time at which the message was sent.
  98. *
  99. * @returns {React$Element<*>}
  100. */
  101. _renderTimestamp() {
  102. return (
  103. <div className = 'timestamp'>
  104. { this._getFormattedTimestamp() }
  105. </div>
  106. );
  107. }
  108. }
  109. export default translate(ChatMessage);