feat: Add option to delete message content (#2532)
This commit is contained in:
committed by
GitHub
parent
30832d8a34
commit
2e71006f9d
@@ -43,6 +43,16 @@
|
|||||||
:source-id="data.source_id"
|
:source-id="data.source_id"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<context-menu
|
||||||
|
v-if="isBubble"
|
||||||
|
:is-open="showContextMenu"
|
||||||
|
:show-copy="hasText"
|
||||||
|
:menu-position="contextMenuPosition"
|
||||||
|
@toggle="handleContextMenuClick"
|
||||||
|
@delete="handleDelete"
|
||||||
|
@copy="handleCopy"
|
||||||
|
/>
|
||||||
|
|
||||||
<spinner v-if="isPending" size="tiny" />
|
<spinner v-if="isPending" size="tiny" />
|
||||||
|
|
||||||
<a
|
<a
|
||||||
@@ -65,13 +75,18 @@
|
|||||||
</li>
|
</li>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
import copy from 'copy-text-to-clipboard';
|
||||||
|
|
||||||
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
|
import messageFormatterMixin from 'shared/mixins/messageFormatterMixin';
|
||||||
import timeMixin from '../../../mixins/time';
|
import timeMixin from '../../../mixins/time';
|
||||||
import BubbleText from './bubble/Text';
|
import BubbleText from './bubble/Text';
|
||||||
import BubbleImage from './bubble/Image';
|
import BubbleImage from './bubble/Image';
|
||||||
import BubbleFile from './bubble/File';
|
import BubbleFile from './bubble/File';
|
||||||
import Spinner from 'shared/components/Spinner';
|
import Spinner from 'shared/components/Spinner';
|
||||||
|
import ContextMenu from 'dashboard/modules/conversations/components/MessageContextMenu';
|
||||||
|
|
||||||
import { isEmptyObject } from 'dashboard/helper/commons';
|
import { isEmptyObject } from 'dashboard/helper/commons';
|
||||||
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
import contentTypeMixin from 'shared/mixins/contentTypeMixin';
|
import contentTypeMixin from 'shared/mixins/contentTypeMixin';
|
||||||
import BubbleActions from './bubble/Actions';
|
import BubbleActions from './bubble/Actions';
|
||||||
import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
|
import { MESSAGE_TYPE, MESSAGE_STATUS } from 'shared/constants/messages';
|
||||||
@@ -84,9 +99,10 @@ export default {
|
|||||||
BubbleText,
|
BubbleText,
|
||||||
BubbleImage,
|
BubbleImage,
|
||||||
BubbleFile,
|
BubbleFile,
|
||||||
|
ContextMenu,
|
||||||
Spinner,
|
Spinner,
|
||||||
},
|
},
|
||||||
mixins: [timeMixin, messageFormatterMixin, contentTypeMixin],
|
mixins: [alertMixin, timeMixin, messageFormatterMixin, contentTypeMixin],
|
||||||
props: {
|
props: {
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -97,6 +113,11 @@ export default {
|
|||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showContextMenu: false,
|
||||||
|
};
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
message() {
|
message() {
|
||||||
const botMessageContent = generateBotMessageContent(
|
const botMessageContent = generateBotMessageContent(
|
||||||
@@ -147,10 +168,13 @@ export default {
|
|||||||
},
|
},
|
||||||
alignBubble() {
|
alignBubble() {
|
||||||
const { message_type: messageType } = this.data;
|
const { message_type: messageType } = this.data;
|
||||||
if (messageType === MESSAGE_TYPE.ACTIVITY) {
|
const isCentered = messageType === MESSAGE_TYPE.ACTIVITY;
|
||||||
return 'center';
|
return {
|
||||||
}
|
center: isCentered,
|
||||||
return !messageType ? 'left' : 'right';
|
left: !messageType,
|
||||||
|
right: !!messageType,
|
||||||
|
'has-context-menu': this.showContextMenu,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
readableTime() {
|
readableTime() {
|
||||||
return this.messageStamp(
|
return this.messageStamp(
|
||||||
@@ -210,6 +234,33 @@ export default {
|
|||||||
if (this.isPending) return false;
|
if (this.isPending) return false;
|
||||||
return !this.sender.type || this.sender.type === 'agent_bot';
|
return !this.sender.type || this.sender.type === 'agent_bot';
|
||||||
},
|
},
|
||||||
|
contextMenuPosition() {
|
||||||
|
const { message_type: messageType } = this.data;
|
||||||
|
return messageType ? 'right' : 'left';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleContextMenuClick() {
|
||||||
|
this.showContextMenu = !this.showContextMenu;
|
||||||
|
},
|
||||||
|
async handleDelete() {
|
||||||
|
const { conversation_id: conversationId, id: messageId } = this.data;
|
||||||
|
try {
|
||||||
|
await this.$store.dispatch('deleteMessage', {
|
||||||
|
conversationId,
|
||||||
|
messageId,
|
||||||
|
});
|
||||||
|
this.showAlert(this.$t('CONVERSATION.SUCCESS_DELETE_MESSAGE'));
|
||||||
|
this.showContextMenu = false;
|
||||||
|
} catch (error) {
|
||||||
|
this.showAlert(this.$t('CONVERSATION.FAIL_DELETE_MESSSAGE'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleCopy() {
|
||||||
|
copy(this.data.content);
|
||||||
|
this.showAlert(this.$t('CONTACT_PANEL.COPY_SUCCESSFUL'));
|
||||||
|
this.showContextMenu = false;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -294,4 +345,35 @@ export default {
|
|||||||
margin-left: var(--space-smaller);
|
margin-left: var(--space-smaller);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.button--delete-message {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrap {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.right .wrap {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
|
li.left,
|
||||||
|
li.right {
|
||||||
|
&:hover .button--delete-message {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.has-context-menu {
|
||||||
|
background: var(--color-background);
|
||||||
|
.button--delete-message {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.context-menu {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
"REMOVE_SELECTION": "Remove Selection",
|
"REMOVE_SELECTION": "Remove Selection",
|
||||||
"DOWNLOAD": "Download",
|
"DOWNLOAD": "Download",
|
||||||
"UPLOADING_ATTACHMENTS": "Uploading attachments...",
|
"UPLOADING_ATTACHMENTS": "Uploading attachments...",
|
||||||
|
"SUCCESS_DELETE_MESSAGE": "Message deleted successfully",
|
||||||
|
"FAIL_DELETE_MESSSAGE": "Couldn't delete message! Try again",
|
||||||
"NO_RESPONSE": "No response",
|
"NO_RESPONSE": "No response",
|
||||||
"RATING_TITLE": "Rating",
|
"RATING_TITLE": "Rating",
|
||||||
"FEEDBACK_TITLE": "Feedback",
|
"FEEDBACK_TITLE": "Feedback",
|
||||||
@@ -66,6 +68,10 @@
|
|||||||
"SELECT_AGENT": "Select Agent",
|
"SELECT_AGENT": "Select Agent",
|
||||||
"REMOVE": "Remove",
|
"REMOVE": "Remove",
|
||||||
"ASSIGN": "Assign"
|
"ASSIGN": "Assign"
|
||||||
|
},
|
||||||
|
"CONTEXT_MENU": {
|
||||||
|
"COPY": "Copy",
|
||||||
|
"DELETE": "Delete"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"EMAIL_TRANSCRIPT": {
|
"EMAIL_TRANSCRIPT": {
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
<template>
|
||||||
|
<div class="context-menu">
|
||||||
|
<woot-button
|
||||||
|
icon="ion-more"
|
||||||
|
size="large"
|
||||||
|
class="button--delete-message"
|
||||||
|
color-scheme="secondary"
|
||||||
|
variant="clear"
|
||||||
|
@click="handleContextMenuClick"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="isOpen"
|
||||||
|
v-on-clickaway="handleContextMenuClick"
|
||||||
|
class="dropdown-pane dropdown-pane--open"
|
||||||
|
:class="`dropdown-pane--${menuPosition}`"
|
||||||
|
>
|
||||||
|
<woot-dropdown-menu>
|
||||||
|
<woot-dropdown-item v-if="showCopy">
|
||||||
|
<woot-button
|
||||||
|
variant="clear"
|
||||||
|
size="small"
|
||||||
|
icon="ion-ios-copy-outline"
|
||||||
|
@click="handleCopy"
|
||||||
|
>
|
||||||
|
{{ $t('CONVERSATION.CONTEXT_MENU.COPY') }}
|
||||||
|
</woot-button>
|
||||||
|
</woot-dropdown-item>
|
||||||
|
<woot-dropdown-item>
|
||||||
|
<woot-button
|
||||||
|
variant="clear"
|
||||||
|
color-scheme="alert"
|
||||||
|
size="small"
|
||||||
|
icon="ion-trash-a"
|
||||||
|
@click="handleDelete"
|
||||||
|
>
|
||||||
|
{{ $t('CONVERSATION.CONTEXT_MENU.DELETE') }}
|
||||||
|
</woot-button>
|
||||||
|
</woot-dropdown-item>
|
||||||
|
</woot-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
|
|
||||||
|
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem';
|
||||||
|
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
WootDropdownMenu,
|
||||||
|
WootDropdownItem,
|
||||||
|
},
|
||||||
|
mixins: [clickaway],
|
||||||
|
props: {
|
||||||
|
isOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
showCopy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
menuPosition: {
|
||||||
|
type: String,
|
||||||
|
default: 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handleContextMenuClick() {
|
||||||
|
this.$emit('toggle', !this.isOpen);
|
||||||
|
},
|
||||||
|
handleCopy() {
|
||||||
|
this.$emit('copy');
|
||||||
|
},
|
||||||
|
handleDelete() {
|
||||||
|
this.$emit('delete');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
/* TDOD: Remove once MenuComponent supports postions */
|
||||||
|
.dropdown-pane {
|
||||||
|
bottom: var(--space-large);
|
||||||
|
}
|
||||||
|
.dropdown-pane--left {
|
||||||
|
right: var(--space-small);
|
||||||
|
}
|
||||||
|
.dropdown-pane--right {
|
||||||
|
left: var(--space-small);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user