Merge pull request #6535 from KDSBrowne/2.2-add-create-br-to-manage-user-menu

Add create breakout room option to manage user menu
This commit is contained in:
Anton Georgiev 2019-01-28 13:44:15 -05:00 committed by GitHub
commit 7349fcabb5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 203 additions and 119 deletions

View File

@ -2,6 +2,4 @@ import { Meteor } from 'meteor/meteor';
const Streamer = new Meteor.Streamer('videos');
export default Streamer
export default Streamer;

View File

@ -145,8 +145,6 @@ class ActionsDropdown extends Component {
pollBtnDesc,
presentationLabel,
presentationDesc,
startRecording,
stopRecording,
createBreakoutRoom,
createBreakoutRoomDesc,
invitationItem,
@ -158,6 +156,10 @@ class ActionsDropdown extends Component {
formatMessage,
} = intl;
const canCreateBreakout = isUserModerator
&& !meetingIsBreakout
&& !hasBreakoutRoom;
const canInviteUsers = isUserModerator
&& !meetingIsBreakout
&& hasBreakoutRoom
@ -209,12 +211,12 @@ class ActionsDropdown extends Component {
/>
)
: null),
(isUserModerator && !meetingIsBreakout && !hasBreakoutRoom
(canCreateBreakout
? (
<DropdownListItem
icon="rooms"
label={intl.formatMessage(intlMessages.createBreakoutRoom)}
description={intl.formatMessage(intlMessages.createBreakoutRoomDesc)}
label={formatMessage(createBreakoutRoom)}
description={formatMessage(createBreakoutRoomDesc)}
key={this.createBreakoutRoomId}
onClick={this.onCreateBreakouts}
/>

View File

@ -127,6 +127,10 @@ class BreakoutRoom extends Component {
preventClosing: true,
valid: true,
};
this.breakoutFormId = _.uniqueId('breakout-form-');
this.freeJoinId = _.uniqueId('free-join-check-');
this.btnLevelId = _.uniqueId('btn-set-level-');
}
componentDidMount() {
@ -295,7 +299,7 @@ class BreakoutRoom extends Component {
};
return (
<div className={styles.boxContainer}>
<div className={styles.boxContainer} key="rooms-grid-">
<label htmlFor="BreakoutRoom" className={!valid ? styles.changeToWarn : null}>
<p
className={styles.freeJoinLabel}
@ -340,7 +344,7 @@ class BreakoutRoom extends Component {
if (isInvitation) return null;
return (
<div className={styles.breakoutSettings}>
<div className={styles.breakoutSettings} key={this.breakoutFormId}>
<label htmlFor="numberOfRooms">
<p className={styles.labelText}>{intl.formatMessage(intlMessages.numberOfRooms)}</p>
<select
@ -422,7 +426,7 @@ class BreakoutRoom extends Component {
if (isInvitation) return null;
const { freeJoin } = this.state;
return (
<label htmlFor="freeJoinCheckbox" className={styles.freeJoinLabel}>
<label htmlFor="freeJoinCheckbox" className={styles.freeJoinLabel} key={this.freeJoinId}>
<input
type="checkbox"
className={styles.freeJoinCheckbox}
@ -534,6 +538,7 @@ class BreakoutRoom extends Component {
size="lg"
label={label}
onClick={() => this.setState({ formFillLevel: level })}
key={this.btnLevelId}
/>
);
}

View File

@ -10,6 +10,7 @@ import DropdownContent from '/imports/ui/components/dropdown/content/component';
import DropdownList from '/imports/ui/components/dropdown/list/component';
import DropdownListItem from '/imports/ui/components/dropdown/list/item/component';
import LockViewersContainer from '/imports/ui/components/lock-viewers/container';
import BreakoutRoom from '/imports/ui/components/actions-bar/create-breakout-room/component';
import { styles } from './styles';
const propTypes = {
@ -21,6 +22,11 @@ const propTypes = {
toggleMuteAllUsersExceptPresenter: PropTypes.func.isRequired,
toggleStatus: PropTypes.func.isRequired,
mountModal: PropTypes.func.isRequired,
users: PropTypes.arrayOf(Object).isRequired,
meetingName: PropTypes.string.isRequired,
createBreakoutRoom: PropTypes.func.isRequired,
meetingIsBreakout: PropTypes.bool.isRequired,
hasBreakoutRoom: PropTypes.bool.isRequired,
};
const intlMessages = defineMessages({
@ -68,6 +74,18 @@ const intlMessages = defineMessages({
id: 'app.userList.userOptions.muteAllExceptPresenterDesc',
description: 'Mute all except presenter description',
},
createBreakoutRoom: {
id: 'app.actionsBar.actionsDropdown.createBreakoutRoom',
description: 'Create breakout room option',
},
createBreakoutRoomDesc: {
id: 'app.actionsBar.actionsDropdown.createBreakoutRoomDesc',
description: 'Description of create breakout room option',
},
invitationItem: {
id: 'app.invitation.title',
description: 'invitation to breakout title',
},
});
class UserOptions extends PureComponent {
@ -78,55 +96,19 @@ class UserOptions extends PureComponent {
isUserOptionsOpen: false,
};
this.clearStatusId = _.uniqueId('list-item-');
this.muteId = _.uniqueId('list-item-');
this.muteAllId = _.uniqueId('list-item-');
this.lockId = _.uniqueId('list-item-');
this.createBreakoutId = _.uniqueId('list-item-');
this.onActionsShow = this.onActionsShow.bind(this);
this.onActionsHide = this.onActionsHide.bind(this);
this.alterMenu = this.alterMenu.bind(this);
}
componentWillMount() {
const {
intl,
isMeetingMuted,
mountModal,
toggleStatus,
toggleMuteAllUsers,
toggleMuteAllUsersExceptPresenter,
} = this.props;
this.menuItems = _.compact([
(<DropdownListItem
key={_.uniqueId('list-item-')}
icon="clear_status"
label={intl.formatMessage(intlMessages.clearAllLabel)}
description={intl.formatMessage(intlMessages.clearAllDesc)}
onClick={toggleStatus}
/>),
(<DropdownListItem
key={_.uniqueId('list-item-')}
icon="mute"
label={intl.formatMessage(intlMessages.muteAllLabel)}
description={intl.formatMessage(intlMessages.muteAllDesc)}
onClick={toggleMuteAllUsers}
/>),
(<DropdownListItem
key={_.uniqueId('list-item-')}
icon="mute"
label={intl.formatMessage(intlMessages.muteAllExceptPresenterLabel)}
description={intl.formatMessage(intlMessages.muteAllExceptPresenterDesc)}
onClick={toggleMuteAllUsersExceptPresenter}
/>),
(<DropdownListItem
key={_.uniqueId('list-item-')}
icon="lock"
label={intl.formatMessage(intlMessages.lockViewersLabel)}
description={intl.formatMessage(intlMessages.lockViewersDesc)}
onClick={() => mountModal(<LockViewersContainer />)}
/>),
]);
if (isMeetingMuted) {
this.alterMenu();
}
this.handleCreateBreakoutRoomClick = this.handleCreateBreakoutRoomClick.bind(this);
this.onCreateBreakouts = this.onCreateBreakouts.bind(this);
this.onInvitationUsers = this.onInvitationUsers.bind(this);
this.renderMenuItems = this.renderMenuItems.bind(this);
}
componentDidUpdate(prevProps) {
@ -148,6 +130,40 @@ class UserOptions extends PureComponent {
});
}
onCreateBreakouts() {
return this.handleCreateBreakoutRoomClick(false);
}
onInvitationUsers() {
return this.handleCreateBreakoutRoomClick(true);
}
handleCreateBreakoutRoomClick(isInvitation) {
const {
createBreakoutRoom,
mountModal,
meetingName,
users,
getUsersNotAssigned,
getBreakouts,
sendInvitation,
} = this.props;
return mountModal(
<BreakoutRoom
{...{
createBreakoutRoom,
meetingName,
users,
getUsersNotAssigned,
isInvitation,
getBreakouts,
sendInvitation,
}}
/>,
);
}
alterMenu() {
const {
intl,
@ -186,9 +202,92 @@ class UserOptions extends PureComponent {
}
}
renderMenuItems() {
const {
intl,
isMeetingMuted,
mountModal,
toggleStatus,
toggleMuteAllUsers,
toggleMuteAllUsersExceptPresenter,
meetingIsBreakout,
hasBreakoutRoom,
getUsersNotAssigned,
isUserModerator,
users,
} = this.props;
const canCreateBreakout = isUserModerator
&& !meetingIsBreakout
&& !hasBreakoutRoom;
const canInviteUsers = isUserModerator
&& !meetingIsBreakout
&& hasBreakoutRoom
&& getUsersNotAssigned(users).length;
this.menuItems = _.compact([
(<DropdownListItem
key={this.clearStatusId}
icon="clear_status"
label={intl.formatMessage(intlMessages.clearAllLabel)}
description={intl.formatMessage(intlMessages.clearAllDesc)}
onClick={toggleStatus}
/>),
(<DropdownListItem
key={this.muteAllId}
icon="mute"
label={intl.formatMessage(intlMessages.muteAllLabel)}
description={intl.formatMessage(intlMessages.muteAllDesc)}
onClick={toggleMuteAllUsers}
/>),
(<DropdownListItem
key={this.muteId}
icon="mute"
label={intl.formatMessage(intlMessages.muteAllExceptPresenterLabel)}
description={intl.formatMessage(intlMessages.muteAllExceptPresenterDesc)}
onClick={toggleMuteAllUsersExceptPresenter}
/>),
(<DropdownListItem
key={this.lockId}
icon="lock"
label={intl.formatMessage(intlMessages.lockViewersLabel)}
description={intl.formatMessage(intlMessages.lockViewersDesc)}
onClick={() => mountModal(<LockViewersContainer />)}
/>),
(canCreateBreakout
? (
<DropdownListItem
key={this.createBreakoutId}
icon="rooms"
label={intl.formatMessage(intlMessages.createBreakoutRoom)}
description={intl.formatMessage(intlMessages.createBreakoutRoomDesc)}
onClick={this.onCreateBreakouts}
/>
) : null
),
(canInviteUsers
? (
<DropdownListItem
icon="rooms"
label={intl.formatMessage(intlMessages.invitationItem)}
key={this.createBreakoutId}
onClick={this.onInvitationUsers}
/>
)
: null),
]);
if (isMeetingMuted) {
this.alterMenu();
}
return this.menuItems;
}
render() {
const { intl } = this.props;
const { isUserOptionsOpen } = this.state;
const { intl } = this.props;
return (
<Dropdown
@ -217,7 +316,7 @@ class UserOptions extends PureComponent {
>
<DropdownList>
{
this.menuItems
this.renderMenuItems()
}
</DropdownList>
</DropdownContent>

View File

@ -1,67 +1,47 @@
import React, { PureComponent } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import PropTypes from 'prop-types';
import Auth from '/imports/ui/services/auth';
import Service from '/imports/ui/components/actions-bar/service';
import UserOptions from './component';
const propTypes = {
users: PropTypes.arrayOf(Object).isRequired,
muteAllUsers: PropTypes.func.isRequired,
muteAllExceptPresenter: PropTypes.func.isRequired,
setEmojiStatus: PropTypes.func.isRequired,
meeting: PropTypes.shape({}).isRequired,
currentUser: PropTypes.shape({
isModerator: PropTypes.bool.isRequired,
}).isRequired,
};
export default class UserOptionsContainer extends PureComponent {
constructor(props) {
super(props);
const UserOptionsContainer = withTracker((props) => {
const {
meeting,
users,
setEmojiStatus,
muteAllExceptPresenter,
muteAllUsers,
} = props;
const { meeting } = this.props;
this.state = {
meetingMuted: meeting.voiceProp.muteOnStart,
};
this.muteMeeting = this.muteMeeting.bind(this);
this.muteAllUsersExceptPresenter = this.muteAllUsersExceptPresenter.bind(this);
this.handleClearStatus = this.handleClearStatus.bind(this);
}
muteMeeting() {
const { muteAllUsers } = this.props;
muteAllUsers(Auth.userID);
}
muteAllUsersExceptPresenter() {
const { muteAllExceptPresenter } = this.props;
muteAllExceptPresenter(Auth.userID);
}
handleClearStatus() {
const { users, setEmojiStatus } = this.props;
users.forEach((id) => {
setEmojiStatus(id, 'none');
});
}
render() {
const { currentUser } = this.props;
const currentUserIsModerator = currentUser.isModerator;
const { meetingMuted } = this.state;
return (
currentUserIsModerator
? (
<UserOptions
toggleMuteAllUsers={this.muteMeeting}
toggleMuteAllUsersExceptPresenter={this.muteAllUsersExceptPresenter}
toggleStatus={this.handleClearStatus}
isMeetingMuted={meetingMuted}
/>) : null
);
}
}
return {
toggleMuteAllUsers: () => muteAllUsers(Auth.userID),
toggleMuteAllUsersExceptPresenter: () => muteAllExceptPresenter(Auth.userID),
toggleStatus: () => users.forEach(id => setEmojiStatus(id, 'none')),
isMeetingMuted: meeting.voiceProp.muteOnStart,
isUserPresenter: Service.isUserPresenter(),
isUserModerator: Service.isUserModerator(),
createBreakoutRoom: Service.createBreakoutRoom,
meetingIsBreakout: Service.meetingIsBreakout(),
hasBreakoutRoom: Service.hasBreakoutRoom(),
meetingName: Service.meetingName(),
users: Service.users(),
getBreakouts: Service.getBreakouts,
sendInvitation: Service.sendInvitation,
getUsersNotAssigned: Service.getUsersNotAssigned,
};
})(UserOptions);
UserOptionsContainer.propTypes = propTypes;
export default UserOptionsContainer;

View File

@ -4,7 +4,7 @@ const iosWebviewAudioPolyfills = function () {
window.RTCPeerConnection.prototype.getRemoteStreams = function () {
return this._remoteStreams ? this._remoteStreams : [];
};
}
}
if (!('onaddstream' in window.RTCPeerConnection.prototype)) {
Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', {
get: function get() {

View File

@ -37,7 +37,7 @@ export function canGenerateIceCandidates() {
resolve();
return;
}
getIceServersList().catch((e) => {
reject();
}).then((iceServersReceived) => {
@ -53,16 +53,16 @@ export function canGenerateIceCandidates() {
Session.set('canGenerateIceCandidates', true);
resolve();
}
}
};
pc.onicegatheringstatechange = function (e) {
if (e.currentTarget.iceGatheringState == 'complete' && countIceCandidates == 0) reject();
}
};
setTimeout(function () {
setTimeout(() => {
pc.close();
if (!countIceCandidates) reject();
}, 5000);
}, 5000);
const p = pc.createOffer({ offerToReceiveVideo: true });
p.then((answer) => { pc.setLocalDescription(answer); });
@ -75,7 +75,7 @@ export function tryGenerateIceCandidates() {
canGenerateIceCandidates().then((ok) => {
resolve();
}).catch((e) => {
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then(function (stream) {
navigator.mediaDevices.getUserMedia({ audio: true, video: false }).then((stream) => {
canGenerateIceCandidates().then((ok) => {
resolve();
}).catch((e) => {
@ -86,4 +86,4 @@ export function tryGenerateIceCandidates() {
});
});
});
}
}