diff --git a/Gemfile b/Gemfile index 53ba9f783..269614d8b 100644 --- a/Gemfile +++ b/Gemfile @@ -121,6 +121,8 @@ gem 'sentry-sidekiq', '>= 5.19.0', require: false gem 'sidekiq', '>= 7.3.1' # We want cron jobs gem 'sidekiq-cron', '>= 1.12.0' +# for sidekiq healthcheck +gem 'sidekiq_alive' ##-- Push notification service --## gem 'fcm' diff --git a/Gemfile.lock b/Gemfile.lock index a4a288f07..405300a7c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -359,6 +359,7 @@ GEM grpc (1.72.0-x86_64-linux) google-protobuf (>= 3.25, < 5.0) googleapis-common-protos-types (~> 1.0) + gserver (0.0.1) haikunator (1.1.1) hairtrigger (1.0.0) activerecord (>= 6.0, < 8) @@ -785,6 +786,9 @@ GEM fugit (~> 1.8) globalid (>= 1.0.1) sidekiq (>= 6) + sidekiq_alive (2.5.0) + gserver (~> 0.0.1) + sidekiq (>= 5, < 9) signet (0.17.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) @@ -1010,6 +1014,7 @@ DEPENDENCIES shoulda-matchers sidekiq (>= 7.3.1) sidekiq-cron (>= 1.12.0) + sidekiq_alive simplecov (= 0.17.1) slack-ruby-client (~> 2.5.2) spring diff --git a/app/actions/contact_identify_action.rb b/app/actions/contact_identify_action.rb index a88d3535b..bcf5a93c3 100644 --- a/app/actions/contact_identify_action.rb +++ b/app/actions/contact_identify_action.rb @@ -6,6 +6,7 @@ # We don't want to update the name of the identified original contact. class ContactIdentifyAction + include UrlHelper pattr_initialize [:contact!, :params!, { retain_original_contact_name: false, discard_invalid_attrs: false }] def perform @@ -104,7 +105,14 @@ class ContactIdentifyAction # TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded @contact.discard_invalid_attrs if discard_invalid_attrs @contact.save! - Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present? && !@contact.avatar.attached? + enqueue_avatar_job + end + + def enqueue_avatar_job + return unless params[:avatar_url].present? && !@contact.avatar.attached? + return unless url_valid?(params[:avatar_url]) + + Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url]) end def merge_contact(base_contact, merge_contact) diff --git a/app/controllers/api/v1/accounts/contacts_controller.rb b/app/controllers/api/v1/accounts/contacts_controller.rb index 4fbe50902..039786905 100644 --- a/app/controllers/api/v1/accounts/contacts_controller.rb +++ b/app/controllers/api/v1/accounts/contacts_controller.rb @@ -122,7 +122,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController def resolved_contacts return @resolved_contacts if @resolved_contacts - @resolved_contacts = Current.account.contacts.resolved_contacts + @resolved_contacts = Current.account.contacts.resolved_contacts(use_crm_v2: Current.account.feature_enabled?('crm_v2')) @resolved_contacts = @resolved_contacts.tagged_with(params[:labels], any: true) if params[:labels].present? @resolved_contacts diff --git a/app/controllers/microsoft_controller.rb b/app/controllers/microsoft_controller.rb index e6a12dafa..3071eac31 100644 --- a/app/controllers/microsoft_controller.rb +++ b/app/controllers/microsoft_controller.rb @@ -2,7 +2,7 @@ class MicrosoftController < ApplicationController after_action :set_version_header def identity_association - microsoft_indentity + microsoft_identity end private @@ -11,7 +11,7 @@ class MicrosoftController < ApplicationController response.headers['Content-Length'] = { associatedApplications: [{ applicationId: @identity_json }] }.to_json.length end - def microsoft_indentity + def microsoft_identity @identity_json = GlobalConfigService.load('AZURE_APP_ID', nil) end end diff --git a/app/controllers/webhooks/instagram_controller.rb b/app/controllers/webhooks/instagram_controller.rb index 3d46334ca..569c2524b 100644 --- a/app/controllers/webhooks/instagram_controller.rb +++ b/app/controllers/webhooks/instagram_controller.rb @@ -4,7 +4,16 @@ class Webhooks::InstagramController < ActionController::API def events Rails.logger.info('Instagram webhook received events') if params['object'].casecmp('instagram').zero? - ::Webhooks::InstagramEventsJob.perform_later(params.to_unsafe_hash[:entry]) + entry_params = params.to_unsafe_hash[:entry] + + if contains_echo_event?(entry_params) + # Add delay to prevent race condition where echo arrives before send message API completes + # This avoids duplicate messages when echo comes early during API processing + ::Webhooks::InstagramEventsJob.set(wait: 2.seconds).perform_later(entry_params) + else + ::Webhooks::InstagramEventsJob.perform_later(entry_params) + end + render json: :ok else Rails.logger.warn("Message is not received from the instagram webhook event: #{params['object']}") @@ -14,6 +23,16 @@ class Webhooks::InstagramController < ActionController::API private + def contains_echo_event?(entry_params) + return false unless entry_params.is_a?(Array) + + entry_params.any? do |entry| + # Check messaging array for echo events + messaging_events = entry[:messaging] || [] + messaging_events.any? { |messaging| messaging.dig(:message, :is_echo).present? } + end + end + def valid_token?(token) # Validates against both IG_VERIFY_TOKEN (Instagram channel via Facebook page) and # INSTAGRAM_VERIFY_TOKEN (Instagram channel via direct Instagram login) diff --git a/app/javascript/dashboard/i18n/locale/am/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/am/inboxMgmt.json index eb999a0e5..12580bcac 100644 --- a/app/javascript/dashboard/i18n/locale/am/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/am/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/am/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/am/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/am/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/am/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/ar/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ar/inboxMgmt.json index 9997b7ce0..c860f0a6f 100644 --- a/app/javascript/dashboard/i18n/locale/ar/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ar/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "تحديث", "WHATSAPP_WEBHOOK_TITLE": "رمز التحقق من Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ar/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ar/whatsappTemplates.json index 7e1af5c74..110eeb8af 100644 --- a/app/javascript/dashboard/i18n/locale/ar/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ar/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "نماذج البحث", "NO_TEMPLATES_FOUND": "لم يتم العثور على قوالب", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "اللغة", "TEMPLATE_BODY": "نص القالب", diff --git a/app/javascript/dashboard/i18n/locale/az/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/az/inboxMgmt.json index eb999a0e5..12580bcac 100644 --- a/app/javascript/dashboard/i18n/locale/az/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/az/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/az/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/az/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/az/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/az/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/bg/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/bg/inboxMgmt.json index 307316da2..30fa620ff 100644 --- a/app/javascript/dashboard/i18n/locale/bg/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/bg/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Обновяване", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/bg/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/bg/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/bg/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/bg/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json index f0a3dc025..3a7961688 100644 --- a/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ca/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Actualitza", "WHATSAPP_WEBHOOK_TITLE": "Token de verificació del webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "Aquest testimoni s'utilitza per verificar l'autenticitat del punt final del webhook.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Actualitza la configuració del formulari de xat prèvia" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ca/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ca/whatsappTemplates.json index f293b6e02..f078ec706 100644 --- a/app/javascript/dashboard/i18n/locale/ca/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ca/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Cerca plantilles", "NO_TEMPLATES_FOUND": "No s'han trobat plantilles per a", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Idioma", "TEMPLATE_BODY": "Cos de la plantilla", diff --git a/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json index becbdf6b5..8b0498ce5 100644 --- a/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/cs/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Aktualizovat", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/cs/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/cs/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/cs/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/cs/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json index fbeca4824..579ee2f75 100644 --- a/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/da/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Opdater", "WHATSAPP_WEBHOOK_TITLE": "Webhook verifikations token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/da/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/da/whatsappTemplates.json index 615e1b198..3acb3acb3 100644 --- a/app/javascript/dashboard/i18n/locale/da/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/da/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Søg Skabeloner", "NO_TEMPLATES_FOUND": "Ingen skabeloner fundet for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Sprog", "TEMPLATE_BODY": "Skabelon Krop", diff --git a/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json index f93636892..2c2eda452 100644 --- a/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/de/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Aktualisieren", "WHATSAPP_WEBHOOK_TITLE": "Webhook-Verifizierungstoken", "WHATSAPP_WEBHOOK_SUBHEADER": "Mit diesem Token wird die Authentizität des Webhook Endpunktes überprüft.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Pre Chat Einstellungen aktualisieren" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/de/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/de/whatsappTemplates.json index 43d36d1a7..b5f1885ae 100644 --- a/app/javascript/dashboard/i18n/locale/de/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/de/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Vorlagen suchen", "NO_TEMPLATES_FOUND": "Keine Vorlagen gefunden für", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Sprache", "TEMPLATE_BODY": "Vorlagenbody", diff --git a/app/javascript/dashboard/i18n/locale/el/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/el/inboxMgmt.json index ed5eb6a9b..686b788f8 100644 --- a/app/javascript/dashboard/i18n/locale/el/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/el/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Ενημέρωση", "WHATSAPP_WEBHOOK_TITLE": "Token Επαλήθευσης Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/el/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/el/whatsappTemplates.json index ce640b102..d78b9cb12 100644 --- a/app/javascript/dashboard/i18n/locale/el/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/el/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Αναζήτηση Προτύπων", "NO_TEMPLATES_FOUND": "Δεν βρέθηκαν πρότυπα για", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Γλώσσα", "TEMPLATE_BODY": "Σώμα Προτύπου", diff --git a/app/javascript/dashboard/i18n/locale/es/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/es/inboxMgmt.json index a1c46f0f5..848b7f3d3 100644 --- a/app/javascript/dashboard/i18n/locale/es/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/es/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Actualizar", "WHATSAPP_WEBHOOK_TITLE": "Token de verificación del Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "Este token se utiliza para verificar la autenticidad del extremo del webhook.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Actualizar configuración de Formulario de Chat" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/es/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/es/whatsappTemplates.json index 85290f8e0..49a89e381 100644 --- a/app/javascript/dashboard/i18n/locale/es/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/es/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Buscar plantillas", "NO_TEMPLATES_FOUND": "No se encontraron plantillas para", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Idioma", "TEMPLATE_BODY": "Cuerpo de plantilla", diff --git a/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json index a54d6afff..356766d0a 100644 --- a/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/fa/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "اعمال شود", "WHATSAPP_WEBHOOK_TITLE": "توکن تایید Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "این توکن برای تأیید صحت نقطه پایانی webhook استفاده می شود.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "به‌روزرسانی تنظیمات فرم قبل از گفتگو" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/fa/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/fa/whatsappTemplates.json index 048df8a7e..3b470e99f 100644 --- a/app/javascript/dashboard/i18n/locale/fa/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/fa/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "جستجوی الگوها", "NO_TEMPLATES_FOUND": "هیچ قالبی برای", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "زبان", "TEMPLATE_BODY": "بدنه الگو", diff --git a/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json index 42f621738..e12f895f4 100644 --- a/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/fi/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Päivitä", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/fi/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/fi/whatsappTemplates.json index d8b18b589..ae8bee085 100644 --- a/app/javascript/dashboard/i18n/locale/fi/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/fi/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Etsi Pohjia", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/fr/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/fr/inboxMgmt.json index c0df640e5..f5c21e5c5 100644 --- a/app/javascript/dashboard/i18n/locale/fr/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/fr/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Mettre à jour", "WHATSAPP_WEBHOOK_TITLE": "Jeton de vérification du Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "Ce jeton est utilisé pour vérifier l'authenticité du point de terminaison du webhook.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Mettre à jour les paramètres du formulaire de pré-chat" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/fr/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/fr/whatsappTemplates.json index 2d0268652..0d4538240 100644 --- a/app/javascript/dashboard/i18n/locale/fr/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/fr/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Rechercher des modèles", "NO_TEMPLATES_FOUND": "Aucun modèle trouvé pour", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Langue", "TEMPLATE_BODY": "Corps du modèle", diff --git a/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json index 12fdadab6..12724f7cc 100644 --- a/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/he/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "עדכן", "WHATSAPP_WEBHOOK_TITLE": "אסימון אימות Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "עדכון הגדרות טופס טרום צ'אט" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/he/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/he/whatsappTemplates.json index 110fa450c..295b89a23 100644 --- a/app/javascript/dashboard/i18n/locale/he/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/he/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "חפש תבניות", "NO_TEMPLATES_FOUND": "לא נמצאו תבניות עבור", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "שפה", "TEMPLATE_BODY": "גוף התבנית", diff --git a/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json index eeef8cd62..57d6e2638 100644 --- a/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/hi/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/hi/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/hi/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/hi/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/hi/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/hr/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/hr/inboxMgmt.json index fc75295f1..09e1f475e 100644 --- a/app/javascript/dashboard/i18n/locale/hr/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/hr/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "Ovaj token se koristi za verifikaciju autentičnosti webhook endpoint-a.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/hr/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/hr/whatsappTemplates.json index 79c85ae02..d943a13c1 100644 --- a/app/javascript/dashboard/i18n/locale/hr/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/hr/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Pretraži Predloške", "NO_TEMPLATES_FOUND": "Nije pronađen predložak za", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Jezik", "TEMPLATE_BODY": "Tijelo predloška", diff --git a/app/javascript/dashboard/i18n/locale/hu/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/hu/inboxMgmt.json index 809801964..76d49274d 100644 --- a/app/javascript/dashboard/i18n/locale/hu/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/hu/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Frissítés", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "Ez a token a webhook-végpont hitelességének ellenőrzésére szolgál.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Csevegés előtti űrlap beállításainak frissítése" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/hu/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/hu/whatsappTemplates.json index 056d12a33..860ef1875 100644 --- a/app/javascript/dashboard/i18n/locale/hu/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/hu/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Sablon keresése", "NO_TEMPLATES_FOUND": "Nem található sablon erre:", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Nyelv", "TEMPLATE_BODY": "Sablon törzse", diff --git a/app/javascript/dashboard/i18n/locale/hy/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/hy/inboxMgmt.json index 06dbdcc73..09d6ca675 100644 --- a/app/javascript/dashboard/i18n/locale/hy/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/hy/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/hy/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/hy/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/hy/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/hy/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/id/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/id/inboxMgmt.json index 7ab7c5442..d0c631673 100644 --- a/app/javascript/dashboard/i18n/locale/id/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/id/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Perbarui", "WHATSAPP_WEBHOOK_TITLE": "Token Verifikasi Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "Token ini digunakan untuk memverifikasi keaslian titik akhir webhook.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Perbarui Pengaturan Formulir Pra Obrolan" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/id/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/id/whatsappTemplates.json index 2138d3686..88a806522 100644 --- a/app/javascript/dashboard/i18n/locale/id/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/id/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Cari Templat", "NO_TEMPLATES_FOUND": "Tidak ditemukan templat untuk", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Bahasa", "TEMPLATE_BODY": "Isi Templat", diff --git a/app/javascript/dashboard/i18n/locale/is/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/is/inboxMgmt.json index 5092c3e80..4e001a8b1 100644 --- a/app/javascript/dashboard/i18n/locale/is/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/is/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Uppfæra", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/is/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/is/whatsappTemplates.json index 769f12f57..0be0dfc90 100644 --- a/app/javascript/dashboard/i18n/locale/is/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/is/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json index 0ad3c6161..6d075169e 100644 --- a/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/it/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Aggiorna", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/it/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/it/whatsappTemplates.json index 4a27a4904..2e1db45c7 100644 --- a/app/javascript/dashboard/i18n/locale/it/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/it/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Cerca modelli", "NO_TEMPLATES_FOUND": "Nessun modello trovato per", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Lingua", "TEMPLATE_BODY": "Corpo modello", diff --git a/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json index f36d38112..af6125b41 100644 --- a/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ja/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "更新", "WHATSAPP_WEBHOOK_TITLE": "Webhook検証トークン", "WHATSAPP_WEBHOOK_SUBHEADER": "このトークンはWebhookエンドポイントの信頼性を検証するために使用されます。", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "プレチャットフォーム設定を更新する" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ja/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ja/whatsappTemplates.json index 665d8d3f8..de389b44c 100644 --- a/app/javascript/dashboard/i18n/locale/ja/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ja/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "テンプレートを検索", "NO_TEMPLATES_FOUND": "該当するテンプレートが見つかりません:", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "言語", "TEMPLATE_BODY": "テンプレート本文", diff --git a/app/javascript/dashboard/i18n/locale/ka/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ka/inboxMgmt.json index eeef8cd62..57d6e2638 100644 --- a/app/javascript/dashboard/i18n/locale/ka/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ka/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ka/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ka/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/ka/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ka/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/ko/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ko/inboxMgmt.json index d8f57d823..44438a260 100644 --- a/app/javascript/dashboard/i18n/locale/ko/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ko/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "업데이트", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ko/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ko/whatsappTemplates.json index 5fe227b68..71fc338da 100644 --- a/app/javascript/dashboard/i18n/locale/ko/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ko/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "언어", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/lt/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/lt/inboxMgmt.json index 03ce79011..e229569ff 100644 --- a/app/javascript/dashboard/i18n/locale/lt/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/lt/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Atnaujinti", "WHATSAPP_WEBHOOK_TITLE": "Webhook Patikros Prieigos Raktas", "WHATSAPP_WEBHOOK_SUBHEADER": "Šis prieigos raktas naudojamas „webhook“ galutinio taško autentiškumui patikrinti.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Atnaujinkite išankstinio pokalbio internetu formos nustatymus" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/lt/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/lt/whatsappTemplates.json index 75eda5a04..7c9073480 100644 --- a/app/javascript/dashboard/i18n/locale/lt/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/lt/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Ieškoti šablonų", "NO_TEMPLATES_FOUND": "Šablonų nerasta", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Kalba", "TEMPLATE_BODY": "Šablono tekstas", diff --git a/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json index bfb996bf1..d1df5a94b 100644 --- a/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/lv/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Atjaunināt", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verifikācijas Token", "WHATSAPP_WEBHOOK_SUBHEADER": "Šis marķieris tiek izmantots, lai pārbaudītu webhook endpoint autentiskumu.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Atjaunināt pirms-tērzēšanas veidlapas iestatījumus" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/lv/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/lv/whatsappTemplates.json index c2ad34cd9..330ab173d 100644 --- a/app/javascript/dashboard/i18n/locale/lv/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/lv/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Meklēt Veidnes", "NO_TEMPLATES_FOUND": "Veidnes nav atrastas", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Valoda", "TEMPLATE_BODY": "Veidnes Pamatteksts", diff --git a/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json index a22c09726..ac8284ac0 100644 --- a/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ml/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "അപ്‌ഡേറ്റ്", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ml/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ml/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/ml/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ml/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/ms/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ms/inboxMgmt.json index 6af7f101a..9e91cd8dc 100644 --- a/app/javascript/dashboard/i18n/locale/ms/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ms/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ms/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ms/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/ms/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ms/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json index a1541301d..3459f22ac 100644 --- a/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ne/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ne/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ne/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/ne/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ne/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json index aefb80c0c..9f1286294 100644 --- a/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/nl/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Vernieuwen", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/nl/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/nl/whatsappTemplates.json index fbdb18c74..4061f4090 100644 --- a/app/javascript/dashboard/i18n/locale/nl/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/nl/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Templates zoeken", "NO_TEMPLATES_FOUND": "Geen templates gevonden voor", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Taal", "TEMPLATE_BODY": "Template bericht", diff --git a/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json index 0c7feb225..88ade0a31 100644 --- a/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/no/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Oppdater", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/no/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/no/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/no/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/no/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/pl/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/pl/inboxMgmt.json index a1d6f5224..95028bbd5 100644 --- a/app/javascript/dashboard/i18n/locale/pl/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/pl/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Aktualizuj", "WHATSAPP_WEBHOOK_TITLE": "Token weryfikacyjny webhooka", "WHATSAPP_WEBHOOK_SUBHEADER": "Ten token służy do weryfikacji autentyczności punktu końcowego webhooka.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Aktualizacja ustawień formularza czatu wstępnego" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/pl/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/pl/whatsappTemplates.json index 027e98826..fb87e1425 100644 --- a/app/javascript/dashboard/i18n/locale/pl/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/pl/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Wyszukaj szablony", "NO_TEMPLATES_FOUND": "Nie znaleziono szablonów dla", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Język", "TEMPLATE_BODY": "Treść szablonu", diff --git a/app/javascript/dashboard/i18n/locale/pt/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/pt/inboxMgmt.json index 6a6e8ae61..6fa646120 100644 --- a/app/javascript/dashboard/i18n/locale/pt/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/pt/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Atualização", "WHATSAPP_WEBHOOK_TITLE": "Webhook de verificação do token", "WHATSAPP_WEBHOOK_SUBHEADER": "Este token é usado para verificar a autenticidade do endpoint do webhook.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Atualizar configurações do formulário pré-chat" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/pt/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/pt/whatsappTemplates.json index a653ccc2b..cba42fd01 100644 --- a/app/javascript/dashboard/i18n/locale/pt/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/pt/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Buscar templates", "NO_TEMPLATES_FOUND": "Nenhum template encontrado para", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Idioma", "TEMPLATE_BODY": "Corpo do Template", diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/pt_BR/inboxMgmt.json index 6fceba988..aac205dec 100644 --- a/app/javascript/dashboard/i18n/locale/pt_BR/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/pt_BR/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Atualizar", "WHATSAPP_WEBHOOK_TITLE": "Token de verificação Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "Este token é usado para verificar a autenticidade do webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Atualizar configurações do Formulário Pre Chat" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/pt_BR/whatsappTemplates.json index b47ce0a0f..1149bc577 100644 --- a/app/javascript/dashboard/i18n/locale/pt_BR/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/pt_BR/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Pesquisar modelos", "NO_TEMPLATES_FOUND": "Não há templates encontrados para", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Idioma", "TEMPLATE_BODY": "Conteúdo do Template", diff --git a/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json index 23910df30..d1079d98a 100644 --- a/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ro/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Actualizare", "WHATSAPP_WEBHOOK_TITLE": "Token de verificare Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "Acest simbol este utilizat pentru a verifica autenticitatea punctului final webhook.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Actualizarea setărilor formularului pre-chat" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ro/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ro/whatsappTemplates.json index c85cda192..fda8d7b10 100644 --- a/app/javascript/dashboard/i18n/locale/ro/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ro/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Caută Șabloane", "NO_TEMPLATES_FOUND": "Nu s-au găsit șabloane pentru", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Limbă", "TEMPLATE_BODY": "Corpul șablonului", diff --git a/app/javascript/dashboard/i18n/locale/ru/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ru/inboxMgmt.json index 12d0263bf..01a066111 100644 --- a/app/javascript/dashboard/i18n/locale/ru/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ru/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Обновить", "WHATSAPP_WEBHOOK_TITLE": "Токен авторизации Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "Этот токен используется для проверки подлинности конечной точки веб-хука.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Обновить настройки формы для чата" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ru/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ru/whatsappTemplates.json index ad80dfe97..65c55ec5a 100644 --- a/app/javascript/dashboard/i18n/locale/ru/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ru/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Найти шаблоны", "NO_TEMPLATES_FOUND": "Не найдено шаблонов для", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Язык", "TEMPLATE_BODY": "Тело шаблона", diff --git a/app/javascript/dashboard/i18n/locale/sh/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sh/inboxMgmt.json index df6c99bfb..3b17580a1 100644 --- a/app/javascript/dashboard/i18n/locale/sh/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sh/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/sh/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/sh/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/sh/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/sh/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json index 87ba5f9ca..90d9c77a9 100644 --- a/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sk/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/sk/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/sk/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/sk/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/sk/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/sl/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sl/inboxMgmt.json index 238693790..8e21df55f 100644 --- a/app/javascript/dashboard/i18n/locale/sl/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sl/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/sl/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/sl/whatsappTemplates.json index ac0c45dd1..eb4acbea6 100644 --- a/app/javascript/dashboard/i18n/locale/sl/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/sl/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Išči predloge", "NO_TEMPLATES_FOUND": "Ni najdenih predlog za", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Jezik", "TEMPLATE_BODY": "Telo predloge", diff --git a/app/javascript/dashboard/i18n/locale/sq/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sq/inboxMgmt.json index aa5f0adee..f8a52e0dd 100644 --- a/app/javascript/dashboard/i18n/locale/sq/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sq/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/sq/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/sq/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/sq/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/sq/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/sr/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sr/inboxMgmt.json index 1a7b2a8a3..4e3769406 100644 --- a/app/javascript/dashboard/i18n/locale/sr/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sr/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Primeni", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/sr/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/sr/whatsappTemplates.json index 3917f4492..27fed1503 100644 --- a/app/javascript/dashboard/i18n/locale/sr/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/sr/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Pretraži šablone", "NO_TEMPLATES_FOUND": "Nijedan šablon nije pronađen", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Jezik", "TEMPLATE_BODY": "Telo šablona", diff --git a/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json index 5c2e6f4ab..3b11970b5 100644 --- a/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/sv/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Uppdatera", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/sv/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/sv/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/sv/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/sv/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json index 7210fbab6..f06cd63aa 100644 --- a/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ta/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "புதுப்பிப்பு", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ta/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ta/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/ta/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ta/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json index dcb41a268..e5ac0a41e 100644 --- a/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/th/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "อัพเดท", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/th/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/th/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/th/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/th/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/tl/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/tl/inboxMgmt.json index eb999a0e5..12580bcac 100644 --- a/app/javascript/dashboard/i18n/locale/tl/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/tl/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/tl/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/tl/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/tl/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/tl/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json index d5c5ffc1c..2250d18bf 100644 --- a/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/tr/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Güncelleme", "WHATSAPP_WEBHOOK_TITLE": "Webhook Onay Anahtarı", "WHATSAPP_WEBHOOK_SUBHEADER": "Bu belirteç, webhook uç noktasının gerçekliğini doğrulamak için kullanılır.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Sohbet Öncesi Form Ayarlarını Güncelleme" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/tr/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/tr/whatsappTemplates.json index 1cf941924..da51ff735 100644 --- a/app/javascript/dashboard/i18n/locale/tr/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/tr/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Şablon Ara", "NO_TEMPLATES_FOUND": "İçin hiç şablon bulunamadı", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Dil", "TEMPLATE_BODY": "Şablon İçeriği", diff --git a/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json index e34582162..0fa97089d 100644 --- a/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/uk/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Оновити", "WHATSAPP_WEBHOOK_TITLE": "Токен вебхука", "WHATSAPP_WEBHOOK_SUBHEADER": "Цей токен використовується для перевірки аутентифікації кінцевої точки вебхука.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Оновити параметри форми чату" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/uk/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/uk/whatsappTemplates.json index 2e931d010..1246919f5 100644 --- a/app/javascript/dashboard/i18n/locale/uk/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/uk/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Знайти шаблони", "NO_TEMPLATES_FOUND": "Шаблонів не знайдено для", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Мова", "TEMPLATE_BODY": "Тіло шаблона", diff --git a/app/javascript/dashboard/i18n/locale/ur/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ur/inboxMgmt.json index a8361a0fe..b3f5d540e 100644 --- a/app/javascript/dashboard/i18n/locale/ur/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ur/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ur/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ur/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/ur/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ur/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/ur_IN/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/ur_IN/inboxMgmt.json index 934486410..03b5606f6 100644 --- a/app/javascript/dashboard/i18n/locale/ur_IN/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/ur_IN/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Update", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/ur_IN/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/ur_IN/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/ur_IN/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/ur_IN/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json index 0c09fd138..1ad17adce 100644 --- a/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/vi/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "Cập nhật", "WHATSAPP_WEBHOOK_TITLE": "Mã xác minh Webhook", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/vi/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/vi/whatsappTemplates.json index c51c559d9..a4abce833 100644 --- a/app/javascript/dashboard/i18n/locale/vi/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/vi/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Tìm kiếm Mẫu", "NO_TEMPLATES_FOUND": "Không tìm thấy mẫu nào cho", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Ngôn ngữ", "TEMPLATE_BODY": "Nội dung của Mẫu", diff --git a/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json index f87105d9e..fa567b20e 100644 --- a/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/zh_CN/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "更新", "WHATSAPP_WEBHOOK_TITLE": "Webhook 验证令牌", "WHATSAPP_WEBHOOK_SUBHEADER": "此令牌用于验证webhook端点的真实性。", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "更新预聊天表单设置" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/zh_CN/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/zh_CN/whatsappTemplates.json index 6d1b67022..cade063c0 100644 --- a/app/javascript/dashboard/i18n/locale/zh_CN/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/zh_CN/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "查找模板", "NO_TEMPLATES_FOUND": "没有找到对应的模版", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "语言", "TEMPLATE_BODY": "模板内容", diff --git a/app/javascript/dashboard/i18n/locale/zh_TW/inboxMgmt.json b/app/javascript/dashboard/i18n/locale/zh_TW/inboxMgmt.json index 5489bff6d..ffd0f7765 100644 --- a/app/javascript/dashboard/i18n/locale/zh_TW/inboxMgmt.json +++ b/app/javascript/dashboard/i18n/locale/zh_TW/inboxMgmt.json @@ -600,6 +600,10 @@ "WHATSAPP_SECTION_UPDATE_BUTTON": "更新", "WHATSAPP_WEBHOOK_TITLE": "Webhook Verification Token", "WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.", + "WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Manually sync message templates from WhatsApp to update your available templates.", + "WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sync Templates", + "WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Templates sync initiated successfully. It may take a couple of minutes to update.", "UPDATE_PRE_CHAT_FORM_SETTINGS": "Update Pre Chat Form Settings" }, "HELP_CENTER": { diff --git a/app/javascript/dashboard/i18n/locale/zh_TW/whatsappTemplates.json b/app/javascript/dashboard/i18n/locale/zh_TW/whatsappTemplates.json index b1d22ecd1..4887d07b6 100644 --- a/app/javascript/dashboard/i18n/locale/zh_TW/whatsappTemplates.json +++ b/app/javascript/dashboard/i18n/locale/zh_TW/whatsappTemplates.json @@ -8,6 +8,10 @@ "PICKER": { "SEARCH_PLACEHOLDER": "Search Templates", "NO_TEMPLATES_FOUND": "No templates found for", + "NO_TEMPLATES_AVAILABLE": "No WhatsApp templates available. Click refresh to sync templates from WhatsApp.", + "REFRESH_BUTTON": "Refresh templates", + "REFRESH_SUCCESS": "Templates refresh initiated. It may take a couple of minutes to update.", + "REFRESH_ERROR": "Failed to refresh templates. Please try again.", "LABELS": { "LANGUAGE": "Language", "TEMPLATE_BODY": "Template Body", diff --git a/app/jobs/account/contacts_export_job.rb b/app/jobs/account/contacts_export_job.rb index 33edcaa34..952795604 100644 --- a/app/jobs/account/contacts_export_job.rb +++ b/app/jobs/account/contacts_export_job.rb @@ -29,9 +29,9 @@ class Account::ContactsExportJob < ApplicationJob result = ::Contacts::FilterService.new(@account, @account_user, @params).perform result[:contacts] elsif @params[:label].present? - @account.contacts.resolved_contacts.tagged_with(@params[:label], any: true) + @account.contacts.resolved_contacts(use_crm_v2: @account.feature_enabled?('crm_v2')).tagged_with(@params[:label], any: true) else - @account.contacts.resolved_contacts + @account.contacts.resolved_contacts(use_crm_v2: @account.feature_enabled?('crm_v2')) end end diff --git a/app/jobs/avatar/avatar_from_gravatar_job.rb b/app/jobs/avatar/avatar_from_gravatar_job.rb index 4a967d74f..46efc3dd8 100644 --- a/app/jobs/avatar/avatar_from_gravatar_job.rb +++ b/app/jobs/avatar/avatar_from_gravatar_job.rb @@ -1,5 +1,5 @@ class Avatar::AvatarFromGravatarJob < ApplicationJob - queue_as :low + queue_as :purgable def perform(avatarable, email) return if GlobalConfigService.load('DISABLE_GRAVATAR', '').present? diff --git a/app/jobs/avatar/avatar_from_url_job.rb b/app/jobs/avatar/avatar_from_url_job.rb index f0d877b54..9996cf3eb 100644 --- a/app/jobs/avatar/avatar_from_url_job.rb +++ b/app/jobs/avatar/avatar_from_url_job.rb @@ -1,5 +1,5 @@ class Avatar::AvatarFromUrlJob < ApplicationJob - queue_as :low + queue_as :purgable def perform(avatarable, avatar_url) return unless avatarable.respond_to?(:avatar) diff --git a/app/models/channel/whatsapp.rb b/app/models/channel/whatsapp.rb index b7bfd0da7..8d054a586 100644 --- a/app/models/channel/whatsapp.rb +++ b/app/models/channel/whatsapp.rb @@ -34,6 +34,7 @@ class Channel::Whatsapp < ApplicationRecord after_create :sync_templates after_create_commit :setup_webhooks + before_destroy :teardown_webhooks def name 'Whatsapp' @@ -105,4 +106,8 @@ class Channel::Whatsapp < ApplicationRecord # Don't raise the error to prevent channel creation from failing # Webhooks can be retried later end + + def teardown_webhooks + Whatsapp::WebhookTeardownService.new(self).perform + end end diff --git a/app/models/contact.rb b/app/models/contact.rb index 83920d9fc..a3570b2af 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -25,6 +25,7 @@ # Indexes # # index_contacts_on_account_id (account_id) +# index_contacts_on_account_id_and_contact_type (account_id,contact_type) # index_contacts_on_account_id_and_last_activity_at (account_id,last_activity_at DESC NULLS LAST) # index_contacts_on_blocked (blocked) # index_contacts_on_lower_email_account_id (lower((email)::text), account_id) @@ -175,8 +176,12 @@ class Contact < ApplicationRecord } end - def self.resolved_contacts - where("contacts.email <> '' OR contacts.phone_number <> '' OR contacts.identifier <> ''") + def self.resolved_contacts(use_crm_v2: false) + if use_crm_v2 + where(contact_type: 'lead') + else + where("contacts.email <> '' OR contacts.phone_number <> '' OR contacts.identifier <> ''") + end end def discard_invalid_attrs diff --git a/app/models/portal.rb b/app/models/portal.rb index cb87929f5..a62ba8e4d 100644 --- a/app/models/portal.rb +++ b/app/models/portal.rb @@ -12,6 +12,7 @@ # name :string not null # page_title :string # slug :string not null +# ssl_settings :jsonb not null # created_at :datetime not null # updated_at :datetime not null # account_id :integer not null @@ -69,3 +70,5 @@ class Portal < ApplicationRecord errors.add(:cofig, "in portal on #{denied_keys.join(',')} is not supported.") if denied_keys.any? end end + +Portal.include_mod_with('Concerns::Portal') diff --git a/app/services/instagram/message_text.rb b/app/services/instagram/message_text.rb index e4b88c64d..3b371a2f4 100644 --- a/app/services/instagram/message_text.rb +++ b/app/services/instagram/message_text.rb @@ -14,10 +14,11 @@ class Instagram::MessageText < Instagram::BaseMessageText return process_successful_response(response) if response.success? - handle_error_response(response) - {} + handle_error_response(response, ig_scope_id) || {} end + private + def process_successful_response(response) result = JSON.parse(response.body).with_indifferent_access { @@ -32,8 +33,9 @@ class Instagram::MessageText < Instagram::BaseMessageText }.with_indifferent_access end - def handle_error_response(response) + def handle_error_response(response, ig_scope_id) parsed_response = response.parsed_response + parsed_response = JSON.parse(parsed_response) if parsed_response.is_a?(String) error_message = parsed_response.dig('error', 'message') error_code = parsed_response.dig('error', 'code') @@ -50,10 +52,17 @@ class Instagram::MessageText < Instagram::BaseMessageText # We can safely ignore this error. return if error_code == 230 - Rails.logger.warn("[InstagramUserFetchError]: account_id #{@inbox.account_id} inbox_id #{@inbox.id}") + # The error occurs when Facebook tries to validate the Facebook App created to authorize Instagram integration. + # The Facebook's agent uses a Bot to make tests on the App where is not a valid user via API, + # returning `{"error"=>{"message"=>"No matching Instagram user", "type"=>"IGApiException", "code"=>9010}}`. + # Then Facebook rejects the request saying this app is still not ready once the integration with Instagram didn't work. + # We can safely create an unknown contact, making this integration work. + return unknown_user(ig_scope_id) if error_code == 9010 + + Rails.logger.warn("[InstagramUserFetchError]: account_id #{@inbox.account_id} inbox_id #{@inbox.id} ig_scope_id #{ig_scope_id}") Rails.logger.warn("[InstagramUserFetchError]: #{error_message} #{error_code}") - exception = StandardError.new("#{error_message} (Code: #{error_code})") + exception = StandardError.new("#{error_message} (Code: #{error_code}, IG Scope ID: #{ig_scope_id})") ChatwootExceptionTracker.new(exception, account: @inbox.account).capture_exception end @@ -66,4 +75,11 @@ class Instagram::MessageText < Instagram::BaseMessageText Messages::Instagram::MessageBuilder.new(@messaging, @inbox, outgoing_echo: agent_message_via_echo?).perform end + + def unknown_user(ig_scope_id) + { + 'name' => "Unknown (IG: #{ig_scope_id})", + 'id' => ig_scope_id + }.with_indifferent_access + end end diff --git a/app/services/instagram/messenger/message_text.rb b/app/services/instagram/messenger/message_text.rb index ed544263e..f383bcdca 100644 --- a/app/services/instagram/messenger/message_text.rb +++ b/app/services/instagram/messenger/message_text.rb @@ -33,6 +33,16 @@ class Instagram::Messenger::MessageText < Instagram::BaseMessageText return end + # Handle error code 9010: No matching Instagram user + # This occurs when trying to fetch an Instagram user that doesn't exist or is not accessible + # We can safely ignore this error and return empty result + if error.message.include?('9010') + Rails.logger.warn("[Instagram User Not Found]: account_id #{@inbox.account_id} inbox_id #{@inbox.id}") + Rails.logger.warn("[Instagram User Not Found]: #{error.message}") + Rails.logger.warn("[Instagram User Not Found]: #{error}") + return + end + Rails.logger.warn("[FacebookUserFetchClientError]: account_id #{@inbox.account_id} inbox_id #{@inbox.id}") Rails.logger.warn("[FacebookUserFetchClientError]: #{error.message}") ChatwootExceptionTracker.new(error, account: @inbox.account).capture_exception diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 7fce0a7dd..56c15b2f3 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -1,6 +1,10 @@ class SearchService pattr_initialize [:current_user!, :current_account!, :params!, :search_type!] + def account_user + @account_user ||= current_account.account_users.find_by(user: current_user) + end + def perform case search_type when 'Message' @@ -78,8 +82,17 @@ class SearchService end def message_base_query - current_account.messages.where(inbox_id: accessable_inbox_ids) - .where('created_at >= ?', 3.months.ago) + query = current_account.messages.where('created_at >= ?', 3.months.ago) + query = query.where(inbox_id: accessable_inbox_ids) unless should_skip_inbox_filtering? + query + end + + def should_skip_inbox_filtering? + account_user.administrator? || user_has_access_to_all_inboxes? + end + + def user_has_access_to_all_inboxes? + accessable_inbox_ids.sort == current_account.inboxes.pluck(:id).sort end def use_gin_search @@ -90,7 +103,9 @@ class SearchService @contacts = current_account.contacts.where( "name ILIKE :search OR email ILIKE :search OR phone_number ILIKE :search OR identifier ILIKE :search", search: "%#{search_query}%" - ).resolved_contacts.order_on_last_activity_at('desc').page(params[:page]).per(15) + ).resolved_contacts( + use_crm_v2: current_account.feature_enabled?('crm_v2') + ).order_on_last_activity_at('desc').page(params[:page]).per(15) end def filter_articles diff --git a/app/services/whatsapp/facebook_api_client.rb b/app/services/whatsapp/facebook_api_client.rb index 1aebdad2a..441e41b1a 100644 --- a/app/services/whatsapp/facebook_api_client.rb +++ b/app/services/whatsapp/facebook_api_client.rb @@ -63,6 +63,15 @@ class Whatsapp::FacebookApiClient handle_response(response, 'Webhook subscription failed') end + def unsubscribe_waba_webhook(waba_id) + response = HTTParty.delete( + "#{BASE_URI}/#{@api_version}/#{waba_id}/subscribed_apps", + headers: request_headers + ) + + handle_response(response, 'Webhook unsubscription failed') + end + private def request_headers diff --git a/app/services/whatsapp/webhook_teardown_service.rb b/app/services/whatsapp/webhook_teardown_service.rb new file mode 100644 index 000000000..c4a39a5eb --- /dev/null +++ b/app/services/whatsapp/webhook_teardown_service.rb @@ -0,0 +1,47 @@ +class Whatsapp::WebhookTeardownService + def initialize(channel) + @channel = channel + end + + def perform + return unless should_teardown_webhook? + + teardown_webhook + rescue StandardError => e + handle_webhook_teardown_error(e) + end + + private + + def should_teardown_webhook? + whatsapp_cloud_provider? && embedded_signup_source? && webhook_config_present? + end + + def whatsapp_cloud_provider? + @channel.provider == 'whatsapp_cloud' + end + + def embedded_signup_source? + @channel.provider_config['source'] == 'embedded_signup' + end + + def webhook_config_present? + @channel.provider_config['business_account_id'].present? && + @channel.provider_config['api_key'].present? + end + + def teardown_webhook + waba_id = @channel.provider_config['business_account_id'] + access_token = @channel.provider_config['api_key'] + api_client = Whatsapp::FacebookApiClient.new(access_token) + + api_client.unsubscribe_waba_webhook(waba_id) + Rails.logger.info "[WHATSAPP] Webhook unsubscribed successfully for channel #{@channel.id}" + end + + def handle_webhook_teardown_error(error) + Rails.logger.error "[WHATSAPP] Webhook teardown failed: #{error.message}" + # Don't raise the error to prevent channel deletion from failing + # Failed webhook teardown shouldn't block deletion + end +end diff --git a/config/features.yml b/config/features.yml index 4706c46f0..db2d46700 100644 --- a/config/features.yml +++ b/config/features.yml @@ -187,3 +187,7 @@ - name: whatsapp_campaign display_name: WhatsApp Campaign enabled: false +- name: crm_v2 + display_name: CRM V2 + enabled: false + chatwoot_internal: true diff --git a/config/initializers/facebook_messenger.rb b/config/initializers/facebook_messenger.rb index 354687cbd..f93829e65 100644 --- a/config/initializers/facebook_messenger.rb +++ b/config/initializers/facebook_messenger.rb @@ -39,6 +39,8 @@ Rails.application.reloader.to_prepare do end Facebook::Messenger::Bot.on :message_echo do |message| - Webhooks::FacebookEventsJob.perform_later(message.to_json) + # Add delay to prevent race condition where echo arrives before send message API completes + # This avoids duplicate messages when echo comes early during API processing + Webhooks::FacebookEventsJob.set(wait: 2.seconds).perform_later(message.to_json) end end diff --git a/config/installation_config.yml b/config/installation_config.yml index 2e8d94a96..53251fc3c 100644 --- a/config/installation_config.yml +++ b/config/installation_config.yml @@ -170,6 +170,10 @@ display_title: 'OpenAI Model' description: 'The OpenAI model configured for use in Captain AI. Default: gpt-4o-mini' locked: false +- name: CAPTAIN_OPEN_AI_ENDPOINT + display_title: 'OpenAI API Endpoint (optional)' + description: 'The OpenAI endpoint configured for use in Captain AI. Default: https://api.openai.com/' + locked: false - name: CAPTAIN_FIRECRAWL_API_KEY display_title: 'FireCrawl API Key (optional)' description: 'The FireCrawl API key for the Captain AI service' @@ -416,3 +420,17 @@ locked: false description: 'The redirect URI configured in your Google OAuth app' ## ------ End of Configs added for Google OAuth ------ ## + +## ------ Configs added for Cloudflare ------ ## +- name: CLOUDFLARE_API_KEY + display_title: 'Cloudflare API Key' + value: + locked: false + description: 'API key for Cloudflare account authentication' + type: secret +- name: CLOUDFLARE_ZONE_ID + display_title: 'Cloudflare Zone ID' + value: + locked: false + description: 'Zone ID for the Cloudflare domain' +## ------ End of Configs added for Cloudflare ------ ## diff --git a/config/locales/ar.yml b/config/locales/ar.yml index afb5800c7..437f35eeb 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -91,7 +91,7 @@ ar: conversations_count: عدد المحادثات avg_first_response_time: متوسط وقت الرد الأول avg_resolution_time: متوسط وقت الحل - avg_reply_time: Avg reply time + avg_reply_time: معدل وقت الرد resolution_count: عدد مرات الإغلاق team_csv: team_name: اسم الفريق @@ -135,19 +135,19 @@ ar: no_content: 'لا يوجد محتوى' conversations: captain: - handoff: 'Transferring to another agent for further assistance.' + handoff: 'تحويل إلى وكيل آخر لمزيد من المساعدة.' messages: instagram_story_content: 'أشار %{story_sender} إليك في القصة: ' instagram_deleted_story_content: هذه القصة لم تعد متاحة. deleted: تم حذف هذه الرسالة whatsapp: - list_button_label: 'Choose an item' + list_button_label: 'اختر عنصر' delivery_status: error_code: 'رمز الخطأ: %{error_code}' activity: captain: - resolved: 'Conversation was marked resolved by %{user_name} due to inactivity' - open: 'Conversation was marked open by %{user_name}' + resolved: 'تم تحديد هذه المحادثة كمحلولة بواسطة %{user_name} بسبب عدم النشاط' + open: 'تم تحديد هذه المحادثة كمفتوحة بواسطة %{user_name}' status: resolved: 'تم تحديث حالة المحادثة لـ"مغلقة" بواسطة %{user_name}' contact_resolved: 'تم حل المحادثة بواسطة %{contact_name}' @@ -155,8 +155,8 @@ ar: pending: 'تم تحديث حالة المحادثة لـ"معلقة" بواسطة %{user_name}' snoozed: 'تم تأجيل المحادثة بواسطة %{user_name}' auto_resolved_days: 'تم وضع علامة على المحادثة كمحلولة من قبل النظام بسبب %{count} أيام من عدم النشاط' - auto_resolved_hours: 'Conversation was marked resolved by system due to %{count} hours of inactivity' - auto_resolved_minutes: 'Conversation was marked resolved by system due to %{count} minutes of inactivity' + auto_resolved_hours: 'تم تحديد هذه المحادثة كمحلولة بواسطة النظام بسبب عدم النشاط لمدة %{count} ساعات' + auto_resolved_minutes: 'تم تحديد هذه المحادثة كمحلولة بواسطة النظام بسبب عدم النشاط لمدة %{count} دقائق' system_auto_open: أعاد النظام فتح المحادثة بسبب رسالة واردة جديدة. priority: added: '%{user_name} حدد الأولوية إلى %{new_priority}' @@ -244,7 +244,7 @@ ar: short_description: 'Create and link Linear issues directly from conversations.' description: 'إنشاء مشكلات في Linear مباشرة من نافذة المحادثة الخاصة بك. بدلاً من ذلك، قم بربط مشكلات Linear القائمة من أجل عملية تتبع أكثر تبسيطاً وكفاءة.' notion: - name: 'Notion' + name: 'نوشن' short_description: 'Integrate databases, documents and pages directly with Captain.' description: 'Connect your Notion workspace to enable Captain to access and generate intelligent responses using content from your databases, documents, and pages to provide more contextual customer support.' shopify: diff --git a/config/routes.rb b/config/routes.rb index 0627c2c6d..c12aa670b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -517,6 +517,7 @@ Rails.application.routes.draw do get '.well-known/assetlinks.json' => 'android_app#assetlinks' get '.well-known/apple-app-site-association' => 'apple_app#site_association' get '.well-known/microsoft-identity-association.json' => 'microsoft#identity_association' + get '.well-known/cf-custom-hostname-challenge/:id', to: 'custom_domains#verify' # ---------------------------------------------------------------------- # Internal Monitoring Routes diff --git a/config/sidekiq.yml b/config/sidekiq.yml index d2d764382..50a47a20b 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -24,6 +24,7 @@ - low - scheduled_jobs - deferred + - purgable - housekeeping - async_database_migration - active_storage_analysis diff --git a/db/migrate/20250722083820_add_ssl_settings_to_portals.rb b/db/migrate/20250722083820_add_ssl_settings_to_portals.rb new file mode 100644 index 000000000..dc59bf89b --- /dev/null +++ b/db/migrate/20250722083820_add_ssl_settings_to_portals.rb @@ -0,0 +1,5 @@ +class AddSslSettingsToPortals < ActiveRecord::Migration[7.1] + def change + add_column :portals, :ssl_settings, :jsonb, default: {}, null: false + end +end diff --git a/db/migrate/20250722152516_add_index_on_contact_type_and_account_id_to_contacts.rb b/db/migrate/20250722152516_add_index_on_contact_type_and_account_id_to_contacts.rb new file mode 100644 index 000000000..1233e417c --- /dev/null +++ b/db/migrate/20250722152516_add_index_on_contact_type_and_account_id_to_contacts.rb @@ -0,0 +1,7 @@ +class AddIndexOnContactTypeAndAccountIdToContacts < ActiveRecord::Migration[7.1] + disable_ddl_transaction! + + def change + add_index :contacts, [:account_id, :contact_type], name: 'index_contacts_on_account_id_and_contact_type', algorithm: :concurrently + end +end diff --git a/db/schema.rb b/db/schema.rb index 34637315b..eb7409b8b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2025_07_14_104358) do +ActiveRecord::Schema[7.1].define(version: 2025_07_22_152516) do # These extensions should be enabled to support this database enable_extension "pg_stat_statements" enable_extension "pg_trgm" @@ -539,6 +539,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_07_14_104358) do t.string "country_code", default: "" t.boolean "blocked", default: false, null: false t.index "lower((email)::text), account_id", name: "index_contacts_on_lower_email_account_id" + t.index ["account_id", "contact_type"], name: "index_contacts_on_account_id_and_contact_type" t.index ["account_id", "email", "phone_number", "identifier"], name: "index_contacts_on_nonempty_fields", where: "(((email)::text <> ''::text) OR ((phone_number)::text <> ''::text) OR ((identifier)::text <> ''::text))" t.index ["account_id", "last_activity_at"], name: "index_contacts_on_account_id_and_last_activity_at", order: { last_activity_at: "DESC NULLS LAST" } t.index ["account_id"], name: "index_contacts_on_account_id" @@ -942,6 +943,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_07_14_104358) do t.jsonb "config", default: {"allowed_locales" => ["en"]} t.boolean "archived", default: false t.bigint "channel_web_widget_id" + t.jsonb "ssl_settings", default: {}, null: false t.index ["channel_web_widget_id"], name: "index_portals_on_channel_web_widget_id" t.index ["custom_domain"], name: "index_portals_on_custom_domain", unique: true t.index ["slug"], name: "index_portals_on_slug", unique: true diff --git a/enterprise/app/controllers/custom_domains_controller.rb b/enterprise/app/controllers/custom_domains_controller.rb new file mode 100644 index 000000000..bdba869a8 --- /dev/null +++ b/enterprise/app/controllers/custom_domains_controller.rb @@ -0,0 +1,22 @@ +class CustomDomainsController < ApplicationController + def verify + challenge_id = permitted_params[:id] + + domain = request.host + portal = Portal.find_by(custom_domain: domain) + + return render plain: 'Domain not found', status: :not_found unless portal + + ssl_settings = portal.ssl_settings || {} + + return render plain: 'Challenge ID not found', status: :not_found unless ssl_settings['cf_verification_id'] == challenge_id + + render plain: ssl_settings['cf_verification_body'], status: :ok + end + + private + + def permitted_params + params.permit(:id) + end +end diff --git a/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb b/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb index 67ce3a6a9..5466c86a4 100644 --- a/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb +++ b/enterprise/app/controllers/enterprise/super_admin/app_configs_controller.rb @@ -10,7 +10,7 @@ module Enterprise::SuperAdmin::AppConfigsController when 'internal' @allowed_configs = internal_config_options when 'captain' - @allowed_configs = %w[CAPTAIN_OPEN_AI_API_KEY CAPTAIN_OPEN_AI_MODEL CAPTAIN_FIRECRAWL_API_KEY] + @allowed_configs = %w[CAPTAIN_OPEN_AI_API_KEY CAPTAIN_OPEN_AI_MODEL CAPTAIN_OPEN_AI_ENDPOINT CAPTAIN_FIRECRAWL_API_KEY] else super end @@ -34,6 +34,6 @@ module Enterprise::SuperAdmin::AppConfigsController def internal_config_options %w[CHATWOOT_INBOX_TOKEN CHATWOOT_INBOX_HMAC_KEY ANALYTICS_TOKEN CLEARBIT_API_KEY DASHBOARD_SCRIPTS INACTIVE_WHATSAPP_NUMBERS BLOCKED_EMAIL_DOMAINS CAPTAIN_CLOUD_PLAN_LIMITS ACCOUNT_SECURITY_NOTIFICATION_WEBHOOK_URL CHATWOOT_INSTANCE_ADMIN_EMAIL - OG_IMAGE_CDN_URL OG_IMAGE_CLIENT_REF] + OG_IMAGE_CDN_URL OG_IMAGE_CLIENT_REF CLOUDFLARE_API_KEY CLOUDFLARE_ZONE_ID] end end diff --git a/enterprise/app/jobs/enterprise/cloudflare_verification_job.rb b/enterprise/app/jobs/enterprise/cloudflare_verification_job.rb new file mode 100644 index 000000000..9b4fd64bd --- /dev/null +++ b/enterprise/app/jobs/enterprise/cloudflare_verification_job.rb @@ -0,0 +1,22 @@ +class Enterprise::CloudflareVerificationJob < ApplicationJob + queue_as :default + + def perform(portal_id) + portal = Portal.find(portal_id) + return unless portal && portal.custom_domain.present? + + result = check_hostname_status(portal) + + create_hostname(portal) if result[:errors].present? + end + + private + + def create_hostname(portal) + Cloudflare::CreateCustomHostnameService.new(portal: portal).perform + end + + def check_hostname_status(portal) + Cloudflare::CheckCustomHostnameService.new(portal: portal).perform + end +end diff --git a/enterprise/app/models/enterprise/concerns/portal.rb b/enterprise/app/models/enterprise/concerns/portal.rb new file mode 100644 index 000000000..9ca76b7b9 --- /dev/null +++ b/enterprise/app/models/enterprise/concerns/portal.rb @@ -0,0 +1,14 @@ +module Enterprise::Concerns::Portal + extend ActiveSupport::Concern + + included do + after_save :enqueue_cloudflare_verification, if: :saved_change_to_custom_domain? + end + + def enqueue_cloudflare_verification + return if custom_domain.blank? + return unless ChatwootApp.chatwoot_cloud? + + Enterprise::CloudflareVerificationJob.perform_later(id) + end +end diff --git a/enterprise/app/services/cloudflare/base_cloudflare_zone_service.rb b/enterprise/app/services/cloudflare/base_cloudflare_zone_service.rb new file mode 100644 index 000000000..7fad50790 --- /dev/null +++ b/enterprise/app/services/cloudflare/base_cloudflare_zone_service.rb @@ -0,0 +1,20 @@ +class Cloudflare::BaseCloudflareZoneService + BASE_URI = 'https://api.cloudflare.com/client/v4'.freeze + + private + + def headers + { + 'Authorization' => "Bearer #{api_token}", + 'Content-Type' => 'application/json' + } + end + + def api_token + InstallationConfig.find_by(name: 'CLOUDFLARE_API_KEY')&.value + end + + def zone_id + InstallationConfig.find_by(name: 'CLOUDFLARE_ZONE_ID')&.value + end +end diff --git a/enterprise/app/services/cloudflare/check_custom_hostname_service.rb b/enterprise/app/services/cloudflare/check_custom_hostname_service.rb new file mode 100644 index 000000000..588a9c4a7 --- /dev/null +++ b/enterprise/app/services/cloudflare/check_custom_hostname_service.rb @@ -0,0 +1,34 @@ +class Cloudflare::CheckCustomHostnameService < Cloudflare::BaseCloudflareZoneService + pattr_initialize [:portal!] + + def perform + return { errors: ['Cloudflare API token or zone ID not found'] } if api_token.blank? || zone_id.blank? + return { errors: ['No custom domain found'] } if @portal.custom_domain.blank? + + response = HTTParty.get( + "#{BASE_URI}/zones/#{zone_id}/custom_hostnames?hostname=#{@portal.custom_domain}", headers: headers + ) + + return { errors: response.parsed_response['errors'] } unless response.success? + + data = response.parsed_response['result'] + + if data.present? + update_portal_ssl_settings(data.first) + return { data: data } + end + + { errors: ['Hostname is missing in Cloudflare'] } + end + + private + + def update_portal_ssl_settings(data) + verification_record = data['ownership_verification_http'] + ssl_settings = { + 'cf_verification_id': verification_record['http_url'].split('/').last, + 'cf_verification_body': verification_record['http_body'] + } + @portal.update(ssl_settings: ssl_settings) + end +end diff --git a/enterprise/app/services/cloudflare/create_custom_hostname_service.rb b/enterprise/app/services/cloudflare/create_custom_hostname_service.rb new file mode 100644 index 000000000..f1546caed --- /dev/null +++ b/enterprise/app/services/cloudflare/create_custom_hostname_service.rb @@ -0,0 +1,40 @@ +class Cloudflare::CreateCustomHostnameService < Cloudflare::BaseCloudflareZoneService + pattr_initialize [:portal!] + + def perform + return { errors: ['Cloudflare API token or zone ID not found'] } if api_token.blank? || zone_id.blank? + return { errors: ['No hostname found'] } if @portal.custom_domain.blank? + + response = create_hostname + + return { errors: response.parsed_response['errors'] } unless response.success? + + data = response.parsed_response['result'] + + if data.present? + update_portal_ssl_settings(data) + return { data: data } + end + + { errors: ['Could not create hostname'] } + end + + private + + def create_hostname + HTTParty.post( + "#{BASE_URI}/zones/#{zone_id}/custom_hostnames", + headers: headers, + body: { hostname: @portal.custom_domain }.to_json + ) + end + + def update_portal_ssl_settings(data) + verification_record = data['ownership_verification_http'] + ssl_settings = { + 'cf_verification_id': verification_record['http_url'].split('/').last, + 'cf_verification_body': verification_record['http_body'] + } + @portal.update(ssl_settings: ssl_settings) + end +end diff --git a/enterprise/app/services/llm/base_open_ai_service.rb b/enterprise/app/services/llm/base_open_ai_service.rb index 1f229f182..04909cbf4 100644 --- a/enterprise/app/services/llm/base_open_ai_service.rb +++ b/enterprise/app/services/llm/base_open_ai_service.rb @@ -4,6 +4,7 @@ class Llm::BaseOpenAiService def initialize @client = OpenAI::Client.new( access_token: InstallationConfig.find_by!(name: 'CAPTAIN_OPEN_AI_API_KEY').value, + uri_base: uri_base, log_errors: Rails.env.development? ) setup_model @@ -13,6 +14,10 @@ class Llm::BaseOpenAiService private + def uri_base + InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_ENDPOINT')&.value || 'https://api.openai.com/' + end + def setup_model config_value = InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_MODEL')&.value @model = (config_value.presence || DEFAULT_MODEL) diff --git a/spec/actions/contact_identify_action_spec.rb b/spec/actions/contact_identify_action_spec.rb index c9bae7b5a..568f4db98 100644 --- a/spec/actions/contact_identify_action_spec.rb +++ b/spec/actions/contact_identify_action_spec.rb @@ -36,12 +36,18 @@ describe ContactIdentifyAction do expect(result.additional_attributes['social_profiles']).to eq({ 'linkedin' => 'saras', 'twitter' => 'saras' }) end - it 'enques avatar job when avatar url parameter is passed' do + it 'enqueues avatar job when valid avatar url parameter is passed' do params = { name: 'test', avatar_url: 'https://chatwoot-assets.local/sample.png' } expect(Avatar::AvatarFromUrlJob).to receive(:perform_later).with(contact, params[:avatar_url]).once described_class.new(contact: contact, params: params).perform end + it 'does not enqueue avatar job when invalid avatar url parameter is passed' do + params = { name: 'test', avatar_url: 'invalid-url' } + expect(Avatar::AvatarFromUrlJob).not_to receive(:perform_later) + described_class.new(contact: contact, params: params).perform + end + context 'when contact with same identifier exists' do it 'merges the current contact to identified contact' do existing_identified_contact = create(:contact, account: account, identifier: 'test_id') diff --git a/spec/controllers/webhooks/instagram_controller_spec.rb b/spec/controllers/webhooks/instagram_controller_spec.rb index df5a6596d..c31d65a2b 100644 --- a/spec/controllers/webhooks/instagram_controller_spec.rb +++ b/spec/controllers/webhooks/instagram_controller_spec.rb @@ -33,5 +33,21 @@ RSpec.describe 'Webhooks::InstagramController', type: :request do post '/webhooks/instagram', params: instagram_params expect(response).to have_http_status(:success) end + + context 'when processing echo events' do + let!(:echo_params) { build(:instagram_story_mention_event_with_echo).with_indifferent_access } + + it 'delays processing for echo events by 2 seconds' do + job_double = class_double(Webhooks::InstagramEventsJob) + allow(Webhooks::InstagramEventsJob).to receive(:set).with(wait: 2.seconds).and_return(job_double) + allow(job_double).to receive(:perform_later) + + instagram_params = echo_params.merge(object: 'instagram') + post '/webhooks/instagram', params: instagram_params + expect(response).to have_http_status(:success) + expect(Webhooks::InstagramEventsJob).to have_received(:set).with(wait: 2.seconds) + expect(job_double).to have_received(:perform_later) + end + end end end diff --git a/spec/enterprise/jobs/enterprise/cloudflare_verification_job_spec.rb b/spec/enterprise/jobs/enterprise/cloudflare_verification_job_spec.rb new file mode 100644 index 000000000..862479034 --- /dev/null +++ b/spec/enterprise/jobs/enterprise/cloudflare_verification_job_spec.rb @@ -0,0 +1,47 @@ +require 'rails_helper' + +RSpec.describe Enterprise::CloudflareVerificationJob do + let(:portal) { create(:portal, custom_domain: 'test.example.com') } + + describe '#perform' do + context 'when portal is not found' do + it 'returns early' do + expect(Portal).to receive(:find).with(0).and_return(nil) + expect(Cloudflare::CheckCustomHostnameService).not_to receive(:new) + expect(Cloudflare::CreateCustomHostnameService).not_to receive(:new) + + described_class.perform_now(0) + end + end + + context 'when portal has no custom domain' do + it 'returns early' do + portal_without_domain = create(:portal, custom_domain: nil) + expect(Cloudflare::CheckCustomHostnameService).not_to receive(:new) + expect(Cloudflare::CreateCustomHostnameService).not_to receive(:new) + + described_class.perform_now(portal_without_domain.id) + end + end + + context 'when portal exists with custom domain' do + it 'checks hostname status' do + check_service = instance_double(Cloudflare::CheckCustomHostnameService, perform: { data: 'success' }) + expect(Cloudflare::CheckCustomHostnameService).to receive(:new).with(portal: portal).and_return(check_service) + expect(Cloudflare::CreateCustomHostnameService).not_to receive(:new) + + described_class.perform_now(portal.id) + end + + it 'creates hostname when check returns errors' do + check_service = instance_double(Cloudflare::CheckCustomHostnameService, perform: { errors: ['Hostname is missing'] }) + create_service = instance_double(Cloudflare::CreateCustomHostnameService, perform: { data: 'success' }) + + expect(Cloudflare::CheckCustomHostnameService).to receive(:new).with(portal: portal).and_return(check_service) + expect(Cloudflare::CreateCustomHostnameService).to receive(:new).with(portal: portal).and_return(create_service) + + described_class.perform_now(portal.id) + end + end + end +end diff --git a/spec/enterprise/models/enterprise/concerns/portal_spec.rb b/spec/enterprise/models/enterprise/concerns/portal_spec.rb new file mode 100644 index 000000000..1dae65e86 --- /dev/null +++ b/spec/enterprise/models/enterprise/concerns/portal_spec.rb @@ -0,0 +1,59 @@ +require 'rails_helper' + +RSpec.describe Enterprise::Concerns::Portal do + describe '#enqueue_cloudflare_verification' do + let(:portal) { create(:portal, custom_domain: nil) } + + context 'when custom_domain is changed' do + context 'when on chatwoot cloud' do + before do + allow(ChatwootApp).to receive(:chatwoot_cloud?).and_return(true) + end + + it 'enqueues cloudflare verification job' do + expect do + portal.update(custom_domain: 'test.example.com') + end.to have_enqueued_job(Enterprise::CloudflareVerificationJob).with(portal.id) + end + end + + context 'when not on chatwoot cloud' do + before do + allow(ChatwootApp).to receive(:chatwoot_cloud?).and_return(false) + end + + it 'does not enqueue cloudflare verification job' do + expect do + portal.update(custom_domain: 'test.example.com') + end.not_to have_enqueued_job(Enterprise::CloudflareVerificationJob) + end + end + end + + context 'when custom_domain is not changed' do + before do + allow(ChatwootApp).to receive(:chatwoot_cloud?).and_return(true) + portal.update(custom_domain: 'test.example.com') + end + + it 'does not enqueue cloudflare verification job' do + expect do + portal.update(name: 'New Name') + end.not_to have_enqueued_job(Enterprise::CloudflareVerificationJob) + end + end + + context 'when custom_domain is set to blank' do + before do + allow(ChatwootApp).to receive(:chatwoot_cloud?).and_return(true) + portal.update(custom_domain: 'test.example.com') + end + + it 'does not enqueue cloudflare verification job' do + expect do + portal.update(custom_domain: '') + end.not_to have_enqueued_job(Enterprise::CloudflareVerificationJob) + end + end + end +end diff --git a/spec/enterprise/services/captain/copilot/chat_service_spec.rb b/spec/enterprise/services/captain/copilot/chat_service_spec.rb index a4274ec4e..a02063b5e 100644 --- a/spec/enterprise/services/captain/copilot/chat_service_spec.rb +++ b/spec/enterprise/services/captain/copilot/chat_service_spec.rb @@ -22,6 +22,7 @@ RSpec.describe Captain::Copilot::ChatService do before do create(:installation_config, name: 'CAPTAIN_OPEN_AI_API_KEY', value: 'test-key') + create(:installation_config, name: 'CAPTAIN_OPEN_AI_ENDPOINT', value: 'https://api.openai.com/') allow(OpenAI::Client).to receive(:new).and_return(mock_openai_client) allow(mock_openai_client).to receive(:chat).and_return({ choices: [{ message: { content: '{ "content": "Hey" }' } }] @@ -47,6 +48,48 @@ RSpec.describe Captain::Copilot::ChatService do expect(messages.second[:role]).to eq('system') expect(messages.second[:content]).to include(account.id.to_s) end + + it 'initializes OpenAI client with configured endpoint' do + expect(OpenAI::Client).to receive(:new).with( + access_token: 'test-key', + uri_base: 'https://api.openai.com/', + log_errors: Rails.env.development? + ) + + described_class.new(assistant, config) + end + + context 'when CAPTAIN_OPEN_AI_ENDPOINT is not configured' do + before do + InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_ENDPOINT')&.destroy + end + + it 'uses default OpenAI endpoint' do + expect(OpenAI::Client).to receive(:new).with( + access_token: 'test-key', + uri_base: 'https://api.openai.com/', + log_errors: Rails.env.development? + ) + + described_class.new(assistant, config) + end + end + + context 'when custom endpoint is configured' do + before do + InstallationConfig.find_by(name: 'CAPTAIN_OPEN_AI_ENDPOINT').update!(value: 'https://custom.azure.com/') + end + + it 'uses custom endpoint for OpenAI client' do + expect(OpenAI::Client).to receive(:new).with( + access_token: 'test-key', + uri_base: 'https://custom.azure.com/', + log_errors: Rails.env.development? + ) + + described_class.new(assistant, config) + end + end end describe '#generate_response' do diff --git a/spec/enterprise/services/cloudflare/check_custom_hostname_service_spec.rb b/spec/enterprise/services/cloudflare/check_custom_hostname_service_spec.rb new file mode 100644 index 000000000..d7ed80b90 --- /dev/null +++ b/spec/enterprise/services/cloudflare/check_custom_hostname_service_spec.rb @@ -0,0 +1,111 @@ +require 'rails_helper' + +RSpec.describe Cloudflare::CheckCustomHostnameService do + let(:portal) { create(:portal, custom_domain: 'test.example.com') } + let(:installation_config_api_key) { create(:installation_config, name: 'CLOUDFLARE_API_KEY', value: 'test-api-key') } + let(:installation_config_zone_id) { create(:installation_config, name: 'CLOUDFLARE_ZONE_ID', value: 'test-zone-id') } + + describe '#perform' do + context 'when API token or zone ID is not found' do + it 'returns error when API token is missing' do + installation_config_zone_id + service = described_class.new(portal: portal) + + result = service.perform + + expect(result).to eq(errors: ['Cloudflare API token or zone ID not found']) + end + + it 'returns error when zone ID is missing' do + installation_config_api_key + service = described_class.new(portal: portal) + + result = service.perform + + expect(result).to eq(errors: ['Cloudflare API token or zone ID not found']) + end + end + + context 'when no hostname ID is found' do + it 'returns error' do + installation_config_api_key + installation_config_zone_id + portal.update(custom_domain: nil) + service = described_class.new(portal: portal) + + result = service.perform + + expect(result).to eq(errors: ['No custom domain found']) + end + end + + context 'when API request is made' do + before do + installation_config_api_key + installation_config_zone_id + end + + context 'when API request fails' do + it 'returns error response' do + service = described_class.new(portal: portal) + error_response = { + 'errors' => [{ 'message' => 'API error' }] + } + + stub_request(:get, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames?hostname=test.example.com') + .to_return(status: 422, body: error_response.to_json, headers: { 'Content-Type' => 'application/json' }) + + result = service.perform + + expect(result[:errors]).to eq(error_response['errors']) + end + end + + context 'when API request succeeds but no data is returned' do + it 'returns hostname missing error' do + service = described_class.new(portal: portal) + success_response = { + 'result' => [] + } + + stub_request(:get, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames?hostname=test.example.com') + .to_return(status: 200, body: success_response.to_json, headers: { 'Content-Type' => 'application/json' }) + + result = service.perform + + expect(result).to eq(errors: ['Hostname is missing in Cloudflare']) + end + end + + context 'when API request succeeds and data is returned' do + it 'updates portal SSL settings and returns success' do + service = described_class.new(portal: portal) + success_response = { + 'result' => [ + { + 'ownership_verification_http' => { + 'http_url' => 'http://example.com/.well-known/cf-verification/verification-id', + 'http_body' => 'verification-body' + } + } + ] + } + + stub_request(:get, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames?hostname=test.example.com') + .to_return(status: 200, body: success_response.to_json, headers: { 'Content-Type' => 'application/json' }) + + expect(portal).to receive(:update).with( + ssl_settings: { + 'cf_verification_id': 'verification-id', + 'cf_verification_body': 'verification-body' + } + ) + + result = service.perform + + expect(result).to eq(data: success_response['result']) + end + end + end + end +end diff --git a/spec/enterprise/services/cloudflare/create_custom_hostname_service_spec.rb b/spec/enterprise/services/cloudflare/create_custom_hostname_service_spec.rb new file mode 100644 index 000000000..a3ddc8273 --- /dev/null +++ b/spec/enterprise/services/cloudflare/create_custom_hostname_service_spec.rb @@ -0,0 +1,111 @@ +require 'rails_helper' + +RSpec.describe Cloudflare::CreateCustomHostnameService do + let(:portal) { create(:portal, custom_domain: 'test.example.com') } + let(:installation_config_api_key) { create(:installation_config, name: 'CLOUDFLARE_API_KEY', value: 'test-api-key') } + let(:installation_config_zone_id) { create(:installation_config, name: 'CLOUDFLARE_ZONE_ID', value: 'test-zone-id') } + + describe '#perform' do + context 'when API token or zone ID is not found' do + it 'returns error when API token is missing' do + installation_config_zone_id + service = described_class.new(portal: portal) + + result = service.perform + + expect(result).to eq(errors: ['Cloudflare API token or zone ID not found']) + end + + it 'returns error when zone ID is missing' do + installation_config_api_key + service = described_class.new(portal: portal) + + result = service.perform + + expect(result).to eq(errors: ['Cloudflare API token or zone ID not found']) + end + end + + context 'when no hostname is found' do + it 'returns error' do + installation_config_api_key + installation_config_zone_id + portal.update(custom_domain: nil) + service = described_class.new(portal: portal) + + result = service.perform + + expect(result).to eq(errors: ['No hostname found']) + end + end + + context 'when API request is made' do + before do + installation_config_api_key + installation_config_zone_id + end + + context 'when API request fails' do + it 'returns error response' do + service = described_class.new(portal: portal) + error_response = { + 'errors' => [{ 'message' => 'API error' }] + } + + stub_request(:post, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames') + .with(headers: { 'Authorization' => 'Bearer test-api-key', 'Content-Type' => 'application/json' }, + body: { hostname: 'test.example.com' }.to_json) + .to_return(status: 422, body: error_response.to_json, headers: { 'Content-Type' => 'application/json' }) + + result = service.perform + + expect(result[:errors]).to eq(error_response['errors']) + end + end + + context 'when API request succeeds but no data is returned' do + it 'returns hostname creation error' do + service = described_class.new(portal: portal) + success_response = { + 'result' => nil + } + + stub_request(:post, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames') + .with(headers: { 'Authorization' => 'Bearer test-api-key', 'Content-Type' => 'application/json' }, + body: { hostname: 'test.example.com' }.to_json) + .to_return(status: 200, body: success_response.to_json, headers: { 'Content-Type' => 'application/json' }) + + result = service.perform + + expect(result).to eq(errors: ['Could not create hostname']) + end + end + + context 'when API request succeeds and data is returned' do + it 'updates portal SSL settings and returns success' do + service = described_class.new(portal: portal) + success_response = { + 'result' => { + 'ownership_verification_http' => { + 'http_url' => 'http://example.com/.well-known/cf-verification/verification-id', + 'http_body' => 'verification-body' + } + } + } + + stub_request(:post, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames') + .with(headers: { 'Authorization' => 'Bearer test-api-key', 'Content-Type' => 'application/json' }, + body: { hostname: 'test.example.com' }.to_json) + .to_return(status: 200, body: success_response.to_json, headers: { 'Content-Type' => 'application/json' }) + + expect(portal).to receive(:update).with(ssl_settings: { 'cf_verification_id': 'verification-id', + 'cf_verification_body': 'verification-body' }) + + result = service.perform + + expect(result).to eq(data: success_response['result']) + end + end + end + end +end diff --git a/spec/jobs/avatar/avatar_from_gravatar_job_spec.rb b/spec/jobs/avatar/avatar_from_gravatar_job_spec.rb index 4f73fd4b2..06ebe739d 100644 --- a/spec/jobs/avatar/avatar_from_gravatar_job_spec.rb +++ b/spec/jobs/avatar/avatar_from_gravatar_job_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Avatar::AvatarFromGravatarJob do it 'enqueues the job' do expect { described_class.perform_later(avatarable, email) }.to have_enqueued_job(described_class) - .on_queue('low') + .on_queue('purgable') end it 'will call AvatarFromUrlJob with gravatar url' do diff --git a/spec/jobs/avatar/avatar_from_url_job_spec.rb b/spec/jobs/avatar/avatar_from_url_job_spec.rb index 25276bc67..2e6d89804 100644 --- a/spec/jobs/avatar/avatar_from_url_job_spec.rb +++ b/spec/jobs/avatar/avatar_from_url_job_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Avatar::AvatarFromUrlJob do it 'enqueues the job' do expect { described_class.perform_later(avatarable, avatar_url) }.to have_enqueued_job(described_class) - .on_queue('low') + .on_queue('purgable') end it 'will attach avatar from url' do diff --git a/spec/jobs/webhooks/instagram_events_job_spec.rb b/spec/jobs/webhooks/instagram_events_job_spec.rb index dfd9f1aed..1962c78a5 100644 --- a/spec/jobs/webhooks/instagram_events_job_spec.rb +++ b/spec/jobs/webhooks/instagram_events_job_spec.rb @@ -279,11 +279,29 @@ describe Webhooks::InstagramEventsJob do expect(instagram_inbox.messages.count).to be 0 end - it 'handle messaging_seen callback' do + it 'handles messaging_seen callback' do expect(Instagram::ReadStatusService).to receive(:new).with(params: message_events[:messaging_seen][:entry][0][:messaging][0], channel: instagram_inbox.channel).and_call_original instagram_webhook.perform_now(message_events[:messaging_seen][:entry]) end + + it 'creates contact when Instagram API call returns `No matching Instagram user` (9010 error code)' do + stub_request(:get, %r{https://graph\.instagram\.com/v22\.0/.*\?.*}) + .to_return(status: 401, body: { error: { message: 'No matching Instagram user', code: 9010 } }.to_json) + + instagram_webhook.perform_now(message_events[:dm][:entry]) + + instagram_inbox.reload + + expect(instagram_inbox.contacts.count).to be 1 + expect(instagram_inbox.contacts.last.name).to eq 'Unknown (IG: Sender-id-1)' + expect(instagram_inbox.contacts.last.contact_inboxes.count).to be 1 + expect(instagram_inbox.contacts.last.contact_inboxes.first.source_id).to eq 'Sender-id-1' + + expect(instagram_inbox.conversations.count).to eq 1 + expect(instagram_inbox.messages.count).to eq 1 + expect(instagram_inbox.messages.last.content_attributes['is_unsupported']).to be_nil + end end end end diff --git a/spec/models/channel/whatsapp_spec.rb b/spec/models/channel/whatsapp_spec.rb index 29a00fd96..b46c984d1 100644 --- a/spec/models/channel/whatsapp_spec.rb +++ b/spec/models/channel/whatsapp_spec.rb @@ -122,4 +122,60 @@ RSpec.describe Channel::Whatsapp do end end end + + describe '#teardown_webhooks' do + let(:account) { create(:account) } + + context 'when channel is whatsapp_cloud with embedded_signup' do + it 'calls WebhookTeardownService on destroy' do + # Mock the setup service to prevent HTTP calls during creation + setup_service = instance_double(Whatsapp::WebhookSetupService) + allow(Whatsapp::WebhookSetupService).to receive(:new).and_return(setup_service) + allow(setup_service).to receive(:perform) + + channel = create(:channel_whatsapp, + account: account, + provider: 'whatsapp_cloud', + provider_config: { + 'source' => 'embedded_signup', + 'business_account_id' => 'test_waba_id', + 'api_key' => 'test_access_token', + 'phone_number_id' => '123456789' + }, + validate_provider_config: false, + sync_templates: false) + + teardown_service = instance_double(Whatsapp::WebhookTeardownService) + allow(Whatsapp::WebhookTeardownService).to receive(:new).with(channel).and_return(teardown_service) + allow(teardown_service).to receive(:perform) + + channel.destroy + + expect(Whatsapp::WebhookTeardownService).to have_received(:new).with(channel) + expect(teardown_service).to have_received(:perform) + end + end + + context 'when channel is not embedded_signup' do + it 'does not call WebhookTeardownService on destroy' do + channel = create(:channel_whatsapp, + account: account, + provider: 'whatsapp_cloud', + provider_config: { + 'source' => 'manual', + 'api_key' => 'test_access_token' + }, + validate_provider_config: false, + sync_templates: false) + + teardown_service = instance_double(Whatsapp::WebhookTeardownService) + allow(Whatsapp::WebhookTeardownService).to receive(:new).with(channel).and_return(teardown_service) + allow(teardown_service).to receive(:perform) + + channel.destroy + + expect(teardown_service).to have_received(:perform) + end + end + end end diff --git a/spec/models/contact_spec.rb b/spec/models/contact_spec.rb index 2ca65fa4e..f21a81978 100644 --- a/spec/models/contact_spec.rb +++ b/spec/models/contact_spec.rb @@ -102,4 +102,98 @@ RSpec.describe Contact do expect(contact.contact_type).to eq 'lead' end end + + describe '.resolved_contacts' do + let(:account) { create(:account) } + + context 'when crm_v2 feature flag is disabled' do + it 'returns contacts with email, phone_number, or identifier using feature flag value' do + # Create contacts with different attributes + contact_with_email = create(:contact, account: account, email: 'test@example.com', name: 'John Doe') + contact_with_phone = create(:contact, account: account, phone_number: '+1234567890', name: 'Jane Smith') + contact_with_identifier = create(:contact, account: account, identifier: 'user123', name: 'Bob Wilson') + contact_without_details = create(:contact, account: account, name: 'Alice Johnson', email: nil, phone_number: nil, identifier: nil) + + resolved = account.contacts.resolved_contacts(use_crm_v2: false) + + expect(resolved).to include(contact_with_email, contact_with_phone, contact_with_identifier) + expect(resolved).not_to include(contact_without_details) + end + end + + context 'when crm_v2 feature flag is enabled' do + it 'returns only contacts with contact_type lead' do + # Contact with email and phone - should be marked as lead + contact_with_details = create(:contact, account: account, email: 'customer@example.com', phone_number: '+1234567890', name: 'Customer One') + expect(contact_with_details.contact_type).to eq('lead') + + # Contact without email/phone - should be marked as visitor + contact_without_details = create(:contact, account: account, name: 'Lead', email: nil, phone_number: nil) + expect(contact_without_details.contact_type).to eq('visitor') + + # Force set contact_type to lead for testing + contact_without_details.update!(contact_type: 'lead') + + resolved = account.contacts.resolved_contacts(use_crm_v2: true) + + expect(resolved).to include(contact_with_details) + expect(resolved).to include(contact_without_details) + end + + it 'includes all lead contacts regardless of email/phone presence' do + # Create a lead contact with only name + lead_contact = create(:contact, account: account, name: 'Test Lead') + lead_contact.update!(contact_type: 'lead') + + # Create a customer contact + customer_contact = create(:contact, account: account, email: 'customer@test.com') + customer_contact.update!(contact_type: 'customer') + + # Create a visitor contact + visitor_contact = create(:contact, account: account, name: 'Visitor') + expect(visitor_contact.contact_type).to eq('visitor') + + resolved = account.contacts.resolved_contacts(use_crm_v2: true) + + expect(resolved).to include(lead_contact) + expect(resolved).not_to include(customer_contact) + expect(resolved).not_to include(visitor_contact) + end + + it 'returns contacts with email, phone_number, or identifier when explicitly passing use_crm_v2: false' do + # Even though feature flag is enabled, we're explicitly passing false + contact_with_email = create(:contact, account: account, email: 'test@example.com', name: 'John Doe') + contact_with_phone = create(:contact, account: account, phone_number: '+1234567890', name: 'Jane Smith') + contact_without_details = create(:contact, account: account, name: 'Alice Johnson', email: nil, phone_number: nil, identifier: nil) + + resolved = account.contacts.resolved_contacts(use_crm_v2: false) + + # Should use the old logic despite feature flag being enabled + expect(resolved).to include(contact_with_email, contact_with_phone) + expect(resolved).not_to include(contact_without_details) + end + end + + context 'with mixed contact types' do + it 'correctly filters based on use_crm_v2 parameter regardless of feature flag' do + # Create different types of contacts + visitor_contact = create(:contact, account: account, name: 'Visitor') + lead_with_email = create(:contact, account: account, email: 'lead@example.com', name: 'Lead') + lead_without_email = create(:contact, account: account, name: 'Lead Only') + lead_without_email.update!(contact_type: 'lead') + customer_contact = create(:contact, account: account, email: 'customer@example.com', name: 'Customer') + customer_contact.update!(contact_type: 'customer') + + # Test with use_crm_v2: false + resolved_old = account.contacts.resolved_contacts(use_crm_v2: false) + expect(resolved_old).to include(lead_with_email, customer_contact) + expect(resolved_old).not_to include(visitor_contact, lead_without_email) + + # Test with use_crm_v2: true + resolved_new = account.contacts.resolved_contacts(use_crm_v2: true) + expect(resolved_new).to include(lead_with_email, lead_without_email) + expect(resolved_new).not_to include(visitor_contact, customer_contact) + end + end + end end diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index 92c397ab7..9ce1b0785 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -185,6 +185,63 @@ describe SearchService do end end + describe '#message_base_query' do + let(:params) { { q: 'test' } } + let(:search_type) { 'Message' } + + context 'when user is admin' do + let(:admin_user) { create(:user) } + let(:admin_search) do + create(:account_user, account: account, user: admin_user, role: 'administrator') + described_class.new(current_user: admin_user, current_account: account, params: params, search_type: search_type) + end + + it 'does not filter by inbox_id' do + # Testing the private method itself seems like the best way to ensure + # that the inboxes are not added to the search query + base_query = admin_search.send(:message_base_query) + + # Should only have the time filter, not inbox filter + expect(base_query.to_sql).to include('created_at >= ') + expect(base_query.to_sql).not_to include('inbox_id') + end + end + + context 'when user is not admin' do + before do + account_user = account.account_users.find_or_create_by(user: user) + account_user.update!(role: 'agent') + end + + it 'filters by accessible inbox_id when user has limited access' do + # Create an additional inbox that user is NOT assigned to + create(:inbox, account: account) + + base_query = search.send(:message_base_query) + + # Should have both time and inbox filters + expect(base_query.to_sql).to include('created_at >= ') + expect(base_query.to_sql).to include('inbox_id') + end + + context 'when user has access to all inboxes' do + before do + # Create additional inbox and assign user to all inboxes + other_inbox = create(:inbox, account: account) + create(:inbox_member, user: user, inbox: other_inbox) + end + + it 'skips inbox filtering as optimization' do + base_query = search.send(:message_base_query) + + # Should only have the time filter, not inbox filter + expect(base_query.to_sql).to include('created_at >= ') + expect(base_query.to_sql).not_to include('inbox_id') + end + end + end + end + describe '#use_gin_search' do let(:params) { { q: 'test' } } diff --git a/spec/services/whatsapp/facebook_api_client_spec.rb b/spec/services/whatsapp/facebook_api_client_spec.rb index 6c2af7716..308d61f62 100644 --- a/spec/services/whatsapp/facebook_api_client_spec.rb +++ b/spec/services/whatsapp/facebook_api_client_spec.rb @@ -194,4 +194,41 @@ describe Whatsapp::FacebookApiClient do end end end + + describe '#unsubscribe_waba_webhook' do + let(:waba_id) { 'test_waba_id' } + + context 'when successful' do + before do + stub_request(:delete, "https://graph.facebook.com/#{api_version}/#{waba_id}/subscribed_apps") + .with( + headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' } + ) + .to_return( + status: 200, + body: { success: true }.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + end + + it 'returns success response' do + result = api_client.unsubscribe_waba_webhook(waba_id) + expect(result['success']).to be(true) + end + end + + context 'when failed' do + before do + stub_request(:delete, "https://graph.facebook.com/#{api_version}/#{waba_id}/subscribed_apps") + .with( + headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' } + ) + .to_return(status: 400, body: { error: 'Webhook unsubscription failed' }.to_json) + end + + it 'raises an error' do + expect { api_client.unsubscribe_waba_webhook(waba_id) }.to raise_error(/Webhook unsubscription failed/) + end + end + end end diff --git a/spec/services/whatsapp/webhook_teardown_service_spec.rb b/spec/services/whatsapp/webhook_teardown_service_spec.rb new file mode 100644 index 000000000..25d2ae374 --- /dev/null +++ b/spec/services/whatsapp/webhook_teardown_service_spec.rb @@ -0,0 +1,81 @@ +require 'rails_helper' + +RSpec.describe Whatsapp::WebhookTeardownService do + describe '#perform' do + let(:channel) { create(:channel_whatsapp, validate_provider_config: false, sync_templates: false) } + let(:service) { described_class.new(channel) } + + context 'when channel is whatsapp_cloud with embedded_signup' do + before do + channel.update!( + provider: 'whatsapp_cloud', + provider_config: { + 'source' => 'embedded_signup', + 'business_account_id' => 'test_waba_id', + 'api_key' => 'test_api_key' + } + ) + end + + it 'calls unsubscribe_waba_webhook on Facebook API client' do + api_client = instance_double(Whatsapp::FacebookApiClient) + allow(Whatsapp::FacebookApiClient).to receive(:new).with('test_api_key').and_return(api_client) + allow(api_client).to receive(:unsubscribe_waba_webhook).with('test_waba_id') + + service.perform + + expect(api_client).to have_received(:unsubscribe_waba_webhook).with('test_waba_id') + end + + it 'handles errors gracefully without raising' do + api_client = instance_double(Whatsapp::FacebookApiClient) + allow(Whatsapp::FacebookApiClient).to receive(:new).and_return(api_client) + allow(api_client).to receive(:unsubscribe_waba_webhook).and_raise(StandardError, 'API Error') + + expect { service.perform }.not_to raise_error + end + end + + context 'when channel is not whatsapp_cloud' do + before do + channel.update!(provider: 'default') + end + + it 'does not attempt to unsubscribe webhook' do + expect(Whatsapp::FacebookApiClient).not_to receive(:new) + + service.perform + end + end + + context 'when channel is whatsapp_cloud but not embedded_signup' do + before do + channel.update!( + provider: 'whatsapp_cloud', + provider_config: { 'source' => 'manual' } + ) + end + + it 'does not attempt to unsubscribe webhook' do + expect(Whatsapp::FacebookApiClient).not_to receive(:new) + + service.perform + end + end + + context 'when required config is missing' do + before do + channel.update!( + provider: 'whatsapp_cloud', + provider_config: { 'source' => 'embedded_signup' } + ) + end + + it 'does not attempt to unsubscribe webhook' do + expect(Whatsapp::FacebookApiClient).not_to receive(:new) + + service.perform + end + end + end +end