feat: add activity message for priority change (#6933)
* feat: add priority const * feat: add toggle priority method * feat: update controller route and specs * refactor: status change method * refactor: abstract label change and mute activity * feat: add priority change_activity * fix: interpolation for previous_changes * refactor: reduce cognitive complexity of priority_change_activity * refactor: move priority activity message handler to a separate module * refactor: move typing logic to a service * refactor: tests to reduce complexity * fix: typo * fix: constants * fix: priority conditions * fix: add a response * fix: argument destructuring in I18n.t --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -64,13 +64,14 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
assign_conversation if @conversation.status == 'open' && Current.user.is_a?(User) && Current.user&.agent?
|
||||
end
|
||||
|
||||
def toggle_priority
|
||||
@conversation.toggle_priority(params[:priority])
|
||||
head :ok
|
||||
end
|
||||
|
||||
def toggle_typing_status
|
||||
case params[:typing_status]
|
||||
when 'on'
|
||||
trigger_typing_event(CONVERSATION_TYPING_ON, params[:is_private])
|
||||
when 'off'
|
||||
trigger_typing_event(CONVERSATION_TYPING_OFF, params[:is_private])
|
||||
end
|
||||
typing_status_manager = ::Conversations::TypingStatusManager.new(@conversation, current_user, params)
|
||||
typing_status_manager.toggle_typing_status
|
||||
head :ok
|
||||
end
|
||||
|
||||
@@ -111,11 +112,6 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
@conversation.update_assignee(@agent)
|
||||
end
|
||||
|
||||
def trigger_typing_event(event, is_private)
|
||||
user = current_user.presence || @resource
|
||||
Rails.configuration.dispatcher.dispatch(event, Time.zone.now, conversation: @conversation, user: user, is_private: is_private)
|
||||
end
|
||||
|
||||
def conversation
|
||||
@conversation ||= Current.account.conversations.find_by!(display_id: params[:id])
|
||||
authorize @conversation.inbox, :show?
|
||||
|
||||
@@ -52,6 +52,12 @@ class ConversationApi extends ApiClient {
|
||||
});
|
||||
}
|
||||
|
||||
togglePriority({ conversationId, priority }) {
|
||||
return axios.post(`${this.url}/${conversationId}/toggle_priority`, {
|
||||
priority,
|
||||
});
|
||||
}
|
||||
|
||||
assignAgent({ conversationId, agentId }) {
|
||||
return axios.post(
|
||||
`${this.url}/${conversationId}/assignments?assignee_id=${agentId}`,
|
||||
|
||||
@@ -19,6 +19,14 @@ export const CONVERSATION_STATUS = {
|
||||
PENDING: 'pending',
|
||||
SNOOZED: 'snoozed',
|
||||
};
|
||||
|
||||
export const CONVERSATION_PRIORITY = {
|
||||
URGENT: 'urgent',
|
||||
HIGH: 'high',
|
||||
LOW: 'low',
|
||||
MEDIUM: 'medium',
|
||||
};
|
||||
|
||||
// Size in mega bytes
|
||||
export const MAXIMUM_FILE_UPLOAD_SIZE = 40;
|
||||
export const MAXIMUM_FILE_UPLOAD_SIZE_TWILIO_SMS_CHANNEL = 5;
|
||||
|
||||
@@ -1,80 +1,77 @@
|
||||
module ActivityMessageHandler
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
include PriorityActivityMessageHandler
|
||||
|
||||
private
|
||||
|
||||
def create_activity
|
||||
user_name = Current.user.name if Current.user.present?
|
||||
status_change_activity(user_name) if saved_change_to_status?
|
||||
priority_change_activity(user_name) if saved_change_to_priority?
|
||||
create_label_change(activity_message_ownner(user_name)) if saved_change_to_label_list?
|
||||
end
|
||||
|
||||
def status_change_activity(user_name)
|
||||
return send_automation_activity if Current.executed_by.present?
|
||||
content = if Current.executed_by.present?
|
||||
automation_status_change_activity_content
|
||||
else
|
||||
user_status_change_activity_content(user_name)
|
||||
end
|
||||
|
||||
create_status_change_message(user_name)
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
end
|
||||
|
||||
def user_status_change_activity_content(user_name)
|
||||
if user_name
|
||||
I18n.t("conversations.activity.status.#{status}", user_name: user_name)
|
||||
elsif Current.contact.present? && resolved?
|
||||
I18n.t('conversations.activity.status.contact_resolved', contact_name: Current.contact.name.capitalize)
|
||||
elsif resolved?
|
||||
I18n.t('conversations.activity.status.auto_resolved', duration: auto_resolve_duration)
|
||||
end
|
||||
end
|
||||
|
||||
def automation_status_change_activity_content
|
||||
if Current.executed_by.instance_of?(AutomationRule)
|
||||
I18n.t("conversations.activity.status.#{status}", user_name: 'Automation System')
|
||||
elsif Current.executed_by.instance_of?(Contact)
|
||||
Current.executed_by = nil
|
||||
I18n.t('conversations.activity.status.system_auto_open')
|
||||
end
|
||||
end
|
||||
|
||||
def activity_message_params(content)
|
||||
{ account_id: account_id, inbox_id: inbox_id, message_type: :activity, content: content }
|
||||
end
|
||||
|
||||
def create_status_change_message(user_name)
|
||||
content = if user_name
|
||||
I18n.t("conversations.activity.status.#{status}", user_name: user_name)
|
||||
elsif Current.contact.present? && resolved?
|
||||
I18n.t('conversations.activity.status.contact_resolved', contact_name: Current.contact.name.capitalize)
|
||||
elsif resolved?
|
||||
I18n.t('conversations.activity.status.auto_resolved', duration: auto_resolve_duration)
|
||||
end
|
||||
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
end
|
||||
|
||||
def send_automation_activity
|
||||
content = if Current.executed_by.instance_of?(AutomationRule)
|
||||
I18n.t("conversations.activity.status.#{status}", user_name: 'Automation System')
|
||||
elsif Current.executed_by.instance_of?(Contact)
|
||||
Current.executed_by = nil
|
||||
I18n.t('conversations.activity.status.system_auto_open')
|
||||
end
|
||||
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
end
|
||||
|
||||
def create_label_added(user_name, labels = [])
|
||||
return unless labels.size.positive?
|
||||
|
||||
params = { user_name: user_name, labels: labels.join(', ') }
|
||||
content = I18n.t('conversations.activity.labels.added', **params)
|
||||
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
create_label_change_activity('added', user_name, labels)
|
||||
end
|
||||
|
||||
def create_label_removed(user_name, labels = [])
|
||||
create_label_change_activity('removed', user_name, labels)
|
||||
end
|
||||
|
||||
def create_label_change_activity(change_type, user_name, labels = [])
|
||||
return unless labels.size.positive?
|
||||
|
||||
params = { user_name: user_name, labels: labels.join(', ') }
|
||||
content = I18n.t('conversations.activity.labels.removed', **params)
|
||||
|
||||
content = I18n.t("conversations.activity.labels.#{change_type}", user_name: user_name, labels: labels.join(', '))
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
end
|
||||
|
||||
def create_muted_message
|
||||
return unless Current.user
|
||||
|
||||
params = { user_name: Current.user.name }
|
||||
content = I18n.t('conversations.activity.muted', **params)
|
||||
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
create_mute_change_activity('muted')
|
||||
end
|
||||
|
||||
def create_unmuted_message
|
||||
create_mute_change_activity('unmuted')
|
||||
end
|
||||
|
||||
def create_mute_change_activity(change_type)
|
||||
return unless Current.user
|
||||
|
||||
params = { user_name: Current.user.name }
|
||||
content = I18n.t('conversations.activity.unmuted', **params)
|
||||
|
||||
content = I18n.t("conversations.activity.#{change_type}", user_name: Current.user.name)
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
end
|
||||
|
||||
|
||||
33
app/models/concerns/priority_activity_message_handler.rb
Normal file
33
app/models/concerns/priority_activity_message_handler.rb
Normal file
@@ -0,0 +1,33 @@
|
||||
module PriorityActivityMessageHandler
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
def priority_change_activity(user_name)
|
||||
old_priority, new_priority = previous_changes.values_at('priority')[0]
|
||||
return unless priority_change?(old_priority, new_priority)
|
||||
|
||||
user = Current.executed_by.instance_of?(AutomationRule) ? 'Automation System' : user_name
|
||||
content = build_priority_change_content(user, old_priority, new_priority)
|
||||
|
||||
::Conversations::ActivityMessageJob.perform_later(self, activity_message_params(content)) if content
|
||||
end
|
||||
|
||||
def priority_change?(old_priority, new_priority)
|
||||
old_priority.present? || new_priority.present?
|
||||
end
|
||||
|
||||
def build_priority_change_content(user_name, old_priority = nil, new_priority = nil)
|
||||
change_type = get_priority_change_type(old_priority, new_priority)
|
||||
|
||||
I18n.t("conversations.activity.priority.#{change_type}", user_name: user_name, new_priority: new_priority, old_priority: old_priority)
|
||||
end
|
||||
|
||||
def get_priority_change_type(old_priority, new_priority)
|
||||
case [old_priority.present?, new_priority.present?]
|
||||
when [true, true] then 'updated'
|
||||
when [false, true] then 'added'
|
||||
when [true, false] then 'removed'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -149,6 +149,11 @@ class Conversation < ApplicationRecord
|
||||
save
|
||||
end
|
||||
|
||||
def toggle_priority(priority = nil)
|
||||
self.priority = priority.presence
|
||||
save
|
||||
end
|
||||
|
||||
def bot_handoff!
|
||||
open!
|
||||
dispatcher_dispatch(CONVERSATION_BOT_HANDOFF)
|
||||
|
||||
26
app/services/conversations/typing_status_manager.rb
Normal file
26
app/services/conversations/typing_status_manager.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
class Conversations::TypingStatusManager
|
||||
include Events::Types
|
||||
|
||||
attr_reader :conversation, :user, :params
|
||||
|
||||
def initialize(conversation, user, params)
|
||||
@conversation = conversation
|
||||
@user = user
|
||||
@params = params
|
||||
end
|
||||
|
||||
def trigger_typing_event(event, is_private)
|
||||
user = @user.presence || @resource
|
||||
Rails.configuration.dispatcher.dispatch(event, Time.zone.now, conversation: @conversation, user: user, is_private: is_private)
|
||||
end
|
||||
|
||||
def toggle_typing_status
|
||||
case params[:typing_status]
|
||||
when 'on'
|
||||
trigger_typing_event(CONVERSATION_TYPING_ON, params[:is_private])
|
||||
when 'off'
|
||||
trigger_typing_event(CONVERSATION_TYPING_OFF, params[:is_private])
|
||||
end
|
||||
# Return the head :ok response from the controller
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user