feat: Add an option to disable endConversation button (#4352)

This commit is contained in:
Pranav Raj S 2022-04-06 13:54:55 +05:30 committed by GitHub
parent 821b953ee9
commit 0b03e4b296
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 81 additions and 10 deletions

View file

@ -45,7 +45,10 @@ class Api::V1::Widget::ConversationsController < Api::V1::Widget::BaseController
end
def toggle_status
head :not_found && return if conversation.nil?
return head :not_found if conversation.nil?
return head :forbidden unless @web_widget.end_conversation?
unless conversation.resolved?
conversation.status = :resolved
conversation.save

View file

@ -395,7 +395,8 @@
"FEATURES": {
"LABEL": "Features",
"DISPLAY_FILE_PICKER": "Display file picker on the widget",
"DISPLAY_EMOJI_PICKER": "Display emoji picker on the widget"
"DISPLAY_EMOJI_PICKER": "Display emoji picker on the widget",
"ALLOW_END_CONVERSATION": "Allow users to end conversation from the widget"
},
"SETTINGS_POPUP": {
"MESSENGER_HEADING": "Messenger Script",

View file

@ -285,6 +285,17 @@
{{ $t('INBOX_MGMT.FEATURES.DISPLAY_EMOJI_PICKER') }}
</label>
</div>
<div v-if="isAWebWidgetInbox" class="settings-item settings-item">
<input
v-model="selectedFeatureFlags"
type="checkbox"
value="end_conversation"
@input="handleFeatureFlag"
/>
<label for="end_conversation">
{{ $t('INBOX_MGMT.FEATURES.ALLOW_END_CONVERSATION') }}
</label>
</div>
<woot-submit-button
v-if="isAPIInbox"

View file

@ -1,7 +1,7 @@
<template>
<div v-if="showHeaderActions" class="actions flex items-center">
<button
v-if="conversationStatus === 'open'"
v-if="conversationStatus === 'open' && hasEndConversationEnabled"
class="button transparent compact"
:title="$t('END_CONVERSATION')"
@click="resolveConversation"
@ -43,12 +43,13 @@ import { mapGetters } from 'vuex';
import { IFrameHelper, RNHelper } from 'widget/helpers/utils';
import { popoutChatWindow } from '../helpers/popoutHelper';
import FluentIcon from 'shared/components/FluentIcon/Index.vue';
import darkModeMixin from 'widget/mixins/darkModeMixin.js';
import darkModeMixin from 'widget/mixins/darkModeMixin';
import configMixin from 'widget/mixins/configMixin';
export default {
name: 'HeaderActions',
components: { FluentIcon },
mixins: [darkModeMixin],
mixins: [configMixin, darkModeMixin],
props: {
showPopoutButton: {
type: Boolean,

View file

@ -18,6 +18,9 @@ export default {
hasAttachmentsEnabled() {
return this.channelConfig.enabledFeatures.includes('attachments');
},
hasEndConversationEnabled() {
return this.channelConfig.enabledFeatures.includes('end_conversation');
},
preChatFormEnabled() {
return window.chatwootWebChannel.preChatFormEnabled;
},

View file

@ -5,7 +5,7 @@ import Vue from 'vue';
global.chatwootWebChannel = {
avatarUrl: 'https://test.url',
hasAConnectedAgentBot: 'AgentBot',
enabledFeatures: ['emoji_picker', 'attachments'],
enabledFeatures: ['emoji_picker', 'attachments', 'end_conversation'],
preChatFormOptions: { require_email: false, pre_chat_message: '' },
};
@ -24,6 +24,7 @@ describe('configMixin', () => {
const vm = new Constructor().$mount();
const wrapper = createWrapper(vm);
expect(wrapper.vm.hasEmojiPickerEnabled).toBe(true);
expect(wrapper.vm.hasEndConversationEnabled).toBe(true);
expect(wrapper.vm.hasAttachmentsEnabled).toBe(true);
expect(wrapper.vm.hasAConnectedAgentBot).toBe(true);
expect(wrapper.vm.useInboxAvatarForBot).toBe(true);
@ -31,7 +32,7 @@ describe('configMixin', () => {
expect(wrapper.vm.channelConfig).toEqual({
avatarUrl: 'https://test.url',
hasAConnectedAgentBot: 'AgentBot',
enabledFeatures: ['emoji_picker', 'attachments'],
enabledFeatures: ['emoji_picker', 'attachments', 'end_conversation'],
preChatFormOptions: {
pre_chat_message: '',
require_email: false,

View file

@ -4,7 +4,7 @@
#
# id :integer not null, primary key
# continuity_via_email :boolean default(TRUE), not null
# feature_flags :integer default(3), not null
# feature_flags :integer default(7), not null
# hmac_mandatory :boolean default(FALSE)
# hmac_token :string
# pre_chat_form_enabled :boolean default(FALSE)
@ -43,6 +43,7 @@ class Channel::WebWidget < ApplicationRecord
has_flags 1 => :attachments,
2 => :emoji_picker,
3 => :end_conversation,
:column => 'feature_flags',
:check_for_column => false

View file

@ -0,0 +1,16 @@
class UpdateWebWidgetFeatureFlags < ActiveRecord::Migration[6.1]
def change
change_column_default(:channel_web_widgets, :feature_flags, from: 3, to: 7)
set_end_conversation_to_default
end
def set_end_conversation_to_default
::Channel::WebWidget.find_in_batches do |widget_batch|
widget_batch.each do |widget|
widget.end_conversation = true
widget.save!
end
end
end
end

View file

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2022_02_18_120357) do
ActiveRecord::Schema.define(version: 2022_04_05_092033) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements"
@ -280,7 +280,7 @@ ActiveRecord::Schema.define(version: 2022_02_18_120357) do
t.string "widget_color", default: "#1f93ff"
t.string "welcome_title"
t.string "welcome_tagline"
t.integer "feature_flags", default: 3, null: false
t.integer "feature_flags", default: 7, null: false
t.integer "reply_time", default: 0
t.string "hmac_token"
t.boolean "pre_chat_form_enabled", default: false

View file

@ -5,9 +5,13 @@ RSpec.describe '/api/v1/widget/conversations/toggle_typing', type: :request do
let(:web_widget) { create(:channel_widget, account: account) }
let(:contact) { create(:contact, account: account, email: nil) }
let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
let(:second_session) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) }
let!(:conversation) { create(:conversation, contact: contact, account: account, inbox: web_widget.inbox, contact_inbox: contact_inbox) }
let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } }
let(:token) { ::Widget::TokenService.new(payload: payload).generate_token }
let(:token_without_conversation) do
::Widget::TokenService.new(payload: { source_id: second_session.source_id, inbox_id: web_widget.inbox.id }).generate_token
end
describe 'GET /api/v1/widget/conversations' do
context 'with a conversation' do
@ -142,5 +146,35 @@ RSpec.describe '/api/v1/widget/conversations/toggle_typing', type: :request do
)
end
end
context 'when end conversation is not permitted' do
before do
web_widget.end_conversation = false
web_widget.save!
end
it 'returns action not permitted status' do
expect(conversation.open?).to be true
get '/api/v1/widget/conversations/toggle_status',
headers: { 'X-Auth-Token' => token },
params: { website_token: web_widget.website_token },
as: :json
expect(response).to have_http_status(:forbidden)
expect(conversation.reload.resolved?).to be false
end
end
context 'when a token without any conversation is used' do
it 'returns not found status' do
get '/api/v1/widget/conversations/toggle_status',
headers: { 'X-Auth-Token' => token_without_conversation },
params: { website_token: web_widget.website_token },
as: :json
expect(response).to have_http_status(:not_found)
end
end
end
end