WIP New API update
This commit is contained in:
parent
96f480dcca
commit
5b6df0fd77
|
@ -194,11 +194,13 @@ const getNodeInfo = async ({ store }) => {
|
|||
if (res.ok) {
|
||||
const data = await res.json()
|
||||
const metadata = data.metadata
|
||||
store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits })
|
||||
|
||||
const features = metadata.features
|
||||
store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') })
|
||||
store.dispatch('setInstanceOption', { name: 'chatAvailable', value: features.includes('chat') })
|
||||
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') })
|
||||
store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') })
|
||||
|
||||
store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames })
|
||||
store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats })
|
||||
|
|
|
@ -22,7 +22,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
currentUserHasVoted () {
|
||||
return this.poll.user_voted
|
||||
return this.poll.voted
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
<template>
|
||||
<div class="poll-form" v-if="visible">
|
||||
<hr />
|
||||
<div class="poll-option"
|
||||
v-for="(option, index) in options"
|
||||
:key="index">
|
||||
<hr>
|
||||
<div class="poll-option" v-for="(option, index) in options" :key="index">
|
||||
<div class="input-container">
|
||||
<input
|
||||
class="poll-option-input"
|
||||
type="text"
|
||||
:placeholder="$t('polls.option')"
|
||||
@input="onUpdateOption($event, index)"
|
||||
:value="option" />
|
||||
:value="option"
|
||||
:maxlength="maxLength"
|
||||
>
|
||||
</div>
|
||||
<div class="icon-container">
|
||||
<i class="icon-cancel" @click="onDeleteOption(index)"></i>
|
||||
|
@ -19,29 +19,77 @@
|
|||
<button
|
||||
class="btn btn-default add-option"
|
||||
type="button"
|
||||
@click="onAddOption">{{ $t("polls.add_option") }}
|
||||
</button>
|
||||
@click="onAddOption"
|
||||
>{{ $t("polls.add_option") }}</button>
|
||||
<div class="poll-type-expiry">
|
||||
<div class="poll-type">
|
||||
<label for="poll-type-selector" class="select">
|
||||
<select id="poll-type-selector" v-model="pollType" @change="onTypeChange">
|
||||
<option value="single">{{$t('polls.single_choice')}}</option>
|
||||
<option value="multiple">{{$t('polls.multiple_choices')}}</option>
|
||||
</select>
|
||||
<i class="icon-down-open"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="poll-expiry">
|
||||
<label for="poll-expiry-selector" class="select">
|
||||
<select id="poll-expiry-selector" v-model="pollExpiry" @change="onExpiryChange">
|
||||
<option v-for="(value, key) in expiryOptions" :value="key" v-bind:key="key">
|
||||
{{ value }}
|
||||
</option>
|
||||
</select>
|
||||
<i class="icon-down-open"/>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// TODO: Make this configurable
|
||||
const maxOptions = 10
|
||||
import { pickBy } from 'lodash'
|
||||
|
||||
export default {
|
||||
name: 'PollForm',
|
||||
props: ['visible'],
|
||||
data: () => ({
|
||||
pollType: 'single',
|
||||
pollExpiry: '86400'
|
||||
}),
|
||||
computed: {
|
||||
optionsLength: function () {
|
||||
return this.$store.state.poll.pollOptions.length
|
||||
optionsLength () {
|
||||
return this.$store.state.poll.options.length
|
||||
},
|
||||
options: function () {
|
||||
return this.$store.state.poll.pollOptions
|
||||
options () {
|
||||
return this.$store.state.poll.options
|
||||
},
|
||||
pollLimits () {
|
||||
return this.$store.state.instance.pollLimits
|
||||
},
|
||||
maxOptions () {
|
||||
return this.pollLimits.max_options
|
||||
},
|
||||
maxLength () {
|
||||
return this.pollLimits.max_option_chars
|
||||
},
|
||||
expiryOptions () {
|
||||
const minExpiration = this.pollLimits.min_expiration
|
||||
const maxExpiration = this.pollLimits.max_expiration
|
||||
const expiryOptions = this.$t('polls.expiry_options')
|
||||
|
||||
return pickBy(expiryOptions, (_value, key) => {
|
||||
if (key === 'custom') {
|
||||
return true
|
||||
}
|
||||
|
||||
const parsedKey = parseInt(key)
|
||||
|
||||
return (parsedKey >= minExpiration && parsedKey <= maxExpiration)
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
onAddOption () {
|
||||
if (this.optionsLength < maxOptions) {
|
||||
if (this.optionsLength < this.maxOptions) {
|
||||
this.$store.dispatch('addPollOption', { option: '' })
|
||||
}
|
||||
},
|
||||
|
@ -51,7 +99,18 @@ export default {
|
|||
}
|
||||
},
|
||||
onUpdateOption (e, index) {
|
||||
this.$store.dispatch('updatePollOption', { index, option: e.target.value })
|
||||
this.$store.dispatch('updatePollOption', {
|
||||
index,
|
||||
option: e.target.value
|
||||
})
|
||||
},
|
||||
onTypeChange (e) {
|
||||
const multiple = e.target.value === 'multiple'
|
||||
|
||||
this.$store.dispatch('setMultiple', { multiple })
|
||||
},
|
||||
onExpiryChange (e) {
|
||||
this.$store.dispatch('setExpiresIn', { expiresIn: e.target.value })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -65,7 +124,7 @@ export default {
|
|||
border: solid 1px #1c2735;
|
||||
}
|
||||
.add-option {
|
||||
margin: 0.8em 0 0;
|
||||
margin: 0.8em 0 0.8em;
|
||||
width: 94%;
|
||||
}
|
||||
.poll-option {
|
||||
|
@ -82,5 +141,16 @@ export default {
|
|||
.icon-container {
|
||||
width: 5%;
|
||||
}
|
||||
.poll-type-expiry {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: 0 0 0.6em;
|
||||
}
|
||||
.poll-expiry-custom {
|
||||
display: none;
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
<template>
|
||||
<div class="poll-vote" v-bind:class="containerClass">
|
||||
<div :id="pollVoteId" class="poll-vote" v-bind:class="containerClass">
|
||||
<div
|
||||
class="poll-choice"
|
||||
v-for="(pollOption, index) in poll.votes"
|
||||
v-for="(pollOption, index) in poll.options"
|
||||
:key="index">
|
||||
<input
|
||||
:disabled="loading"
|
||||
type="radio"
|
||||
type="checkbox"
|
||||
:id="optionID(index)"
|
||||
:value="pollOption.name"
|
||||
:value="pollOption.title"
|
||||
name="choice"
|
||||
@change="onChoice">
|
||||
<label :for="optionID(index)">{{pollOption.name}}</label>
|
||||
<label :for="optionID(index)">{{pollOption.title}}</label>
|
||||
</div>
|
||||
<button class="btn btn-default poll-vote-button" @click="onVote">{{$t('polls.vote')}}</button>
|
||||
</div>
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -23,7 +23,8 @@ export default {
|
|||
props: ['poll'],
|
||||
data () {
|
||||
return {
|
||||
loading: false
|
||||
loading: false,
|
||||
choices: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -31,18 +32,24 @@ export default {
|
|||
return {
|
||||
loading: this.loading
|
||||
}
|
||||
},
|
||||
pollVoteId: function () {
|
||||
return `poll-vote-${this.poll.id}`
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
optionID (index) {
|
||||
return `pollOption${index}`
|
||||
return `pollOption${this.poll.id}#${index}`
|
||||
},
|
||||
async onChoice (e) {
|
||||
const pollID = this.poll.id
|
||||
const optionName = e.target.value
|
||||
|
||||
// TODO
|
||||
},
|
||||
async onVote () {
|
||||
this.loading = true
|
||||
const poll = await this.$store.state.api.backendInteractor.vote(pollID, optionName)
|
||||
|
||||
const pollID = this.poll.id
|
||||
const poll = await this.$store.state.api.backendInteractor.vote(pollID, this.choices)
|
||||
|
||||
this.loading = false
|
||||
this.$emit('user-has-voted', poll)
|
||||
}
|
||||
|
@ -60,5 +67,8 @@ export default {
|
|||
.poll-choice {
|
||||
padding: 0.4em 0;
|
||||
}
|
||||
.poll-vote-button {
|
||||
margin: 1em 0 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -66,7 +66,7 @@ const PostStatusForm = {
|
|||
? this.$store.state.instance.postContentType
|
||||
: this.$store.state.config.postContentType
|
||||
|
||||
const pollOptions = this.$store.state.poll.pollOptions || []
|
||||
const poll = this.$store.state.poll || {}
|
||||
|
||||
return {
|
||||
dropFiles: [],
|
||||
|
@ -79,7 +79,7 @@ const PostStatusForm = {
|
|||
status: statusText,
|
||||
nsfw: false,
|
||||
files: [],
|
||||
pollOptions,
|
||||
poll,
|
||||
visibility: scope,
|
||||
contentType
|
||||
},
|
||||
|
@ -188,6 +188,9 @@ const PostStatusForm = {
|
|||
},
|
||||
safeDMEnabled () {
|
||||
return this.$store.state.instance.safeDM
|
||||
},
|
||||
pollsAvailable () {
|
||||
return this.$store.state.instance.pollsAvailable
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -262,7 +265,7 @@ const PostStatusForm = {
|
|||
visibility: newStatus.visibility,
|
||||
sensitive: newStatus.nsfw,
|
||||
media: newStatus.files,
|
||||
pollOptions: newStatus.pollOptions,
|
||||
poll: newStatus.poll,
|
||||
store: this.$store,
|
||||
inReplyToStatusId: this.replyTo,
|
||||
contentType: newStatus.contentType
|
||||
|
@ -273,7 +276,8 @@ const PostStatusForm = {
|
|||
spoilerText: '',
|
||||
files: [],
|
||||
visibility: newStatus.visibility,
|
||||
contentType: newStatus.contentType
|
||||
contentType: newStatus.contentType,
|
||||
poll: this.$store.state.poll
|
||||
}
|
||||
this.$store.dispatch('swapPollOptions', { options: ['', ''] })
|
||||
this.pollFormVisible = false
|
||||
|
|
|
@ -74,10 +74,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<poll-form :visible="pollFormVisible" :options="newStatus.pollOptions" />
|
||||
<poll-form v-if="pollsAvailable" :visible="pollFormVisible" />
|
||||
<div class='form-bottom'>
|
||||
<media-upload ref="mediaUpload" @uploading="disableSubmit" @uploaded="addMediaFile" @upload-failed="uploadFailed" :drop-files="dropFiles"></media-upload>
|
||||
<div class="poll-icon">
|
||||
<div v-if="pollsAvailable" class="poll-icon">
|
||||
<label
|
||||
class="btn btn-default"
|
||||
:title="$t('tool_tip.poll')"
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
<a v-if="showingMore" href="#" class="status-unhider" @click.prevent="toggleShowMore">{{$t("general.show_less")}}</a>
|
||||
</div>
|
||||
|
||||
<div v-if="status.poll && status.poll.votes">
|
||||
<div v-if="status.poll && status.poll.options">
|
||||
<poll :poll="status.poll" />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -72,7 +72,19 @@
|
|||
"polls": {
|
||||
"add_option": "Add Option",
|
||||
"option": "Option",
|
||||
"votes": "votes"
|
||||
"votes": "votes",
|
||||
"vote": "Vote",
|
||||
"single_choice": "Allow one choice",
|
||||
"multiple_choices": "Allow multiple choices",
|
||||
"expiry_options": {
|
||||
"300": "5 minutes",
|
||||
"1800": "30 minutes",
|
||||
"3600": "1 hour",
|
||||
"21600": "6 hours",
|
||||
"86400": "1 day",
|
||||
"259200": "3 days",
|
||||
"604800": "7 days"
|
||||
}
|
||||
},
|
||||
"post_status": {
|
||||
"new_status": "Post new status",
|
||||
|
|
|
@ -1,19 +1,27 @@
|
|||
const poll = {
|
||||
state: {
|
||||
pollOptions: ['', '']
|
||||
options: ['', ''],
|
||||
multiple: false,
|
||||
expiresIn: '86400'
|
||||
},
|
||||
mutations: {
|
||||
ADD_OPTION (state, { option }) {
|
||||
state.pollOptions.push(option)
|
||||
state.options.push(option)
|
||||
},
|
||||
UPDATE_OPTION (state, { index, option }) {
|
||||
state.pollOptions[index] = option
|
||||
state.options[index] = option
|
||||
},
|
||||
DELETE_OPTION (state, { index }) {
|
||||
state.pollOptions.splice(index, 1)
|
||||
state.options.splice(index, 1)
|
||||
},
|
||||
SWAP_OPTIONS (state, { options }) {
|
||||
state.pollOptions = options
|
||||
state.options = options
|
||||
},
|
||||
SET_MULTIPLE (state, { multiple }) {
|
||||
state.multiple = multiple
|
||||
},
|
||||
SET_EXPIRES_IN (state, { expiresIn }) {
|
||||
state.expiresIn = expiresIn
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
|
@ -28,6 +36,12 @@ const poll = {
|
|||
},
|
||||
swapPollOptions (store, { options }) {
|
||||
store.commit('SWAP_OPTIONS', { options })
|
||||
},
|
||||
setMultiple (store, { multiple }) {
|
||||
store.commit('SET_MULTIPLE', { multiple })
|
||||
},
|
||||
setExpiresIn (store, { expiresIn }) {
|
||||
store.commit('SET_EXPIRES_IN', { expiresIn })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ const MASTODON_MUTE_USER_URL = id => `/api/v1/accounts/${id}/mute`
|
|||
const MASTODON_UNMUTE_USER_URL = id => `/api/v1/accounts/${id}/unmute`
|
||||
const MASTODON_POST_STATUS_URL = '/api/v1/statuses'
|
||||
const MASTODON_MEDIA_UPLOAD_URL = '/api/v1/media'
|
||||
const MASTODON_VOTE_URL = '/api/v1/polls/vote'
|
||||
const MASTODON_VOTE_URL = id => `/api/v1/polls/${id}/votes`
|
||||
const MASTODON_POLL_URL = id => `/api/v1/polls/${id}`
|
||||
|
||||
import { each, map } from 'lodash'
|
||||
|
@ -573,8 +573,9 @@ const unretweet = ({ id, credentials }) => {
|
|||
.then((data) => parseStatus(data))
|
||||
}
|
||||
|
||||
const postStatus = ({credentials, status, spoilerText, visibility, sensitive, pollOptions = [], mediaIds = [], inReplyToStatusId, contentType}) => {
|
||||
const postStatus = ({credentials, status, spoilerText, visibility, sensitive, poll, mediaIds = [], inReplyToStatusId, contentType}) => {
|
||||
const form = new FormData()
|
||||
const pollOptions = poll.options || []
|
||||
|
||||
form.append('status', status)
|
||||
form.append('source', 'Pleroma FE')
|
||||
|
@ -585,9 +586,19 @@ const postStatus = ({credentials, status, spoilerText, visibility, sensitive, po
|
|||
mediaIds.forEach(val => {
|
||||
form.append('media_ids[]', val)
|
||||
})
|
||||
pollOptions.forEach(val => {
|
||||
form.append('poll_options[]', val)
|
||||
if (pollOptions.some(option => option !== '')) {
|
||||
const normalizedPoll = {
|
||||
expires_in: poll.expiresIn,
|
||||
multiple: poll.multiple
|
||||
}
|
||||
Object.keys(normalizedPoll).forEach(key => {
|
||||
form.append(`poll[${key}]`, normalizedPoll[key])
|
||||
})
|
||||
|
||||
pollOptions.forEach(option => {
|
||||
form.append('poll[options][]', option)
|
||||
})
|
||||
}
|
||||
if (inReplyToStatusId) {
|
||||
form.append('in_reply_to_id', inReplyToStatusId)
|
||||
}
|
||||
|
@ -727,16 +738,15 @@ const markNotificationsAsSeen = ({id, credentials}) => {
|
|||
}).then((data) => data.json())
|
||||
}
|
||||
|
||||
const vote = ({pollID, optionName, credentials}) => {
|
||||
const vote = ({pollID, choices, credentials}) => {
|
||||
const form = new FormData()
|
||||
|
||||
form.append('option_name', optionName)
|
||||
form.append('question_id', pollID)
|
||||
form.append('choices', choices)
|
||||
|
||||
return promisedRequest(
|
||||
MASTODON_VOTE_URL,
|
||||
MASTODON_VOTE_URL(encodeURIComponent(pollID)),
|
||||
{
|
||||
method: 'PATCH',
|
||||
method: 'POST',
|
||||
headers: authHeaders(credentials),
|
||||
body: form
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { map } from 'lodash'
|
||||
import apiService from '../api/api.service.js'
|
||||
|
||||
const postStatus = ({ store, status, spoilerText, visibility, sensitive, pollOptions = [], media = [], inReplyToStatusId = undefined, contentType = 'text/plain' }) => {
|
||||
const postStatus = ({ store, status, spoilerText, visibility, sensitive, poll, media = [], inReplyToStatusId = undefined, contentType = 'text/plain' }) => {
|
||||
const mediaIds = map(media, 'id')
|
||||
|
||||
return apiService.postStatus({
|
||||
|
@ -13,7 +13,7 @@ const postStatus = ({ store, status, spoilerText, visibility, sensitive, pollOpt
|
|||
mediaIds,
|
||||
inReplyToStatusId,
|
||||
contentType,
|
||||
pollOptions})
|
||||
poll})
|
||||
.then((data) => {
|
||||
if (!data.error) {
|
||||
store.dispatch('addNewStatuses', {
|
||||
|
|
Loading…
Reference in New Issue