diff --git a/bigbluebutton-html5/imports/ui/components/nav-bar/component.jsx b/bigbluebutton-html5/imports/ui/components/nav-bar/component.jsx index 47d5f9d34b..b70a205db1 100755 --- a/bigbluebutton-html5/imports/ui/components/nav-bar/component.jsx +++ b/bigbluebutton-html5/imports/ui/components/nav-bar/component.jsx @@ -14,7 +14,7 @@ import browserInfo from '/imports/utils/browserInfo'; import deviceInfo from '/imports/utils/deviceInfo'; import { PANELS, ACTIONS } from '../layout/enums'; import { isEqual } from 'radash'; -import LeaveMeetingButton from './leave-meeting-button/component'; +import LeaveMeetingButtonContainer from './leave-meeting-button/container'; const intlMessages = defineMessages({ toggleUserListLabel: { @@ -37,10 +37,6 @@ const intlMessages = defineMessages({ id: 'app.createBreakoutRoom.room', description: 'default breakout room name', }, - leaveMeetingLabel: { - id: 'app.navBar.leaveMeetingBtnLabel', - description: 'Leave meeting button label', - }, }); const propTypes = { @@ -253,7 +249,7 @@ class NavBar extends Component { {ConnectionStatusService.isEnabled() ? : null} {isDirectLeaveButtonEnabled && isMeteorConnected - ? + ? : null} { - const leaveSession = () => { +const defaultProps = { + amIModerator: false, + isBreakoutRoom: false, + isDropdownOpen: false, +}; + +class LeaveMeetingButton extends PureComponent { + constructor(props) { + super(props); + + this.state = { + isEndMeetingConfirmationModalOpen: false, + }; + + // Set the logout code to 680 because it's not a real code and can be matched on the other side + this.LOGOUT_CODE = '680'; + + this.setEndMeetingConfirmationModalIsOpen = this.setEndMeetingConfirmationModalIsOpen.bind(this); + this.leaveSession = this.leaveSession.bind(this); + } + + setEndMeetingConfirmationModalIsOpen(value) { + this.setState({isEndMeetingConfirmationModalOpen: value}) + } + + leaveSession() { makeCall('userLeftMeeting'); // we don't check askForFeedbackOnLogout here, // it is checked in meeting-ended component - Session.set('codeError', LOGOUT_CODE); - }; + Session.set('codeError', this.LOGOUT_CODE); + } + + renderMenuItems() { + const { + intl, amIModerator, isBreakoutRoom, isMeteorConnected, + } = this.props; - return ( - leaveSession()} - icon="logout" - /> - ); -}; + const allowedToEndMeeting = amIModerator && !isBreakoutRoom; + + const { allowLogout: allowLogoutSetting } = Meteor.settings.public.app; + + this.menuItems = []; + + if (allowLogoutSetting && isMeteorConnected) { + this.menuItems.push( + { + key: 'list-item-logout', + dataTest: 'logout-button', + icon: 'logout', + label: intl.formatMessage(intlMessages.leaveSessionLabel), + description: intl.formatMessage(intlMessages.leaveSessionDesc), + onClick: () => this.leaveSession(), + }, + ); + } + + if (allowedToEndMeeting && isMeteorConnected) { + const customStyles = { background: colorDanger, color: colorWhite }; + + this.menuItems.push( + { + key: 'list-item-end-meeting', + icon: 'application', + label: intl.formatMessage(intlMessages.endMeetingLabel), + description: intl.formatMessage(intlMessages.endMeetingDesc), + customStyles, + onClick: () => this.setEndMeetingConfirmationModalIsOpen(true), + }, + ); + } + + return this.menuItems; + } + + renderModal(isOpen, setIsOpen, priority, Component, otherOptions) { + return isOpen ? setIsOpen(false), + priority, + setIsOpen, + isOpen + }} + /> : null + } + + render() { + const { + intl, + isDropdownOpen, + isMobile, + isRTL, + } = this.props; + + const { isEndMeetingConfirmationModalOpen } = this.state; + + const customStyles = { top: '1rem' }; + + return ( + <> + null} + /> + )} + actions={this.renderMenuItems()} + opts={{ + id: 'app-leave-meeting-menu', + keepMounted: true, + transitionDuration: 0, + elevation: 3, + getcontentanchorel: null, + fullwidth: 'true', + anchorOrigin: { vertical: 'bottom', horizontal: isRTL ? 'left' : 'right' }, + transformorigin: { vertical: 'top', horizontal: isRTL ? 'left' : 'right' }, + }} + /> + {this.renderModal(isEndMeetingConfirmationModalOpen, this.setEndMeetingConfirmationModalIsOpen, + "low", EndMeetingConfirmationContainer)} + + ); + } +} LeaveMeetingButton.propTypes = propTypes; - -export default LeaveMeetingButton; +LeaveMeetingButton.defaultProps = defaultProps; +export default injectIntl(LeaveMeetingButton); diff --git a/bigbluebutton-html5/imports/ui/components/nav-bar/leave-meeting-button/container.jsx b/bigbluebutton-html5/imports/ui/components/nav-bar/leave-meeting-button/container.jsx new file mode 100644 index 0000000000..f175b65efb --- /dev/null +++ b/bigbluebutton-html5/imports/ui/components/nav-bar/leave-meeting-button/container.jsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { withTracker } from 'meteor/react-meteor-data'; +import deviceInfo from '/imports/utils/deviceInfo'; +import LeaveMeetingButton from './component'; +import { meetingIsBreakout } from '/imports/ui/components/app/service'; +import { layoutSelectInput, layoutSelect } from '../../layout/context'; +import { SMALL_VIEWPORT_BREAKPOINT } from '../../layout/enums'; + +const LeaveMeetingButtonContainer = (props) => { + const { width: browserWidth } = layoutSelectInput((i) => i.browser); + const isMobile = browserWidth <= SMALL_VIEWPORT_BREAKPOINT; + const isRTL = layoutSelect((i) => i.isRTL); + + return ( + + ); +}; + +export default withTracker((props) => { + return { + amIModerator: props.amIModerator, + isMobile: deviceInfo.isMobile, + isMeteorConnected: Meteor.status().connected, + isBreakoutRoom: meetingIsBreakout(), + isDropdownOpen: Session.get('dropdownOpen'), + }; +})(LeaveMeetingButtonContainer); diff --git a/bigbluebutton-html5/imports/ui/components/nav-bar/leave-meeting-button/styles.js b/bigbluebutton-html5/imports/ui/components/nav-bar/leave-meeting-button/styles.js index 1382548cc3..c40e98fc58 100644 --- a/bigbluebutton-html5/imports/ui/components/nav-bar/leave-meeting-button/styles.js +++ b/bigbluebutton-html5/imports/ui/components/nav-bar/leave-meeting-button/styles.js @@ -1,12 +1,22 @@ import styled from 'styled-components'; +import { smallOnly } from '/imports/ui/stylesheets/styled-components/breakpoints'; import Button from '/imports/ui/components/common/button/component'; const LeaveButton = styled(Button)` - border-radius: 1.1rem; - margin: 0.5rem; - font-size: 1rem; - line-height: 1.1rem; - font-weight: 400; + ${({ state }) => state === 'open' && ` + @media ${smallOnly} { + display: none; + } + `} + + ${({ state }) => state === 'closed' && ` + border-radius: 1.1rem; + margin: 0.5rem; + font-size: 1rem; + line-height: 1.1rem; + font-weight: 400; + z-index: 3; + `} `; export default {