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.

PreMeetingScreen.tsx 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. /* eslint-disable lines-around-comment */
  2. import clsx from 'clsx';
  3. import React, { ReactNode } from 'react';
  4. import { connect } from 'react-redux';
  5. import { makeStyles } from 'tss-react/mui';
  6. import { IReduxState } from '../../../../app/types';
  7. import DeviceStatus from '../../../../prejoin/components/web/preview/DeviceStatus';
  8. // @ts-ignore
  9. import { Toolbox } from '../../../../toolbox/components/web';
  10. import { getConferenceName } from '../../../conference/functions';
  11. import { PREMEETING_BUTTONS, THIRD_PARTY_PREJOIN_BUTTONS } from '../../../config/constants';
  12. import { getToolbarButtons, isToolbarButtonEnabled } from '../../../config/functions.web';
  13. import { withPixelLineHeight } from '../../../styles/functions.web';
  14. import ConnectionStatus from './ConnectionStatus';
  15. // @ts-ignore
  16. import Preview from './Preview';
  17. /* eslint-enable lines-around-comment */
  18. interface IProps {
  19. /**
  20. * The list of toolbar buttons to render.
  21. */
  22. _buttons: Array<string>;
  23. /**
  24. * The branding background of the premeeting screen(lobby/prejoin).
  25. */
  26. _premeetingBackground: string;
  27. /**
  28. * The name of the meeting that is about to be joined.
  29. */
  30. _roomName: string;
  31. /**
  32. * Children component(s) to be rendered on the screen.
  33. */
  34. children?: ReactNode;
  35. /**
  36. * Additional CSS class names to set on the icon container.
  37. */
  38. className?: string;
  39. /**
  40. * The name of the participant.
  41. */
  42. name?: string;
  43. /**
  44. * Indicates whether the copy url button should be shown.
  45. */
  46. showCopyUrlButton?: boolean;
  47. /**
  48. * Indicates whether the device status should be shown.
  49. */
  50. showDeviceStatus: boolean;
  51. /**
  52. * The 'Skip prejoin' button to be rendered (if any).
  53. */
  54. skipPrejoinButton?: ReactNode;
  55. /**
  56. * Whether it's used in the 3rdParty prejoin screen or not.
  57. */
  58. thirdParty?: boolean;
  59. /**
  60. * Title of the screen.
  61. */
  62. title?: string;
  63. /**
  64. * True if the preview overlay should be muted, false otherwise.
  65. */
  66. videoMuted?: boolean;
  67. /**
  68. * The video track to render as preview (if omitted, the default local track will be rendered).
  69. */
  70. videoTrack?: Object;
  71. }
  72. const useStyles = makeStyles()(theme => {
  73. return {
  74. container: {
  75. height: '100%',
  76. position: 'absolute',
  77. inset: '0 0 0 0',
  78. display: 'flex',
  79. backgroundColor: theme.palette.ui01,
  80. zIndex: 252,
  81. '@media (max-width: 720px)': {
  82. flexDirection: 'column-reverse'
  83. }
  84. },
  85. content: {
  86. display: 'flex',
  87. flexDirection: 'column',
  88. alignItems: 'center',
  89. flexShrink: 0,
  90. boxSizing: 'border-box',
  91. margin: '0 48px',
  92. padding: '24px 0 16px',
  93. position: 'relative',
  94. width: '300px',
  95. height: '100%',
  96. zIndex: 252,
  97. '@media (max-width: 720px)': {
  98. height: 'auto',
  99. margin: '0 auto'
  100. },
  101. // mobile phone landscape
  102. '@media (max-width: 420px)': {
  103. padding: '16px 16px 0 16px',
  104. width: '100%'
  105. },
  106. '@media (max-width: 400px)': {
  107. padding: '16px'
  108. }
  109. },
  110. contentControls: {
  111. display: 'flex',
  112. flexDirection: 'column',
  113. alignItems: 'center',
  114. margin: 'auto',
  115. width: '100%'
  116. },
  117. title: {
  118. ...withPixelLineHeight(theme.typography.heading4),
  119. color: `${theme.palette.text01}!important`,
  120. marginBottom: theme.spacing(3),
  121. textAlign: 'center',
  122. '@media (max-width: 400px)': {
  123. display: 'none'
  124. }
  125. },
  126. roomName: {
  127. ...withPixelLineHeight(theme.typography.heading5),
  128. color: theme.palette.text01,
  129. marginBottom: theme.spacing(4),
  130. overflow: 'hidden',
  131. textAlign: 'center',
  132. textOverflow: 'ellipsis',
  133. whiteSpace: 'nowrap',
  134. width: '100%'
  135. }
  136. };
  137. });
  138. const PreMeetingScreen = ({
  139. _buttons,
  140. _premeetingBackground,
  141. _roomName,
  142. children,
  143. className,
  144. showDeviceStatus,
  145. skipPrejoinButton,
  146. title,
  147. videoMuted,
  148. videoTrack
  149. }: IProps) => {
  150. const { classes } = useStyles();
  151. const style = _premeetingBackground ? {
  152. background: _premeetingBackground,
  153. backgroundPosition: 'center',
  154. backgroundSize: 'cover'
  155. } : {};
  156. return (
  157. <div className = { clsx('premeeting-screen', classes.container, className) }>
  158. <div style = { style }>
  159. <div className = { classes.content }>
  160. <ConnectionStatus />
  161. <div className = { classes.contentControls }>
  162. <h1 className = { classes.title }>
  163. {title}
  164. </h1>
  165. {_roomName && (
  166. <span className = { classes.roomName }>
  167. {_roomName}
  168. </span>
  169. )}
  170. {children}
  171. {_buttons.length && <Toolbox toolbarButtons = { _buttons } />}
  172. {skipPrejoinButton}
  173. {showDeviceStatus && <DeviceStatus />}
  174. </div>
  175. </div>
  176. </div>
  177. <Preview
  178. videoMuted = { videoMuted }
  179. videoTrack = { videoTrack } />
  180. </div>
  181. );
  182. };
  183. /**
  184. * Maps (parts of) the redux state to the React {@code Component} props.
  185. *
  186. * @param {Object} state - The redux state.
  187. * @param {Object} ownProps - The props passed to the component.
  188. * @returns {Object}
  189. */
  190. function mapStateToProps(state: IReduxState, ownProps: Partial<IProps>) {
  191. const { hiddenPremeetingButtons, hideConferenceSubject } = state['features/base/config'];
  192. const toolbarButtons = getToolbarButtons(state);
  193. const premeetingButtons = (ownProps.thirdParty
  194. ? THIRD_PARTY_PREJOIN_BUTTONS
  195. : PREMEETING_BUTTONS).filter((b: any) => !(hiddenPremeetingButtons || []).includes(b));
  196. const { premeetingBackground } = state['features/dynamic-branding'];
  197. return {
  198. // For keeping backwards compat.: if we pass an empty hiddenPremeetingButtons
  199. // array through external api, we have all prejoin buttons present on premeeting
  200. // screen regardless of passed values into toolbarButtons config overwrite.
  201. // If hiddenPremeetingButtons is missing, we hide the buttons according to
  202. // toolbarButtons config overwrite.
  203. _buttons: hiddenPremeetingButtons
  204. ? premeetingButtons
  205. : premeetingButtons.filter(b => isToolbarButtonEnabled(b, toolbarButtons)),
  206. _premeetingBackground: premeetingBackground,
  207. _roomName: (hideConferenceSubject ? undefined : getConferenceName(state)) ?? ''
  208. };
  209. }
  210. export default connect(mapStateToProps)(PreMeetingScreen);