Browse Source

feat(polls): allow to update drafts

Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
pull/14254/head
Maksim Sukharev 9 months ago
committed by backportbot[bot]
parent
commit
306c4f6a02
  1. 22
      src/components/MessagesList/MessagesGroup/Message/MessagePart/Poll.vue
  2. 10
      src/components/PollViewer/PollDraftHandler.vue
  3. 38
      src/components/PollViewer/PollEditor.vue
  4. 5
      src/components/PollViewer/PollManager.vue
  5. 2
      src/services/EventBus.ts

22
src/components/MessagesList/MessagesGroup/Message/MessagePart/Poll.vue

@ -9,6 +9,15 @@
<span class="poll-card__header poll-card__header--draft">
<IconPoll class="poll-card__header-icon" :size="20" />
<span class="poll-card__header-name">{{ name }}</span>
<NcButton v-if="canEditPollDraft"
type="tertiary"
:title="t('spreed', 'Edit poll draft')"
:aria-label="t('spreed', 'Edit poll draft')"
@click.stop="editDraft">
<template #icon>
<IconPencil :size="20" />
</template>
</NcButton>
<NcButton type="tertiary"
:title="t('spreed', 'Delete poll draft')"
:aria-label="t('spreed', 'Delete poll draft')"
@ -50,6 +59,7 @@
import { vIntersectionObserver as IntersectionObserver } from '@vueuse/components'
import IconDelete from 'vue-material-design-icons/Delete.vue'
import IconPencil from 'vue-material-design-icons/Pencil.vue'
import IconPoll from 'vue-material-design-icons/Poll.vue'
import { t, n } from '@nextcloud/l10n'
@ -57,6 +67,7 @@ import { t, n } from '@nextcloud/l10n'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import { POLL } from '../../../../../constants.ts'
import { hasTalkFeature } from '../../../../../services/CapabilitiesManager.ts'
import { usePollsStore } from '../../../../../stores/polls.ts'
export default {
@ -65,6 +76,7 @@ export default {
components: {
NcButton,
IconDelete,
IconPencil,
IconPoll,
},
@ -127,6 +139,10 @@ export default {
: t('spreed', 'Poll')
}
},
canEditPollDraft() {
return this.draft && hasTalkFeature(this.token, 'edit-draft-poll')
}
},
methods: {
@ -142,7 +158,11 @@ export default {
},
openDraft() {
this.$emit('click', this.id)
this.$emit('click', { id: this.id, action: 'fill' })
},
editDraft() {
this.$emit('click', { id: this.id, action: 'edit' })
},
deleteDraft() {

10
src/components/PollViewer/PollDraftHandler.vue

@ -30,7 +30,7 @@
@click="openPollEditor" />
</div>
<template v-if="!props.editorOpened" #actions>
<NcButton @click="openPollEditor(null)">
<NcButton @click="openPollEditor({ id: null, action: 'fill' })">
{{ t('spreed', 'Create new poll') }}
</NcButton>
</template>
@ -73,10 +73,12 @@ const pollDraftsLoaded = computed(() => pollsStore.draftsLoaded(props.token))
/**
* Opens poll editor pre-filled from the draft
* @param id poll draft ID
* @param payload method payload
* @param payload.id poll draft ID
* @param payload.action required action ('fill' from draft or 'edit' draft)
*/
function openPollEditor(id: number | null) {
EventBus.emit('poll-editor-open', { id, fromDrafts: !props.editorOpened, selector: props.container })
function openPollEditor({ id, action } : { id: number | null, action?: string }) {
EventBus.emit('poll-editor-open', { id, fromDrafts: !props.editorOpened, action, selector: props.container })
}
</script>

38
src/components/PollViewer/PollEditor.vue

@ -4,7 +4,7 @@
-->
<template>
<NcDialog :name="t('spreed', 'Create new poll')"
<NcDialog :name="dialogName"
:close-on-click-outside="!isFilled"
:container="container"
v-on="$listeners"
@ -89,7 +89,7 @@
</div>
<template #actions>
<NcActions v-if="supportPollDrafts" force-menu>
<NcActionButton v-if="props.canCreatePollDrafts" :disabled="!isFilled" @click="createPollDraft">
<NcActionButton v-if="props.canCreatePollDrafts && !editingDraftId" :disabled="!isFilled" @click="createPollDraft">
<template #icon>
<IconFileEdit :size="20" />
</template>
@ -102,7 +102,7 @@
{{ t('spreed', 'Export draft to file') }}
</NcActionLink>
</NcActions>
<NcButton type="primary" :disabled="!isFilled" @click="createPoll">
<NcButton type="primary" :disabled="!isFilled" @click="handleSubmit">
{{ createPollLabel }}
</NcButton>
</template>
@ -157,6 +157,7 @@ const store = useStore()
const pollsStore = usePollsStore()
const isOpenedFromDraft = ref(false)
const editingDraftId = ref<number | null>(null)
const pollOption = ref<InstanceType<typeof NcTextField>[] | null>(null)
const pollImport = ref<HTMLInputElement | null>(null)
@ -168,7 +169,14 @@ const pollForm = reactive<createPollParams>({
})
const isFilled = computed(() => Boolean(pollForm.question) && pollForm.options.filter(option => Boolean(option)).length >= 2)
const dialogName = computed(() => {
return editingDraftId.value ? t('spreed', 'Edit poll draft') : t('spreed', 'Create new poll')
})
const createPollLabel = computed(() => {
if (editingDraftId.value) {
return t('spreed', 'Save')
}
return store.getters.getToken() !== props.token
? t('spreed', 'Create poll in {name}', { name: store.getters.conversation(props.token).displayName },
undefined, { escape: false, sanitize: false })
@ -217,7 +225,22 @@ function addOption() {
/**
* Post a poll into conversation
*/
async function createPoll() {
async function handleSubmit() {
if (editingDraftId.value) {
const pollDraft = await pollsStore.updatePollDraft({
token: props.token,
pollId: editingDraftId.value,
form: pollForm,
})
if (pollDraft) {
openPollDraftHandler()
nextTick(() => {
emit('close')
})
}
return
}
const poll = await pollsStore.createPoll({
token: props.token,
form: pollForm,
@ -231,12 +254,17 @@ async function createPoll() {
* Pre-fills form from the draft
* @param id poll draft ID
* @param fromDrafts whether editor was opened from drafts handler
* @param action required action ('fill' from draft or 'edit' draft)
*/
function fillPollEditorFromDraft(id: number | null, fromDrafts: boolean) {
function fillPollEditorFromDraft(id: number | null, fromDrafts: boolean, action?: string) {
if (fromDrafts) {
// Show 'Back' button, do not reset until closed
isOpenedFromDraft.value = true
}
if (action === 'edit') {
// Show Edit interface
editingDraftId.value = id
}
if (id === null) {
return

5
src/components/PollViewer/PollManager.vue

@ -57,13 +57,14 @@ function openPollDraftHandler({ selector }: Events['poll-drafts-open']) {
* @param payload event payload
* @param payload.id poll draft ID to fill form with (null for empty form)
* @param payload.fromDrafts whether editor was opened from PollDraftHandler dialog
* @param payload.action required action ('fill' from draft or 'edit' draft)
* @param [payload.selector] selector to mount dialog to (body by default)
*/
function openPollEditor({ id, fromDrafts, selector }: Events['poll-editor-open']) {
function openPollEditor({ id, fromDrafts, action, selector }: Events['poll-editor-open']) {
container.value = selector
showPollEditor.value = true
nextTick(() => {
pollEditorRef.value?.fillPollEditorFromDraft(id, fromDrafts)
pollEditorRef.value?.fillPollEditorFromDraft(id, fromDrafts, action)
// Wait for editor to be mounted and filled before unmounting drafts dialog to avoid issues when inserting nodes
showPollDraftHandler.value = false
})

2
src/services/EventBus.ts

@ -25,7 +25,7 @@ export type Events = {
'joined-conversation': { token: string },
'message-height-changed': { heightDiff: number },
'poll-drafts-open': { selector?: string },
'poll-editor-open': { id: number | null, fromDrafts: boolean, selector?: string },
'poll-editor-open': { id: number | null, fromDrafts: boolean, action?: string, selector?: string },
'refresh-peer-list': void,
'retry-message': number,
'route-change': { from: Route, to: Route },

Loading…
Cancel
Save