feat: Display story replies with attachment and context label (#13356)

Fixes https://github.com/chatwoot/chatwoot/issues/13354
Fixes
https://linear.app/chatwoot/issue/CW-6394/story-responses-are-not-being-shown-in-the-ui
When someone replies to your Instagram story, agents in Chatwoot only
see the reply text with no story image and no indication that it was a
story reply. This makes it impossible to understand what the customer is
responding to the message looks like a random text with no context. For
example, if a customer replies "Love this!" to your story, the agent
just sees "Love this!" with no way to know which story triggered the
conversation. This PR fixes the issue by storing the story attachment
and adding a context label.

<img width="1408" height="2052" alt="CleanShot 2026-01-27 at 19 19
38@2x"
src="https://github.com/user-attachments/assets/341afea9-98e3-4e47-b2fa-ef77fe32851f"
/>
This commit is contained in:
Muhsin Keloth
2026-01-28 16:47:04 +04:00
committed by GitHub
parent b870a48734
commit aaeea6c9bf
7 changed files with 48 additions and 20 deletions

View File

@@ -103,23 +103,10 @@ describe Messages::Instagram::MessageBuilder do
it 'creates message with story id' do
messaging = instagram_story_reply_event[:entry][0]['messaging'][0]
create_instagram_contact_for_sender(messaging['sender']['id'], instagram_inbox)
story_source_id = messaging['message']['mid']
story_url = messaging['message']['reply_to']['story']['url']
stub_request(:get, %r{https://graph\.instagram\.com/.*?/#{story_source_id}\?.*})
.to_return(
status: 200,
body: {
story: {
mention: {
id: 'chatwoot-app-user-id-1'
}
},
from: {
username: instagram_inbox.channel.instagram_id
}
}.to_json,
headers: { 'Content-Type' => 'application/json' }
)
stub_request(:get, story_url)
.to_return(status: 200, body: 'image_data', headers: { 'Content-Type' => 'image/png' })
described_class.new(messaging, instagram_inbox).perform
@@ -128,6 +115,9 @@ describe Messages::Instagram::MessageBuilder do
expect(message.content).to eq('This is the story reply')
expect(message.content_attributes[:story_sender]).to eq(instagram_inbox.channel.instagram_id)
expect(message.content_attributes[:story_id]).to eq('chatwoot-app-user-id-1')
expect(message.content_attributes[:image_type]).to eq('ig_story_reply')
expect(message.attachments.first.file_type).to eq('ig_story')
expect(message.attachments.first.external_url).to eq(story_url)
end
it 'creates message with reply to mid' do

View File

@@ -104,6 +104,7 @@ describe Messages::Instagram::Messenger::MessageBuilder do
it 'creates message with for reply with story id' do
messaging = instagram_story_reply_event[:entry][0]['messaging'][0]
sender_id = messaging['sender']['id']
story_url = messaging['message']['reply_to']['story']['url']
allow(Koala::Facebook::API).to receive(:new).and_return(fb_object)
allow(fb_object).to receive(:get_object).and_return(
@@ -114,6 +115,8 @@ describe Messages::Instagram::Messenger::MessageBuilder do
profile_pic: 'https://chatwoot-assets.local/sample.png'
}.with_indifferent_access
)
stub_request(:get, story_url)
.to_return(status: 200, body: 'image_data', headers: { 'Content-Type' => 'image/png' })
create_instagram_contact_for_sender(sender_id, instagram_messenger_inbox)
described_class.new(messaging, instagram_messenger_inbox).perform
@@ -123,7 +126,10 @@ describe Messages::Instagram::Messenger::MessageBuilder do
expect(message.content).to eq('This is the story reply')
expect(message.content_attributes[:story_sender]).to eq(instagram_messenger_inbox.channel.instagram_id)
expect(message.content_attributes[:story_id]).to eq('chatwoot-app-user-id-1')
expect(message.content_attributes[:story_url]).to eq('https://chatwoot-assets.local/sample.png')
expect(message.content_attributes[:story_url]).to eq(story_url)
expect(message.content_attributes[:image_type]).to eq('ig_story_reply')
expect(message.attachments.first.file_type).to eq('ig_story')
expect(message.attachments.first.external_url).to eq(story_url)
end
it 'creates message with for reply with mid' do