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.

ParticipantItem.js 4.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. // @flow
  2. import React, { type Node } from 'react';
  3. import { useTranslation } from 'react-i18next';
  4. import { useSelector } from 'react-redux';
  5. import { Avatar } from '../../base/avatar';
  6. import {
  7. Icon,
  8. IconCameraEmpty,
  9. IconCameraEmptyDisabled,
  10. IconMicrophoneEmpty,
  11. IconMicrophoneEmptySlash
  12. } from '../../base/icons';
  13. import { getParticipantDisplayNameWithId } from '../../base/participants';
  14. import { ACTION_TRIGGER, MEDIA_STATE, type ActionTrigger, type MediaState } from '../constants';
  15. import { RaisedHandIndicator } from './RaisedHandIndicator';
  16. import {
  17. ColoredIcon,
  18. ParticipantActionsHover,
  19. ParticipantActionsPermanent,
  20. ParticipantContainer,
  21. ParticipantContent,
  22. ParticipantName,
  23. ParticipantNameContainer,
  24. ParticipantStates
  25. } from './styled';
  26. /**
  27. * Participant actions component mapping depending on trigger type.
  28. */
  29. const Actions = {
  30. [ACTION_TRIGGER.HOVER]: ParticipantActionsHover,
  31. [ACTION_TRIGGER.PERMANENT]: ParticipantActionsPermanent
  32. };
  33. /**
  34. * Icon mapping for possible participant audio states.
  35. */
  36. const AudioStateIcons: {[MediaState]: React$Element<any> | null} = {
  37. [MEDIA_STATE.FORCE_MUTED]: (
  38. <ColoredIcon color = '#E04757'>
  39. <Icon
  40. size = { 16 }
  41. src = { IconMicrophoneEmptySlash } />
  42. </ColoredIcon>
  43. ),
  44. [MEDIA_STATE.MUTED]: (
  45. <Icon
  46. size = { 16 }
  47. src = { IconMicrophoneEmptySlash } />
  48. ),
  49. [MEDIA_STATE.UNMUTED]: (
  50. <ColoredIcon color = '#1EC26A'>
  51. <Icon
  52. size = { 16 }
  53. src = { IconMicrophoneEmpty } />
  54. </ColoredIcon>
  55. ),
  56. [MEDIA_STATE.NONE]: null
  57. };
  58. /**
  59. * Icon mapping for possible participant video states.
  60. */
  61. const VideoStateIcons = {
  62. [MEDIA_STATE.FORCE_MUTED]: (
  63. <Icon
  64. size = { 16 }
  65. src = { IconCameraEmptyDisabled } />
  66. ),
  67. [MEDIA_STATE.MUTED]: (
  68. <Icon
  69. size = { 16 }
  70. src = { IconCameraEmptyDisabled } />
  71. ),
  72. [MEDIA_STATE.UNMUTED]: (
  73. <Icon
  74. size = { 16 }
  75. src = { IconCameraEmpty } />
  76. ),
  77. [MEDIA_STATE.NONE]: null
  78. };
  79. type Props = {
  80. /**
  81. * Type of trigger for the participant actions
  82. */
  83. actionsTrigger: ActionTrigger,
  84. /**
  85. * Media state for audio
  86. */
  87. audioMediaState: MediaState,
  88. /**
  89. * React children
  90. */
  91. children: Node,
  92. /**
  93. * Is this item highlighted/raised
  94. */
  95. isHighlighted?: boolean,
  96. /**
  97. * The name of the participant. Used for showing lobby names.
  98. */
  99. name?: string,
  100. /**
  101. * Callback for when the mouse leaves this component
  102. */
  103. onLeave?: Function,
  104. /**
  105. * Participant reference
  106. */
  107. participant: Object,
  108. /**
  109. * Media state for video
  110. */
  111. videoMuteState: MediaState
  112. }
  113. export const ParticipantItem = ({
  114. children,
  115. isHighlighted,
  116. onLeave,
  117. actionsTrigger = ACTION_TRIGGER.HOVER,
  118. audioMediaState = MEDIA_STATE.NONE,
  119. videoMuteState = MEDIA_STATE.NONE,
  120. name,
  121. participant: p
  122. }: Props) => {
  123. const ParticipantActions = Actions[actionsTrigger];
  124. const { t } = useTranslation();
  125. const displayName = name || useSelector(getParticipantDisplayNameWithId(p.id));
  126. return (
  127. <ParticipantContainer
  128. isHighlighted = { isHighlighted }
  129. onMouseLeave = { onLeave }
  130. trigger = { actionsTrigger }>
  131. <Avatar
  132. className = 'participant-avatar'
  133. participantId = { p.id }
  134. size = { 32 } />
  135. <ParticipantContent>
  136. <ParticipantNameContainer>
  137. <ParticipantName>
  138. { displayName }
  139. </ParticipantName>
  140. { p.local ? <span>&nbsp;({t('chat.you')})</span> : null }
  141. </ParticipantNameContainer>
  142. { !p.local && <ParticipantActions children = { children } /> }
  143. <ParticipantStates>
  144. {p.raisedHand && <RaisedHandIndicator />}
  145. {VideoStateIcons[videoMuteState]}
  146. {AudioStateIcons[audioMediaState]}
  147. </ParticipantStates>
  148. </ParticipantContent>
  149. </ParticipantContainer>
  150. );
  151. };