2019-06-18 20:28:31 +00:00
|
|
|
import Timeago from '../timeago/timeago.vue'
|
|
|
|
import { forEach, map } from 'lodash'
|
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'Poll',
|
2019-06-20 13:02:04 +00:00
|
|
|
props: ['pollId'],
|
2019-06-18 20:28:31 +00:00
|
|
|
components: { Timeago },
|
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
loading: false,
|
2019-06-20 13:02:04 +00:00
|
|
|
choices: []
|
2019-06-18 20:28:31 +00:00
|
|
|
}
|
|
|
|
},
|
2019-06-20 13:02:04 +00:00
|
|
|
mounted () {
|
|
|
|
this.$store.dispatch('trackPoll', this.pollId)
|
2019-06-18 20:28:31 +00:00
|
|
|
},
|
|
|
|
destroyed () {
|
2019-06-20 13:02:04 +00:00
|
|
|
this.$store.dispatch('untrackPoll', this.pollId)
|
2019-06-18 20:28:31 +00:00
|
|
|
},
|
|
|
|
computed: {
|
2019-06-20 13:02:04 +00:00
|
|
|
poll () {
|
|
|
|
const storePoll = this.$store.state.polls.pollsObject[this.pollId]
|
|
|
|
return storePoll || {}
|
|
|
|
},
|
|
|
|
options () {
|
|
|
|
return (this.poll && this.poll.options) || []
|
|
|
|
},
|
|
|
|
expiresAt () {
|
|
|
|
return (this.poll && this.poll.expires_at) || 0
|
|
|
|
},
|
2019-06-18 20:28:31 +00:00
|
|
|
expired () {
|
2019-06-20 13:02:04 +00:00
|
|
|
return Date.now() > Date.parse(this.expiresAt)
|
2019-06-18 20:28:31 +00:00
|
|
|
},
|
|
|
|
loggedIn () {
|
|
|
|
return this.$store.state.users.currentUser
|
|
|
|
},
|
|
|
|
showResults () {
|
|
|
|
return this.poll.voted || this.expired || !this.loggedIn
|
|
|
|
},
|
|
|
|
totalVotesCount () {
|
|
|
|
return this.poll.votes_count
|
|
|
|
},
|
|
|
|
containerClass () {
|
|
|
|
return {
|
|
|
|
loading: this.loading
|
|
|
|
}
|
|
|
|
},
|
|
|
|
choiceIndices () {
|
|
|
|
// Convert array of booleans into an array of indices of the
|
|
|
|
// items that were 'true', so [true, false, false, true] becomes
|
|
|
|
// [0, 3].
|
|
|
|
return this.choices
|
|
|
|
.map((entry, index) => entry && index)
|
|
|
|
.filter(value => typeof value === 'number')
|
|
|
|
},
|
|
|
|
isDisabled () {
|
|
|
|
const noChoice = this.choiceIndices.length === 0
|
|
|
|
return this.loading || noChoice
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
percentageForOption (count) {
|
|
|
|
return this.totalVotesCount === 0 ? 0 : Math.round(count / this.totalVotesCount * 100)
|
|
|
|
},
|
|
|
|
resultTitle (option) {
|
|
|
|
return `${option.votes_count}/${this.totalVotesCount} ${this.$t('polls.votes')}`
|
|
|
|
},
|
|
|
|
fetchPoll () {
|
|
|
|
this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
|
|
|
|
},
|
|
|
|
activateOption (index) {
|
|
|
|
// forgive me father: doing checking the radio/checkboxes
|
|
|
|
// in code because of customized input elements need either
|
|
|
|
// a) an extra element for the actual graphic, or b) use a
|
|
|
|
// pseudo element for the label. We use b) which mandates
|
|
|
|
// using "for" and "id" matching which isn't nice when the
|
|
|
|
// same poll appears multiple times on the site (notifs and
|
|
|
|
// timeline for example). With code we can make sure it just
|
|
|
|
// works without altering the pseudo element implementation.
|
|
|
|
const allElements = this.$el.querySelectorAll('input')
|
|
|
|
const clickedElement = this.$el.querySelector(`input[value="${index}"]`)
|
|
|
|
if (this.poll.multiple) {
|
|
|
|
// Checkboxes, toggle only the clicked one
|
|
|
|
clickedElement.checked = !clickedElement.checked
|
|
|
|
} else {
|
|
|
|
// Radio button, uncheck everything and check the clicked one
|
|
|
|
forEach(allElements, element => { element.checked = false })
|
|
|
|
clickedElement.checked = true
|
|
|
|
}
|
|
|
|
this.choices = map(allElements, e => e.checked)
|
|
|
|
},
|
|
|
|
optionId (index) {
|
|
|
|
return `poll${this.poll.id}-${index}`
|
|
|
|
},
|
|
|
|
vote () {
|
|
|
|
if (this.choiceIndices.length === 0) return
|
|
|
|
this.loading = true
|
|
|
|
this.$store.dispatch(
|
|
|
|
'votePoll',
|
|
|
|
{ id: this.statusId, pollId: this.poll.id, choices: this.choiceIndices }
|
|
|
|
).then(poll => {
|
|
|
|
this.loading = false
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
2019-06-20 13:02:04 +00:00
|
|
|
}
|