feat: Add a dropdown to change status to "bot" (#1997)

This commit is contained in:
Nithin David Thomas 2021-04-07 11:44:58 +05:30 committed by GitHub
parent 7a890e543a
commit 7c9cd8aa1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 129 additions and 54 deletions

View file

@ -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 }) {

View file

@ -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;

View file

@ -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>

View file

@ -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"

View file

@ -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

View file

@ -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"