feat(widget): Add captain handoff request
This commit is contained in:
@@ -62,6 +62,12 @@ const toggleStatus = async () => {
|
||||
);
|
||||
};
|
||||
|
||||
const requestHandoff = async () => {
|
||||
return API.post(
|
||||
`/api/v1/widget/conversations/request_handoff${window.location.search}`
|
||||
);
|
||||
};
|
||||
|
||||
const setCustomAttributes = async customAttributes => {
|
||||
return API.post(
|
||||
`/api/v1/widget/conversations/set_custom_attributes${window.location.search}`,
|
||||
@@ -90,6 +96,7 @@ export {
|
||||
setUserLastSeenAt,
|
||||
sendEmailTranscript,
|
||||
toggleStatus,
|
||||
requestHandoff,
|
||||
setCustomAttributes,
|
||||
deleteCustomAttribute,
|
||||
};
|
||||
|
||||
@@ -5,12 +5,15 @@ import CustomButton from 'shared/components/Button.vue';
|
||||
import FooterReplyTo from 'widget/components/FooterReplyTo.vue';
|
||||
import ChatInputWrap from 'widget/components/ChatInputWrap.vue';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
import { CONVERSATION_STATUS } from 'shared/constants/messages';
|
||||
import { sendEmailTranscript } from 'widget/api/conversation';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { IFrameHelper } from '../helpers/utils';
|
||||
import { CHATWOOT_ON_START_CONVERSATION } from '../constants/sdkEvents';
|
||||
import { emitter } from 'shared/helpers/mitt';
|
||||
|
||||
const CAPTAIN_HANDOFF_REPLY_THRESHOLD = 5;
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChatInputWrap,
|
||||
@@ -24,6 +27,7 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
inReplyTo: null,
|
||||
isRequestingHandoff: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -31,6 +35,7 @@ export default {
|
||||
conversationAttributes: 'conversationAttributes/getConversationParams',
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
conversationSize: 'conversation/getConversationSize',
|
||||
captainReplyCount: 'conversation/getCaptainReplyCount',
|
||||
currentUser: 'contacts/getCurrentUser',
|
||||
isWidgetStyleFlat: 'appConfig/isWidgetStyleFlat',
|
||||
}),
|
||||
@@ -45,6 +50,12 @@ export default {
|
||||
showEmailTranscriptButton() {
|
||||
return this.hasEmail;
|
||||
},
|
||||
showCaptainHandoffButton() {
|
||||
return (
|
||||
this.conversationAttributes.status === CONVERSATION_STATUS.PENDING &&
|
||||
this.captainReplyCount >= CAPTAIN_HANDOFF_REPLY_THRESHOLD
|
||||
);
|
||||
},
|
||||
hasEmail() {
|
||||
return this.currentUser && this.currentUser.has_email;
|
||||
},
|
||||
@@ -58,7 +69,11 @@ export default {
|
||||
emitter.on(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.toggleReplyTo);
|
||||
},
|
||||
methods: {
|
||||
...mapActions('conversation', ['sendMessage', 'sendAttachment']),
|
||||
...mapActions('conversation', [
|
||||
'sendMessage',
|
||||
'sendAttachment',
|
||||
'requestHandoff',
|
||||
]),
|
||||
...mapActions('conversationAttributes', ['getAttributes']),
|
||||
async handleSendMessage(content) {
|
||||
await this.sendMessage({
|
||||
@@ -90,6 +105,18 @@ export default {
|
||||
toggleReplyTo(message) {
|
||||
this.inReplyTo = message;
|
||||
},
|
||||
async handleRequestHandoff() {
|
||||
try {
|
||||
this.isRequestingHandoff = true;
|
||||
await this.requestHandoff();
|
||||
} catch (error) {
|
||||
emitter.emit(BUS_EVENTS.SHOW_ALERT, {
|
||||
message: this.$t('CAPTAIN_HANDOFF.ERROR'),
|
||||
});
|
||||
} finally {
|
||||
this.isRequestingHandoff = false;
|
||||
}
|
||||
},
|
||||
async sendTranscript() {
|
||||
if (this.hasEmail) {
|
||||
try {
|
||||
@@ -124,6 +151,17 @@ export default {
|
||||
:in-reply-to="inReplyTo"
|
||||
@dismiss="inReplyTo = null"
|
||||
/>
|
||||
<CustomButton
|
||||
v-if="showCaptainHandoffButton"
|
||||
block
|
||||
class="mb-2 font-medium"
|
||||
:bg-color="widgetColor"
|
||||
:text-color="textColor"
|
||||
:disabled="isRequestingHandoff"
|
||||
@click="handleRequestHandoff"
|
||||
>
|
||||
{{ $t('CAPTAIN_HANDOFF.BUTTON_TEXT') }}
|
||||
</CustomButton>
|
||||
<ChatInputWrap
|
||||
class="shadow-sm"
|
||||
:on-send-message="handleSendMessage"
|
||||
|
||||
@@ -47,6 +47,10 @@
|
||||
"CONTINUE_CONVERSATION": "Continue conversation",
|
||||
"YOU": "You",
|
||||
"START_NEW_CONVERSATION": "Start a new conversation",
|
||||
"CAPTAIN_HANDOFF": {
|
||||
"BUTTON_TEXT": "Talk to a support agent",
|
||||
"ERROR": "Could not request a handoff, please try again"
|
||||
},
|
||||
"VIEW_UNREAD_MESSAGES": "You have unread messages",
|
||||
"UNREAD_VIEW": {
|
||||
"VIEW_MESSAGES_BUTTON": "See new messages",
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
toggleTyping,
|
||||
setUserLastSeenAt,
|
||||
toggleStatus,
|
||||
requestHandoff,
|
||||
setCustomAttributes,
|
||||
deleteCustomAttribute,
|
||||
} from 'widget/api/conversation';
|
||||
@@ -212,6 +213,11 @@ export const actions = {
|
||||
await toggleStatus();
|
||||
},
|
||||
|
||||
requestHandoff: async ({ dispatch }) => {
|
||||
await requestHandoff();
|
||||
dispatch('conversationAttributes/getAttributes', {}, { root: true });
|
||||
},
|
||||
|
||||
setCustomAttributes: async (
|
||||
{ commit, rootGetters },
|
||||
customAttributes = {}
|
||||
|
||||
@@ -39,6 +39,15 @@ export const getters = {
|
||||
getMessageCount: _state => {
|
||||
return Object.values(_state.conversations).length;
|
||||
},
|
||||
getCaptainReplyCount: _state => {
|
||||
return Object.values(_state.conversations).filter(message => {
|
||||
const { message_type: messageType, sender = {} } = message;
|
||||
return (
|
||||
messageType === MESSAGE_TYPE.OUTGOING &&
|
||||
sender.type === 'captain_assistant'
|
||||
);
|
||||
}).length;
|
||||
},
|
||||
getUnreadMessageCount: _state => {
|
||||
const { userLastSeenAt } = _state.meta;
|
||||
return Object.values(_state.conversations).filter(chat => {
|
||||
|
||||
Reference in New Issue
Block a user