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

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