Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking β€œSign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: draft polls management πŸ“Š #13518

Merged
merged 4 commits into from
Oct 18, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: browse poll drafts from poll editor and shared items
Signed-off-by: Maksim Sukharev <[email protected]>
Antreesy committed Oct 18, 2024
commit 5a07116455413ac8e7ceb806a028792ce6891e54
Original file line number Diff line number Diff line change
@@ -5,7 +5,16 @@

<template>
<!-- Poll card -->
<a v-if="!showAsButton"
<div v-if="draft" class="poll-card" @click="openDraft">
<span class="poll-card__header">
<PollIcon :size="20" />
<span>{{ name }}</span>
</span>
<span class="poll-card__footer">
{{ pollFooterText }}
</span>
</div>
<a v-else-if="!showAsButton"
v-intersection-observer="getPollData"
:aria-label="t('spreed', 'Poll')"
class="poll-card"
@@ -34,7 +43,7 @@ import { vIntersectionObserver as IntersectionObserver } from '@vueuse/component

import PollIcon from 'vue-material-design-icons/Poll.vue'

import { t } from '@nextcloud/l10n'
import { t, n } from '@nextcloud/l10n'

import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'

@@ -73,8 +82,15 @@ export default {
type: Boolean,
default: false,
},

draft: {
type: Boolean,
default: false,
},
},

emits: ['click'],

setup() {
return {
pollsStore: usePollsStore(),
@@ -83,14 +99,18 @@ export default {

computed: {
poll() {
return this.pollsStore.getPoll(this.token, this.id)
return !this.draft
? this.pollsStore.getPoll(this.token, this.id)
: this.pollsStore.drafts[this.token][this.id]
},

pollFooterText() {
if (this.poll?.status === POLL.STATUS.OPEN) {
return this.poll?.votedSelf.length > 0
? t('spreed', 'Open poll β€’ You voted already')
: t('spreed', 'Open poll β€’ Click to vote')
} else if (this.draft) {
return n('spreed', 'Poll draft β€’ %n option', 'Poll draft β€’ %n options', this.poll?.options?.length)
} else {
return this.poll?.status === POLL.STATUS.CLOSED
? t('spreed', 'Poll β€’ Ended')
@@ -101,6 +121,7 @@ export default {

methods: {
t,
n,
getPollData() {
if (!this.poll) {
this.pollsStore.getPollData({
@@ -110,6 +131,10 @@ export default {
}
},

openDraft() {
this.$emit('click', this.id)
},

openPoll() {
this.pollsStore.setActivePoll({
token: this.token,
17 changes: 17 additions & 0 deletions src/components/NewMessage/NewMessage.vue
Original file line number Diff line number Diff line change
@@ -151,6 +151,10 @@
:token="token"
@close="togglePollEditor" />

<PollDraftHandler v-if="canCreatePollDrafts && showPollDraftHandler"
:token="token"
@close="togglePollDraftHandler" />

<!-- New file creation dialog -->
<NewMessageNewFileDialog v-if="showNewFileDialog !== -1"
:token="token"
@@ -194,6 +198,7 @@ import NewMessageAudioRecorder from './NewMessageAudioRecorder.vue'
import NewMessageNewFileDialog from './NewMessageNewFileDialog.vue'
import NewMessagePollEditor from './NewMessagePollEditor.vue'
import NewMessageTypingIndicator from './NewMessageTypingIndicator.vue'
import PollDraftHandler from '../PollViewer/PollDraftHandler.vue'
import Quote from '../Quote.vue'

import { useIsDarkTheme } from '../../composables/useIsDarkTheme.ts'
@@ -226,6 +231,7 @@ export default {
NewMessageAudioRecorder,
NewMessageNewFileDialog,
NewMessagePollEditor,
PollDraftHandler,
NewMessageTypingIndicator,
Quote,
// Icons
@@ -301,6 +307,7 @@ export default {
// True when the audio recorder component is recording
isRecordingAudio: false,
showPollEditor: false,
showPollDraftHandler: false,
showNewFileDialog: -1,
showFilePicker: false,
// Check empty template by default
@@ -386,6 +393,10 @@ export default {
&& this.conversation.type !== CONVERSATION.TYPE.NOTE_TO_SELF
},

canCreatePollDrafts() {
return hasTalkFeature(this.token, 'talk-polls-drafts') && this.$store.getters.isModerator
},

currentConversationIsJoined() {
return this.$store.getters.currentConversationIsJoined
},
@@ -538,6 +549,7 @@ export default {
EventBus.on('upload-discard', this.handleUploadSideEffects)
EventBus.on('retry-message', this.handleRetryMessage)
EventBus.on('smart-picker-open', this.handleOpenTributeMenu)
EventBus.on('poll-drafts-open', this.togglePollDraftHandler)

if (!this.$store.getters.areFileTemplatesInitialised) {
this.$store.dispatch('getFileTemplates')
@@ -550,6 +562,7 @@ export default {
EventBus.off('upload-discard', this.handleUploadSideEffects)
EventBus.off('retry-message', this.handleRetryMessage)
EventBus.off('smart-picker-open', this.handleOpenTributeMenu)
EventBus.off('poll-drafts-open', this.togglePollDraftHandler)
},

methods: {
@@ -892,6 +905,10 @@ export default {
this.showPollEditor = !this.showPollEditor
},

togglePollDraftHandler() {
this.showPollDraftHandler = !this.showPollDraftHandler
},

async autoComplete(search, callback) {
const response = await searchPossibleMentions(this.token, search)
if (!response) {
26 changes: 25 additions & 1 deletion src/components/NewMessage/NewMessagePollEditor.vue
Original file line number Diff line number Diff line change
@@ -12,7 +12,17 @@
<p class="poll-editor__caption">
{{ t('spreed', 'Question') }}
</p>
<NcTextField :value.sync="pollForm.question" :label="t('spreed', 'Ask a question')" v-on="$listeners" />
<div class="poll-editor__wrapper">
<NcTextField :value.sync="pollForm.question" :label="t('spreed', 'Ask a question')" v-on="$listeners" />
<NcActions v-if="supportPollDrafts" force-menu>
<NcActionButton v-if="isModerator" close-after-click @click="openPollDraftHandler">
<template #icon>
<IconFileEdit :size="20" />
</template>
{{ t('spreed', 'Browse poll drafts') }}
</NcActionButton>
</NcActions>
Antreesy marked this conversation as resolved.
Show resolved Hide resolved
</div>

<!-- Poll options -->
<p class="poll-editor__caption">
@@ -89,6 +99,7 @@ import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import { useStore } from '../../composables/useStore.js'
import { POLL } from '../../constants.js'
import { hasTalkFeature } from '../../services/CapabilitiesManager.ts'
import { EventBus } from '../../services/EventBus.js'
import { usePollsStore } from '../../stores/polls.ts'
import type { createPollParams } from '../../types/index.ts'

@@ -174,10 +185,23 @@ async function createPollDraft() {
form: pollForm,
})
}

/**
* Open a PollDraftHandler dialog
*/
function openPollDraftHandler() {
EventBus.emit('poll-drafts-open')
}
</script>

<style lang="scss" scoped>
.poll-editor {
&__wrapper {
display: flex;
align-items: flex-end;
gap: var(--default-grid-baseline);
}

&__caption {
margin: calc(var(--default-grid-baseline) * 2) 0 var(--default-grid-baseline);
font-weight: bold;
79 changes: 79 additions & 0 deletions src/components/PollViewer/PollDraftHandler.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<!--
- SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
- SPDX-License-Identifier: AGPL-3.0-or-later
-->

<template>
<NcDialog class="drafts"
Antreesy marked this conversation as resolved.
Show resolved Hide resolved
:name="t('spreed', 'Poll drafts')"
size="normal"
close-on-click-outside
v-on="$listeners"
@update:open="emit('close')">
<EmptyView v-if="!pollDrafts.length"
class="drafts__empty"
:name="t('spreed', 'No poll drafts')"
:description="t('spreed', 'There is no poll drafts yet saved for this conversation')">
<template #icon>
<IconPoll />
</template>
</EmptyView>
<div v-else class="drafts__wrapper">
<Poll v-for="item in pollDrafts"
:id="item.id.toString()"
:key="item.id"
:token="token"
:name="item.question"
draft />
</div>
</NcDialog>
</template>

<script setup lang="ts">
import { computed } from 'vue'

import IconPoll from 'vue-material-design-icons/Poll.vue'

import { t } from '@nextcloud/l10n'

import NcDialog from '@nextcloud/vue/dist/Components/NcDialog.js'

import EmptyView from '../EmptyView.vue'
import Poll from '../MessagesList/MessagesGroup/Message/MessagePart/Poll.vue'

import { useStore } from '../../composables/useStore.js'
import { usePollsStore } from '../../stores/polls.ts'

const props = defineProps<{
token: string,
}>()
const emit = defineEmits<{
(event: 'close'): void,
}>()

const store = useStore()
const pollsStore = usePollsStore()
/**
* Receive poll drafts for the current conversation as owner/moderator
*/
pollsStore.getPollDrafts(props.token)
const pollDrafts = computed(() => pollsStore.getDrafts(props.token))
</script>

<style lang="scss" scoped>
.drafts {
:deep(.dialog__content) {
min-height: 200px;
}

&__wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: var(--default-grid-baseline);
}

&__empty {
margin: 0 !important;
}
}
</style>
20 changes: 20 additions & 0 deletions src/components/RightSidebar/SharedItems/SharedItemsTab.vue
Original file line number Diff line number Diff line change
@@ -8,6 +8,14 @@
<LoadingComponent v-if="loading" class="shared-items-tab__loading" />

<template v-else>
<NcButton v-if="canCreatePollDrafts"
wide
@click="openPollDraftHandler">
<template #icon>
<IconPoll :size="20" />
</template>
{{ t('spreed', 'Browse poll drafts') }}
</NcButton>
<!-- Shared items grouped by type -->
<template v-for="type in sharedItemsOrder">
<div v-if="sharedItems[type]" :key="type">
@@ -68,6 +76,7 @@
<script>
import DotsHorizontal from 'vue-material-design-icons/DotsHorizontal.vue'
import FolderMultipleImage from 'vue-material-design-icons/FolderMultipleImage.vue'
import IconPoll from 'vue-material-design-icons/Poll.vue'

import { loadState } from '@nextcloud/initial-state'
import { t } from '@nextcloud/l10n'
@@ -88,6 +97,8 @@ import {
sharedItemsWithPreviewLimit,
sharedItemTitle,
} from './sharedItemsConstants.js'
import { hasTalkFeature } from '../../../services/CapabilitiesManager.ts'
import { EventBus } from '../../../services/EventBus.js'
import { useSharedItemsStore } from '../../../stores/sharedItems.js'
import { useSidebarStore } from '../../../stores/sidebar.js'

@@ -98,6 +109,7 @@ export default {
components: {
DotsHorizontal,
FolderMultipleImage,
IconPoll,
LoadingComponent,
NcAppNavigationCaption,
NcButton,
@@ -148,6 +160,10 @@ export default {
return this.$store.getters.conversation(this.token)
},

canCreatePollDrafts() {
return hasTalkFeature(this.token, 'talk-polls-drafts') && this.$store.getters.isModerator
},

loading() {
return !this.sharedItemsStore.overviewLoaded[this.token]
},
@@ -194,6 +210,10 @@ export default {
limit(type) {
return this.sharedItemsWithPreviewLimit.includes(type) ? 2 : 6
},

openPollDraftHandler() {
EventBus.emit('poll-drafts-open')
}
},
}
</script>