add dropdown selection for leave/end on leave meeting button

This commit is contained in:
Jan Kessler 2023-11-28 17:55:34 +01:00
parent 409cf1decb
commit f19aac1895
4 changed files with 210 additions and 32 deletions

View File

@ -14,7 +14,7 @@ import browserInfo from '/imports/utils/browserInfo';
import deviceInfo from '/imports/utils/deviceInfo'; import deviceInfo from '/imports/utils/deviceInfo';
import { PANELS, ACTIONS } from '../layout/enums'; import { PANELS, ACTIONS } from '../layout/enums';
import { isEqual } from 'radash'; import { isEqual } from 'radash';
import LeaveMeetingButton from './leave-meeting-button/component'; import LeaveMeetingButtonContainer from './leave-meeting-button/container';
const intlMessages = defineMessages({ const intlMessages = defineMessages({
toggleUserListLabel: { toggleUserListLabel: {
@ -37,10 +37,6 @@ const intlMessages = defineMessages({
id: 'app.createBreakoutRoom.room', id: 'app.createBreakoutRoom.room',
description: 'default breakout room name', description: 'default breakout room name',
}, },
leaveMeetingLabel: {
id: 'app.navBar.leaveMeetingBtnLabel',
description: 'Leave meeting button label',
},
}); });
const propTypes = { const propTypes = {
@ -253,7 +249,7 @@ class NavBar extends Component {
<Styled.Right> <Styled.Right>
{ConnectionStatusService.isEnabled() ? <ConnectionStatusButton /> : null} {ConnectionStatusService.isEnabled() ? <ConnectionStatusButton /> : null}
{isDirectLeaveButtonEnabled && isMeteorConnected {isDirectLeaveButtonEnabled && isMeteorConnected
? <LeaveMeetingButton label={intl.formatMessage(intlMessages.leaveMeetingLabel)}/> ? <LeaveMeetingButtonContainer amIModerator={amIModerator} />
: null} : null}
<SettingsDropdownContainer <SettingsDropdownContainer
amIModerator={amIModerator} amIModerator={amIModerator}

View File

@ -1,34 +1,179 @@
import React from 'react'; import React, { PureComponent } from 'react';
import { defineMessages, injectIntl } from 'react-intl';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Styled from './styles'; import EndMeetingConfirmationContainer from '/imports/ui/components/end-meeting-confirmation/container';
import { makeCall } from '/imports/ui/services/api'; import { makeCall } from '/imports/ui/services/api';
import BBBMenu from '/imports/ui/components/common/menu/component';
import { colorDanger, colorWhite } from '/imports/ui/stylesheets/styled-components/palette';
import Styled from './styles';
// Set the logout code to 680 because it's not a real code and can be matched on the other side const intlMessages = defineMessages({
const LOGOUT_CODE = '680'; leaveMeetingLabel: {
id: 'app.navBar.leaveMeetingBtnLabel',
description: 'Leave meeting button label',
},
leaveSessionLabel: {
id: 'app.navBar.settingsDropdown.leaveSessionLabel',
description: 'Leave session button label',
},
leaveSessionDesc: {
id: 'app.navBar.settingsDropdown.leaveSessionDesc',
description: 'Describes leave session option',
},
endMeetingLabel: {
id: 'app.navBar.settingsDropdown.endMeetingLabel',
description: 'End meeting options label',
},
endMeetingDesc: {
id: 'app.navBar.settingsDropdown.endMeetingDesc',
description: 'Describes settings option closing the current meeting',
},
});
const propTypes = { const propTypes = {
label: PropTypes.string.isRequired, intl: PropTypes.shape({
formatMessage: PropTypes.func.isRequired,
}).isRequired,
amIModerator: PropTypes.bool,
isBreakoutRoom: PropTypes.bool,
isMeteorConnected: PropTypes.bool.isRequired,
isDropdownOpen: PropTypes.bool,
isMobile: PropTypes.bool.isRequired,
}; };
const LeaveMeetingButton = ({ label }) => { const defaultProps = {
const leaveSession = () => { 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'); makeCall('userLeftMeeting');
// we don't check askForFeedbackOnLogout here, // we don't check askForFeedbackOnLogout here,
// it is checked in meeting-ended component // 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;
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 ? <Component
{...{
...otherOptions,
onRequestClose: () => setIsOpen(false),
priority,
setIsOpen,
isOpen
}}
/> : null
}
render() {
const {
intl,
isDropdownOpen,
isMobile,
isRTL,
} = this.props;
const { isEndMeetingConfirmationModalOpen } = this.state;
const customStyles = { top: '1rem' };
return ( return (
<>
<BBBMenu
customStyles={!isMobile ? customStyles : null}
trigger={(
<Styled.LeaveButton <Styled.LeaveButton
tooltipLabel={label} state={isDropdownOpen ? 'open' : 'closed'}
tooltipLabel={intl.formatMessage(intlMessages.leaveMeetingLabel)}
icon="logout"
color="danger" color="danger"
size="lg" size="lg"
onClick={() => leaveSession()} // FIXME: Without onClick react proptypes keep warning
icon="logout" // even after the DropdownTrigger inject an onClick handler
onClick={() => 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; LeaveMeetingButton.propTypes = propTypes;
LeaveMeetingButton.defaultProps = defaultProps;
export default LeaveMeetingButton; export default injectIntl(LeaveMeetingButton);

View File

@ -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 (
<LeaveMeetingButton {...{ isMobile, isRTL, ...props }} />
);
};
export default withTracker((props) => {
return {
amIModerator: props.amIModerator,
isMobile: deviceInfo.isMobile,
isMeteorConnected: Meteor.status().connected,
isBreakoutRoom: meetingIsBreakout(),
isDropdownOpen: Session.get('dropdownOpen'),
};
})(LeaveMeetingButtonContainer);

View File

@ -1,12 +1,22 @@
import styled from 'styled-components'; import styled from 'styled-components';
import { smallOnly } from '/imports/ui/stylesheets/styled-components/breakpoints';
import Button from '/imports/ui/components/common/button/component'; import Button from '/imports/ui/components/common/button/component';
const LeaveButton = styled(Button)` const LeaveButton = styled(Button)`
${({ state }) => state === 'open' && `
@media ${smallOnly} {
display: none;
}
`}
${({ state }) => state === 'closed' && `
border-radius: 1.1rem; border-radius: 1.1rem;
margin: 0.5rem; margin: 0.5rem;
font-size: 1rem; font-size: 1rem;
line-height: 1.1rem; line-height: 1.1rem;
font-weight: 400; font-weight: 400;
z-index: 3;
`}
`; `;
export default { export default {