Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

ChatMessage.tsx 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. import { Theme } from '@mui/material';
  2. import { withStyles } from '@mui/styles';
  3. import clsx from 'clsx';
  4. import React from 'react';
  5. import { connect } from 'react-redux';
  6. import { IReduxState } from '../../../app/types';
  7. import { translate } from '../../../base/i18n/functions';
  8. import Message from '../../../base/react/components/web/Message';
  9. import { withPixelLineHeight } from '../../../base/styles/functions.web';
  10. import { MESSAGE_TYPE_LOCAL } from '../../constants';
  11. import AbstractChatMessage, { IProps as AbstractProps } from '../AbstractChatMessage';
  12. import PrivateMessageButton from './PrivateMessageButton';
  13. interface IProps extends AbstractProps {
  14. classes: any;
  15. type: string;
  16. }
  17. const styles = (theme: Theme) => {
  18. return {
  19. chatMessageWrapper: {
  20. maxWidth: '100%',
  21. '&.remote': {
  22. maxWidth: 'calc(100% - 40px)' // 100% - avatar and margin
  23. }
  24. },
  25. chatMessage: {
  26. display: 'inline-flex',
  27. padding: '12px',
  28. backgroundColor: theme.palette.ui02,
  29. borderRadius: '4px 12px 12px 12px',
  30. maxWidth: '100%',
  31. marginTop: '4px',
  32. boxSizing: 'border-box' as const,
  33. '&.privatemessage': {
  34. backgroundColor: theme.palette.support05
  35. },
  36. '&.local': {
  37. backgroundColor: theme.palette.ui04,
  38. borderRadius: '12px 4px 12px 12px',
  39. '&.privatemessage': {
  40. backgroundColor: theme.palette.support05
  41. }
  42. },
  43. '&.error': {
  44. backgroundColor: 'rgb(215, 121, 118)',
  45. borderRadius: 0,
  46. fontWeight: 100
  47. },
  48. '&.lobbymessage': {
  49. backgroundColor: theme.palette.support05
  50. }
  51. },
  52. replyWrapper: {
  53. display: 'flex',
  54. flexDirection: 'row' as const,
  55. alignItems: 'center',
  56. maxWidth: '100%'
  57. },
  58. messageContent: {
  59. maxWidth: '100%',
  60. overflow: 'hidden',
  61. flex: 1
  62. },
  63. replyButtonContainer: {
  64. display: 'flex',
  65. alignItems: 'flex-start',
  66. height: '100%'
  67. },
  68. replyButton: {
  69. padding: '2px'
  70. },
  71. displayName: {
  72. ...withPixelLineHeight(theme.typography.labelBold),
  73. color: theme.palette.text02,
  74. whiteSpace: 'nowrap',
  75. textOverflow: 'ellipsis',
  76. overflow: 'hidden',
  77. marginBottom: theme.spacing(1)
  78. },
  79. userMessage: {
  80. ...withPixelLineHeight(theme.typography.bodyShortRegular),
  81. color: theme.palette.text01,
  82. whiteSpace: 'pre-wrap',
  83. wordBreak: 'break-word'
  84. },
  85. privateMessageNotice: {
  86. ...withPixelLineHeight(theme.typography.labelRegular),
  87. color: theme.palette.text02,
  88. marginTop: theme.spacing(1)
  89. },
  90. timestamp: {
  91. ...withPixelLineHeight(theme.typography.labelRegular),
  92. color: theme.palette.text03,
  93. marginTop: theme.spacing(1)
  94. }
  95. };
  96. };
  97. /**
  98. * Renders a single chat message.
  99. */
  100. class ChatMessage extends AbstractChatMessage<IProps> {
  101. /**
  102. * Implements React's {@link Component#render()}.
  103. *
  104. * @inheritdoc
  105. * @returns {ReactElement}
  106. */
  107. render() {
  108. const { message, t, knocking, classes, type } = this.props;
  109. return (
  110. <div
  111. className = { clsx(classes.chatMessageWrapper, type) }
  112. id = { this.props.message.messageId }
  113. tabIndex = { -1 }>
  114. <div
  115. className = { clsx('chatmessage', classes.chatMessage, type,
  116. message.privateMessage && 'privatemessage',
  117. message.lobbyChat && !knocking && 'lobbymessage') }>
  118. <div className = { classes.replyWrapper }>
  119. <div className = { clsx('messagecontent', classes.messageContent) }>
  120. { this.props.showDisplayName && this._renderDisplayName() }
  121. <div className = { clsx('usermessage', classes.userMessage) }>
  122. <span className = 'sr-only'>
  123. { this.props.message.displayName === this.props.message.recipient
  124. ? t('chat.messageAccessibleTitleMe')
  125. : t('chat.messageAccessibleTitle',
  126. { user: this.props.message.displayName }) }
  127. </span>
  128. <Message text = { this._getMessageText() } />
  129. </div>
  130. { (message.privateMessage || (message.lobbyChat && !knocking))
  131. && this._renderPrivateNotice() }
  132. </div>
  133. { (message.privateMessage || (message.lobbyChat && !knocking))
  134. && message.messageType !== MESSAGE_TYPE_LOCAL
  135. && (
  136. <div
  137. className = { classes.replyButtonContainer }>
  138. <PrivateMessageButton
  139. isLobbyMessage = { message.lobbyChat }
  140. participantID = { message.id } />
  141. </div>
  142. ) }
  143. </div>
  144. </div>
  145. { this.props.showTimestamp && this._renderTimestamp() }
  146. </div>
  147. );
  148. }
  149. /**
  150. * Renders the display name of the sender.
  151. *
  152. * @returns {React$Element<*>}
  153. */
  154. _renderDisplayName() {
  155. return (
  156. <div
  157. aria-hidden = { true }
  158. className = { clsx('display-name', this.props.classes.displayName) }>
  159. { this.props.message.displayName }
  160. </div>
  161. );
  162. }
  163. /**
  164. * Renders the message privacy notice.
  165. *
  166. * @returns {React$Element<*>}
  167. */
  168. _renderPrivateNotice() {
  169. return (
  170. <div className = { this.props.classes.privateMessageNotice }>
  171. { this._getPrivateNoticeMessage() }
  172. </div>
  173. );
  174. }
  175. /**
  176. * Renders the time at which the message was sent.
  177. *
  178. * @returns {React$Element<*>}
  179. */
  180. _renderTimestamp() {
  181. return (
  182. <div className = { clsx('timestamp', this.props.classes.timestamp) }>
  183. { this._getFormattedTimestamp() }
  184. </div>
  185. );
  186. }
  187. }
  188. /**
  189. * Maps part of the Redux store to the props of this component.
  190. *
  191. * @param {Object} state - The Redux state.
  192. * @returns {IProps}
  193. */
  194. function _mapStateToProps(state: IReduxState) {
  195. const { knocking } = state['features/lobby'];
  196. return {
  197. knocking
  198. };
  199. }
  200. export default translate(connect(_mapStateToProps)(withStyles(styles)(ChatMessage)));