Compare commits

...
Author SHA1 Message Date
Muhsin 662922cd75 fix(conversations): add id tiebreaker to message thread seed so CSAT survey renders
The dashboard seeds the message thread from the conversation payload and then
paginates backward by id (before: messages[0].id). The seed was ordered by
created_at only, so on an auto-resolve burst where the input_csat survey shares
the exact same second as trailing activity messages, a lower-id activity could
win the tie and become the seed. Backward pagination then never loads the
higher-id survey, so the CSAT bubble is missing from the conversation even
though the rating exists and is counted in reports.

Order the seed by created_at DESC, id DESC: the seed stays the chronologically
latest message (no change for delayed-webhook rows), and same-second ties
resolve to the highest id so the survey is always reachable.
2026-07-03 13:27:48 +04:00
@@ -27,13 +27,18 @@ json.meta do
end
json.id conversation.display_id
if conversation.messages.where(account_id: conversation.account_id).last.blank?
# The dashboard seeds the message thread from this array and then paginates BACKWARD
# by id (before: messages[0].id). Keep the seed as the chronologically latest message,
# but add an id tiebreaker: without it, same-second siblings (e.g. the input_csat survey
# created alongside activity messages during an auto-resolve burst) could resolve to a
# lower-id activity, and backward pagination would then never load the higher-id survey.
last_message = conversation.messages.where(account_id: conversation.account_id)
.includes([{ attachments: [{ file_attachment: [:blob] }] }])
.reorder(created_at: :desc, id: :desc).first
if last_message.blank?
json.messages []
else
json.messages [
conversation.messages.where(account_id: conversation.account_id)
.includes([{ attachments: [{ file_attachment: [:blob] }] }]).last.try(:push_event_data)
]
json.messages [last_message.try(:push_event_data)]
end
json.account_id conversation.account_id