diff options
author | dartcafe <github@dartcafe.de> | 2021-03-04 01:44:24 +0300 |
---|---|---|
committer | dartcafe <github@dartcafe.de> | 2021-03-04 01:44:24 +0300 |
commit | ff07d8d8c438442c9d3beb51ea1dd91b54af36ed (patch) | |
tree | 4972683acc7e670668438f46cb2ffcf278701e07 /src/js/components/Base | |
parent | 5246479c3059edc8e42f7ef08d154909a5a66daf (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.vue | 85 | ||||
-rw-r--r-- | src/js/components/Base/PollInformation.vue | 25 | ||||
-rw-r--r-- | src/js/components/Base/UserItem.vue | 5 | ||||
-rw-r--r-- | src/js/components/Base/UserMenu.vue | 271 |
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> |