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.tsx 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import React, { ReactElement, useCallback } from 'react';
  2. import { WithTranslation } from 'react-i18next';
  3. import { makeStyles } from 'tss-react/mui';
  4. // @ts-ignore
  5. import { Avatar } from '../../../base/avatar';
  6. import ListItem from '../../../base/components/participants-pane-list/ListItem';
  7. import { translate } from '../../../base/i18n/functions';
  8. import { withPixelLineHeight } from '../../../base/styles/functions.web';
  9. import {
  10. ACTION_TRIGGER,
  11. type ActionTrigger,
  12. AudioStateIcons,
  13. MEDIA_STATE,
  14. MediaState,
  15. VideoStateIcons
  16. } from '../../constants';
  17. import { RaisedHandIndicator } from './RaisedHandIndicator';
  18. interface IProps extends WithTranslation {
  19. /**
  20. * Type of trigger for the participant actions.
  21. */
  22. actionsTrigger?: ActionTrigger;
  23. /**
  24. * Media state for audio.
  25. */
  26. audioMediaState?: MediaState;
  27. /**
  28. * React children.
  29. */
  30. children?: ReactElement | boolean;
  31. /**
  32. * Whether or not to disable the moderator indicator.
  33. */
  34. disableModeratorIndicator?: boolean;
  35. /**
  36. * The name of the participant. Used for showing lobby names.
  37. */
  38. displayName?: string;
  39. /**
  40. * Is this item highlighted/raised.
  41. */
  42. isHighlighted?: boolean;
  43. /**
  44. * Whether or not the participant is a moderator.
  45. */
  46. isModerator?: boolean;
  47. /**
  48. * True if the participant is local.
  49. */
  50. local?: boolean;
  51. /**
  52. * Callback for when the mouse leaves this component.
  53. */
  54. onLeave?: (e?: React.MouseEvent) => void;
  55. /**
  56. * Opens a drawer with participant actions.
  57. */
  58. openDrawerForParticipant?: Function;
  59. /**
  60. * If an overflow drawer can be opened.
  61. */
  62. overflowDrawer?: boolean;
  63. /**
  64. * The ID of the participant.
  65. */
  66. participantID: string;
  67. /**
  68. * True if the participant have raised hand.
  69. */
  70. raisedHand?: boolean;
  71. /**
  72. * Media state for video.
  73. */
  74. videoMediaState?: MediaState;
  75. /**
  76. * The translated "you" text.
  77. */
  78. youText?: string;
  79. }
  80. const useStyles = makeStyles()(theme => {
  81. return {
  82. nameContainer: {
  83. display: 'flex',
  84. flex: 1,
  85. overflow: 'hidden'
  86. },
  87. name: {
  88. overflow: 'hidden',
  89. textOverflow: 'ellipsis',
  90. whiteSpace: 'nowrap'
  91. },
  92. moderatorLabel: {
  93. ...withPixelLineHeight(theme.typography.labelRegular),
  94. color: theme.palette.text03
  95. }
  96. };
  97. });
  98. /**
  99. * A component representing a participant entry in ParticipantPane and Lobby.
  100. *
  101. * @param {IProps} props - The props of the component.
  102. * @returns {ReactNode}
  103. */
  104. function ParticipantItem({
  105. actionsTrigger = ACTION_TRIGGER.HOVER,
  106. audioMediaState = MEDIA_STATE.NONE,
  107. children,
  108. disableModeratorIndicator,
  109. displayName,
  110. isHighlighted,
  111. isModerator,
  112. local,
  113. onLeave,
  114. openDrawerForParticipant,
  115. overflowDrawer,
  116. participantID,
  117. raisedHand,
  118. t,
  119. videoMediaState = MEDIA_STATE.NONE,
  120. youText
  121. }: IProps) {
  122. const onClick = useCallback(
  123. () => openDrawerForParticipant?.({
  124. participantID,
  125. displayName
  126. }), []);
  127. const { classes: styles } = useStyles();
  128. const icon = (
  129. <Avatar
  130. className = 'participant-avatar'
  131. displayName = { displayName }
  132. participantId = { participantID }
  133. size = { 32 } />
  134. );
  135. const text = (
  136. <>
  137. <div className = { styles.nameContainer }>
  138. <div className = { styles.name }>
  139. {displayName}
  140. </div>
  141. {local ? <span>&nbsp;({youText})</span> : null}
  142. </div>
  143. {isModerator && !disableModeratorIndicator && <div className = { styles.moderatorLabel }>
  144. {t('videothumbnail.moderator')}
  145. </div>}
  146. </>
  147. );
  148. const indicators = (
  149. <>
  150. {raisedHand && <RaisedHandIndicator />}
  151. {VideoStateIcons[videoMediaState]}
  152. {AudioStateIcons[audioMediaState]}
  153. </>
  154. );
  155. return (
  156. <ListItem
  157. actions = { children }
  158. hideActions = { local }
  159. icon = { icon }
  160. id = { `participant-item-${participantID}` }
  161. indicators = { indicators }
  162. isHighlighted = { isHighlighted }
  163. onClick = { !local && overflowDrawer ? onClick : undefined }
  164. onMouseLeave = { onLeave }
  165. textChildren = { text }
  166. trigger = { actionsTrigger } />
  167. );
  168. }
  169. export default translate(ParticipantItem);