Skip to content

Commit

Permalink
Implement undo for send now action in outbox message list
Browse files Browse the repository at this point in the history
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
  • Loading branch information
st3iny authored and ChristophWurst committed May 2, 2022
1 parent 8e75eb5 commit d778791
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 41 deletions.
36 changes: 5 additions & 31 deletions src/components/NewMessageModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import logger from '../logger'
import { toPlain } from '../util/text'
import { saveDraft } from '../service/MessageService'
import Composer from './Composer'
import { showError, showSuccess, showUndo } from '@nextcloud/dialogs'
import { showError, showSuccess } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import { UNDO_DELAY } from '../store/constants'
Expand Down Expand Up @@ -127,46 +127,20 @@ export default {
dataForServer.sendAt = Math.floor((now + UNDO_DELAY) / 1000)
}
let message
if (!this.composerData.id) {
message = await this.$store.dispatch('outbox/enqueueMessage', {
await this.$store.dispatch('outbox/enqueueMessage', {
message: dataForServer,
})
} else {
message = await this.$store.dispatch('outbox/updateMessage', {
await this.$store.dispatch('outbox/updateMessage', {
message: dataForServer,
id: this.composerData.id,
})
}
if (!data.sendAt || data.sendAt < Math.floor((now + UNDO_DELAY) / 1000)) {
showUndo(
t('mail', 'Message sent'),
async() => {
logger.info('Attempting to stop sending message ' + message.id)
const stopped = await this.$store.dispatch('outbox/stopMessage', { message })
logger.info('Message ' + message.id + ' stopped', { message: stopped })
await this.$store.dispatch('showMessageComposer', {
type: 'outbox',
data: {
...message, // For id and other properties
...data, // For the correct body values
},
})
}, {
timeout: UNDO_DELAY,
close: true,
}
)
setTimeout(() => {
try {
this.$store.dispatch('outbox/sendMessage', { id: message.id })
} catch (error) {
showError(t('mail', 'Could not send message'))
logger.error('Could not delay-send message ' + message.id, { message })
}
}, UNDO_DELAY)
// Awaiting here would keep the modal open for a long time and thus block the user
this.$store.dispatch('outbox/sendMessageWithUndo', { id: this.composerData.id })
}
if (data.draftId) {
// Remove old draft envelope
Expand Down
16 changes: 8 additions & 8 deletions src/components/OutboxMessageListItem.vue
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
<ActionButton
icon="icon-checkmark"
:close-after-click="true"
@click="sendMessage">
@click="sendMessageNow">
{{ t('mail', 'Send now') }}
<template #icon>
<Send
Expand Down Expand Up @@ -71,6 +71,7 @@ import { showError, showSuccess } from '@nextcloud/dialogs'
import { matchError } from '../errors/match'
import { html, plain } from '../util/text'
import Send from 'vue-material-design-icons/Send'
import { UNDO_DELAY } from '../store/constants'
export default {
name: 'OutboxMessageListItem',
Expand Down Expand Up @@ -128,14 +129,13 @@ export default {
}))
}
},
async sendMessage(data) {
logger.debug('sending message', { data })
try {
await this.$store.dispatch('outbox/sendMessage', { id: this.message.id, force: true })
showSuccess(t('mail', 'Message sent'))
} catch (error) {
showError(t('mail', 'Could not send message'))
async sendMessageNow() {
const message = {
...this.message,
sendAt: (new Date().getTime() + UNDO_DELAY) / 1000,
}
await this.$store.dispatch('outbox/updateMessage', { message, id: message.id })
await this.$store.dispatch('outbox/sendMessageWithUndo', { id: message.id })
},
async openModal() {
await this.$store.dispatch('showMessageComposer', {
Expand Down
66 changes: 64 additions & 2 deletions src/store/outbox/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@

import * as OutboxService from '../../service/OutboxService'
import logger from '../../logger'
import { showError, showUndo } from '@nextcloud/dialogs'
import { translate as t } from '@nextcloud/l10n'
import { UNDO_DELAY } from '../constants'
import { html, plain } from '../../util/text'

export default {
async fetchMessages({ getters, commit }) {
Expand Down Expand Up @@ -87,18 +90,29 @@ export default {
return updatedMessage
},

/**
* Send an outbox message right now.
*
* @param {object} store Vuex destructuring object
* @param {function} store.commit Vuex commit object
* @param {object} store.getters Vuex getters object
* @param {object} data Action data
* @param {number} data.id Id of outbox message to send
* @param {boolean} data.force Force sending a message even if it has no sendAt timestamp
* @returns {Promise<boolean>} Resolves to false if sending was skipped
*/
async sendMessage({ commit, getters }, { id, force = false }) {
// Skip if the message has been deleted/undone in the meantime
const message = getters.getMessage(id)
logger.debug('Sending message ' + id, { message, force })
if (!force && (!message || !message.sendAt)) {
logger.debug('Skipped sending message that was undone')
return
return false
}

if (message.sendAt * 1000 > new Date().getTime() + UNDO_DELAY) {
logger.debug('Skipped sending message that is scheduled for the future')
return
return false
}

try {
Expand All @@ -110,5 +124,53 @@ export default {
}

commit('deleteMessage', { id })
return true
},

/**
* Wait for UNDO_DELAY before sending the message and show a toast with an undo action.
*
* @param {object} store Vuex destructuring object
* @param {function} store.dispatch Vuex dispatch object
* @param {object} store.getters Vuex getters object
* @param {object} data Action data
* @param {number} data.id Id of outbox message to send
* @returns {Promise<boolean>} Resolves to false if sending was skipped. Resolves after UNDO_DELAY has elapsed and the message dispatch was triggered. Warning: This might take a long time, depending on UNDO_DELAY.
*/
async sendMessageWithUndo({ getters, dispatch }, { id }) {
return new Promise((resolve, reject) => {
const message = getters.getMessage(id)

showUndo(
t('mail', 'Message sent'),
async() => {
logger.info('Attempting to stop sending message ' + message.id)
const stopped = await dispatch('stopMessage', { message })
logger.info('Message ' + message.id + ' stopped', { message: stopped })
await dispatch('showMessageComposer', {
type: 'outbox',
data: {
...message,
// The composer expects rich body data and not just a string
body: message.isHtml ? html(message.body) : plain(message.body),
},
}, { root: true })
}, {
timeout: UNDO_DELAY,
close: true,
}
)

setTimeout(async() => {
try {
const wasSent = await dispatch('sendMessage', { id: message.id })
resolve(wasSent)
} catch (error) {
showError(t('mail', 'Could not send message'))
logger.error('Could not delay-send message ' + message.id, { message })
reject(error)
}
}, UNDO_DELAY)
})
},
}

0 comments on commit d778791

Please sign in to comment.