feat: Add a dropdown to change status to "bot" (#1997)
This commit is contained in:
parent
7a890e543a
commit
7c9cd8aa1e
6 changed files with 129 additions and 54 deletions
|
@ -28,8 +28,10 @@ class ConversationApi extends ApiClient {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleStatus(conversationId) {
|
toggleStatus({ conversationId, status }) {
|
||||||
return axios.post(`${this.url}/${conversationId}/toggle_status`, {});
|
return axios.post(`${this.url}/${conversationId}/toggle_status`, {
|
||||||
|
status,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
assignAgent({ conversationId, agentId }) {
|
assignAgent({ conversationId, agentId }) {
|
||||||
|
|
|
@ -8,12 +8,6 @@ $resolve-button-width: 13.2rem;
|
||||||
@include flex-align($x: justify, $y: middle);
|
@include flex-align($x: justify, $y: middle);
|
||||||
@include border-normal-bottom;
|
@include border-normal-bottom;
|
||||||
|
|
||||||
// Resolve Button
|
|
||||||
.button {
|
|
||||||
@include margin(0);
|
|
||||||
@include flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.multiselect-box {
|
.multiselect-box {
|
||||||
@include flex;
|
@include flex;
|
||||||
@include flex-align($x: justify, $y: middle);
|
@include flex-align($x: justify, $y: middle);
|
||||||
|
@ -66,26 +60,6 @@ $resolve-button-width: 13.2rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.resolve--button {
|
|
||||||
@include flex-align($x: center, $y: middle);
|
|
||||||
font-size: var(--font-size-default);
|
|
||||||
width: $resolve-button-width;
|
|
||||||
|
|
||||||
>.icon {
|
|
||||||
font-size: $font-size-default;
|
|
||||||
padding-right: $space-small;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner {
|
|
||||||
margin-right: $space-smaller;
|
|
||||||
padding: 0 $space-one;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
border-top-color: $color-white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.header-actions-wrap {
|
.header-actions-wrap {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -1,29 +1,86 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<div class="resolve-actions">
|
||||||
type="button"
|
<div class="button-group">
|
||||||
class="button resolve--button"
|
<woot-button
|
||||||
:class="buttonClass"
|
v-if="isOpen"
|
||||||
@click="toggleStatus"
|
class-names="resolve"
|
||||||
|
color-scheme="success"
|
||||||
|
icon="ion-checkmark"
|
||||||
|
:is-loading="isLoading"
|
||||||
|
@click="() => toggleStatus(STATUS_TYPE.RESOLVED)"
|
||||||
>
|
>
|
||||||
<i v-if="!isLoading" class="icon" :class="buttonIconClass" />
|
{{ this.$t('CONVERSATION.HEADER.RESOLVE_ACTION') }}
|
||||||
<spinner v-if="isLoading" />
|
</woot-button>
|
||||||
{{ currentStatus }}
|
<woot-button
|
||||||
</button>
|
v-else-if="isResolved"
|
||||||
|
class-names="resolve"
|
||||||
|
color-scheme="warning"
|
||||||
|
icon="ion-refresh"
|
||||||
|
:is-loading="isLoading"
|
||||||
|
@click="() => toggleStatus(STATUS_TYPE.OPEN)"
|
||||||
|
>
|
||||||
|
{{ this.$t('CONVERSATION.HEADER.REOPEN_ACTION') }}
|
||||||
|
</woot-button>
|
||||||
|
<woot-button
|
||||||
|
v-else-if="isBot"
|
||||||
|
class-names="resolve"
|
||||||
|
color-scheme="primary"
|
||||||
|
icon="ion-person"
|
||||||
|
:is-loading="isLoading"
|
||||||
|
@click="() => toggleStatus(STATUS_TYPE.OPEN)"
|
||||||
|
>
|
||||||
|
{{ this.$t('CONVERSATION.HEADER.OPEN_ACTION') }}
|
||||||
|
</woot-button>
|
||||||
|
<woot-button
|
||||||
|
v-if="showDropDown"
|
||||||
|
class="icon--small"
|
||||||
|
:color-scheme="buttonClass"
|
||||||
|
:disabled="isLoading"
|
||||||
|
icon="ion-arrow-down-b"
|
||||||
|
@click="openDropdown"
|
||||||
|
>
|
||||||
|
</woot-button>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="showDropdown"
|
||||||
|
v-on-clickaway="closeDropdown"
|
||||||
|
class="dropdown-pane dropdown-pane--open"
|
||||||
|
>
|
||||||
|
<woot-dropdown-menu>
|
||||||
|
<woot-dropdown-item v-if="!isBot">
|
||||||
|
<woot-button
|
||||||
|
variant="clear"
|
||||||
|
@click="() => toggleStatus(STATUS_TYPE.BOT)"
|
||||||
|
>
|
||||||
|
{{ this.$t('CONVERSATION.RESOLVE_DROPDOWN.OPEN_BOT') }}
|
||||||
|
</woot-button>
|
||||||
|
</woot-dropdown-item>
|
||||||
|
</woot-dropdown-menu>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { mapGetters } from 'vuex';
|
import { mapGetters } from 'vuex';
|
||||||
import Spinner from 'shared/components/Spinner';
|
import { mixin as clickaway } from 'vue-clickaway';
|
||||||
|
import alertMixin from 'shared/mixins/alertMixin';
|
||||||
|
|
||||||
|
import WootDropdownItem from 'shared/components/ui/dropdown/DropdownItem.vue';
|
||||||
|
import WootDropdownMenu from 'shared/components/ui/dropdown/DropdownMenu.vue';
|
||||||
import wootConstants from '../../constants';
|
import wootConstants from '../../constants';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Spinner,
|
WootDropdownItem,
|
||||||
|
WootDropdownMenu,
|
||||||
},
|
},
|
||||||
|
mixins: [clickaway, alertMixin],
|
||||||
props: { conversationId: { type: [String, Number], required: true } },
|
props: { conversationId: { type: [String, Number], required: true } },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
showDropdown: false,
|
||||||
|
STATUS_TYPE: wootConstants.STATUS_TYPE,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -33,26 +90,60 @@ export default {
|
||||||
isOpen() {
|
isOpen() {
|
||||||
return this.currentChat.status === wootConstants.STATUS_TYPE.OPEN;
|
return this.currentChat.status === wootConstants.STATUS_TYPE.OPEN;
|
||||||
},
|
},
|
||||||
currentStatus() {
|
isBot() {
|
||||||
return this.isOpen
|
return this.currentChat.status === wootConstants.STATUS_TYPE.BOT;
|
||||||
? this.$t('CONVERSATION.HEADER.RESOLVE_ACTION')
|
},
|
||||||
: this.$t('CONVERSATION.HEADER.REOPEN_ACTION');
|
isResolved() {
|
||||||
|
return this.currentChat.status === wootConstants.STATUS_TYPE.RESOLVED;
|
||||||
},
|
},
|
||||||
buttonClass() {
|
buttonClass() {
|
||||||
return this.isOpen ? 'success' : 'warning';
|
if (this.isBot) return 'primary';
|
||||||
|
if (this.isOpen) return 'success';
|
||||||
|
if (this.isResolved) return 'warning';
|
||||||
|
return '';
|
||||||
},
|
},
|
||||||
buttonIconClass() {
|
showDropDown() {
|
||||||
return this.isOpen ? 'ion-checkmark' : 'ion-refresh';
|
return !this.isBot;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleStatus() {
|
closeDropdown() {
|
||||||
|
this.showDropdown = false;
|
||||||
|
},
|
||||||
|
openDropdown() {
|
||||||
|
this.showDropdown = true;
|
||||||
|
},
|
||||||
|
toggleStatus(status) {
|
||||||
|
this.closeDropdown();
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
this.$store.dispatch('toggleStatus', this.currentChat.id).then(() => {
|
this.$store
|
||||||
bus.$emit('newToastMessage', this.$t('CONVERSATION.CHANGE_STATUS'));
|
.dispatch('toggleStatus', {
|
||||||
|
conversationId: this.currentChat.id,
|
||||||
|
status,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.showAlert(this.$t('CONVERSATION.CHANGE_STATUS'));
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.resolve-actions {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.dropdown-pane {
|
||||||
|
left: unset;
|
||||||
|
top: 4.2rem;
|
||||||
|
margin-top: var(--space-micro);
|
||||||
|
right: 0;
|
||||||
|
max-width: 20rem;
|
||||||
|
}
|
||||||
|
.icon--small::v-deep .icon {
|
||||||
|
font-size: var(--font-size-small);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -29,10 +29,14 @@
|
||||||
"HEADER": {
|
"HEADER": {
|
||||||
"RESOLVE_ACTION": "Resolve",
|
"RESOLVE_ACTION": "Resolve",
|
||||||
"REOPEN_ACTION": "Reopen",
|
"REOPEN_ACTION": "Reopen",
|
||||||
|
"OPEN_ACTION": "Open",
|
||||||
"OPEN": "More",
|
"OPEN": "More",
|
||||||
"CLOSE": "Close",
|
"CLOSE": "Close",
|
||||||
"DETAILS": "details"
|
"DETAILS": "details"
|
||||||
},
|
},
|
||||||
|
"RESOLVE_DROPDOWN": {
|
||||||
|
"OPEN_BOT": "Open with bot"
|
||||||
|
},
|
||||||
"FOOTER": {
|
"FOOTER": {
|
||||||
"MSG_INPUT": "Shift + enter for new line. Start with '/' to select a Canned Response.",
|
"MSG_INPUT": "Shift + enter for new line. Start with '/' to select a Canned Response.",
|
||||||
"PRIVATE_MSG_INPUT": "Shift + enter for new line. This will be visible only to Agents"
|
"PRIVATE_MSG_INPUT": "Shift + enter for new line. This will be visible only to Agents"
|
||||||
|
|
|
@ -135,9 +135,12 @@ const actions = {
|
||||||
commit(types.default.ASSIGN_TEAM, team);
|
commit(types.default.ASSIGN_TEAM, team);
|
||||||
},
|
},
|
||||||
|
|
||||||
toggleStatus: async ({ commit }, data) => {
|
toggleStatus: async ({ commit }, { conversationId, status }) => {
|
||||||
try {
|
try {
|
||||||
const response = await ConversationApi.toggleStatus(data);
|
const response = await ConversationApi.toggleStatus({
|
||||||
|
conversationId,
|
||||||
|
status,
|
||||||
|
});
|
||||||
commit(
|
commit(
|
||||||
types.default.RESOLVE_CONVERSATION,
|
types.default.RESOLVE_CONVERSATION,
|
||||||
response.data.payload.current_status
|
response.data.payload.current_status
|
||||||
|
|
|
@ -63,6 +63,7 @@ en:
|
||||||
status:
|
status:
|
||||||
resolved: "Conversation was marked resolved by %{user_name}"
|
resolved: "Conversation was marked resolved by %{user_name}"
|
||||||
open: "Conversation was reopened by %{user_name}"
|
open: "Conversation was reopened by %{user_name}"
|
||||||
|
bot: "Conversation was transferred to bot by %{user_name}"
|
||||||
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
auto_resolved: "Conversation was marked resolved by system due to %{duration} days of inactivity"
|
||||||
assignee:
|
assignee:
|
||||||
self_assigned: "%{user_name} self-assigned this conversation"
|
self_assigned: "%{user_name} self-assigned this conversation"
|
||||||
|
|
Loading…
Reference in a new issue