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.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // @flow
  2. import React from 'react';
  3. import { toArray } from 'react-emoji-render';
  4. import Linkify from 'react-linkify';
  5. import { translate } from '../../../base/i18n';
  6. import AbstractChatMessage, {
  7. type Props
  8. } from '../AbstractChatMessage';
  9. /**
  10. * Renders a single chat message.
  11. */
  12. class ChatMessage extends AbstractChatMessage<Props> {
  13. /**
  14. * Implements React's {@link Component#render()}.
  15. *
  16. * @inheritdoc
  17. * @returns {ReactElement}
  18. */
  19. render() {
  20. const { message } = this.props;
  21. let messageTypeClassname = '';
  22. let messageToDisplay = message.message;
  23. switch (message.messageType) {
  24. case 'local':
  25. messageTypeClassname = 'localuser';
  26. break;
  27. case 'error':
  28. messageTypeClassname = 'error';
  29. messageToDisplay = this.props.t('chat.error', {
  30. error: message.error,
  31. originalText: messageToDisplay
  32. });
  33. break;
  34. default:
  35. messageTypeClassname = 'remoteuser';
  36. }
  37. // replace links and smileys
  38. // Strophe already escapes special symbols on sending,
  39. // so we escape here only tags to avoid double &amp;
  40. const escMessage = messageToDisplay.replace(/</g, '&lt;')
  41. .replace(/>/g, '&gt;')
  42. .replace(/\n/g, '<br/>');
  43. const processedMessage = [];
  44. // content is an array of text and emoji components
  45. const content = toArray(escMessage, { className: 'smiley' });
  46. content.forEach(i => {
  47. if (typeof i === 'string') {
  48. processedMessage.push(
  49. <Linkify
  50. key = { i }
  51. properties = {{
  52. rel: 'noopener noreferrer',
  53. target: '_blank'
  54. }}>{ i }</Linkify>);
  55. } else {
  56. processedMessage.push(i);
  57. }
  58. });
  59. return (
  60. <div className = { `chatmessage ${messageTypeClassname}` }>
  61. <div className = 'display-name'>
  62. { message.displayName }
  63. </div>
  64. <div className = { 'timestamp' }>
  65. { ChatMessage.formatTimestamp(message.timestamp) }
  66. </div>
  67. <div className = 'usermessage'>
  68. { processedMessage }
  69. </div>
  70. </div>
  71. );
  72. }
  73. /**
  74. * Returns a timestamp formatted for display.
  75. *
  76. * @param {number} timestamp - The timestamp for the chat message.
  77. * @private
  78. * @returns {string}
  79. */
  80. static formatTimestamp(timestamp) {
  81. const now = new Date(timestamp);
  82. let hour = now.getHours();
  83. let minute = now.getMinutes();
  84. let second = now.getSeconds();
  85. if (hour.toString().length === 1) {
  86. hour = `0${hour}`;
  87. }
  88. if (minute.toString().length === 1) {
  89. minute = `0${minute}`;
  90. }
  91. if (second.toString().length === 1) {
  92. second = `0${second}`;
  93. }
  94. return `${hour}:${minute}:${second}`;
  95. }
  96. }
  97. export default translate(ChatMessage, { wait: false });