feat: Improve CSAT responses (#11485)

# Pull Request Template

## Description

This PR introduces basic customization options for the CSAT survey:

* **Display Type**: Option to use star ratings instead of emojis.
* **Message Text**: Customize the survey message (up to 200 characters).
* **Survey Rules**: Send surveys based on labels — trigger when a
conversation has or doesn't have a specific label.

Fixes
https://linear.app/chatwoot/document/improve-csat-responses-a61cf30e054e

## Type of change

- [x] New feature (non-breaking change which adds functionality)

## How Has This Been Tested?

### Loom videos

**Website Channel (Widget)**

https://www.loom.com/share/7f47836cde7940ae9d17b7997d060a18?sid=aad2ad0a-140a-4a09-8829-e01fa2e102c5

**Email Channel (Survey link)**

https://www.loom.com/share/e92f4c4c0f73417ba300a25885e093ce?sid=4bb006f0-1c2a-4352-a232-8bf684e3d757

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [x] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Pranav <pranavrajs@gmail.com>
This commit is contained in:
Sivin Varghese
2025-05-16 14:18:52 +05:30
committed by GitHub
parent e9cda40b71
commit d0611cb7f2
26 changed files with 812 additions and 54 deletions

View File

@@ -1,13 +1,100 @@
require 'rails_helper'
describe MessageTemplates::Template::CsatSurvey do
context 'when this hook is called' do
let(:conversation) { create(:conversation) }
let(:account) { create(:account) }
let(:inbox) { create(:inbox, account: account) }
let(:conversation) { create(:conversation, account: account, inbox: inbox) }
let(:service) { described_class.new(conversation: conversation) }
it 'creates the out of office messages' do
described_class.new(conversation: conversation).perform
expect(conversation.messages.template.count).to eq(1)
expect(conversation.messages.template.first.content_type).to eq('input_csat')
describe '#perform' do
context 'when no survey rules are configured' do
it 'creates a CSAT survey message' do
inbox.update(csat_config: {})
service.perform
expect(conversation.messages.template.count).to eq(1)
expect(conversation.messages.template.first.content_type).to eq('input_csat')
end
end
end
describe '#perform with contains operator' do
let(:csat_config) do
{
'display_type' => 'emoji',
'message' => 'Please rate your experience',
'survey_rules' => {
'operator' => 'contains',
'values' => %w[support help]
}
}
end
before do
inbox.update(csat_config: csat_config)
end
context 'when conversation has matching labels' do
it 'creates a CSAT survey message' do
conversation.update(label_list: %w[support urgent])
service.perform
expect(conversation.messages.template.count).to eq(1)
message = conversation.messages.template.first
expect(message.content_type).to eq('input_csat')
expect(message.content).to eq('Please rate your experience')
expect(message.content_attributes['display_type']).to eq('emoji')
end
end
context 'when conversation has no matching labels' do
it 'does not create a CSAT survey message' do
conversation.update(label_list: %w[billing-support payment])
service.perform
expect(conversation.messages.template.count).to eq(0)
end
end
end
describe '#perform with does_not_contain operator' do
let(:csat_config) do
{
'display_type' => 'emoji',
'message' => 'Please rate your experience',
'survey_rules' => {
'operator' => 'does_not_contain',
'values' => %w[support help]
}
}
end
before do
inbox.update(csat_config: csat_config)
end
context 'when conversation does not have matching labels' do
it 'creates a CSAT survey message' do
conversation.update(label_list: %w[billing payment])
service.perform
expect(conversation.messages.template.count).to eq(1)
expect(conversation.messages.template.first.content_type).to eq('input_csat')
end
end
context 'when conversation has matching labels' do
it 'does not create a CSAT survey message' do
conversation.update(label_list: %w[support urgent])
service.perform
expect(conversation.messages.template.count).to eq(0)
end
end
end
end