refs #874 Show voted polls with percentage in timeline

This commit is contained in:
AkiraFukushima 2019-07-14 22:06:57 +09:00
parent 3d862068c0
commit 369ff3097b
3 changed files with 68 additions and 9 deletions

View File

@ -1,11 +1,22 @@
<template> <template>
<div class="poll"> <div class="poll">
<ul class="poll-list" v-if="poll"> <ul class="poll-list" v-if="poll">
<li v-for="(option, id) in poll.options" v-bind:key="id"> <template v-if="poll.voted">
<el-radio v-model="pollRadio" :label="option.title">{{ option.title }}</el-radio> <li class="voted" v-for="(option, id) in poll.options" v-bind:key="id">
<span class="progress-bar" :style="progress(option.votes_count * 100 / poll.votes_count)"></span>
<label class="text">
<span class="percentage">{{ option.votes_count * 100 / poll.votes_count }}%</span>
<span>{{ option.title }}</span>
</label>
</li> </li>
</template>
<template v-else>
<li class="not-voted" v-for="(option, id) in poll.options" v-bind:key="id">
<el-radio v-model="pollRadio" :label="id">{{ option.title }}</el-radio>
</li>
</template>
</ul> </ul>
<el-button type="success" @click="vote" :disabled="pollRadio === null">Vote</el-button> <el-button type="success" @click="vote" v-if="!poll.voted" :disabled="pollRadio === null">Vote</el-button>
{{ poll.votes_count }} votes, {{ poll.votes_count }} votes,
until {{ parseDatetime(poll.expires_at, now) }} until {{ parseDatetime(poll.expires_at, now) }}
</div> </div>
@ -49,6 +60,9 @@ export default {
if (this.pollRadio !== null) { if (this.pollRadio !== null) {
this.$emit('vote', [this.pollRadio]) this.$emit('vote', [this.pollRadio])
} }
},
progress(percent) {
return `width: ${percent}%`
} }
} }
} }
@ -61,7 +75,31 @@ export default {
padding-left: 16px; padding-left: 16px;
li { li {
position: relative;
margin: 4px 0; margin: 4px 0;
line-height: 32px;
}
.voted {
max-width: 200px;
.progress-bar {
position: absolute;
display: inline-block;
height: 100%;
background-color: #409eff;
border-radius: 4px;
}
.text {
position: relative;
display: inline-block;
padding-left: 8px;
.percentage {
font-weight: bold;
}
}
} }
} }
} }

View File

@ -199,7 +199,8 @@ export default {
showContent: this.$store.state.App.ignoreCW, showContent: this.$store.state.App.ignoreCW,
showAttachments: this.$store.state.App.ignoreNFSW, showAttachments: this.$store.state.App.ignoreNFSW,
hideAllAttachments: this.$store.state.App.hideAllAttachments, hideAllAttachments: this.$store.state.App.hideAllAttachments,
now: Date.now() now: Date.now(),
pollResponse: null
} }
}, },
props: { props: {
@ -279,7 +280,11 @@ export default {
return !this.spoilered || this.showContent return !this.spoilered || this.showContent
}, },
poll: function() { poll: function() {
if (this.pollResponse) {
return this.pollResponse
} else {
return this.originalMessage.poll return this.originalMessage.poll
}
}, },
sensitive: function() { sensitive: function() {
return (this.hideAllAttachments || this.originalMessage.sensitive) && this.mediaAttachments.length > 0 return (this.hideAllAttachments || this.originalMessage.sensitive) && this.mediaAttachments.length > 0
@ -555,8 +560,12 @@ export default {
break break
} }
}, },
vote(choices) { async vote(choices) {
console.log(choices) const res = await this.$store.dispatch('organisms/Toot/vote', {
id: this.poll.id,
choices: choices
})
this.pollResponse = res
} }
} }
} }

View File

@ -1,8 +1,13 @@
import Mastodon, { Response, Status, Account } from 'megalodon' import Mastodon, { Response, Status, Account, Poll } from 'megalodon'
import { ipcRenderer } from 'electron' import { ipcRenderer } from 'electron'
import { Module, ActionTree } from 'vuex' import { Module, ActionTree } from 'vuex'
import { RootState } from '@/store' import { RootState } from '@/store'
type VoteParam = {
id: string
choices: Array<string>
}
export type TootState = {} export type TootState = {}
const state = (): TootState => ({}) const state = (): TootState => ({})
@ -45,6 +50,13 @@ const actions: ActionTree<TootState, RootState> = {
block: async ({ rootState }, account: Account) => { block: async ({ rootState }, account: Account) => {
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1') const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
return client.post(`/accounts/${account.id}/block`) return client.post(`/accounts/${account.id}/block`)
},
vote: async({ rootState }, params: VoteParam): Promise<Poll> => {
const client = new Mastodon(rootState.TimelineSpace.account.accessToken!, rootState.TimelineSpace.account.baseURL + '/api/v1')
const res = await client.post<Poll>(`/polls/${params.id}/votes`, {
choices: params.choices
})
return res.data
} }
} }