bigbluebutton-Github/bigbluebutton-html5/imports/ui/components/poll/component.jsx

313 lines
8.4 KiB
React
Raw Normal View History

2018-09-15 01:50:18 +08:00
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import _ from 'lodash';
2018-10-18 22:31:17 +08:00
import { Session } from 'meteor/session';
2018-09-15 01:50:18 +08:00
import Button from '/imports/ui/components/button/component';
2018-10-29 23:27:50 +08:00
import LiveResult from './live-result/component';
2018-09-15 01:50:18 +08:00
import { styles } from './styles.scss';
const intlMessages = defineMessages({
pollPaneTitle: {
id: 'app.poll.pollPaneTitle',
description: 'heading label for the poll menu',
},
2018-10-30 23:57:10 +08:00
closeLabel: {
id: 'app.poll.closeLabel',
description: 'label for poll pane close button',
},
hidePollDesc: {
id: 'app.poll.hidePollDesc',
description: 'aria label description for hide poll button',
},
customPollLabel: {
id: 'app.poll.customPollLabel',
description: 'label for custom poll button',
},
startCustomLabel: {
id: 'app.poll.startCustomLabel',
description: 'label for button to start custom poll',
},
customPollInstruction: {
id: 'app.poll.customPollInstruction',
description: 'instructions for using custom poll',
},
quickPollInstruction: {
id: 'app.poll.quickPollInstruction',
description: 'instructions for using pre configured polls',
},
2018-09-25 06:43:54 +08:00
activePollInstruction: {
id: 'app.poll.activePollInstruction',
description: 'instructions displayed when a poll is active',
},
customPlaceholder: {
id: 'app.poll.customPlaceholder',
description: 'custom poll input field placeholder text',
},
tf: {
id: 'app.poll.tf',
description: 'label for true / false poll',
},
yn: {
id: 'app.poll.yn',
description: 'label for Yes / No poll',
},
a2: {
id: 'app.poll.a2',
description: 'label for A / B poll',
},
a3: {
id: 'app.poll.a3',
description: 'label for A / B / C poll',
},
a4: {
id: 'app.poll.a4',
description: 'label for A / B / C / D poll',
},
a5: {
id: 'app.poll.a5',
description: 'label for A / B / C / D / E poll',
},
});
2018-10-03 07:59:45 +08:00
const MAX_CUSTOM_FIELDS = Meteor.settings.public.poll.max_custom;
2018-09-15 01:50:18 +08:00
class Poll extends Component {
constructor(props) {
super(props);
this.state = {
customPollReq: false,
2018-09-25 06:43:54 +08:00
isPolling: false,
customPollValues: [],
2018-09-15 01:50:18 +08:00
};
this.inputEditor = [];
2018-09-15 01:50:18 +08:00
this.toggleCustomFields = this.toggleCustomFields.bind(this);
this.renderQuickPollBtns = this.renderQuickPollBtns.bind(this);
2018-09-24 06:20:20 +08:00
this.renderInputFields = this.renderInputFields.bind(this);
this.nonPresenterRedirect = this.nonPresenterRedirect.bind(this);
2018-09-24 06:20:20 +08:00
this.getInputFields = this.getInputFields.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
this.handleBackClick = this.handleBackClick.bind(this);
}
componentWillMount() {
this.nonPresenterRedirect();
}
componentDidUpdate() {
this.nonPresenterRedirect();
}
2018-09-24 06:20:20 +08:00
handleInputChange(index, event) {
// This regex will replace any instance of 2 or more consecutive white spaces
// with a single white space character.
const option = event.target.value.replace(/\s{2,}/g, ' ').trim();
this.inputEditor[index] = option === '' ? '' : option;
this.setState({ customPollValues: this.inputEditor });
}
2018-09-24 06:20:20 +08:00
getInputFields() {
const { intl } = this.props;
2018-09-24 06:20:20 +08:00
const items = [];
items = _.range(1, MAX_CUSTOM_FIELDS + 1).map((ele, index) => (
<input
key={`custom-poll-${index}`}
placeholder={intl.formatMessage(intlMessages.customPlaceholder)}
2018-09-24 06:20:20 +08:00
className={styles.input}
onChange={event => this.handleInputChange(index, event)}
defaultValue={this.state.customPollValues[index]}
/>
));
2018-09-24 06:20:20 +08:00
return items;
}
nonPresenterRedirect() {
2018-10-18 22:31:17 +08:00
const { currentUser } = this.props;
if (!currentUser.presenter) {
Session.set('isUserListOpen', true);
return Session.set('isPollOpen', false);
}
}
2018-09-15 01:50:18 +08:00
toggleCustomFields() {
const { customPollReq } = this.state;
2018-09-24 06:20:20 +08:00
this.inputEditor = [];
2018-09-24 06:20:20 +08:00
return this.setState({ customPollReq: !this.state.customPollReq });
}
renderQuickPollBtns() {
const { pollTypes, startPoll, intl } = this.props;
const btns = pollTypes.map((type) => {
if (type === 'custom') return;
2018-09-24 06:20:20 +08:00
const label = intl.formatMessage(
// regex removes the - to match the message id
intlMessages[type.replace(/-/g, '').toLowerCase()]);
return (
<Button
label={label}
color="default"
className={styles.pollBtn}
key={_.uniqueId('quick-poll-')}
onClick={() => {
2018-09-25 06:43:54 +08:00
this.setState({ isPolling: true }, () => startPoll(type));
}}
/>);
});
return btns;
2018-09-15 01:50:18 +08:00
}
2018-09-24 06:20:20 +08:00
renderInputFields() {
const { intl, startCustomPoll } = this.props;
const isDisabled = _.compact(this.inputEditor).length < 2;
return (
2018-09-24 06:20:20 +08:00
<div className={styles.customInputWrapper}>
{this.getInputFields()}
<Button
2018-09-24 06:20:20 +08:00
onClick={() => {
if (this.inputEditor.length > 1) {
this.setState({ isPolling: true }, () => startCustomPoll('custom', _.compact(this.inputEditor)));
2018-09-24 06:20:20 +08:00
}
}}
label={intl.formatMessage(intlMessages.startCustomLabel)}
2018-09-24 06:20:20 +08:00
color="primary"
aria-disabled={isDisabled}
2018-09-24 06:20:20 +08:00
className={styles.btn}
/>
</div>
);
2018-09-15 01:50:18 +08:00
}
handleBackClick() {
2018-10-24 22:17:13 +08:00
const { stopPoll } = this.props;
stopPoll();
this.inputEditor = [];
this.setState({
isPolling: false,
customPollValues: this.inputEditor,
}, document.activeElement.blur());
}
2018-09-25 06:43:54 +08:00
renderActivePollOptions() {
const {
2018-10-29 23:27:50 +08:00
intl, publishPoll, stopPoll, currentUser, currentPoll, getUser,
2018-09-25 06:43:54 +08:00
} = this.props;
return (
<div>
2018-10-11 02:25:35 +08:00
<div className={styles.instructions}>
{intl.formatMessage(intlMessages.activePollInstruction)}
</div>
2018-10-29 23:27:50 +08:00
<LiveResult
{...{
publishPoll,
stopPoll,
currentUser,
getUser,
currentPoll,
}}
handleBackClick={this.handleBackClick}
2018-10-29 23:27:50 +08:00
/>
2018-09-25 06:43:54 +08:00
</div>
);
}
renderPollOptions() {
const { intl } = this.props;
const { customPollReq } = this.state;
2018-09-15 01:50:18 +08:00
return (
2018-09-24 06:20:20 +08:00
<div>
<div className={styles.instructions}>
{intl.formatMessage(intlMessages.quickPollInstruction)}
2018-09-15 01:50:18 +08:00
</div>
<div className={styles.grid}>
{this.renderQuickPollBtns()}
</div>
<div className={styles.instructions}>
{intl.formatMessage(intlMessages.customPollInstruction)}
</div>
<Button
className={styles.customBtn}
color="default"
onClick={this.toggleCustomFields}
label={intl.formatMessage(intlMessages.customPollLabel)}
/>
2018-09-24 06:20:20 +08:00
{!customPollReq ? null : this.renderInputFields()}
2018-09-15 01:50:18 +08:00
</div>
);
}
2018-09-25 06:43:54 +08:00
render() {
const {
2018-10-29 23:27:50 +08:00
intl, stopPoll, currentPoll,
2018-09-25 06:43:54 +08:00
} = this.props;
return (
<div>
<header className={styles.header}>
2018-10-18 22:31:17 +08:00
<Button
tabIndex={0}
label={intl.formatMessage(intlMessages.pollPaneTitle)}
icon="left_arrow"
2018-09-25 06:43:54 +08:00
aria-label={intl.formatMessage(intlMessages.hidePollDesc)}
2018-10-18 22:31:17 +08:00
className={styles.hideBtn}
2018-09-25 06:43:54 +08:00
onClick={() => {
2018-10-18 22:31:17 +08:00
Session.set('isPollOpen', false);
2018-10-24 22:17:13 +08:00
Session.set('forcePollOpen', true);
Session.set('isUserListOpen', true);
2018-09-25 06:43:54 +08:00
}}
/>
2018-10-24 22:17:13 +08:00
<Button
2018-10-30 23:57:10 +08:00
label={intl.formatMessage(intlMessages.closeLabel)}
2018-10-24 22:17:13 +08:00
onClick={() => {
2018-10-29 23:27:50 +08:00
if (currentPoll) {
2018-10-24 22:17:13 +08:00
stopPoll();
}
Session.set('isPollOpen', false);
Session.set('forcePollOpen', false);
Session.set('isUserListOpen', true);
}}
className={styles.closeBtn}
2018-10-30 00:14:05 +08:00
icon="close"
size="sm"
2018-10-30 23:57:10 +08:00
hideLabel
2018-10-24 22:17:13 +08:00
/>
2018-09-25 06:43:54 +08:00
</header>
{
2018-10-29 23:27:50 +08:00
this.state.isPolling || !this.state.isPolling && currentPoll
? this.renderActivePollOptions() : this.renderPollOptions()
2018-09-25 06:43:54 +08:00
}
</div>
);
}
2018-09-15 01:50:18 +08:00
}
export default injectIntl(Poll);
Poll.propTypes = {
intl: PropTypes.shape({
formatMessage: PropTypes.func.isRequired,
}).isRequired,
currentUser: PropTypes.instanceOf(Object).isRequired,
pollTypes: PropTypes.instanceOf(Array).isRequired,
startPoll: PropTypes.func.isRequired,
startCustomPoll: PropTypes.func.isRequired,
stopPoll: PropTypes.func.isRequired,
publishPoll: PropTypes.func.isRequired,
};