Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/polls.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordartcafe <github@dartcafe.de>2021-03-04 01:44:24 +0300
committerdartcafe <github@dartcafe.de>2021-03-04 01:44:24 +0300
commitff07d8d8c438442c9d3beb51ea1dd91b54af36ed (patch)
tree4972683acc7e670668438f46cb2ffcf278701e07 /src/js/components/Base
parent5246479c3059edc8e42f7ef08d154909a5a66daf (diff)
Move actions to usermenu
Signed-off-by: dartcafe <github@dartcafe.de>
Diffstat (limited to 'src/js/components/Base')
-rw-r--r--src/js/components/Base/PersonalLink.vue85
-rw-r--r--src/js/components/Base/PollInformation.vue25
-rw-r--r--src/js/components/Base/UserItem.vue5
-rw-r--r--src/js/components/Base/UserMenu.vue271
4 files changed, 301 insertions, 85 deletions
diff --git a/src/js/components/Base/PersonalLink.vue b/src/js/components/Base/PersonalLink.vue
deleted file mode 100644
index 628eaceb..00000000
--- a/src/js/components/Base/PersonalLink.vue
+++ /dev/null
@@ -1,85 +0,0 @@
-<!--
- - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de>
- -
- - @author René Gieling <github@dartcafe.de>
- -
- - @license GNU AGPL version 3 or any later version
- -
- - This program is free software: you can redistribute it and/or modify
- - it under the terms of the GNU Affero General Public License as
- - published by the Free Software Foundation, either version 3 of the
- - License, or (at your option) any later version.
- -
- - This program is distributed in the hope that it will be useful,
- - but WITHOUT ANY WARRANTY; without even the implied warranty of
- - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - GNU Affero General Public License for more details.
- -
- - You should have received a copy of the GNU Affero General Public License
- - along with this program. If not, see <http://www.gnu.org/licenses/>.
- -
- -->
-
-<template>
- <div v-show="share.type !== 'public'">
- <h2 class="title">
- {{ t('polls', 'This is a public poll.') }}
- </h2>
- <p>{{ t('polls', 'The following link is your personal access to this poll. You can reenter this poll at any time, change your vote and leave comments.') }}</p>
- <p>{{ t('polls', 'Your personal link to this poll: {linkURL}', { linkURL: personalLink} ) }}</p>
- <ButtonDiv icon="icon-clippy" :title="t('polls','Copy this link to the clipboard')" @click="copyLink()" />
- <ButtonDiv v-if="share.emailAddress"
- icon="icon-mail"
- :title="t('polls','Resend invitation mail to {emailAdress}', { emailAdress: share.emailAddress })"
- @click="resendInvitation()" />
- </div>
-</template>
-
-<script>
-import ButtonDiv from '../Base/ButtonDiv'
-import { showSuccess, showError } from '@nextcloud/dialogs'
-import { mapState } from 'vuex'
-
-export default {
- name: 'PersonalLink',
-
- components: {
- ButtonDiv,
- },
-
- computed: {
- ...mapState({
- share: state => state.share,
- }),
-
- personalLink() {
- return window.location.origin
- + this.$router.resolve({
- name: 'publicVote',
- params: { token: this.$route.params.token },
- }).href
- },
-
- },
-
- methods: {
- async resendInvitation() {
- try {
- const response = await this.$store.dispatch('share/resendInvitation')
- showSuccess(t('polls', 'Invitation resent to {emailAddress}', { emailAddress: response.data.share.emailAddress }))
- } catch {
- showError(t('polls', 'Mail could not be resent to {emailAddress}', { emailAddress: this.share.emailAddress }))
- }
- },
-
- async copyLink() {
- try {
- await this.$copyText(this.personalLink)
- showSuccess(t('polls', 'Link copied to clipboard'))
- } catch {
- showError(t('polls', 'Error while copying link to clipboard'))
- }
- },
- },
-}
-</script>
diff --git a/src/js/components/Base/PollInformation.vue b/src/js/components/Base/PollInformation.vue
index a332dad2..d08d39c2 100644
--- a/src/js/components/Base/PollInformation.vue
+++ b/src/js/components/Base/PollInformation.vue
@@ -42,6 +42,9 @@
<div v-if="poll.anonymous" class="anonymous">
{{ t('polls', 'Anonymous poll') }}
</div>
+ <div v-if="participantsVoted.length && acl.allowSeeResults" class="participants">
+ {{ n('polls', '%n Participant', '%n Participants', participantsVoted.length) }}
+ </div>
<div class="timezone">
{{ t('polls', 'Time zone: ') }} {{ currentTimeZone }}
</div>
@@ -51,6 +54,12 @@
<div v-if="poll.optionLimit" class="option-limit">
{{ n('polls', 'Only %n vote per option.', 'Only %n votes per option.', poll.optionLimit) }}
</div>
+ <div v-if="$route.name === 'publicVote' && share.emailAddress" class="email-address">
+ {{ share.emailAddress }}
+ </div>
+ <div v-if="subscribed" class="subscribed">
+ {{ t('polls', 'You subscribed to this poll') }}
+ </div>
</div>
</Popover>
</template>
@@ -72,8 +81,10 @@ export default {
computed: {
...mapState({
+ share: state => state.share,
acl: state => state.poll.acl,
poll: state => state.poll,
+ subscribed: state => state.subscription.subscribed,
}),
...mapGetters({
@@ -98,6 +109,7 @@ export default {
dateExpiryString() {
return moment.unix(this.poll.expire).format('LLLL')
},
+
dateExpiryRelative() {
return moment.unix(this.poll.expire).fromNow()
},
@@ -139,12 +151,25 @@ export default {
background-image: var(--icon-clock);
}
+ .participants {
+ background-image: var(--icon-user-000);
+ }
+
+ .subscribed {
+ background-image: var(--icon-polls-confirmed);
+ }
+
.vote-limit {
background-image: var(--icon-checkmark-000);
}
+
.option-limit {
background-image: var(--icon-close-000);
}
+
+ .email-address {
+ background-image: var(--icon-mail-000);
+ }
}
</style>
diff --git a/src/js/components/Base/UserItem.vue b/src/js/components/Base/UserItem.vue
index bdf7bd29..164c2857 100644
--- a/src/js/components/Base/UserItem.vue
+++ b/src/js/components/Base/UserItem.vue
@@ -23,6 +23,7 @@
<template>
<div class="user-item" :class="type">
<Avatar :disable-menu="disableMenu"
+ :disable-tooltip="disableTooltip"
class="user-item__avatar"
:is-guest="$route.name === 'publicVote'"
:menu-position="menuPosition"
@@ -62,6 +63,10 @@ export default {
type: Boolean,
default: true,
},
+ disableTooltip: {
+ type: Boolean,
+ default: true,
+ },
menuPosition: {
type: String,
default: 'left',
diff --git a/src/js/components/Base/UserMenu.vue b/src/js/components/Base/UserMenu.vue
new file mode 100644
index 00000000..3c8ea306
--- /dev/null
+++ b/src/js/components/Base/UserMenu.vue
@@ -0,0 +1,271 @@
+<!--
+ - @copyright Copyright (c) 2018 René Gieling <github@dartcafe.de>
+ -
+ - @author René Gieling <github@dartcafe.de>
+ -
+ - @license GNU AGPL version 3 or any later version
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+ -->
+
+<template>
+ <Actions>
+ <ActionButton v-if="$route.name === 'publicVote'" icon="icon-clippy" @click="copyLink()">
+ {{ t('polls', 'Copy your personal link to clipboard') }}
+ </ActionButton>
+ <ActionSeparator />
+ <ActionButton v-if="$route.name === 'publicVote'"
+ :value="emailAddress"
+ icon="icon-share"
+ @click="resendInvitation()">
+ {{ t('polls', 'Get your personal link per mail') }}
+ </ActionButton>
+ <ActionCheckbox :checked="subscribed" :disabled="!acl.allowSubscribe" title="check"
+ @change="switchSubscription">
+ {{ t('polls', 'Subscribe to notifications') }}
+ </ActionCheckbox>
+ <ActionButton v-if="$route.name === 'publicVote'"
+ :disabled="!emailAddress"
+ icon="icon-delete"
+ @click="deleteEmailAddress">
+ {{ t('polls', 'remove Email Address') }}
+ </ActionButton>
+ <ActionInput v-if="$route.name === 'publicVote'" icon="icon-edit" :class="check.status"
+ :value="emailAddressTemp"
+ @click="deleteEmailAddress"
+ @update:value="validateEmailAddress"
+ @submit="submitEmailAddress">
+ {{ t('polls', 'edit Email Address') }}
+ </ActionInput>
+ <ActionText v-if="$route.name === 'publicVote'" icon="icon-mail" :title="emailAddressCheck.title">
+ {{ emailAddressCheck.text }}
+ </ActionText>
+ <ActionButton v-if="acl.allowEdit" icon="icon-clippy" @click="getAddresses()">
+ {{ t('polls', 'Copy list of email addresses to clipboard') }}
+ </ActionButton>
+ </Actions>
+</template>
+
+<script>
+import debounce from 'lodash/debounce'
+import axios from '@nextcloud/axios'
+import { showSuccess, showError } from '@nextcloud/dialogs'
+import { generateUrl } from '@nextcloud/router'
+import { Actions, ActionButton, ActionCheckbox, ActionInput, ActionSeparator, ActionText } from '@nextcloud/vue'
+import { mapState } from 'vuex'
+
+export default {
+ name: 'UserMenu',
+
+ components: {
+ Actions,
+ ActionButton,
+ ActionCheckbox,
+ ActionInput,
+ ActionSeparator,
+ ActionText,
+ },
+
+ data() {
+ return {
+ emailAddressTemp: '',
+ checkResult: '',
+ checkStatus: '',
+ checking: false,
+ }
+ },
+
+ computed: {
+ ...mapState({
+ acl: state => state.poll.acl,
+ share: state => state.share,
+ subscribed: state => state.subscription.subscribed,
+ emailAddress: state => state.share.emailAddress,
+ }),
+
+ emailAddressUnchanged() {
+ return this.emailAddress === this.emailAddressTemp
+ },
+
+ check() {
+ if (this.checking) {
+ return {
+ result: t('polls', 'Checking email address …'),
+ status: 'checking',
+ }
+ } else if (this.emailAddressUnchanged) {
+ return {
+ result: '',
+ status: '',
+ }
+ } else {
+ return {
+ result: this.checkResult,
+ status: this.checkStatus,
+ }
+ }
+ },
+
+ emailAddressCheck() {
+ if (this.emailAddress) {
+ return {
+ title: t('polls', 'Notifications will be'),
+ text: t('polls', 'sent to {emailAddress}', { emailAddress: this.emailAddress }),
+ }
+ } else {
+ return {
+ title: t('polls', 'Add your email Address, '),
+ text: t('polls', 'if you want to subscribe or receive your personal link via email.'),
+ }
+ }
+ },
+
+ personalLink() {
+ return window.location.origin
+ + this.$router.resolve({
+ name: 'publicVote',
+ params: { token: this.$route.params.token },
+ }).href
+ },
+ },
+
+ watch: {
+ emailAddress: function() {
+ this.emailAddressTemp = this.emailAddress
+ },
+ },
+
+ created() {
+ this.emailAddressTemp = this.emailAddress
+ },
+
+ methods: {
+ async switchSubscription() {
+ await this.$store.dispatch('subscription/update', !this.subscribed)
+ },
+
+ async deleteEmailAddress() {
+ try {
+ await this.$store.dispatch('share/deleteEmailAddress')
+ showSuccess(t('polls', 'Email address deleted.'))
+ } catch {
+ showError(t('polls', 'Error deleting email address {emailAddress}', { emailAddress: this.emailAddressTemp }))
+ }
+ },
+
+ validateEmailAddress: debounce(async function(value) {
+ this.emailAddressTemp = value
+ try {
+ this.checking = true
+ await axios.get(generateUrl('apps/polls/check/emailaddress') + '/' + this.emailAddressTemp)
+ this.checkResult = t('polls', 'valid email address.')
+ this.checkStatus = 'success'
+ } catch {
+ this.checkResult = t('polls', 'Invalid email address.')
+ this.checkStatus = 'error'
+ } finally {
+ this.checking = false
+ }
+ }, 500),
+
+ async submitEmailAddress() {
+ try {
+ await this.$store.dispatch('share/updateEmailAddress', { emailAddress: this.emailAddressTemp })
+ showSuccess(t('polls', 'Email address {emailAddress} saved.', { emailAddress: this.emailAddressTemp }))
+ } catch {
+ showError(t('polls', 'Error saving email address {emailAddress}', { emailAddress: this.emailAddressTemp }))
+ }
+ },
+
+ async resendInvitation() {
+ try {
+ const response = await this.$store.dispatch('share/resendInvitation')
+ showSuccess(t('polls', 'Invitation resent to {emailAddress}', { emailAddress: response.data.share.emailAddress }))
+ } catch {
+ showError(t('polls', 'Mail could not be resent to {emailAddress}', { emailAddress: this.share.emailAddress }))
+ }
+ },
+
+ async copyLink() {
+ try {
+ await this.$copyText(this.personalLink)
+ showSuccess(t('polls', 'Link copied to clipboard'))
+ } catch {
+ showError(t('polls', 'Error while copying link to clipboard'))
+ }
+ },
+ async getAddresses() {
+ try {
+ const response = await this.$store.dispatch('poll/getParticipantsEmailAddresses')
+ await this.$copyText(response.data)
+ showSuccess(t('polls', 'Link copied to clipboard'))
+ } catch {
+ showError(t('polls', 'Error while copying link to clipboard'))
+ }
+ },
+ },
+}
+</script>
+
+<style lang="scss">
+ .action {
+ input.action-input__input {
+ background-repeat: no-repeat;
+ background-position: right 12px center;
+ &:empty:before {
+ color: grey;
+ }
+ }
+
+ &.error {
+ input.action-input__input, label.action-input__label {
+ border-color: var(--color-error);
+ background-color: var(--color-background-error);
+ color: var(--color-foreground-error);
+ }
+ input.action-input__input {
+ background-image: var(--icon-polls-no);
+ }
+ label.action-input__label {
+ cursor: not-allowed;
+ }
+ }
+
+ &.checking input.action-input__input {
+ border-color: var(--color-warning);
+ background-image: var(--icon-polls-loading);
+ }
+
+ &.success {
+ input.action-input__input, label.action-input__label {
+ border-color: var(--color-success);
+ background-color: var(--color-background-success) !important;
+ color: var(--color-foreground-success);
+ }
+ input.action-input__input {
+ background-image: var(--icon-polls-yes);
+ }
+ }
+
+ &.success input.action-input__input , &.icon-confirm.success input.action-input__input {
+ border-color: var(--color-success);
+ background-image: var(--icon-polls-yes);
+ background-color: var(--color-background-success) !important;
+ color: var(--color-foreground-success);
+ }
+
+ }
+
+</style>