diff --git a/app/javascript/dashboard/api/captain/notificationTemplates.js b/app/javascript/dashboard/api/captain/notificationTemplates.js deleted file mode 100644 index b98bd0173..000000000 --- a/app/javascript/dashboard/api/captain/notificationTemplates.js +++ /dev/null @@ -1,29 +0,0 @@ -import ApiClient from '../ApiClient'; - -class NotificationTemplatesAPI extends ApiClient { - constructor() { - super('inboxes', { accountScoped: true }); - } - - getAll(inboxId) { - return this.get(`${inboxId}/notification_templates`); - } - - create(inboxId, data) { - return this.post(`${inboxId}/notification_templates`, { - notification_template: data, - }); - } - - update(inboxId, id, data) { - return this.patch(`${inboxId}/notification_templates/${id}`, { - notification_template: data, - }); - } - - delete(inboxId, id) { - return this.delete(`${inboxId}/notification_templates/${id}`); - } -} - -export default new NotificationTemplatesAPI(); diff --git a/app/javascript/dashboard/components-next/sidebar/Sidebar.vue b/app/javascript/dashboard/components-next/sidebar/Sidebar.vue index efd55fb7a..138c93c9f 100644 --- a/app/javascript/dashboard/components-next/sidebar/Sidebar.vue +++ b/app/javascript/dashboard/components-next/sidebar/Sidebar.vue @@ -436,12 +436,6 @@ const menuItems = computed(() => { activeOn: ['captain_settings_reports'], to: accountScopedRoute('captain_settings_reports'), }, - { - name: 'Notifications', - label: t('SIDEBAR.CAPTAIN_NOTIFICATIONS'), - activeOn: ['captain_settings_notifications'], - to: accountScopedRoute('captain_settings_notifications'), - }, ], }, { diff --git a/app/javascript/dashboard/i18n/locale/en/captain.json b/app/javascript/dashboard/i18n/locale/en/captain.json index ccb25ce3c..f80e866b0 100644 --- a/app/javascript/dashboard/i18n/locale/en/captain.json +++ b/app/javascript/dashboard/i18n/locale/en/captain.json @@ -433,46 +433,6 @@ "LABEL": "Available for agent sending" } } - }, - "NOTIFICATIONS": { - "TITLE": "Automatic Notifications", - "DESCRIPTION": "Configure messages sent automatically before or after the guest's arrival.", - "LOADING": "Loading notifications...", - "ADD": "Add notification", - "ACTIVE": "Active", - "INACTIVE": "Inactive", - "DIRECTION": { - "BEFORE": "before", - "AFTER": "after", - "OF_ARRIVAL": "arrival" - }, - "FORM": { - "LABEL_PLACEHOLDER": "Template name (e.g. Arrival Instructions)", - "CONTENT_PLACEHOLDER": "Message to send... Use {{guest_name}}, {{check_in_time}}, {{suite_name}}", - "SEND": "Send", - "MINUTES": "min", - "CANCEL": "Cancel", - "SAVE": "Save" - }, - "CREATE": { - "SUCCESS": "Notification created successfully!", - "ERROR": "Error creating notification. Please try again." - }, - "UPDATE": { - "SUCCESS": "Notification updated!", - "ERROR": "Error updating notification." - }, - "DELETE": { - "SUCCESS": "Notification removed.", - "ERROR": "Error removing notification." - }, - "INBOX_LABEL": "Select inbox", - "NO_CAPTAIN_INBOXES": "No inboxes with Captain configured.", - "SELECT_INBOX_HINT": "Click an inbox above to view and configure its templates.", - "EMPTY": { - "TITLE": "No templates configured", - "DESC": "Create automatic message templates for this inbox." - } } }, "CAPTAIN": { diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json index 2d1d53aa2..7fe22491f 100644 --- a/app/javascript/dashboard/i18n/locale/en/settings.json +++ b/app/javascript/dashboard/i18n/locale/en/settings.json @@ -347,7 +347,6 @@ "CAPTAIN_FUNNEL": "Conversion Funnel", "CAPTAIN_LIFECYCLE": "Customer Journey", "CAPTAIN_REPORTS": "AI Reports", - "CAPTAIN_NOTIFICATIONS": "Automatic Notifications", "HOME": "Home", "AGENTS": "Agents", "AGENT_BOTS": "Bots", diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/captain.json b/app/javascript/dashboard/i18n/locale/pt_BR/captain.json index c7f291426..183529ed2 100644 --- a/app/javascript/dashboard/i18n/locale/pt_BR/captain.json +++ b/app/javascript/dashboard/i18n/locale/pt_BR/captain.json @@ -434,47 +434,6 @@ "LABEL": "Disponível para envio pelos agentes" } } - }, - "NOTIFICATIONS": { - "TITLE": "Notificações Automáticas", - "DESCRIPTION": "Configure mensagens automáticas enviadas antes ou depois da chegada do hóspede.", - "LOADING": "Carregando notificações...", - "ADD": "Adicionar notificação", - "ACTIVE": "Ativo", - "INACTIVE": "Inativo", - "DIRECTION": { - "BEFORE": "antes", - "AFTER": "depois", - "OF_ARRIVAL": "da chegada" - }, - "TIMING_LABEL": "da chegada", - "FORM": { - "LABEL_PLACEHOLDER": "Nome do template (ex: Orientações de Chegada)", - "CONTENT_PLACEHOLDER": "Mensagem a enviar... Use {{guest_name}}, {{check_in_time}}, {{suite_name}}", - "SEND": "Enviar", - "MINUTES": "min", - "CANCEL": "Cancelar", - "SAVE": "Salvar" - }, - "CREATE": { - "SUCCESS": "Notificação criada com sucesso!", - "ERROR": "Erro ao criar notificação. Tente novamente." - }, - "UPDATE": { - "SUCCESS": "Notificação atualizada!", - "ERROR": "Erro ao atualizar notificação." - }, - "DELETE": { - "SUCCESS": "Notificação removida.", - "ERROR": "Erro ao remover notificação." - }, - "INBOX_LABEL": "Selecione a caixa de entrada", - "NO_CAPTAIN_INBOXES": "Nenhuma caixa de entrada com Captain configurado.", - "SELECT_INBOX_HINT": "Clique em uma caixa de entrada acima para ver e configurar os templates.", - "EMPTY": { - "TITLE": "Nenhum template configurado", - "DESC": "Configure as permissões das informações que o sistema utiliza. Por ex.: Quais imagens enviar durante as aproximações." - } } }, "CAPTAIN": { diff --git a/app/javascript/dashboard/i18n/locale/pt_BR/settings.json b/app/javascript/dashboard/i18n/locale/pt_BR/settings.json index b893d9ac1..294a1f9a0 100644 --- a/app/javascript/dashboard/i18n/locale/pt_BR/settings.json +++ b/app/javascript/dashboard/i18n/locale/pt_BR/settings.json @@ -346,7 +346,6 @@ "CAPTAIN_FUNNEL": "Funil de Conversão", "CAPTAIN_LIFECYCLE": "Jornada do Cliente", "CAPTAIN_REPORTS": "Relatórios IA", - "CAPTAIN_NOTIFICATIONS": "Notificações Automáticas", "HOME": "Principal", "AGENTS": "Agentes", "AGENT_BOTS": "Robôs", diff --git a/app/javascript/dashboard/routes/dashboard/settings/captain/captain.routes.js b/app/javascript/dashboard/routes/dashboard/settings/captain/captain.routes.js index 91f75deb3..c99b08b3c 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/captain/captain.routes.js +++ b/app/javascript/dashboard/routes/dashboard/settings/captain/captain.routes.js @@ -8,7 +8,6 @@ import UnitEdit from './units/Edit.vue'; import GalleryIndex from './gallery/Index.vue'; import GalleryEdit from './gallery/Edit.vue'; const ReportsIndex = () => import('./reports/Index.vue'); -const NotificationsIndex = () => import('./notifications/Index.vue'); export default { routes: [ @@ -78,14 +77,6 @@ export default { permissions: ['administrator'], }, }, - { - path: 'notifications', - name: 'captain_settings_notifications', - component: NotificationsIndex, - meta: { - permissions: ['administrator'], - }, - }, ], }, ], diff --git a/app/javascript/dashboard/routes/dashboard/settings/captain/notifications/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/captain/notifications/Index.vue deleted file mode 100644 index 1f7778b25..000000000 --- a/app/javascript/dashboard/routes/dashboard/settings/captain/notifications/Index.vue +++ /dev/null @@ -1,443 +0,0 @@ - - - - - - - - - - - - - - - - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.INBOX_LABEL') }} - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.NO_CAPTAIN_INBOXES') }} - - - - - {{ inbox.name }} - - - - - - - - - - - - {{ - template.label - }} - {{ - template.content - }} - - {{ timingDisplay(template) }} - - - - - {{ - template.active - ? t('CAPTAIN_SETTINGS.NOTIFICATIONS.ACTIVE') - : t('CAPTAIN_SETTINGS.NOTIFICATIONS.INACTIVE') - }} - - - - - - - - - - - - - - - - - - {{ v }} - - - - - {{ - t('CAPTAIN_SETTINGS.NOTIFICATIONS.FORM.SEND') - }} - - {{ - t('CAPTAIN_SETTINGS.NOTIFICATIONS.FORM.MINUTES') - }} - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.DIRECTION.BEFORE') }} - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.DIRECTION.AFTER') }} - - - {{ - t('CAPTAIN_SETTINGS.NOTIFICATIONS.DIRECTION.OF_ARRIVAL') - }} - - - - - - - - - - - - - - - - {{ v }} - - - - - {{ - t('CAPTAIN_SETTINGS.NOTIFICATIONS.FORM.SEND') - }} - - {{ - t('CAPTAIN_SETTINGS.NOTIFICATIONS.FORM.MINUTES') - }} - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.DIRECTION.BEFORE') }} - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.DIRECTION.AFTER') }} - - - {{ - t('CAPTAIN_SETTINGS.NOTIFICATIONS.DIRECTION.OF_ARRIVAL') - }} - - - - - - - - - - - - - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.EMPTY.TITLE') }} - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.EMPTY.DESC') }} - - - - - - - - - - - {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.SELECT_INBOX_HINT') }} - - - - - - diff --git a/app/javascript/dashboard/store/captain/notificationTemplates.js b/app/javascript/dashboard/store/captain/notificationTemplates.js deleted file mode 100644 index cfda78060..000000000 --- a/app/javascript/dashboard/store/captain/notificationTemplates.js +++ /dev/null @@ -1,84 +0,0 @@ -import notificationTemplatesAPI from '../../api/captain/notificationTemplates'; - -const state = { - records: [], - uiFlags: { - isFetching: false, - isSaving: false, - }, -}; - -const getters = { - getRecords: $state => $state.records, - getUIFlags: $state => $state.uiFlags, -}; - -const actions = { - async fetch({ commit }, inboxId) { - commit('SET_UI_FLAG', { isFetching: true }); - try { - const { data } = await notificationTemplatesAPI.getAll(inboxId); - commit('SET_RECORDS', data); - } finally { - commit('SET_UI_FLAG', { isFetching: false }); - } - }, - - async create({ commit }, { inboxId, payload }) { - commit('SET_UI_FLAG', { isSaving: true }); - try { - const { data } = await notificationTemplatesAPI.create(inboxId, payload); - commit('ADD_RECORD', data); - return data; - } finally { - commit('SET_UI_FLAG', { isSaving: false }); - } - }, - - async update({ commit }, { inboxId, id, payload }) { - commit('SET_UI_FLAG', { isSaving: true }); - try { - const { data } = await notificationTemplatesAPI.update( - inboxId, - id, - payload - ); - commit('UPDATE_RECORD', data); - return data; - } finally { - commit('SET_UI_FLAG', { isSaving: false }); - } - }, - - async delete({ commit }, { inboxId, id }) { - await notificationTemplatesAPI.delete(inboxId, id); - commit('DELETE_RECORD', id); - }, -}; - -const mutations = { - SET_RECORDS($state, records) { - $state.records = records; - }, - ADD_RECORD($state, record) { - $state.records.push(record); - }, - UPDATE_RECORD($state, record) { - const idx = $state.records.findIndex(r => r.id === record.id); - if (idx !== -1) $state.records.splice(idx, 1, record); - }, - DELETE_RECORD($state, id) { - $state.records = $state.records.filter(r => r.id !== id); - }, - SET_UI_FLAG($state, flags) { - $state.uiFlags = { ...$state.uiFlags, ...flags }; - }, -}; - -export default { - namespaced: true, - state, - getters, - actions, - mutations, -}; diff --git a/app/javascript/dashboard/store/index.js b/app/javascript/dashboard/store/index.js index d8d9ac621..d402a3cfd 100755 --- a/app/javascript/dashboard/store/index.js +++ b/app/javascript/dashboard/store/index.js @@ -66,7 +66,6 @@ import captainLifecycleDeliveries from './captain/lifecycleDeliveries'; import captainUnits from './modules/captainUnits'; import captainGalleryItems from './modules/captainGalleryItems'; import captainReports from './modules/captainReports'; -import captainNotificationTemplates from './captain/notificationTemplates'; const plugins = []; @@ -138,7 +137,6 @@ export default createStore({ captainUnits, captainGalleryItems, captainReports, - captainNotificationTemplates, }, plugins, }); diff --git a/app/services/whatsapp/incoming_message_wuzapi_service.rb b/app/services/whatsapp/incoming_message_wuzapi_service.rb index ba877575e..ffa0bd3a3 100644 --- a/app/services/whatsapp/incoming_message_wuzapi_service.rb +++ b/app/services/whatsapp/incoming_message_wuzapi_service.rb @@ -158,9 +158,9 @@ class Whatsapp::IncomingMessageWuzapiService < Whatsapp::IncomingMessageBaseServ # Se a mensagem vier do celular (outgoing) e a assinatura estiver ativa, # e o conteúdo não parecer já ter uma assinatura (evita duplicar em ecos) - if is_outgoing && inbox_obj.message_signature_enabled? && content.present? && !content.start_with?('*[') && !content.start_with?('*') + if is_outgoing && inbox_obj.message_signature_enabled? && content.present? && !content.start_with?('*') signature_name = inbox_obj.shift_signature_name - content = "*[ #{signature_name} ]*\n#{content}" if signature_name.present? + content = "*#{signature_name}*\n#{content}" if signature_name.present? end msg_params = { diff --git a/app/services/whatsapp/providers/wuzapi_service.rb b/app/services/whatsapp/providers/wuzapi_service.rb index 8e8ee8a9c..cfb1f61bd 100644 --- a/app/services/whatsapp/providers/wuzapi_service.rb +++ b/app/services/whatsapp/providers/wuzapi_service.rb @@ -175,7 +175,7 @@ class Whatsapp::Providers::WuzapiService < Whatsapp::Providers::BaseService return content unless message.inbox.message_signature_enabled? name = sender_name_for(message) - name.present? ? "*[ #{name} ]*\n#{content}" : content + name.present? ? "*#{name}*\n#{content}" : content end def reply_params(message) diff --git a/config/routes.rb b/config/routes.rb index 4b3451d44..8e17989e3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -275,8 +275,6 @@ Rails.application.routes.draw do post :sync_templates, on: :member get :health, on: :member post :on_whatsapp, on: :member - resources :notification_templates, only: [:index, :create, :update, :destroy], - module: 'captain' if ChatwootApp.enterprise? resource :conference, only: %i[create destroy], controller: 'conference' do get :token, on: :member diff --git a/enterprise/app/controllers/api/v1/accounts/captain/notification_templates_controller.rb b/enterprise/app/controllers/api/v1/accounts/captain/notification_templates_controller.rb deleted file mode 100644 index cb5ff9fb7..000000000 --- a/enterprise/app/controllers/api/v1/accounts/captain/notification_templates_controller.rb +++ /dev/null @@ -1,45 +0,0 @@ -class Api::V1::Accounts::Captain::NotificationTemplatesController < Api::V1::Accounts::BaseController - before_action :set_inbox - before_action :set_template, only: [:update, :destroy] - - def index - templates = @inbox.captain_notification_templates.ordered - render json: templates - end - - def create - template = @inbox.captain_notification_templates.new(template_params) - if template.save - render json: template, status: :created - else - render json: { error: template.errors.full_messages.join(', ') }, status: :unprocessable_entity - end - end - - def update - if @template.update(template_params) - render json: @template - else - render json: { error: @template.errors.full_messages.join(', ') }, status: :unprocessable_entity - end - end - - def destroy - @template.destroy! - head :no_content - end - - private - - def set_inbox - @inbox = current_account.inboxes.find(params[:inbox_id]) - end - - def set_template - @template = @inbox.captain_notification_templates.find(params[:id]) - end - - def template_params - params.require(:notification_template).permit(:label, :content, :timing_minutes, :timing_direction, :active, :position) - end -end diff --git a/enterprise/app/jobs/captain/notifications/notification_scanner_job.rb b/enterprise/app/jobs/captain/notifications/notification_scanner_job.rb deleted file mode 100644 index 7b1c20f60..000000000 --- a/enterprise/app/jobs/captain/notifications/notification_scanner_job.rb +++ /dev/null @@ -1,41 +0,0 @@ -class Captain::Notifications::NotificationScannerJob < ApplicationJob - queue_as :scheduled_jobs - - # Tolerance window around the target time (job runs every 5 min, so ±5 min ensures coverage) - WINDOW_MINUTES = 5 - - def perform - Captain::NotificationTemplate.active.find_each do |template| - eligible_reservations_for(template).find_each do |reservation| - Captain::Notifications::SendNotificationService.new(reservation, template).perform - end - end - end - - private - - def eligible_reservations_for(template) - target_time = compute_target_time(template) - window_start = target_time - WINDOW_MINUTES.minutes - window_end = target_time + WINDOW_MINUTES.minutes - - Captain::Reservation - .joins(:conversation) - .where(conversations: { inbox_id: template.inbox_id }) - .where(status: Captain::Reservation.statuses.slice(:confirmed, :active).values) - .where(check_in_at: window_start..window_end) - .where.not(conversation_id: nil) - .where( - "NOT (captain_reservations.metadata->'notified_templates' @> ?::jsonb)", - "[#{template.id}]" - ) - end - - def compute_target_time(template) - if template.before? - template.timing_minutes.minutes.from_now - else - template.timing_minutes.minutes.ago - end - end -end diff --git a/enterprise/app/models/captain/notification_template.rb b/enterprise/app/models/captain/notification_template.rb deleted file mode 100644 index 4efee2f15..000000000 --- a/enterprise/app/models/captain/notification_template.rb +++ /dev/null @@ -1,40 +0,0 @@ -# == Schema Information -# -# Table name: captain_notification_templates -# -# id :bigint not null, primary key -# active :boolean default(TRUE), not null -# content :text not null -# label :string not null -# position :integer default(0), not null -# timing_direction :integer default("before"), not null -# timing_minutes :integer default(10), not null -# created_at :datetime not null -# updated_at :datetime not null -# inbox_id :bigint not null -# -# Indexes -# -# idx_notif_templates_inbox_active (inbox_id,active) -# -# Foreign Keys -# -# fk_rails_... (inbox_id => inboxes.id) -# -class Captain::NotificationTemplate < ApplicationRecord - self.table_name = 'captain_notification_templates' - - belongs_to :inbox, inverse_of: :captain_notification_templates - - enum timing_direction: { before: 0, after: 1 } - - validates :label, presence: true - validates :content, presence: true - validates :timing_minutes, presence: true, numericality: { greater_than: 0 } - validates :timing_direction, presence: true - validates :inbox_id, presence: true - - scope :active, -> { where(active: true) } - scope :ordered, -> { order(:position, :id) } - scope :for_inbox, ->(inbox_id) { where(inbox_id: inbox_id) } -end
- {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.EMPTY.TITLE') }} -
- {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.EMPTY.DESC') }} -
- {{ t('CAPTAIN_SETTINGS.NOTIFICATIONS.SELECT_INBOX_HINT') }} -