feat: Add ability to create a new conversation if the previous conversation is resolved (#2512)
Co-authored-by: Pranav Raj S <pranav@chatwoot.com>
This commit is contained in:
parent
e6e9916fdb
commit
f0f66c7da6
13 changed files with 119 additions and 16 deletions
|
@ -2,4 +2,5 @@ export const BUS_EVENTS = {
|
|||
SET_REFERRER_HOST: 'SET_REFERRER_HOST',
|
||||
SET_TWEET_REPLY: 'SET_TWEET_REPLY',
|
||||
ATTACHMENT_SIZE_CHECK_ERROR: 'ATTACHMENT_SIZE_CHECK_ERROR',
|
||||
START_NEW_CONVERSATION: 'START_NEW_CONVERSATION',
|
||||
};
|
||||
|
|
|
@ -77,7 +77,7 @@ export default {
|
|||
this.registerListeners();
|
||||
this.sendRNWebViewLoadedEvent();
|
||||
}
|
||||
this.$store.dispatch('conversationAttributes/get');
|
||||
this.$store.dispatch('conversationAttributes/getAttributes');
|
||||
this.setWidgetColor(window.chatwootWebChannel);
|
||||
this.registerUnreadEvents();
|
||||
this.registerCampaignEvents();
|
||||
|
|
|
@ -1,19 +1,33 @@
|
|||
<template>
|
||||
<footer class="footer">
|
||||
<footer v-if="!hideReplyBox" class="footer">
|
||||
<ChatInputWrap
|
||||
:on-send-message="handleSendMessage"
|
||||
:on-send-attachment="handleSendAttachment"
|
||||
/>
|
||||
</footer>
|
||||
<custom-button
|
||||
v-else
|
||||
class="font-medium"
|
||||
block
|
||||
:bg-color="widgetColor"
|
||||
:text-color="textColor"
|
||||
@click="startNewConversation"
|
||||
>
|
||||
{{ $t('START_NEW_CONVERSATION') }}
|
||||
</custom-button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import { mapActions, mapGetters } from 'vuex';
|
||||
import { getContrastingTextColor } from '@chatwoot/utils';
|
||||
import CustomButton from 'shared/components/Button';
|
||||
import ChatInputWrap from 'widget/components/ChatInputWrap.vue';
|
||||
import { BUS_EVENTS } from 'shared/constants/busEvents';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ChatInputWrap,
|
||||
CustomButton,
|
||||
},
|
||||
props: {
|
||||
msg: {
|
||||
|
@ -21,16 +35,49 @@ export default {
|
|||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
conversationAttributes: 'conversationAttributes/getConversationParams',
|
||||
widgetColor: 'appConfig/getWidgetColor',
|
||||
getConversationSize: 'conversation/getConversationSize',
|
||||
}),
|
||||
textColor() {
|
||||
return getContrastingTextColor(this.widgetColor);
|
||||
},
|
||||
hideReplyBox() {
|
||||
const { csatSurveyEnabled } = window.chatwootWebChannel;
|
||||
const { status } = this.conversationAttributes;
|
||||
return csatSurveyEnabled && status === 'resolved';
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapActions('conversation', ['sendMessage', 'sendAttachment']),
|
||||
handleSendMessage(content) {
|
||||
this.sendMessage({
|
||||
...mapActions('conversation', [
|
||||
'sendMessage',
|
||||
'sendAttachment',
|
||||
'clearConversations',
|
||||
]),
|
||||
...mapActions('conversationAttributes', [
|
||||
'getAttributes',
|
||||
'clearConversationAttributes',
|
||||
]),
|
||||
async handleSendMessage(content) {
|
||||
const conversationSize = this.getConversationSize;
|
||||
await this.sendMessage({
|
||||
content,
|
||||
});
|
||||
// Update conversation attributes on new conversation
|
||||
if (conversationSize === 0) {
|
||||
this.getAttributes();
|
||||
}
|
||||
},
|
||||
handleSendAttachment(attachment) {
|
||||
this.sendAttachment({ attachment });
|
||||
},
|
||||
startNewConversation() {
|
||||
this.clearConversations();
|
||||
this.clearConversationAttributes();
|
||||
window.bus.$emit(BUS_EVENTS.START_NEW_CONVERSATION);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
"IN_A_DAY": "Typically replies in a day"
|
||||
},
|
||||
"START_CONVERSATION": "Start Conversation",
|
||||
"START_NEW_CONVERSATION": "Start a new conversation",
|
||||
"UNREAD_VIEW": {
|
||||
"VIEW_MESSAGES_BUTTON": "See new messages",
|
||||
"CLOSE_MESSAGES_BUTTON": "Close",
|
||||
|
|
|
@ -22,10 +22,16 @@ export default {
|
|||
return window.chatwootWebChannel.preChatFormEnabled;
|
||||
},
|
||||
preChatFormOptions() {
|
||||
let requireEmail = false;
|
||||
let preChatMessage = '';
|
||||
const options = window.chatwootWebChannel.preChatFormOptions || {};
|
||||
if (!this.isOnNewConversation) {
|
||||
requireEmail = options.require_email;
|
||||
preChatMessage = options.pre_chat_message;
|
||||
}
|
||||
return {
|
||||
requireEmail: options.require_email,
|
||||
preChatMessage: options.pre_chat_message,
|
||||
requireEmail,
|
||||
preChatMessage,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
|
|
@ -6,6 +6,7 @@ global.chatwootWebChannel = {
|
|||
avatarUrl: 'https://test.url',
|
||||
hasAConnectedAgentBot: 'AgentBot',
|
||||
enabledFeatures: ['emoji_picker', 'attachments'],
|
||||
preChatFormOptions: { require_email: false, pre_chat_message: '' },
|
||||
};
|
||||
|
||||
global.chatwootWidgetDefaults = {
|
||||
|
@ -31,6 +32,14 @@ describe('configMixin', () => {
|
|||
avatarUrl: 'https://test.url',
|
||||
hasAConnectedAgentBot: 'AgentBot',
|
||||
enabledFeatures: ['emoji_picker', 'attachments'],
|
||||
preChatFormOptions: {
|
||||
pre_chat_message: '',
|
||||
require_email: false,
|
||||
},
|
||||
});
|
||||
expect(wrapper.vm.preChatFormOptions).toEqual({
|
||||
requireEmail: false,
|
||||
preChatMessage: '',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,7 +11,7 @@ import { refreshActionCableConnector } from '../../../helpers/actionCable';
|
|||
import { createTemporaryMessage, onNewMessageCreated } from './helpers';
|
||||
|
||||
export const actions = {
|
||||
createConversation: async ({ commit }, params) => {
|
||||
createConversation: async ({ commit, dispatch }, params) => {
|
||||
commit('setConversationUIFlag', { isCreating: true });
|
||||
try {
|
||||
const { data } = await createConversationAPI(params);
|
||||
|
@ -22,6 +22,7 @@ export const actions = {
|
|||
const [message = {}] = messages;
|
||||
commit('pushMessageToConversation', message);
|
||||
refreshActionCableConnector(pubsubToken);
|
||||
dispatch('conversationAttributes/getAttributes', {}, { root: true });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
// Ignore error
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {
|
||||
SET_CONVERSATION_ATTRIBUTES,
|
||||
UPDATE_CONVERSATION_ATTRIBUTES,
|
||||
CLEAR_CONVERSATION_ATTRIBUTES,
|
||||
} from '../types';
|
||||
import { getConversationAPI } from '../../api/conversation';
|
||||
|
||||
|
@ -14,7 +15,7 @@ export const getters = {
|
|||
};
|
||||
|
||||
export const actions = {
|
||||
get: async ({ commit }) => {
|
||||
getAttributes: async ({ commit }) => {
|
||||
try {
|
||||
const { data } = await getConversationAPI();
|
||||
const { contact_last_seen_at: lastSeen } = data;
|
||||
|
@ -27,6 +28,9 @@ export const actions = {
|
|||
update({ commit }, data) {
|
||||
commit(UPDATE_CONVERSATION_ATTRIBUTES, data);
|
||||
},
|
||||
clearConversationAttributes: ({ commit }) => {
|
||||
commit('CLEAR_CONVERSATION_ATTRIBUTES');
|
||||
},
|
||||
};
|
||||
|
||||
export const mutations = {
|
||||
|
@ -40,6 +44,10 @@ export const mutations = {
|
|||
$state.status = data.status;
|
||||
}
|
||||
},
|
||||
[CLEAR_CONVERSATION_ATTRIBUTES]($state) {
|
||||
$state.id = '';
|
||||
$state.status = '';
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
|
|
|
@ -5,10 +5,10 @@ const commit = jest.fn();
|
|||
jest.mock('widget/helpers/axios');
|
||||
|
||||
describe('#actions', () => {
|
||||
describe('#update', () => {
|
||||
describe('#get attributes', () => {
|
||||
it('sends mutation if api is success', async () => {
|
||||
API.get.mockResolvedValue({ data: { id: 1, status: 'bot' } });
|
||||
await actions.get({ commit });
|
||||
await actions.getAttributes({ commit });
|
||||
expect(commit.mock.calls).toEqual([
|
||||
['SET_CONVERSATION_ATTRIBUTES', { id: 1, status: 'bot' }],
|
||||
['conversation/setMetaUserLastSeenAt', undefined, { root: true }],
|
||||
|
@ -16,12 +16,12 @@ describe('#actions', () => {
|
|||
});
|
||||
it('doesnot send mutation if api is error', async () => {
|
||||
API.get.mockRejectedValue({ message: 'Invalid Headers' });
|
||||
await actions.get({ commit });
|
||||
await actions.getAttributes({ commit });
|
||||
expect(commit.mock.calls).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#update', () => {
|
||||
describe('#update attributes', () => {
|
||||
it('sends correct mutations', () => {
|
||||
actions.update({ commit }, { id: 1, status: 'bot' });
|
||||
expect(commit).toBeCalledWith('UPDATE_CONVERSATION_ATTRIBUTES', {
|
||||
|
@ -30,4 +30,10 @@ describe('#actions', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
describe('#clear attributes', () => {
|
||||
it('sends correct mutations', () => {
|
||||
actions.clearConversationAttributes({ commit });
|
||||
expect(commit).toBeCalledWith('CLEAR_CONVERSATION_ATTRIBUTES');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -30,4 +30,15 @@ describe('#mutations', () => {
|
|||
expect(state).toEqual({ id: 1, status: 'bot' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('#CLEAR_CONVERSATION_ATTRIBUTES', () => {
|
||||
it('clear status if it is same conversation', () => {
|
||||
const state = { id: 1, status: 'open' };
|
||||
mutations.CLEAR_CONVERSATION_ATTRIBUTES(state, {
|
||||
id: 1,
|
||||
status: 'open',
|
||||
});
|
||||
expect(state).toEqual({ id: '', status: '' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export const SET_WIDGET_COLOR = 'SET_WIDGET_COLOR';
|
||||
export const SET_CONVERSATION_ATTRIBUTES = 'SET_CONVERSATION_ATTRIBUTES';
|
||||
export const UPDATE_CONVERSATION_ATTRIBUTES = 'UPDATE_CONVERSATION_ATTRIBUTES';
|
||||
export const CLEAR_CONVERSATION_ATTRIBUTES = 'CLEAR_CONVERSATION_ATTRIBUTES';
|
||||
|
|
|
@ -113,7 +113,11 @@ export default {
|
|||
},
|
||||
},
|
||||
data() {
|
||||
return { isOnCollapsedView: false, showAttachmentError: false };
|
||||
return {
|
||||
isOnCollapsedView: false,
|
||||
showAttachmentError: false,
|
||||
isOnNewConversation: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
|
@ -130,7 +134,10 @@ export default {
|
|||
if (this.conversationSize) {
|
||||
return 'messageView';
|
||||
}
|
||||
if (this.preChatFormEnabled && !currentUserEmail) {
|
||||
if (
|
||||
this.isOnNewConversation ||
|
||||
(this.preChatFormEnabled && !currentUserEmail)
|
||||
) {
|
||||
return 'preChatFormView';
|
||||
}
|
||||
return 'messageView';
|
||||
|
@ -163,6 +170,10 @@ export default {
|
|||
this.showAttachmentError = false;
|
||||
}, 3000);
|
||||
});
|
||||
bus.$on(BUS_EVENTS.START_NEW_CONVERSATION, () => {
|
||||
this.isOnCollapsedView = true;
|
||||
this.isOnNewConversation = true;
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
startConversation() {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
preChatFormEnabled: <%= @web_widget.pre_chat_form_enabled %>,
|
||||
preChatFormOptions: <%= @web_widget.pre_chat_form_options.to_json.html_safe %>,
|
||||
workingHoursEnabled: <%= @web_widget.inbox.working_hours_enabled %>,
|
||||
csatSurveyEnabled: <%= @web_widget.inbox.csat_survey_enabled %>,
|
||||
workingHours: <%= @web_widget.inbox.working_hours.to_json.html_safe %>,
|
||||
outOfOfficeMessage: <%= @web_widget.inbox.out_of_office_message.to_json.html_safe %>,
|
||||
utcOffset: '<%= ActiveSupport::TimeZone[@web_widget.inbox.timezone].formatted_offset %>'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue