From 7ee70628433185407eb3558e5fbf8230aa372ae3 Mon Sep 17 00:00:00 2001 From: "Aswin Dev P.S" Date: Tue, 11 Jan 2022 00:32:03 -0800 Subject: [PATCH] feat: Toggle to disallow users to send messages after a conversation is resolved (#3605) --- .../api/v1/accounts/inboxes_controller.rb | 2 +- .../dashboard/i18n/locale/en/inboxMgmt.json | 8 ++++- .../dashboard/settings/inbox/Settings.vue | 22 +++++++++++++ .../widget/components/ChatFooter.vue | 4 +-- app/models/inbox.rb | 33 ++++++++++--------- app/views/api/v1/models/_inbox.json.jbuilder | 1 + app/views/widgets/show.html.erb | 3 +- ..._allow_messages_after_resolved_to_inbox.rb | 16 +++++++++ db/schema.rb | 3 +- .../v1/accounts/inboxes_controller_spec.rb | 21 ++++++++++++ 10 files changed, 91 insertions(+), 22 deletions(-) create mode 100644 db/migrate/20211216110209_add_allow_messages_after_resolved_to_inbox.rb diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb index 1720ee692..9f2cfba8c 100644 --- a/app/controllers/api/v1/accounts/inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/inboxes_controller.rb @@ -118,7 +118,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController def permitted_params(channel_attributes = []) params.permit( :name, :avatar, :greeting_enabled, :greeting_message, :enable_email_collect, :csat_survey_enabled, - :enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone, + :enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone, :allow_messages_after_resolved, channel: [:type, *channel_attributes] ) end diff --git a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json index b64362027..fb1d5c35f 100644 --- a/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/en/inboxMgmt.json @@ -306,6 +306,10 @@ "ENABLED": "Enabled", "DISABLED": "Disabled" }, + "ALLOW_MESSAGES_AFTER_RESOLVED": { + "ENABLED": "Enabled", + "DISABLED": "Disabled" + }, "ENABLE_HMAC": { "LABEL": "Enable" } @@ -362,7 +366,9 @@ "INBOX_IDENTIFIER": "Inbox Identifier", "INBOX_IDENTIFIER_SUB_TEXT": "Use the `inbox_identifier` token shown here to authentication your API clients.", "FORWARD_EMAIL_TITLE": "Forward to Email", - "FORWARD_EMAIL_SUB_TEXT": "Start forwarding your emails to the following email address." + "FORWARD_EMAIL_SUB_TEXT": "Start forwarding your emails to the following email address.", + "ALLOW_MESSAGES_AFTER_RESOLVED": "Allow messages after conversation resolved", + "ALLOW_MESSAGES_AFTER_RESOLVED_SUB_TEXT": "Allow the end-users to send messages even after the conversation is resolved." }, "FACEBOOK_REAUTHORIZE": { "TITLE": "Reauthorize", diff --git a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue index cb61c2f97..79acdfef2 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/inbox/Settings.vue @@ -215,6 +215,25 @@

+ + @@ -420,6 +439,7 @@ export default { emailCollectEnabled: false, isAgentListUpdating: false, csatSurveyEnabled: false, + allowMessagesAfterResolved: true, selectedInboxName: '', channelWebsiteUrl: '', webhookUrl: '', @@ -583,6 +603,7 @@ export default { this.autoAssignment = this.inbox.enable_auto_assignment; this.emailCollectEnabled = this.inbox.enable_email_collect; this.csatSurveyEnabled = this.inbox.csat_survey_enabled; + this.allowMessagesAfterResolved = this.inbox.allow_messages_after_resolved; this.channelWebsiteUrl = this.inbox.website_url; this.channelWelcomeTitle = this.inbox.welcome_title; this.channelWelcomeTagline = this.inbox.welcome_tagline; @@ -625,6 +646,7 @@ export default { enable_auto_assignment: this.autoAssignment, enable_email_collect: this.emailCollectEnabled, csat_survey_enabled: this.csatSurveyEnabled, + allow_messages_after_resolved: this.allowMessagesAfterResolved, greeting_enabled: this.greetingEnabled, greeting_message: this.greetingMessage || '', channel: { diff --git a/app/javascript/widget/components/ChatFooter.vue b/app/javascript/widget/components/ChatFooter.vue index 58538d0c6..7561f1930 100755 --- a/app/javascript/widget/components/ChatFooter.vue +++ b/app/javascript/widget/components/ChatFooter.vue @@ -58,9 +58,9 @@ export default { return getContrastingTextColor(this.widgetColor); }, hideReplyBox() { - const { csatSurveyEnabled } = window.chatwootWebChannel; + const { allowMessagesAfterResolved } = window.chatwootWebChannel; const { status } = this.conversationAttributes; - return csatSurveyEnabled && status === 'resolved'; + return !allowMessagesAfterResolved && status === 'resolved'; }, showEmailTranscriptButton() { return this.currentUser && this.currentUser.email; diff --git a/app/models/inbox.rb b/app/models/inbox.rb index f16a5ca92..774c66f9d 100644 --- a/app/models/inbox.rb +++ b/app/models/inbox.rb @@ -4,22 +4,23 @@ # # Table name: inboxes # -# id :integer not null, primary key -# channel_type :string -# csat_survey_enabled :boolean default(FALSE) -# email_address :string -# enable_auto_assignment :boolean default(TRUE) -# enable_email_collect :boolean default(TRUE) -# greeting_enabled :boolean default(FALSE) -# greeting_message :string -# name :string not null -# out_of_office_message :string -# timezone :string default("UTC") -# working_hours_enabled :boolean default(FALSE) -# created_at :datetime not null -# updated_at :datetime not null -# account_id :integer not null -# channel_id :integer not null +# id :integer not null, primary key +# allow_messages_after_resolved :boolean default(TRUE) +# channel_type :string +# csat_survey_enabled :boolean default(FALSE) +# email_address :string +# enable_auto_assignment :boolean default(TRUE) +# enable_email_collect :boolean default(TRUE) +# greeting_enabled :boolean default(FALSE) +# greeting_message :string +# name :string not null +# out_of_office_message :string +# timezone :string default("UTC") +# working_hours_enabled :boolean default(FALSE) +# created_at :datetime not null +# updated_at :datetime not null +# account_id :integer not null +# channel_id :integer not null # # Indexes # diff --git a/app/views/api/v1/models/_inbox.json.jbuilder b/app/views/api/v1/models/_inbox.json.jbuilder index f76b8566d..eca35c466 100644 --- a/app/views/api/v1/models/_inbox.json.jbuilder +++ b/app/views/api/v1/models/_inbox.json.jbuilder @@ -13,6 +13,7 @@ json.out_of_office_message resource.out_of_office_message json.working_hours resource.weekly_schedule json.timezone resource.timezone json.callback_webhook_url resource.callback_webhook_url +json.allow_messages_after_resolved resource.allow_messages_after_resolved json.tweets_enabled resource.channel.try(:tweets_enabled) if resource.twitter? diff --git a/app/views/widgets/show.html.erb b/app/views/widgets/show.html.erb index 0cd60c453..02361ce7b 100644 --- a/app/views/widgets/show.html.erb +++ b/app/views/widgets/show.html.erb @@ -23,7 +23,8 @@ 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].now.formatted_offset %>' + utcOffset: '<%= ActiveSupport::TimeZone[@web_widget.inbox.timezone].now.formatted_offset %>', + allowMessagesAfterResolved: <%= @web_widget.inbox.allow_messages_after_resolved %> } window.chatwootWidgetDefaults = { useInboxAvatarForBot: <%= ActiveModel::Type::Boolean.new.cast(ENV.fetch('USE_INBOX_AVATAR_FOR_BOT', false)) %>, diff --git a/db/migrate/20211216110209_add_allow_messages_after_resolved_to_inbox.rb b/db/migrate/20211216110209_add_allow_messages_after_resolved_to_inbox.rb new file mode 100644 index 000000000..4c44ac2bb --- /dev/null +++ b/db/migrate/20211216110209_add_allow_messages_after_resolved_to_inbox.rb @@ -0,0 +1,16 @@ +class AddAllowMessagesAfterResolvedToInbox < ActiveRecord::Migration[6.1] + def change + add_column :inboxes, :allow_messages_after_resolved, :boolean, default: true + + update_csat_enabled_inboxes + end + + def update_csat_enabled_inboxes + ::Inbox.where(channel_type: 'Channel::WebWidget', csat_survey_enabled: true).find_in_batches do |inboxes_batch| + inboxes_batch.each do |inbox| + inbox.allow_messages_after_resolved = false + inbox.save! + end + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 14b64b78a..ad5bc66b0 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -461,6 +461,7 @@ ActiveRecord::Schema.define(version: 2021_12_21_125545) do t.string "timezone", default: "UTC" t.boolean "enable_email_collect", default: true t.boolean "csat_survey_enabled", default: false + t.boolean 'allow_messages_after_resolved', default: true t.index ["account_id"], name: "index_inboxes_on_account_id" end @@ -829,4 +830,4 @@ ActiveRecord::Schema.define(version: 2021_12_21_125545) do "NEW.display_id := nextval('camp_dpid_seq_' || NEW.account_id);" end -end +end \ No newline at end of file diff --git a/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb b/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb index ea28dcbd5..1c7082abc 100644 --- a/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/inboxes_controller_spec.rb @@ -308,6 +308,17 @@ RSpec.describe 'Inboxes API', type: :request do expect(response.body).to include('Line Inbox') expect(response.body).to include('callback_webhook_url') end + + it 'creates the webwidget inbox that allow messages after conversation is resolved' do + post "/api/v1/accounts/#{account.id}/inboxes", + headers: admin.create_new_auth_token, + params: valid_params, + as: :json + + expect(response).to have_http_status(:success) + json_response = JSON.parse(response.body) + expect(json_response['allow_messages_after_resolved']).to be true + end end end @@ -467,6 +478,16 @@ RSpec.describe 'Inboxes API', type: :request do inbox.reload expect(inbox.reload.weekly_schedule.find { |schedule| schedule['day_of_week'] == 0 }['open_hour']).to eq 9 end + + it 'updates the webwidget inbox to disallow the messages after conversation is resolved' do + patch "/api/v1/accounts/#{account.id}/inboxes/#{inbox.id}", + headers: admin.create_new_auth_token, + params: valid_params.merge({ allow_messages_after_resolved: false }), + as: :json + + expect(response).to have_http_status(:success) + expect(inbox.reload.allow_messages_after_resolved).to be_falsey + end end end