diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index e6270c807..86e21d9fd 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -24,9 +24,8 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController def search render json: { error: 'Specify search string with parameter q' }, status: :unprocessable_entity if params[:q].blank? && return - contacts = resolved_contacts.where( - 'name ILIKE :search OR email ILIKE :search OR phone_number ILIKE :search OR contacts.identifier LIKE :search - OR contacts.additional_attributes->>\'company_name\' ILIKE :search', + contacts = Current.account.contacts.where( + 'name ILIKE :search OR email ILIKE :search OR phone_number ILIKE :search OR contacts.identifier LIKE :search', search: "%#{params[:q].strip}%" ) @contacts = fetch_contacts(contacts) diff --git a/app/controllers/api/v1/accounts/conversations_controller.rb b/app/controllers/api/v1/accounts/conversations_controller.rb index 4301eaa4a..e2b930ac9 100644 --- a/app/controllers/api/v1/accounts/conversations_controller.rb +++ b/app/controllers/api/v1/accounts/conversations_controller.rb @@ -110,6 +110,15 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro end def update_last_seen + # High-traffic accounts generate excessive DB writes when agents frequently switch between conversations. + # Throttle last_seen updates to once per hour when there are no unread messages to reduce DB load. + # Always update immediately if there are unread messages to maintain accurate read/unread state. + return update_last_seen_on_conversation(DateTime.now.utc, true) if assignee? && @conversation.assignee_unread_messages.any? + return update_last_seen_on_conversation(DateTime.now.utc, false) if !assignee? && @conversation.unread_messages.any? + + # No unread messages - apply throttling to limit DB writes + return unless should_update_last_seen? + update_last_seen_on_conversation(DateTime.now.utc, assignee?) end @@ -142,12 +151,25 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro end def update_last_seen_on_conversation(last_seen_at, update_assignee) + updates = { agent_last_seen_at: last_seen_at } + updates[:assignee_last_seen_at] = last_seen_at if update_assignee.present? + # rubocop:disable Rails/SkipsModelValidations - @conversation.update_column(:agent_last_seen_at, last_seen_at) - @conversation.update_column(:assignee_last_seen_at, last_seen_at) if update_assignee.present? + @conversation.update_columns(updates) # rubocop:enable Rails/SkipsModelValidations end + def should_update_last_seen? + # Update if at least one relevant timestamp is older than 1 hour or not set + # This prevents redundant DB writes when agents repeatedly view the same conversation + agent_needs_update = @conversation.agent_last_seen_at.blank? || @conversation.agent_last_seen_at < 1.hour.ago + return agent_needs_update unless assignee? + + # For assignees, check both timestamps - update if either is old + assignee_needs_update = @conversation.assignee_last_seen_at.blank? || @conversation.assignee_last_seen_at < 1.hour.ago + agent_needs_update || assignee_needs_update + end + def set_conversation_status @conversation.status = params[:status] @conversation.snoozed_until = parse_date_time(params[:snoozed_until].to_s) if params[:snoozed_until] diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index 57062a5b2..bcbf80355 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -92,8 +92,11 @@ class Api::V1::AccountsController < Api::BaseController end def settings_params - params.permit(:auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting, :audio_transcriptions, :auto_resolve_label, - conversation_required_attributes: []) + params.permit(*permitted_settings_attributes) + end + + def permitted_settings_attributes + [:auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting, :audio_transcriptions, :auto_resolve_label] end def check_signup_enabled @@ -112,3 +115,5 @@ class Api::V1::AccountsController < Api::BaseController } end end + +Api::V1::AccountsController.prepend_mod_with('Api::V1::AccountsSettings') diff --git a/app/javascript/dashboard/assets/images/auth/signup-bg.jpg b/app/javascript/dashboard/assets/images/auth/signup-bg.jpg new file mode 100644 index 000000000..884a57922 Binary files /dev/null and b/app/javascript/dashboard/assets/images/auth/signup-bg.jpg differ diff --git a/app/javascript/dashboard/components-next/Conversation/ConversationRequiredEmpty.vue b/app/javascript/dashboard/components-next/Conversation/ConversationRequiredEmpty.vue new file mode 100644 index 000000000..36687245e --- /dev/null +++ b/app/javascript/dashboard/components-next/Conversation/ConversationRequiredEmpty.vue @@ -0,0 +1,17 @@ + + + diff --git a/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationRequiredAttributeItem.vue b/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationRequiredAttributeItem.vue new file mode 100644 index 000000000..70b4a7af5 --- /dev/null +++ b/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationRequiredAttributeItem.vue @@ -0,0 +1,56 @@ + + + diff --git a/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationRequiredAttributes.vue b/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationRequiredAttributes.vue new file mode 100644 index 000000000..e611dd637 --- /dev/null +++ b/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationRequiredAttributes.vue @@ -0,0 +1,186 @@ + + + diff --git a/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationResolveAttributesModal.vue b/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationResolveAttributesModal.vue new file mode 100644 index 000000000..12e13f11e --- /dev/null +++ b/app/javascript/dashboard/components-next/ConversationWorkflow/ConversationResolveAttributesModal.vue @@ -0,0 +1,248 @@ + + +