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

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