diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index bcbf80355..a5ef309c5 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -96,7 +96,8 @@ class Api::V1::AccountsController < Api::BaseController end def permitted_settings_attributes - [:auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting, :audio_transcriptions, :auto_resolve_label] + [:auto_resolve_after, :auto_resolve_message, :auto_resolve_ignore_waiting, :audio_transcriptions, :auto_resolve_label, + :aggressive_alert_enabled] end def check_signup_enabled diff --git a/app/javascript/dashboard/components/app/AggressiveConversationBanner.vue b/app/javascript/dashboard/components/app/AggressiveConversationBanner.vue index 76dd19469..b7df23925 100644 --- a/app/javascript/dashboard/components/app/AggressiveConversationBanner.vue +++ b/app/javascript/dashboard/components/app/AggressiveConversationBanner.vue @@ -9,6 +9,7 @@ export default { data() { return { alerts: [], + maxLevel: null, }; }, computed: { @@ -16,38 +17,74 @@ export default { hasAlerts() { return this.alerts.length > 0; }, - bannerLabel() { - if (this.alerts.length === 1) { + bannerClass() { + return [ + 'aggressive-banner', + this.maxLevel ? `aggressive-banner--${this.maxLevel}` : '', + ]; + }, + bannerHeadline() { + const count = this.alerts.length; + if (count === 1) { + const a = this.alerts[0]; + if (a.kind === 'reopened') { + return this.$t( + 'AGGRESSIVE_CONVERSATION_BANNER.HEADLINE_REOPENED', + 'Conversa reaberta — responda agora' + ); + } + // inactivity — mostra tempo + if (a.minutes >= 28) { + return this.$t( + 'AGGRESSIVE_CONVERSATION_BANNER.HEADLINE_28', + { minutes: a.minutes }, + `🚨 ${a.minutes} MIN SEM RESPOSTA — conversa fecha em breve` + ); + } + if (a.minutes >= 15) { + return this.$t( + 'AGGRESSIVE_CONVERSATION_BANNER.HEADLINE_15', + { minutes: a.minutes }, + `⚠️ ${a.minutes} MIN SEM RESPOSTA` + ); + } return this.$t( - 'AGGRESSIVE_CONVERSATION_BANNER.SINGLE', - 'Conversa aguardando resposta!' + 'AGGRESSIVE_CONVERSATION_BANNER.HEADLINE_5', + { minutes: a.minutes }, + `⏰ ${a.minutes} min sem resposta` ); } return this.$t( - 'AGGRESSIVE_CONVERSATION_BANNER.MULTIPLE', - { count: this.alerts.length }, - `${this.alerts.length} conversas aguardando resposta!` + 'AGGRESSIVE_CONVERSATION_BANNER.HEADLINE_MULTIPLE', + { count }, + `🚨 ${count} conversas aguardando resposta` + ); + }, + explanation() { + return this.$t( + 'AGGRESSIVE_CONVERSATION_BANNER.EXPLANATION', + 'Este alerta só some quando você RESPONDER a conversa. Clicar no × esconde temporariamente.' ); }, }, mounted() { - emitter.on(BUS_EVENTS.AGGRESSIVE_ALERT_TRIGGER, this.handleTrigger); - emitter.on(BUS_EVENTS.AGGRESSIVE_ALERT_DISMISS, this.handleDismiss); + emitter.on(BUS_EVENTS.AGGRESSIVE_ALERT_TRIGGER, this.refreshAlerts); + emitter.on(BUS_EVENTS.AGGRESSIVE_ALERT_DISMISS, this.refreshAlerts); // Rehidrata se alertas foram disparados antes do componente montar - this.alerts = aggressiveAlert.getActiveConversations(); + this.refreshAlerts(); }, beforeUnmount() { - emitter.off(BUS_EVENTS.AGGRESSIVE_ALERT_TRIGGER, this.handleTrigger); - emitter.off(BUS_EVENTS.AGGRESSIVE_ALERT_DISMISS, this.handleDismiss); + emitter.off(BUS_EVENTS.AGGRESSIVE_ALERT_TRIGGER, this.refreshAlerts); + emitter.off(BUS_EVENTS.AGGRESSIVE_ALERT_DISMISS, this.refreshAlerts); }, methods: { - handleTrigger() { - this.alerts = aggressiveAlert.getActiveConversations(); - }, - handleDismiss() { + refreshAlerts() { this.alerts = aggressiveAlert.getActiveConversations(); + this.maxLevel = aggressiveAlert.getMaxLevel(); }, openConversation(alert) { + // Clica no item → abre conversa E esconde o alerta dela (mas se + // não responder, volta a aparecer no próximo threshold). aggressiveAlert.dismiss(alert.id); if (!this.currentAccountId) return; this.$router.push({ @@ -58,40 +95,42 @@ export default { dismissOne(alert) { aggressiveAlert.dismiss(alert.id); }, - dismissAll() { - aggressiveAlert.dismissAll(); + alertItemClass(alert) { + return [ + 'aggressive-banner__item', + `aggressive-banner__item--${alert.level}`, + ]; + }, + alertContextLabel(alert) { + if (alert.kind === 'reopened') { + return this.$t( + 'AGGRESSIVE_CONVERSATION_BANNER.KIND_REOPENED', + 'reabriu' + ); + } + return this.$t( + 'AGGRESSIVE_CONVERSATION_BANNER.KIND_WAITING', + { minutes: alert.minutes || '?' }, + `${alert.minutes || '?'} min sem resposta` + ); }, }, };