import React, { Component } from 'react'; import PropTypes from 'prop-types'; import cx from 'classnames'; import Modal from '/imports/ui/components/modal/simple/component'; import Button from '/imports/ui/components/button/component'; import { Session } from 'meteor/session'; import { defineMessages, injectIntl, intlShape, FormattedMessage, } from 'react-intl'; import { styles } from './styles'; import PermissionsOverlay from '../permissions-overlay/component'; import AudioSettings from '../audio-settings/component'; import EchoTest from '../echo-test/component'; import Help from '../help/component'; import AudioDial from '../audio-dial/component'; import AudioAutoplayPrompt from '../autoplay/component'; const propTypes = { intl: intlShape.isRequired, closeModal: PropTypes.func.isRequired, joinMicrophone: PropTypes.func.isRequired, joinListenOnly: PropTypes.func.isRequired, joinEchoTest: PropTypes.func.isRequired, exitAudio: PropTypes.func.isRequired, leaveEchoTest: PropTypes.func.isRequired, changeInputDevice: PropTypes.func.isRequired, changeOutputDevice: PropTypes.func.isRequired, isEchoTest: PropTypes.bool.isRequired, isConnecting: PropTypes.bool.isRequired, isConnected: PropTypes.bool.isRequired, inputDeviceId: PropTypes.string, outputDeviceId: PropTypes.string, formattedDialNum: PropTypes.string.isRequired, showPermissionsOvelay: PropTypes.bool.isRequired, listenOnlyMode: PropTypes.bool.isRequired, skipCheck: PropTypes.bool.isRequired, joinFullAudioImmediately: PropTypes.bool.isRequired, joinFullAudioEchoTest: PropTypes.bool.isRequired, forceListenOnlyAttendee: PropTypes.bool.isRequired, audioLocked: PropTypes.bool.isRequired, resolve: PropTypes.func, isMobileNative: PropTypes.bool.isRequired, isIOSChrome: PropTypes.bool.isRequired, isIEOrEdge: PropTypes.bool.isRequired, hasMediaDevices: PropTypes.bool.isRequired, formattedTelVoice: PropTypes.string.isRequired, autoplayBlocked: PropTypes.bool.isRequired, handleAllowAutoplay: PropTypes.func.isRequired, }; const defaultProps = { inputDeviceId: null, outputDeviceId: null, resolve: null, }; const intlMessages = defineMessages({ microphoneLabel: { id: 'app.audioModal.microphoneLabel', description: 'Join mic audio button label', }, listenOnlyLabel: { id: 'app.audioModal.listenOnlyLabel', description: 'Join listen only audio button label', }, closeLabel: { id: 'app.audioModal.closeLabel', description: 'close audio modal button label', }, audioChoiceLabel: { id: 'app.audioModal.audioChoiceLabel', description: 'Join audio modal title', }, iOSError: { id: 'app.audioModal.iOSBrowser', description: 'Audio/Video Not supported warning', }, iOSErrorDescription: { id: 'app.audioModal.iOSErrorDescription', description: 'Audio/Video not supported description', }, iOSErrorRecommendation: { id: 'app.audioModal.iOSErrorRecommendation', description: 'Audio/Video recommended action', }, echoTestTitle: { id: 'app.audioModal.echoTestTitle', description: 'Title for the echo test', }, settingsTitle: { id: 'app.audioModal.settingsTitle', description: 'Title for the audio modal', }, helpTitle: { id: 'app.audioModal.helpTitle', description: 'Title for the audio help', }, audioDialTitle: { id: 'app.audioModal.audioDialTitle', description: 'Title for the audio dial', }, connecting: { id: 'app.audioModal.connecting', description: 'Message for audio connecting', }, connectingEchoTest: { id: 'app.audioModal.connectingEchoTest', description: 'Message for echo test connecting', }, ariaModalTitle: { id: 'app.audioModal.ariaTitle', description: 'aria label for modal title', }, autoplayPromptTitle: { id: 'app.audioModal.autoplayBlockedDesc', description: 'Message for autoplay audio block', }, }); class AudioModal extends Component { constructor(props) { super(props); this.state = { content: null, hasError: false, }; this.handleGoToAudioOptions = this.handleGoToAudioOptions.bind(this); this.handleGoToAudioSettings = this.handleGoToAudioSettings.bind(this); this.handleRetryGoToEchoTest = this.handleRetryGoToEchoTest.bind(this); this.handleGoToEchoTest = this.handleGoToEchoTest.bind(this); this.handleJoinMicrophone = this.handleJoinMicrophone.bind(this); this.handleJoinListenOnly = this.handleJoinListenOnly.bind(this); this.skipAudioOptions = this.skipAudioOptions.bind(this); this.contents = { echoTest: { title: intlMessages.echoTestTitle, component: () => this.renderEchoTest(), }, settings: { title: intlMessages.settingsTitle, component: () => this.renderAudioSettings(), }, help: { title: intlMessages.helpTitle, component: () => this.renderHelp(), }, audioDial: { title: intlMessages.audioDialTitle, component: () => this.renderAudioDial(), }, autoplayBlocked: { title: intlMessages.autoplayPromptTitle, component: () => this.renderAutoplayOverlay(), }, }; this.failedMediaElements = []; } componentDidMount() { const { joinFullAudioImmediately, joinFullAudioEchoTest, forceListenOnlyAttendee, audioLocked, } = this.props; if (joinFullAudioImmediately) { this.handleJoinMicrophone(); } if (joinFullAudioEchoTest) { this.handleGoToEchoTest(); } if (forceListenOnlyAttendee || audioLocked) { this.handleJoinListenOnly(); } } componentDidUpdate(prevProps) { const { autoplayBlocked, closeModal } = this.props; if (autoplayBlocked !== prevProps.autoplayBlocked) { autoplayBlocked ? this.setState({ content: 'autoplayBlocked' }) : closeModal(); } } componentWillUnmount() { const { isEchoTest, exitAudio, resolve, } = this.props; if (isEchoTest) { exitAudio(); } if (resolve) resolve(); Session.set('audioModalIsOpen', false); } handleGoToAudioOptions() { this.setState({ content: null, hasError: true, }); } handleGoToAudioSettings() { const { leaveEchoTest } = this.props; leaveEchoTest().then(() => { this.setState({ content: 'settings', }); }); } handleRetryGoToEchoTest() { const { joinFullAudioImmediately } = this.props; this.setState({ hasError: false, content: null, }); if (joinFullAudioImmediately) return this.joinMicrophone(); return this.handleGoToEchoTest(); } handleGoToEchoTest() { const { inputDeviceId, outputDeviceId, joinEchoTest, } = this.props; this.setState({ hasError: false, }); return joinEchoTest().then(() => { console.log(inputDeviceId, outputDeviceId); this.setState({ content: 'echoTest', }); }).catch((err) => { if (err.type === 'MEDIA_ERROR') { this.setState({ content: 'help', }); } }); } handleJoinListenOnly() { const { joinListenOnly, } = this.props; return joinListenOnly().catch((err) => { if (err.type === 'MEDIA_ERROR') { this.setState({ content: 'help', }); } }); } handleJoinMicrophone() { const { joinMicrophone, } = this.props; this.setState({ hasError: false, }); joinMicrophone().catch(this.handleGoToAudioOptions); } skipAudioOptions() { const { isConnecting, joinFullAudioImmediately, joinFullAudioEchoTest, forceListenOnlyAttendee, } = this.props; const { content, hasError, } = this.state; return ( isConnecting || forceListenOnlyAttendee || joinFullAudioImmediately || joinFullAudioEchoTest ) && !content && !hasError; } renderAudioOptions() { const { intl, listenOnlyMode, forceListenOnlyAttendee, skipCheck, audioLocked, isMobileNative, formattedDialNum, isRTL, } = this.props; const showMicrophone = forceListenOnlyAttendee || audioLocked; const dialAudioLabel = isRTL ? `🡸 ${intl.formatMessage(intlMessages.audioDialTitle)}` : `${intl.formatMessage(intlMessages.audioDialTitle)} 🡺`; return (