import React, { Component } from 'react'; import PropTypes from 'prop-types'; import injectWbResizeEvent from '/imports/ui/components/presentation/resize-wrapper/component'; import { defineMessages, injectIntl } from 'react-intl'; import { Meteor } from 'meteor/meteor'; import Styled from './styles'; import AudioService from '/imports/ui/components/audio/service'; import Checkbox from '/imports/ui/components/common/checkbox/component'; const MAX_INPUT_CHARS = Meteor.settings.public.poll.maxTypedAnswerLength; const intlMessages = defineMessages({ pollingTitleLabel: { id: 'app.polling.pollingTitle', }, pollAnswerLabel: { id: 'app.polling.pollAnswerLabel', }, pollAnswerDesc: { id: 'app.polling.pollAnswerDesc', }, pollQuestionTitle: { id: 'app.polling.pollQuestionTitle', }, responseIsSecret: { id: 'app.polling.responseSecret', }, responseNotSecret: { id: 'app.polling.responseNotSecret', }, submitLabel: { id: 'app.polling.submitLabel', }, submitAriaLabel: { id: 'app.polling.submitAriaLabel', }, responsePlaceholder: { id: 'app.polling.responsePlaceholder', }, }); const validateInput = (i) => { let _input = i; if (/^\s/.test(_input)) _input = ''; return _input; }; class Polling extends Component { constructor(props) { super(props); this.state = { typedAns: '', checkedAnswers: [], }; this.pollingContainer = null; this.play = this.play.bind(this); this.handleUpdateResponseInput = this.handleUpdateResponseInput.bind(this); this.renderButtonAnswers = this.renderButtonAnswers.bind(this); this.handleCheckboxChange = this.handleCheckboxChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.renderCheckboxAnswers = this.renderCheckboxAnswers.bind(this); this.handleMessageKeyDown = this.handleMessageKeyDown.bind(this); } componentDidMount() { this.play(); this.pollingContainer && this.pollingContainer?.focus(); } play() { AudioService.playAlertSound(`${Meteor.settings.public.app.cdn + Meteor.settings.public.app.basename + Meteor.settings.public.app.instanceId}` + '/resources/sounds/Poll.mp3'); } handleUpdateResponseInput(e) { this.responseInput.value = validateInput(e.target.value); this.setState({ typedAns: this.responseInput.value }); } handleSubmit(pollId) { const { handleVote } = this.props; const { checkedAnswers } = this.state; handleVote(pollId, checkedAnswers); } handleCheckboxChange(pollId, answerId) { const { checkedAnswers } = this.state; if (checkedAnswers.includes(answerId)) { checkedAnswers.splice(checkedAnswers.indexOf(answerId), 1); } else { checkedAnswers.push(answerId); } checkedAnswers.sort(); this.setState({ checkedAnswers }); } handleMessageKeyDown(e) { const { poll, handleTypedVote, } = this.props; const { typedAns, } = this.state; if (e.keyCode === 13 && typedAns.length > 0) { handleTypedVote(poll.pollId, typedAns); } } renderButtonAnswers() { const { isMeteorConnected, intl, poll, handleVote, handleTypedVote, pollAnswerIds, pollTypes, isDefaultPoll, } = this.props; const { typedAns, } = this.state; if (!poll) return null; const { stackOptions, answers, question, pollType } = poll; const defaultPoll = isDefaultPoll(pollType); return (
{ poll.pollType !== pollTypes.Response && ( { question.length === 0 && ( {intl.formatMessage(intlMessages.pollingTitleLabel)} ) } {answers.map((pollAnswer) => { const formattedMessageIndex = pollAnswer?.key?.toLowerCase(); let label = pollAnswer.key; if ((defaultPoll || pollType.includes('CUSTOM')) && pollAnswerIds[formattedMessageIndex]) { label = intl.formatMessage(pollAnswerIds[formattedMessageIndex]); } return ( handleVote(poll.pollId, [pollAnswer.id])} aria-labelledby={`pollAnswerLabel${pollAnswer.key}`} aria-describedby={`pollAnswerDesc${pollAnswer.key}`} data-test="pollAnswerOption" /> {intl.formatMessage(intlMessages.pollAnswerLabel, { 0: label })} {intl.formatMessage(intlMessages.pollAnswerDesc, { 0: label })} ); })} ) } { poll.pollType === pollTypes.Response && ( { this.handleUpdateResponseInput(e); }} onKeyDown={(e) => { this.handleMessageKeyDown(e); }} type="text" placeholder={intl.formatMessage(intlMessages.responsePlaceholder)} maxLength={MAX_INPUT_CHARS} ref={(r) => { this.responseInput = r; }} onPaste={(e) => { e.stopPropagation(); }} onCut={(e) => { e.stopPropagation(); }} onCopy={(e) => { e.stopPropagation(); }} /> { handleTypedVote(poll.pollId, typedAns); }} /> ) } {intl.formatMessage(poll.secretPoll ? intlMessages.responseIsSecret : intlMessages.responseNotSecret)}
); } renderCheckboxAnswers() { const { isMeteorConnected, intl, poll, pollAnswerIds, } = this.props; const { checkedAnswers } = this.state; const { question } = poll; return (
{question.length === 0 && ( {intl.formatMessage(intlMessages.pollingTitleLabel)} )} {poll.answers.map((pollAnswer) => { const formattedMessageIndex = pollAnswer?.key?.toLowerCase(); let label = pollAnswer?.key; if (pollAnswerIds[formattedMessageIndex]) { label = intl.formatMessage(pollAnswerIds[formattedMessageIndex]); } return ( this.handleCheckboxChange(poll.pollId, pollAnswer.id)} checked={checkedAnswers.includes(pollAnswer.id)} ariaLabelledBy={`pollAnswerLabel${pollAnswer.key}`} ariaDescribedBy={`pollAnswerDesc${pollAnswer.key}`} /> {intl.formatMessage(intlMessages.pollAnswerDesc, { 0: label })} ); })}
this.handleSubmit(poll.pollId)} data-test="submitAnswersMultiple" />
); } render() { const { intl, poll, } = this.props; if (!poll) return null; const { stackOptions, question } = poll; return ( this.pollingContainer = el} tabIndex={-1} > { question.length > 0 && ( {intl.formatMessage(intlMessages.pollQuestionTitle)} {question} ) } {poll.isMultipleResponse ? this.renderCheckboxAnswers() : this.renderButtonAnswers()} ); } } export default injectIntl(injectWbResizeEvent(Polling)); Polling.propTypes = { intl: PropTypes.shape({ formatMessage: PropTypes.func.isRequired, }).isRequired, handleVote: PropTypes.func.isRequired, handleTypedVote: PropTypes.func.isRequired, poll: PropTypes.shape({ pollId: PropTypes.string.isRequired, answers: PropTypes.arrayOf(PropTypes.shape({ id: PropTypes.number.isRequired, key: PropTypes.string, }).isRequired).isRequired, }).isRequired, };