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

Fix confirmation mails and move CTAs #3110

Merged
merged 4 commits into from
Oct 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ All notable changes to this project will be documented in this file.
- Fixed granting admin rights to shares
- Fixed a bug, where exports were prevented
- Fixed a visually bug when using Nextcloud's Dark Mode
- Fixed result reporting about sent and failed confirmation mails
### New
- Reveal hidden voters if hidden in case of performance concerns
- Support better readability of vote page
- Added locking of shares
- Shares can now be locked which works as a read only share mechanism. Locked shares can still enter the poll, but every interaction (voting and commenting) is disabled.
- Deletion of locked shares deletes the users votes as well
- Moved request for option proposals to a card on top of the vote page
- Moved CTA for confirmation mails to card on top of the vote page
- Added a card with a more prominent hint for closed polls

### Changes
- Improved username check for public polls with a large number of groups in the backend
## [5.3.2] - 2023-09-11
Expand Down
22 changes: 5 additions & 17 deletions lib/Service/MailService.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,14 @@ public function sendConfirmations(int $pollId): SentResult {

foreach ($participants as $participant) {
try {
$this->sendConfirmationMail($sentResult, $participant, $pollId);
$this->sendConfirmationMail($participant, $pollId);
$sentResult->AddSentMail($participant);
} catch (InvalidEmailAddress $e) {
$sentResult->AddAbortedMail($participant, SentResult::INVALID_EMAIL_ADDRESS);
$this->logger->warning('Invalid or no email address for confirmation: ' . json_encode($participant));
$sentResult->AddAbortedMail($participant, SentResult::INVALID_EMAIL_ADDRESS);
} catch (\Exception $e) {
$sentResult->AddAbortedMail($participant);
$this->logger->error('Error sending confirmation to ' . json_encode($participant));
$sentResult->AddAbortedMail($participant);
}
}

Expand All @@ -179,21 +179,9 @@ private function processSharesForAutoReminder(Poll $poll): void {
}
}

private function sendConfirmationMail(SentResult &$sentResult, UserBase $participant, int $pollId) : SentResult {
private function sendConfirmationMail(UserBase $participant, int $pollId): void {
$confirmation = new ConfirmationMail($participant->getId(), $pollId);

try {
$confirmation->send();
$sentResult->AddSentMail($participant);
} catch (InvalidEmailAddress $e) {
$sentResult->AddAbortedMail($participant, SentResult::INVALID_EMAIL_ADDRESS);
$this->logger->warning('Invalid or no email address for confirmation: ' . json_encode($participant));
} catch (\Exception $e) {
$sentResult->AddAbortedMail($participant);
$this->logger->error('Error sending confirmation to ' . json_encode($participant));
}

return $sentResult;
$confirmation->send();
}

private function sendAutoReminderToRecipients(Share $share, Poll $poll): void {
Expand Down
2 changes: 1 addition & 1 deletion src/js/components/Actions/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export { default as ActionChangeView } from './modules/ActionChangeView.vue'
export { default as ActionDelete } from './modules/ActionDelete.vue'
export { default as ActionSendConfirmedOptions } from './modules/ActionSendConfirmedOptions.vue'
export { default as ActionSendConfirmed } from './modules/ActionSendConfirmed.vue'
export { default as ActionSortOptions } from './modules/ActionSortOptions.vue'
export { default as ActionToggleSidebar } from './modules/ActionToggleSidebar.vue'
113 changes: 113 additions & 0 deletions src/js/components/Actions/modules/ActionSendConfirmed.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<!--
- @copyright Copyright (c) 2021 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 class="action send-confirmations">
<NcButton v-tooltip="sendButtonCaption"
type="primary"
:aria-label="sendButtonCaption"
:disabled="disableButton"
@click="clickAction()">
<template #icon>
<EmailCheckIcon />
</template>
<template #default>
{{ t('polls', 'Send confirmation emails') }}
</template>
</NcButton>

<NcModal :show.sync="showModal"
:title="t('polls', 'Result of sent confirmation mails')"
size="small">
<div class="modal-confirmation-result">
<div v-if="confirmations?.countSentMails > 0" class="sent-confirmations">
<h2>{{ n('polls', '%n confirmation has been sent', '%n confirmations have been sent', confirmations.countSentMails) }}</h2>
<ul>
<li v-for="(item) in confirmations.sentMails" :key="item.displayName">
{{ item.displayName }} &lt;{{ item.emailAddress }}&gt;
</li>
</ul>
</div>
<div v-if="confirmations?.countAbortedMails > 0" class="error-confirmations">
<h2>{{ n('polls', '%n confirmation could not be sent', '%n confirmations could not be sent:', confirmations.countAbortedMails) }}</h2>
<ul>
<li v-for="(item) in confirmations.abortedMails" :key="item.displayName">
{{ item.displayName }} ({{ item.reason === 'InvalidMail' ? t('polls', 'No valid email address') : t('polls', 'Unknown error') }})
</li>
</ul>
</div>
</div>
</NcModal>
</div>
</template>

<script>
import { NcButton, NcModal } from '@nextcloud/vue'
import EmailCheckIcon from 'vue-material-design-icons/EmailCheck.vue' // view-comfy-outline
import { PollsAPI } from '../../../Api/index.js'

export default {
name: 'ActionSendConfirmed',

components: {
EmailCheckIcon,
NcButton,
NcModal,
},

data() {
return {
showModal: false,
sendButtonCaption: t('polls', 'Send information about confirmed options by email'),
confirmations: null,
disableButton: false,
}
},

methods: {
async clickAction() {
try {
this.disableButton = true
const result = await PollsAPI.sendConfirmation(this.$route.params.id)
this.disableButton = false
this.confirmations = result.data.confirmations
this.showModal = true
} catch (e) {
console.error(e)
}
},
},
}
</script>

<style lang="scss">
.modal-confirmation-result {
padding: 24px;
ul {
list-style: initial;
}

.sent-confirmations, .error-confirmations {
padding: 12px;
}
}
</style>
128 changes: 0 additions & 128 deletions src/js/components/Actions/modules/ActionSendConfirmedOptions.vue

This file was deleted.

33 changes: 23 additions & 10 deletions src/js/views/Vote.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,28 @@
</template>
</CardDiv>

<CardDiv v-if="closed" type="warning">
<CardDiv v-if="acl.allowAddOptions && proposalsOpen && !closed" type="success">
{{ t('polls', 'You are asked to propose more options. ') }}
<p v-if="proposalsExpirySet && !proposalsExpired">
{{ t('polls', 'The proposal period ends {timeRelative}.', { timeRelative: proposalsExpireRelative }) }}
</p>
<OptionProposals v-if="poll.type === 'textPoll'" />
<template #button>
<OptionProposals v-if="poll.type === 'datePoll'" />
</template>
</CardDiv>

<CardDiv v-if="closed && !showConfirmationMail" type="warning">
{{ t('polls', 'This poll is closed. No further action is possible.') }}
</CardDiv>

<CardDiv v-else-if="showConfirmationMail" type="success">
{{ t('polls', 'You have confirmed options. Inform your participants about the result via email.') }}
<template #button>
<ActionSendConfirmed />
</template>
</CardDiv>

<CardDiv v-else-if="share.locked" type="warning">
{{ lockedShareCardCaption }}
</CardDiv>
Expand All @@ -55,13 +73,6 @@
<MarkUpDescription />
</div>

<div v-if="acl.allowAddOptions && proposalsOpen && !closed" class="area__proposal">
<OptionProposals />
</div>
<div v-if="showConfirmationMail" class="area__confirmation">
<ActionSendConfirmedOptions />
</div>

<div class="area__main" :class="viewMode">
<VoteTable v-show="options.length" :view-mode="viewMode" />

Expand Down Expand Up @@ -115,12 +126,12 @@ import PollHeaderButtons from '../components/Poll/PollHeaderButtons.vue'
import { CardDiv, HeaderBar } from '../components/Base/index.js'
import DatePollIcon from 'vue-material-design-icons/CalendarBlank.vue'
import TextPollIcon from 'vue-material-design-icons/FormatListBulletedSquare.vue'
import { ActionSendConfirmedOptions } from '../components/Actions/index.js'
import { ActionSendConfirmed } from '../components/Actions/index.js'

export default {
name: 'Vote',
components: {
ActionSendConfirmedOptions,
ActionSendConfirmed,
NcAppContent,
NcButton,
NcEmptyContent,
Expand Down Expand Up @@ -159,6 +170,8 @@ export default {
viewMode: 'poll/viewMode',
proposalsAllowed: 'poll/proposalsAllowed',
proposalsOpen: 'poll/proposalsOpen',
proposalsExpirySet: 'poll/proposalsExpirySet',
proposalsExpireRelative: 'poll/proposalsExpireRelative',
countHiddenParticipants: 'poll/countHiddenParticipants',
safeTable: 'poll/safeTable',
confirmedOptions: 'options/confirmed',
Expand Down