import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import { withModalMounter } from '/imports/ui/components/modal/service';
import _ from 'lodash';
import { Session } from 'meteor/session';
import cx from 'classnames';
import Button from '/imports/ui/components/button/component';
import Toggle from '/imports/ui/components/switch/component';
import LiveResult from './live-result/component';
import { styles } from './styles.scss';
import { PANELS, ACTIONS } from '../layout/enums';
import DragAndDrop from './dragAndDrop/component';
const intlMessages = defineMessages({
pollPaneTitle: {
id: 'app.poll.pollPaneTitle',
description: 'heading label for the poll menu',
},
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',
},
quickPollInstruction: {
id: 'app.poll.quickPollInstruction',
description: 'instructions for using pre configured polls',
},
activePollInstruction: {
id: 'app.poll.activePollInstruction',
description: 'instructions displayed when a poll is active',
},
dragDropPollInstruction: {
id: 'app.poll.dragDropPollInstruction',
description: 'instructions for upload poll options via drag and drop',
},
ariaInputCount: {
id: 'app.poll.ariaInputCount',
description: 'aria label for custom poll input field',
},
customPlaceholder: {
id: 'app.poll.customPlaceholder',
description: 'custom poll input field placeholder text',
},
noPresentationSelected: {
id: 'app.poll.noPresentationSelected',
description: 'no presentation label',
},
clickHereToSelect: {
id: 'app.poll.clickHereToSelect',
description: 'open uploader modal button label',
},
questionErr: {
id: 'app.poll.questionErr',
description: 'question text area error label',
},
optionErr: {
id: 'app.poll.optionErr',
description: 'poll input error label',
},
tf: {
id: 'app.poll.tf',
description: 'label for true / false poll',
},
a4: {
id: 'app.poll.a4',
description: 'label for A / B / C / D poll',
},
delete: {
id: 'app.poll.optionDelete.label',
description: '',
},
pollPanelDesc: {
id: 'app.poll.panel.desc',
description: '',
},
questionLabel: {
id: 'app.poll.question.label',
description: '',
},
userResponse: {
id: 'app.poll.userResponse.label',
description: '',
},
responseChoices: {
id: 'app.poll.responseChoices.label',
description: '',
},
typedResponseDesc: {
id: 'app.poll.typedResponse.desc',
description: '',
},
responseTypesLabel: {
id: 'app.poll.responseTypes.label',
description: '',
},
addOptionLabel: {
id: 'app.poll.addItem.label',
description: '',
},
startPollLabel: {
id: 'app.poll.start.label',
description: '',
},
secretPollLabel: {
id: 'app.poll.secretPoll.label',
description: '',
},
isSecretPollLabel: {
id: 'app.poll.secretPoll.isSecretLabel',
description: '',
},
nonSecretPollLabel: {
id: 'app.poll.secretPoll.notSecretLabel',
description: 'label explaining that the presenter will see for which option everyone voted',
},
questionTitle: {
id: 'app.poll.question.title',
description: '',
},
true: {
id: 'app.poll.answer.true',
description: '',
},
false: {
id: 'app.poll.answer.false',
description: '',
},
a: {
id: 'app.poll.answer.a',
description: '',
},
b: {
id: 'app.poll.answer.b',
description: '',
},
c: {
id: 'app.poll.answer.c',
description: '',
},
d: {
id: 'app.poll.answer.d',
description: '',
},
yna: {
id: 'app.poll.yna',
description: '',
},
yes: {
id: 'app.poll.y',
description: '',
},
no: {
id: 'app.poll.n',
description: '',
},
abstention: {
id: 'app.poll.abstention',
description: '',
},
startPollDesc: {
id: 'app.poll.startPollDesc',
description: '',
},
showRespDesc: {
id: 'app.poll.showRespDesc',
description: '',
},
addRespDesc: {
id: 'app.poll.addRespDesc',
description: '',
},
deleteRespDesc: {
id: 'app.poll.deleteRespDesc',
description: '',
},
on: {
id: 'app.switch.onLabel',
description: 'label for toggle switch on state',
},
off: {
id: 'app.switch.offLabel',
description: 'label for toggle switch off state',
},
});
const POLL_SETTINGS = Meteor.settings.public.poll;
const MAX_CUSTOM_FIELDS = POLL_SETTINGS.maxCustom;
const MAX_INPUT_CHARS = POLL_SETTINGS.maxTypedAnswerLength;
const QUESTION_MAX_INPUT_CHARS = 400;
const FILE_DRAG_AND_DROP_ENABLED = POLL_SETTINGS.allowDragAndDropFile;
const validateInput = (i) => {
let _input = i;
if (/^\s/.test(_input)) _input = '';
return _input;
};
class Poll extends Component {
constructor(props) {
super(props);
this.state = {
isPolling: false,
question: '',
optList: [],
error: null,
secretPoll: false,
};
this.handleBackClick = this.handleBackClick.bind(this);
this.handleAddOption = this.handleAddOption.bind(this);
this.handleRemoveOption = this.handleRemoveOption.bind(this);
this.handleTextareaChange = this.handleTextareaChange.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
this.displayToggleStatus = this.displayToggleStatus.bind(this);
}
componentDidMount() {
const { props } = this.hideBtn;
const { className } = props;
const hideBtn = document.getElementsByClassName(`${className}`);
if (hideBtn[0]) hideBtn[0].focus();
}
componentDidUpdate() {
const { amIPresenter, layoutContextDispatch } = this.props;
if (Session.equals('resetPollPanel', true)) {
this.handleBackClick();
}
if (!amIPresenter) {
layoutContextDispatch({
type: ACTIONS.SET_SIDEBAR_CONTENT_IS_OPEN,
value: false,
});
layoutContextDispatch({
type: ACTIONS.SET_SIDEBAR_CONTENT_PANEL,
value: PANELS.NONE,
});
}
}
handleBackClick() {
const { stopPoll } = this.props;
this.setState({
isPolling: false,
error: null,
}, () => {
stopPoll();
Session.set('resetPollPanel', false);
document.activeElement.blur();
});
}
handleInputTextChange(index, text) {
const { optList } = this.state;
// This regex will replace any instance of 2 or more consecutive white spaces
// with a single white space character.
const option = text.replace(/\s{2,}/g, ' ').trim();
if (index < optList.length) optList[index].val = option === '' ? '' : option;
this.setState({ optList });
}
handleInputChange(e, index) {
const { optList, type, error } = this.state;
const { pollTypes } = this.props;
const list = [...optList];
const validatedVal = validateInput(e.target.value).replace(/\s{2,}/g, ' ');
const clearError = validatedVal.length > 0 && type !== pollTypes.Response;
list[index] = { val: validatedVal };
this.setState({ optList: list, error: clearError ? null : error });
}
handleTextareaChange(e) {
const { type, error } = this.state;
const { pollTypes } = this.props;
const validatedQuestion = validateInput(e.target.value);
const clearError = validatedQuestion.length > 0 && type === pollTypes.Response;
this.setState({ question: validateInput(e.target.value), error: clearError ? null : error });
}
handlePollValuesText(text) {
if (text && text.length > 0) {
this.pushToCustomPollValues(text);
}
}
handleRemoveOption(index) {
const { optList } = this.state;
const list = [...optList];
list.splice(index, 1);
this.setState({ optList: list });
}
handleAddOption() {
const { optList } = this.state;
this.setState({ optList: [...optList, { val: '' }] });
}
handleToggle() {
const { secretPoll } = this.state;
const toggledValue = !secretPoll;
Session.set('secretPoll', toggledValue);
this.setState({ secretPoll: toggledValue });
}
setOptListLength(len) {
const { optList } = this.state;
let diff = len > MAX_CUSTOM_FIELDS
? MAX_CUSTOM_FIELDS - optList.length
: len - optList.length;
if (diff > 0) {
while (diff > 0) {
this.handleAddOption();
diff -= 1;
}
} else {
while (diff < 0) {
this.handleRemoveOption();
diff += 1;
}
}
}
displayToggleStatus(status) {
const { intl } = this.props;
return (
{status ? intl.formatMessage(intlMessages.on)
: intl.formatMessage(intlMessages.off)}
);
}
pushToCustomPollValues(text) {
const lines = text.split('\n');
this.setOptListLength(lines.length);
for (let i = 0; i < MAX_CUSTOM_FIELDS; i += 1) {
let line = '';
if (i < lines.length) {
line = lines[i];
line = line.length > MAX_INPUT_CHARS ? line.substring(0, MAX_INPUT_CHARS) : line;
}
this.handleInputTextChange(i, line);
}
}
renderInputs() {
const { intl, pollTypes } = this.props;
const { optList, type, error } = this.state;
let hasVal = false;
return optList.map((o, i) => {
if (o.val.length > 0) hasVal = true;
const pollOptionKey = `poll-option-${i}`;
return (