2018-10-10 23:49:58 +08:00
|
|
|
import React, { Component } from 'react';
|
2018-10-16 03:58:07 +08:00
|
|
|
import PropTypes from 'prop-types';
|
2018-10-10 23:49:58 +08:00
|
|
|
import _ from 'lodash';
|
2018-10-16 03:05:50 +08:00
|
|
|
import { defineMessages, injectIntl } from 'react-intl';
|
2018-10-24 22:17:13 +08:00
|
|
|
import { Session } from 'meteor/session';
|
|
|
|
import Button from '/imports/ui/components/button/component';
|
2018-10-10 23:49:58 +08:00
|
|
|
import { styles } from './styles';
|
|
|
|
|
2018-10-16 03:05:50 +08:00
|
|
|
const intlMessages = defineMessages({
|
|
|
|
usersTitle: {
|
|
|
|
id: 'app.poll.liveResult.usersTitle',
|
|
|
|
description: 'heading label for poll users',
|
|
|
|
},
|
|
|
|
responsesTitle: {
|
|
|
|
id: 'app.poll.liveResult.responsesTitle',
|
|
|
|
description: 'heading label for poll responses',
|
|
|
|
},
|
2018-10-24 22:17:13 +08:00
|
|
|
publishLabel: {
|
|
|
|
id: 'app.poll.publishLabel',
|
|
|
|
description: 'label for the publish button',
|
|
|
|
},
|
|
|
|
backLabel: {
|
|
|
|
id: 'app.poll.backLabel',
|
|
|
|
description: 'label for the return to poll options button',
|
|
|
|
},
|
2018-10-16 03:05:50 +08:00
|
|
|
});
|
|
|
|
|
2018-10-10 23:49:58 +08:00
|
|
|
class LiveResult extends Component {
|
|
|
|
constructor(props) {
|
|
|
|
super(props);
|
|
|
|
|
2018-10-31 21:18:33 +08:00
|
|
|
this.renderPollStats = this.renderPollStats.bind(this);
|
2018-10-31 03:18:32 +08:00
|
|
|
this.renderAnswers = this.renderAnswers.bind(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderAnswers() {
|
|
|
|
const { currentPoll, getUser } = this.props;
|
|
|
|
|
|
|
|
if (!currentPoll) return null;
|
|
|
|
|
|
|
|
const { answers, responses, users } = currentPoll;
|
|
|
|
|
|
|
|
let userAnswers = responses
|
|
|
|
? [...users, ...responses.map(u => u.userId)]
|
|
|
|
: [...users];
|
|
|
|
|
2018-10-31 04:05:56 +08:00
|
|
|
const sortByResponse = (a, b) => {
|
|
|
|
if (a.answer.toLowerCase() > b.answer.toLowerCase()) {
|
|
|
|
return -1;
|
|
|
|
} else if (a.answer.toLowerCase() < b.answer.toLowerCase()) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
const sortByName = (a, b) => {
|
|
|
|
if (a.name.toLowerCase() < b.name.toLowerCase()) {
|
|
|
|
return -1;
|
|
|
|
} else if (a.name.toLowerCase() > b.name.toLowerCase()) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
const sortUsers = (a, b) => {
|
|
|
|
let sort = sortByResponse(a, b);
|
|
|
|
if (sort === 0) sort = sortByName(a, b);
|
|
|
|
return sort;
|
|
|
|
};
|
|
|
|
|
2018-10-31 03:18:32 +08:00
|
|
|
userAnswers = userAnswers.map(id => getUser(id))
|
|
|
|
.filter(user => user.connectionStatus === 'online')
|
|
|
|
.map((user) => {
|
|
|
|
let answer = '-';
|
|
|
|
|
|
|
|
if (responses) {
|
|
|
|
const response = responses.find(r => r.userId === user.userId);
|
|
|
|
if (response) answer = answers[response.answerId].key;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
name: user.name,
|
|
|
|
answer,
|
|
|
|
};
|
|
|
|
})
|
2018-10-31 04:05:56 +08:00
|
|
|
.sort(sortUsers)
|
2018-10-31 03:18:32 +08:00
|
|
|
.reduce((acc, user) => [
|
|
|
|
...acc,
|
|
|
|
<div className={styles.item} key={_.uniqueId('stats-')}>{user.name}</div>,
|
|
|
|
<div className={styles.itemR} key={_.uniqueId('stats-')}>{user.answer}</div>,
|
|
|
|
], []);
|
|
|
|
|
|
|
|
return userAnswers;
|
2018-10-10 23:49:58 +08:00
|
|
|
}
|
|
|
|
|
2018-10-31 21:18:33 +08:00
|
|
|
renderPollStats() {
|
2018-10-10 23:49:58 +08:00
|
|
|
const { currentPoll } = this.props;
|
|
|
|
|
|
|
|
const pollStats = [];
|
|
|
|
|
2018-10-31 21:28:32 +08:00
|
|
|
if (!currentPoll) return;
|
|
|
|
|
|
|
|
const {
|
|
|
|
answers,
|
|
|
|
numRespondents,
|
|
|
|
} = currentPoll;
|
|
|
|
|
|
|
|
if (!answers) return;
|
|
|
|
|
|
|
|
answers.map((obj) => {
|
|
|
|
const pct = Math.round(obj.numVotes / numRespondents * 100);
|
|
|
|
|
|
|
|
return pollStats.push(<div className={styles.main} key={_.uniqueId('stats-')}>
|
|
|
|
<div className={styles.left}>
|
|
|
|
{obj.key}
|
|
|
|
</div>
|
|
|
|
<div className={styles.center}>
|
|
|
|
{obj.numVotes}
|
|
|
|
</div>
|
|
|
|
<div className={styles.right}>
|
|
|
|
{`${isNaN(pct) ? 0 : pct}%`}
|
|
|
|
</div>
|
|
|
|
</div>);
|
|
|
|
});
|
2018-10-10 23:49:58 +08:00
|
|
|
|
|
|
|
return pollStats;
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2018-10-24 22:17:13 +08:00
|
|
|
const {
|
2018-10-30 21:17:40 +08:00
|
|
|
intl, publishPoll, stopPoll, handleBackClick,
|
2018-10-24 22:17:13 +08:00
|
|
|
} = this.props;
|
2018-10-16 03:05:50 +08:00
|
|
|
|
2018-10-10 23:49:58 +08:00
|
|
|
return (
|
|
|
|
<div>
|
|
|
|
<div className={styles.stats}>
|
2018-10-31 21:18:33 +08:00
|
|
|
{this.renderPollStats()}
|
2018-10-10 23:49:58 +08:00
|
|
|
</div>
|
2018-10-24 22:17:13 +08:00
|
|
|
<Button
|
|
|
|
onClick={() => {
|
|
|
|
publishPoll();
|
|
|
|
stopPoll();
|
|
|
|
Session.set('isUserListOpen', true);
|
|
|
|
Session.set('isPollOpen', false);
|
|
|
|
Session.set('forcePollOpen', false);
|
|
|
|
}}
|
|
|
|
label={intl.formatMessage(intlMessages.publishLabel)}
|
|
|
|
color="primary"
|
|
|
|
className={styles.btn}
|
|
|
|
/>
|
|
|
|
<Button
|
|
|
|
onClick={() => {
|
2018-10-30 21:17:40 +08:00
|
|
|
handleBackClick();
|
2018-10-24 22:17:13 +08:00
|
|
|
}}
|
|
|
|
label={intl.formatMessage(intlMessages.backLabel)}
|
|
|
|
color="default"
|
|
|
|
className={styles.btn}
|
|
|
|
/>
|
2018-10-10 23:49:58 +08:00
|
|
|
<div className={styles.container}>
|
2018-10-16 03:05:50 +08:00
|
|
|
<div className={styles.usersHeading}>{intl.formatMessage(intlMessages.usersTitle)}</div>
|
|
|
|
<div className={styles.responseHeading}>{intl.formatMessage(intlMessages.responsesTitle)}</div>
|
2018-10-31 03:18:32 +08:00
|
|
|
{this.renderAnswers()}
|
2018-10-10 23:49:58 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-16 03:05:50 +08:00
|
|
|
export default injectIntl(LiveResult);
|
2018-10-16 03:58:07 +08:00
|
|
|
|
|
|
|
LiveResult.propTypes = {
|
|
|
|
intl: PropTypes.shape({
|
|
|
|
formatMessage: PropTypes.func.isRequired,
|
|
|
|
}).isRequired,
|
|
|
|
};
|