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

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