Compare commits

...
Author SHA1 Message Date
Shivam Mishra 729a551571 fix: email sanitizer 2025-08-21 14:40:15 +05:30
7fe94dc1a2 feat(voice): Call button on Contacts with inbox picker (#12218)
## Description
This introduces a reusable Call button used in the Contacts details
header (between Block contact and Send message) and
in the conversation contact panel. The button shows only when the
account has at least one Voice inbox and the contact
has a phone number. If multiple Voice inboxes are present, clicking
opens a picker modal; otherwise, a “Calling is under
development” toast is shown

> Actual wiring to functionality will available in follow up PRs

references: #11602 , #11481 

## Screens 

<img width="250" alt="Screenshot 2025-08-18 at 8 33 02 PM"
src="https://github.com/user-attachments/assets/d7a09a9d-8eff-4461-a75f-27854540c2a0"
/>
<img width="250" alt="Screenshot 2025-08-18 at 8 32 31 PM"
src="https://github.com/user-attachments/assets/682ae66e-dd5f-4750-9c30-0a210e120250"
/>
<img width="250" alt="Screenshot 2025-08-18 at 8 32 40 PM"
src="https://github.com/user-attachments/assets/7de0d753-eefc-4b7f-942b-ecca1964fcd7"
/>


## Test Cases

- Enable voice feature and create inboxes and test the cases for both
contact details view and contact card view in conversation
  - Details: 0 Voice inboxes → no Call button.
- Details: 1+ Voice inboxes, no phone number for contact → no Call
button.
- Details: 1 Voice inbox + phone number for contact → button visible;
click → toast.
- Details: >1 Voice inboxes + phone number for contact → click → modal →
choose → toast.

---------

Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com>
2025-08-19 15:42:01 +05:30
Chatwoot BotandGitHub cae097c5fa chore: Update translations (#12208) 2025-08-19 12:27:13 +05:30
faf35738b3 fix: Prevent reopening a resolved conversation (#11168)
# Pull Request Template

## Description

This PR addresses the issue where navigating back and starting a new
conversation incorrectly shows the previous messages or message screen.

Fixes
https://linear.app/chatwoot/issue/CW-4169/prevent-continue-conversation-in-previously-resolved-conversation

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## How Has This Been Tested?

### Loom video
**Before**

https://www.loom.com/share/18172a3b26ff4e8faf8e1c3c1a0ba279?sid=ffbda52a-93e1-400f-bedc-17b925bae4d3

**After**

https://www.loom.com/share/584177d411424ad38c6812be868eb060?sid=fe5e771a-3faa-4c14-a5fe-918a3ccdb408

## Checklist:

- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my code
- [ ] I have commented on my code, particularly in hard-to-understand
areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [ ] Any dependent changes have been merged and published in downstream
modules

---------

Co-authored-by: Pranav <pranav@chatwoot.com>
Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
2025-08-19 12:06:22 +05:30
20 changed files with 344 additions and 235 deletions
@@ -7,6 +7,7 @@ import { vOnClickOutside } from '@vueuse/components';
import Button from 'dashboard/components-next/button/Button.vue';
import Breadcrumb from 'dashboard/components-next/breadcrumb/Breadcrumb.vue';
import ComposeConversation from 'dashboard/components-next/NewConversation/ComposeConversation.vue';
import VoiceCallButton from 'dashboard/components-next/Contacts/VoiceCallButton.vue';
const props = defineProps({
selectedContact: {
@@ -99,6 +100,11 @@ const closeMobileSidebar = () => {
:disabled="isUpdating"
@click="toggleBlock"
/>
<VoiceCallButton
:phone="selectedContact?.phoneNumber"
:label="$t('CONTACT_PANEL.CALL')"
size="sm"
/>
<ComposeConversation :contact-id="contactId">
<template #trigger="{ toggle }">
<Button
@@ -0,0 +1,91 @@
<script setup>
import { computed, ref, useAttrs } from 'vue';
import { useI18n } from 'vue-i18n';
import { useMapGetter } from 'dashboard/composables/store';
import { INBOX_TYPES } from 'dashboard/helper/inbox';
import { useAlert } from 'dashboard/composables';
import Button from 'dashboard/components-next/button/Button.vue';
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
const props = defineProps({
phone: { type: String, default: '' },
label: { type: String, default: '' },
icon: { type: [String, Object, Function], default: '' },
size: { type: String, default: 'sm' },
tooltipLabel: { type: String, default: '' },
});
defineOptions({ inheritAttrs: false });
const attrs = useAttrs();
const { t } = useI18n();
const inboxesList = useMapGetter('inboxes/getInboxes');
const voiceInboxes = computed(() =>
(inboxesList.value || []).filter(
inbox => inbox.channel_type === INBOX_TYPES.VOICE
)
);
const hasVoiceInboxes = computed(() => voiceInboxes.value.length > 0);
// Unified behavior: hide when no phone
const shouldRender = computed(() => hasVoiceInboxes.value && !!props.phone);
const dialogRef = ref(null);
const onClick = () => {
if (voiceInboxes.value.length > 1) {
dialogRef.value?.open();
return;
}
useAlert(t('CONTACT_PANEL.CALL_UNDER_DEVELOPMENT'));
};
const onPickInbox = () => {
// Placeholder until actual call wiring happens
useAlert(t('CONTACT_PANEL.CALL_UNDER_DEVELOPMENT'));
dialogRef.value?.close();
};
</script>
<template>
<span class="contents">
<Button
v-if="shouldRender"
v-tooltip.top-end="tooltipLabel || null"
v-bind="attrs"
:label="label"
:icon="icon"
:size="size"
@click="onClick"
/>
<Dialog
v-if="shouldRender && voiceInboxes.length > 1"
ref="dialogRef"
:title="$t('CONTACT_PANEL.VOICE_INBOX_PICKER.TITLE')"
show-cancel-button
:show-confirm-button="false"
width="md"
>
<div class="flex flex-col gap-2">
<button
v-for="inbox in voiceInboxes"
:key="inbox.id"
type="button"
class="flex items-center justify-between w-full px-4 py-2 text-left rounded-lg hover:bg-n-alpha-2"
@click="onPickInbox(inbox)"
>
<div class="flex items-center gap-2">
<span class="i-ri-phone-fill text-n-slate-10" />
<span class="text-sm text-n-slate-12">{{ inbox.name }}</span>
</div>
<span v-if="inbox.phone_number" class="text-xs text-n-slate-10">
{{ inbox.phone_number }}
</span>
</button>
</div>
</Dialog>
</span>
</template>
@@ -17,6 +17,11 @@
"IP_ADDRESS": "IP Address",
"CREATED_AT_LABEL": "Created",
"NEW_MESSAGE": "New message",
"CALL": "Call",
"CALL_UNDER_DEVELOPMENT": "Calling is under development",
"VOICE_INBOX_PICKER": {
"TITLE": "Choose a voice inbox"
},
"CONVERSATIONS": {
"NO_RECORDS_FOUND": "There are no previous conversations associated to this contact.",
"TITLE": "Previous Conversations"
@@ -13,7 +13,7 @@
"TEXT": "Texto",
"NUMBER": "Número",
"LINK": "Link",
"DATE": "Date",
"DATE": "Data",
"LIST": "Lista",
"CHECKBOX": "Checkbox"
},
@@ -131,7 +131,7 @@
"CONVERSATION_CREATED": "Conversa Criada",
"CONVERSATION_UPDATED": "Conversa Atualizada",
"MESSAGE_CREATED": "Mensagem Criada",
"CONVERSATION_RESOLVED": "Conversation Resolved",
"CONVERSATION_RESOLVED": "Conversa resolvida",
"CONVERSATION_OPENED": "Conversa Aberta"
},
"ACTIONS": {
@@ -153,8 +153,8 @@
"OPEN_CONVERSATION": "Abrir conversa"
},
"MESSAGE_TYPES": {
"INCOMING": "Incoming Message",
"OUTGOING": "Outgoing Message"
"INCOMING": "Mensagem Recebida",
"OUTGOING": "Mensagem de Saída"
},
"PRIORITY_TYPES": {
"NONE": "Nenhuma",
@@ -138,11 +138,11 @@
}
},
"WHATSAPP": {
"HEADER_TITLE": "WhatsApp campaigns",
"HEADER_TITLE": "Campanhas do WhatsApp",
"NEW_CAMPAIGN": "Criar campanha",
"EMPTY_STATE": {
"TITLE": "No WhatsApp campaigns are available",
"SUBTITLE": "Launch a WhatsApp campaign to reach your customers directly. Send offers or make announcements with ease. Click 'Create campaign' to get started."
"TITLE": "Nenhuma campanha do WhatsApp está disponível",
"SUBTITLE": "Inicie uma campanha do WhatsApp para atingir seus clientes diretamente. Envie ofertas ou faça anúncios facilmente. Clique em \"Criar campanha\" para começar."
},
"CARD": {
"STATUS": {
@@ -155,7 +155,7 @@
}
},
"CREATE": {
"TITLE": "Create WhatsApp campaign",
"TITLE": "Criar campanha do WhatsApp",
"CANCEL_BUTTON_TEXT": "Cancelar",
"CREATE_BUTTON_TEXT": "Criar",
"FORM": {
@@ -170,15 +170,15 @@
"ERROR": "Caixa de entrada obrigatória"
},
"TEMPLATE": {
"LABEL": "WhatsApp Template",
"PLACEHOLDER": "Select a template",
"INFO": "Select a template to use for this campaign.",
"ERROR": "Template is required",
"LABEL": "Modelo do WhatsApp",
"PLACEHOLDER": "Selecione um modelo",
"INFO": "Selecione um modelo para usar para esta campanha.",
"ERROR": "Modelo é obrigatório",
"PREVIEW_TITLE": "Processar {templateName}",
"LANGUAGE": "Idioma",
"CATEGORY": "Categoria",
"VARIABLES_LABEL": "Variáveis",
"VARIABLE_PLACEHOLDER": "Enter value for {variable}"
"VARIABLE_PLACEHOLDER": "Digite um valor para {variable}"
},
"AUDIENCE": {
"LABEL": "Público",
@@ -195,7 +195,7 @@
"CANCEL": "Cancelar"
},
"API": {
"SUCCESS_MESSAGE": "WhatsApp campaign created successfully",
"SUCCESS_MESSAGE": "Campanha do WhatsApp criada com sucesso",
"ERROR_MESSAGE": "Houve um erro. Por favor, tente novamente."
}
}
@@ -51,6 +51,6 @@
"PLACEHOLDER": "Insira a duração"
},
"CHANNEL_SELECTOR": {
"COMING_SOON": "Coming Soon!"
"COMING_SOON": "Em breve!"
}
}
@@ -144,9 +144,9 @@
"AGENTS_LOADING": "Carregando agentes...",
"ASSIGN_TEAM": "Atribuir time",
"DELETE": "Excluir conversa",
"OPEN_IN_NEW_TAB": "Open in new tab",
"COPY_LINK": "Copy conversation link",
"COPY_LINK_SUCCESS": "Conversation link copied to clipboard",
"OPEN_IN_NEW_TAB": "Abrir em nova aba",
"COPY_LINK": "Copiar link da conversa",
"COPY_LINK_SUCCESS": "Link da conversa copiado",
"API": {
"AGENT_ASSIGNMENT": {
"SUCCESFUL": "ID da conversa {conversationId} atribuído para \"{agentName}\"",
@@ -3,7 +3,7 @@
"LIMIT_MESSAGES": {
"CONVERSATION": "Você excedeu o limite de conversas. O plano Hacker permite apenas 500 conversas.",
"INBOXES": "Você excedeu o limite da caixa de entrada. O plano Hacker só suporta chat ao vivo do site. Caixas adicionais como e-mail, WhatsApp etc. requerem um plano pago.",
"AGENTS": "You have exceeded the agent limit. Your plan only allows {allowedAgents} agents.",
"AGENTS": "Você excedeu o limite do agente. Seu plano permite apenas {allowedAgents} agentes.",
"NON_ADMIN": "Entre em contato com o administrador para atualizar o plano e continuar usando todos os recursos."
},
"TITLE": "Conta",
@@ -134,7 +134,7 @@
"MULTISELECT": {
"ENTER_TO_SELECT": "Digite enter para selecionar",
"ENTER_TO_REMOVE": "Digite enter para remover",
"NO_OPTIONS": "List is empty",
"NO_OPTIONS": "Lista vazia",
"SELECT_ONE": "Selecione um",
"SELECT": "Selecionar"
}
@@ -160,8 +160,8 @@
},
"SEND_CNAME_INSTRUCTIONS": {
"API": {
"SUCCESS_MESSAGE": "CNAME instructions sent successfully",
"ERROR_MESSAGE": "Error while sending CNAME instructions"
"SUCCESS_MESSAGE": "Instruções do CNAME enviadas com sucesso",
"ERROR_MESSAGE": "Erro ao enviar as instruções CNAME"
}
}
},
@@ -732,7 +732,7 @@
"HOME_PAGE_LINK": {
"LABEL": "Link da Página Inicial",
"PLACEHOLDER": "Link da página inicial do portal",
"ERROR": "Enter a valid URL. The Home page link must start with 'http://' or 'https://'."
"ERROR": "Digite uma URL válida. O link da página inicial deve começar com 'http://' ou 'https://'."
},
"SLUG": {
"LABEL": "Slug",
@@ -753,14 +753,14 @@
"HEADER": "Domínio personalizado",
"LABEL": "Domínio personalizado:",
"DESCRIPTION": "Você pode hospedar seu portal em um domínio personalizado. Por exemplo, se seu site for meudominio.com e você quer o seu portal disponível em docs.meudominio.com, basta digitar isso neste campo.",
"STATUS_DESCRIPTION": "Your custom portal will start working as soon as it is verified.",
"STATUS_DESCRIPTION": "Seu portal personalizado começará a funcionar assim que for verificado.",
"PLACEHOLDER": "Domínio personalizado do portal",
"EDIT_BUTTON": "Alterar",
"ADD_BUTTON": "Adicionar domínio personalizado",
"STATUS": {
"LIVE": "Em tempo real",
"PENDING": "Awaiting verification",
"ERROR": "Verification failed"
"PENDING": "Aguardando verificação",
"ERROR": "Verificação falhou"
},
"DIALOG": {
"ADD_HEADER": "Adicionar domínio personalizado",
@@ -770,17 +770,17 @@
"LABEL": "Domínio personalizado",
"PLACEHOLDER": "Domínio personalizado do portal",
"ERROR": "Domínio personalizado é obrigatório",
"FORMAT_ERROR": "Please enter a valid domain URL e.g. docs.yourdomain.com"
"FORMAT_ERROR": "Por favor, insira um domínio de URL válido, ex.: docs.seudominio.com"
},
"DNS_CONFIGURATION_DIALOG": {
"HEADER": "Configuração de DNS",
"DESCRIPTION": "Faça o login na conta que você tem com seu provedor DNS e adicione um registro CNAME para subdomínio apontando para chatwoot.help",
"COPY": "Successfully copied CNAME",
"COPY": "CNAME copiado com sucesso",
"SEND_INSTRUCTIONS": {
"HEADER": "Send instructions",
"DESCRIPTION": "If you would prefer to have someone from your development team to handle this step, you can enter email address below, and we will send them the required instructions.",
"PLACEHOLDER": "Enter their email",
"ERROR": "Enter a valid email address",
"HEADER": "Enviar instruções",
"DESCRIPTION": "Se você preferir ter alguém da sua equipe de desenvolvimento para lidar com essa etapa, você pode digitar o endereço de e-mail abaixo e nós enviaremos as instruções necessárias.",
"PLACEHOLDER": "Insira o e-mail dele",
"ERROR": "Insira um endereço de e-mail válido",
"SEND_BUTTON": "Enviar"
}
}
@@ -74,21 +74,21 @@
"DELETE_ALL_READ": "Todas as notificações lidas foram excluídas"
},
"REAUTHORIZE": {
"TITLE": "Reauthorization Required",
"DESCRIPTION": "Your WhatsApp connection has expired. Please reconnect to continue receiving and sending messages.",
"BUTTON_TEXT": "Reconnect WhatsApp",
"LOADING_FACEBOOK": "Loading Facebook SDK...",
"SUCCESS": "WhatsApp reconnected successfully",
"ERROR": "Failed to reconnect WhatsApp. Please try again.",
"WHATSAPP_APP_ID_MISSING": "WhatsApp App ID is not configured. Please contact your administrator.",
"WHATSAPP_CONFIG_ID_MISSING": "WhatsApp Configuration ID is not configured. Please contact your administrator.",
"CONFIGURATION_ERROR": "Configuration error occurred during reauthorization.",
"FACEBOOK_LOAD_ERROR": "Failed to load Facebook SDK. Please try again.",
"TITLE": "Reautenticação necessária",
"DESCRIPTION": "Sua conexão com o WhatsApp expirou. Por favor, reconecte para continuar recebendo e enviando mensagens.",
"BUTTON_TEXT": "Reconectar WhatsApp",
"LOADING_FACEBOOK": "Carregando SDK do Facebook...",
"SUCCESS": "WhatsApp reconectado com sucesso",
"ERROR": "Falha ao reconectar o WhatsApp. Por favor, tente novamente.",
"WHATSAPP_APP_ID_MISSING": "WhatsApp App ID não está configurado. Por favor, contate seu administrador.",
"WHATSAPP_CONFIG_ID_MISSING": "WhatsApp Configuration ID não está configurado. Por favor, contate seu administrador.",
"CONFIGURATION_ERROR": "Ocorreu um erro de configuração ao reautenticar.",
"FACEBOOK_LOAD_ERROR": "Falha para carregar o SDK do Facebook. Por favor, tente novamente.",
"TROUBLESHOOTING": {
"TITLE": "Troubleshooting",
"POPUP_BLOCKED": "Ensure pop-ups are allowed for this site",
"COOKIES": "Third-party cookies must be enabled",
"ADMIN_ACCESS": "You need admin access to the WhatsApp Business Account"
"TITLE": "Solucionar problemas",
"POPUP_BLOCKED": "Certifique-se de que os pop-ups são permitidos para este site",
"COOKIES": "_Cookies_ de terceiros devem estar habilitados",
"ADMIN_ACCESS": "Você precisa de acesso de administrador na conta do WhatsApp Business"
}
}
}
@@ -225,13 +225,13 @@
"WHATSAPP_EMBEDDED": "WhatsApp Business",
"TWILIO": "Twilio",
"WHATSAPP_CLOUD": "Cloud do WhatsApp",
"WHATSAPP_CLOUD_DESC": "Quick setup through Meta",
"TWILIO_DESC": "Connect via Twilio credentials",
"WHATSAPP_CLOUD_DESC": "Configuração rápida via Meta",
"TWILIO_DESC": "Conectar através de credenciais Twilio",
"360_DIALOG": "360Dialog"
},
"SELECT_PROVIDER": {
"TITLE": "Select your API provider",
"DESCRIPTION": "Choose your WhatsApp provider. You can connect directly through Meta which requires no setup, or connect through Twilio using your account credentials."
"TITLE": "Selecione seu provedor de API",
"DESCRIPTION": "Escolha seu provedor do WhatsApp. Você pode se conectar diretamente através de metade, que não requer nenhuma configuração ou se conectar pelo Twilio usando as credenciais da sua conta."
},
"INBOX_NAME": {
"LABEL": "Nome da Caixa de Entrada",
@@ -272,74 +272,74 @@
},
"SUBMIT_BUTTON": "Criar canal do WhatsApp",
"EMBEDDED_SIGNUP": {
"TITLE": "Quick Setup with Meta",
"DESC": "You will be redirected to Meta to log into your WhatsApp Business account. Having admin access will help make the setup smooth and easy.",
"TITLE": "Configuração rápida com Meta",
"DESC": "Você será redirecionado para a Meta para entrar na sua conta do WhatsApp Business. Ter acesso administrativo ajudará a facilitar a instalação.",
"BENEFITS": {
"TITLE": "Benefits of Embedded Signup:",
"EASY_SETUP": "No manual configuration required",
"SECURE_AUTH": "Secure OAuth based authentication",
"AUTO_CONFIG": "Automatic webhook and phone number configuration"
"TITLE": "Benefícios da inscrição incorporada:",
"EASY_SETUP": "Nenhuma configuração manual é necessária",
"SECURE_AUTH": "Autenticação segura baseada em OAuth",
"AUTO_CONFIG": "Configuração automática de webhook e número de telefone"
},
"LEARN_MORE": {
"TEXT": "To learn more about integrated signup, pricing, and limitations, visit",
"LINK_TEXT": "this link.",
"TEXT": "Para saber mais sobre inscrições integradas, preços e limitações visite",
"LINK_TEXT": "este link.",
"LINK_URL": "https://developers.facebook.com/docs/whatsapp/embedded-signup/custom-flows/onboarding-business-app-users#limitations"
},
"SUBMIT_BUTTON": "Connect with WhatsApp Business",
"AUTH_PROCESSING": "Authenticating with Meta",
"WAITING_FOR_BUSINESS_INFO": "Please complete business setup in the Meta window...",
"PROCESSING": "Setting up your WhatsApp Business Account",
"LOADING_SDK": "Loading Facebook SDK...",
"CANCELLED": "WhatsApp Signup was cancelled",
"SUCCESS_TITLE": "WhatsApp Business Account Connected!",
"WAITING_FOR_AUTH": "Waiting for authentication...",
"INVALID_BUSINESS_DATA": "Invalid business data received from Facebook. Please try again.",
"SIGNUP_ERROR": "Signup error occurred",
"AUTH_NOT_COMPLETED": "Authentication not completed. Please restart the process.",
"SUCCESS_FALLBACK": "WhatsApp Business Account has been successfully configured"
"SUBMIT_BUTTON": "Conecte-se com WhatsApp Business",
"AUTH_PROCESSING": "Autenticando com Meta",
"WAITING_FOR_BUSINESS_INFO": "Por favor, complete a configuração do negócio na janela da Meta...",
"PROCESSING": "Configurando sua conta do WhatsApp Business",
"LOADING_SDK": "Carregando SDK do Facebook...",
"CANCELLED": "A inscrição no WhatsApp foi cancelada",
"SUCCESS_TITLE": "Conta do WhatsApp Business conectada!",
"WAITING_FOR_AUTH": "Aguardando autenticação...",
"INVALID_BUSINESS_DATA": "Dados de negócio inválidos recebidos do Facebook. Por favor, tente novamente.",
"SIGNUP_ERROR": "Ocorreu um erro no cadastro",
"AUTH_NOT_COMPLETED": "Autenticação não concluída. Por favor, reinicie o processo.",
"SUCCESS_FALLBACK": "A conta do WhatsApp Business foi configurada com sucesso"
},
"API": {
"ERROR_MESSAGE": "Não foi possível salvar o canal do WhatsApp"
}
},
"VOICE": {
"TITLE": "Voice Channel",
"DESC": "Integrate Twilio Voice and start supporting your customers via phone calls.",
"TITLE": "Canal de Voz",
"DESC": "Integre o Twilio Voice e comece a oferecer suporte a seus clientes através de chamadas telefônicas.",
"PHONE_NUMBER": {
"LABEL": "Número de Telefone",
"PLACEHOLDER": "Enter your phone number (e.g. +1234567890)",
"ERROR": "Please provide a valid phone number in E.164 format (e.g. +1234567890)"
"PLACEHOLDER": "Digite seu número de telefone (por exemplo, +551234567890)",
"ERROR": "Por favor, forneça um número de telefone válido no formato E.164 (por exemplo, +551234567890)"
},
"TWILIO": {
"ACCOUNT_SID": {
"LABEL": "SID da Conta",
"PLACEHOLDER": "Enter your Twilio Account SID",
"REQUIRED": "Account SID is required"
"PLACEHOLDER": "Insira o SID da sua Conta Twilio",
"REQUIRED": "O SID da conta é necessário"
},
"AUTH_TOKEN": {
"LABEL": "Token de autenticação",
"PLACEHOLDER": "Enter your Twilio Auth Token",
"REQUIRED": "Auth Token is required"
"PLACEHOLDER": "Por favor, digite seu Token de Autenticação do Twilio",
"REQUIRED": "Um Token de autenticação é necessário"
},
"API_KEY_SID": {
"LABEL": "Chave da API SID",
"PLACEHOLDER": "Enter your Twilio API Key SID",
"REQUIRED": "API Key SID is required"
"PLACEHOLDER": "Insira sua chave de API do Twilio SID",
"REQUIRED": "API Key SID é obrigatório"
},
"API_KEY_SECRET": {
"LABEL": "Segredo da Chave API",
"PLACEHOLDER": "Enter your Twilio API Key Secret",
"REQUIRED": "API Key Secret is required"
"PLACEHOLDER": "Digite o segredo da sua chave de API do Twilio",
"REQUIRED": "Segredo da chave da API é obrigatório"
},
"TWIML_APP_SID": {
"LABEL": "TwiML App SID",
"PLACEHOLDER": "Enter your Twilio TwiML App SID (starts with AP)",
"REQUIRED": "TwiML App SID is required"
"PLACEHOLDER": "Insira seu Twilio TwiML App SID (começa com AP)",
"REQUIRED": "TwiML App SID é obrigatório"
}
},
"SUBMIT_BUTTON": "Create Voice Channel",
"SUBMIT_BUTTON": "Criar Canal de Voz",
"API": {
"ERROR_MESSAGE": "We were not able to create the voice channel"
"ERROR_MESSAGE": "Não conseguimos criar o canal de voz"
}
},
"API_CHANNEL": {
@@ -603,27 +603,27 @@
"WHATSAPP_SECTION_UPDATE_TITLE": "Atualizar Chave de API",
"WHATSAPP_SECTION_UPDATE_PLACEHOLDER": "Digite a nova chave de API aqui",
"WHATSAPP_SECTION_UPDATE_BUTTON": "Atualizar",
"WHATSAPP_EMBEDDED_SIGNUP_TITLE": "WhatsApp Embedded Signup",
"WHATSAPP_EMBEDDED_SIGNUP_SUBHEADER": "This inbox is connected through WhatsApp embedded signup.",
"WHATSAPP_EMBEDDED_SIGNUP_DESCRIPTION": "You can reconfigure this inbox to update your WhatsApp Business settings.",
"WHATSAPP_RECONFIGURE_BUTTON": "Reconfigure",
"WHATSAPP_CONNECT_TITLE": "Connect to WhatsApp Business",
"WHATSAPP_CONNECT_SUBHEADER": "Upgrade to WhatsApp embedded signup for easier management.",
"WHATSAPP_CONNECT_DESCRIPTION": "Connect this inbox to WhatsApp Business for enhanced features and easier management.",
"WHATSAPP_EMBEDDED_SIGNUP_TITLE": "Inscrição incorporada do WhatsApp",
"WHATSAPP_EMBEDDED_SIGNUP_SUBHEADER": "Esta caixa de entrada está conectada através da inscrição incorporada do WhatsApp.",
"WHATSAPP_EMBEDDED_SIGNUP_DESCRIPTION": "Você pode reconfigurar esta caixa de entrada para atualizar suas configurações do WhatsApp Business.",
"WHATSAPP_RECONFIGURE_BUTTON": "Reconfigurar",
"WHATSAPP_CONNECT_TITLE": "Conectar ao WhatsApp Business",
"WHATSAPP_CONNECT_SUBHEADER": ".",
"WHATSAPP_CONNECT_DESCRIPTION": "Conecte esta caixa de entrada ao WhatsApp Business para ter recursos aprimorados e um gerenciamento mais fácil.",
"WHATSAPP_CONNECT_BUTTON": "Conectar",
"WHATSAPP_CONNECT_SUCCESS": "Successfully connected to WhatsApp Business!",
"WHATSAPP_CONNECT_ERROR": "Failed to connect to WhatsApp Business. Please try again.",
"WHATSAPP_RECONFIGURE_SUCCESS": "Successfully reconfigured WhatsApp Business!",
"WHATSAPP_RECONFIGURE_ERROR": "Failed to reconfigure WhatsApp Business. Please try again.",
"WHATSAPP_APP_ID_MISSING": "WhatsApp App ID is not configured. Please contact your administrator.",
"WHATSAPP_CONFIG_ID_MISSING": "WhatsApp Configuration ID is not configured. Please contact your administrator.",
"WHATSAPP_LOGIN_CANCELLED": "WhatsApp login was cancelled. Please try again.",
"WHATSAPP_CONNECT_SUCCESS": "Conectado com sucesso ao WhatsApp Business!",
"WHATSAPP_CONNECT_ERROR": "Não foi possível reconfigurar o WhatsApp Business. Tente novamente.",
"WHATSAPP_RECONFIGURE_SUCCESS": "WhatsApp Business reconfigurado com sucesso!",
"WHATSAPP_RECONFIGURE_ERROR": "Não foi possível reconfigurar o WhatsApp Business. Tente novamente.",
"WHATSAPP_APP_ID_MISSING": "O ID do WhatsApp não está configurado. Por favor, contate o administrador.",
"WHATSAPP_CONFIG_ID_MISSING": "O ID de Configuração do WhatsApp não está configurado. Por favor, contate o administrador.",
"WHATSAPP_LOGIN_CANCELLED": "O login do WhatsApp foi cancelado. Por favor, tente novamente.",
"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.",
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sincronizar Modelos",
"WHATSAPP_TEMPLATES_SYNC_SUBHEADER": "Sincronize manualmente os modelos de mensagens do WhatsApp para atualizar seus modelos disponíveis.",
"WHATSAPP_TEMPLATES_SYNC_BUTTON": "Sincronizar Modelos",
"WHATSAPP_TEMPLATES_SYNC_SUCCESS": "Sincronização de modelos iniciada com sucesso. Pode demorar alguns minutos para atualizar.",
"UPDATE_PRE_CHAT_FORM_SETTINGS": "Atualizar configurações do Formulário Pre Chat"
},
"HELP_CENTER": {
@@ -883,7 +883,7 @@
"LINE": "Line",
"API": "Canal da API",
"INSTAGRAM": "Instagram",
"VOICE": "Voice"
"VOICE": "Voz"
}
}
}
@@ -334,8 +334,8 @@
},
"NOTION": {
"DELETE": {
"TITLE": "Are you sure you want to delete the Notion integration?",
"MESSAGE": "Deleting this integration will remove access to your Notion workspace and stop all related functionality.",
"TITLE": "Você tem certeza que deseja excluir a integração com Notion?",
"MESSAGE": "Excluir essa integração removerá o acesso ao seu espaço de trabalho Notion e encerrará todas as funcionalidades relacionadas.",
"CONFIRM": "Sim, excluir",
"CANCEL": "Cancelar"
}
@@ -473,7 +473,7 @@
"TITLE": "Funcionalidades",
"ALLOW_CONVERSATION_FAQS": "Gerar perguntas frequentes a partir de conversas resolvidas",
"ALLOW_MEMORIES": "Capture os principais detalhes como memórias de interações do cliente.",
"ALLOW_CITATIONS": "Include source citations in responses"
"ALLOW_CITATIONS": "Incluir fonte de citações nas respostas"
}
},
"EDIT": {
@@ -487,28 +487,28 @@
"ASSISTANT": "Assistente"
},
"BASIC_SETTINGS": {
"TITLE": "Basic settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
"TITLE": "Configurações básicas",
"DESCRIPTION": "Personalize o que o assistente diz quando termina uma conversa ou transfere para um humano."
},
"SYSTEM_SETTINGS": {
"TITLE": "System settings",
"DESCRIPTION": "Customize what the assistant says when ending a conversation or transferring to a human."
"TITLE": "Configurações do sistema",
"DESCRIPTION": "Personalize o que o assistente diz quando termina uma conversa ou transfere para um humano."
},
"CONTROL_ITEMS": {
"TITLE": "The Fun Stuff",
"DESCRIPTION": "Add more control to the assistant. (a bit more visual like a story : Query guardrailscenarios → output) Nudges user to actually utilise these.",
"TITLE": "As Coisas Divertidas",
"DESCRIPTION": "Adicione mais controle ao assistente. (algo mais visual como uma história: Consulta → cenários → saída) Força o usuário para realmente utilizá-los.",
"OPTIONS": {
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic."
"TITLE": "Proteções",
"DESCRIPTION": "Mantém as coisas no caminho — apenas os tipos de perguntas que você quer que seu assistente responda, nada fora de limites ou fora do tópico."
},
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”"
"TITLE": "Cenários",
"DESCRIPTION": "Dê algum contexto ao seu assistente — como \"o que fazer quando um usuário estiver com problemas\", ou \"como agir durante uma solicitação de reembolso\"."
},
"RESPONSE_GUIDELINES": {
"TITLE": "Response guidelines",
"DESCRIPTION": "The vibe and structure of your assistants replies—clear and friendly? Short and snappy? Detailed and formal?"
"TITLE": "Diretrizes de resposta",
"DESCRIPTION": "O jeito e a estrutura das respostas do seu assistente — tranquilo e amigável? Curto e ágil? Detalhado e formal?"
}
}
}
@@ -527,138 +527,138 @@
}
},
"GUARDRAILS": {
"TITLE": "Guardrails",
"DESCRIPTION": "Keeps things on track—only the kinds of questions you want your assistant to answer, nothing off-limits or off-topic.",
"TITLE": "Proteções",
"DESCRIPTION": "Mantém as coisas no caminho — apenas os tipos de perguntas que você quer que seu assistente responda, nada fora de limites ou fora do tópico.",
"BREADCRUMB": {
"TITLE": "Guardrails"
"TITLE": "Proteções"
},
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECTED": "{count} item selecionado | {count} itens selecionados",
"SELECT_ALL": "Selecionar todos ({count})",
"UNSELECT_ALL": "Desmarcar todos ({count})",
"BULK_DELETE_BUTTON": "Excluir"
},
"ADD": {
"SUGGESTED": {
"TITLE": "Example guardrails",
"ADD": "Add all",
"ADD_SINGLE": "Add this",
"SAVE": "Add and save (↵)",
"PLACEHOLDER": "Type in another guardrail..."
"TITLE": "Exemplos de proteções",
"ADD": "Adicionar todos",
"ADD_SINGLE": "Adicionar este",
"SAVE": "Adicionar e salvar (↵)",
"PLACEHOLDER": "Escreva outra proteção"
},
"NEW": {
"TITLE": "Add a guardrail",
"TITLE": "Adicionar proteção",
"CREATE": "Criar",
"CANCEL": "Cancelar",
"PLACEHOLDER": "Type in another guardrail...",
"TEST_ALL": "Test all"
"PLACEHOLDER": "Escreva outra proteção",
"TEST_ALL": "Testar tudo"
}
},
"LIST": {
"SEARCH_PLACEHOLDER": "Pesquisar..."
},
"EMPTY_MESSAGE": "No guardrails found. Create or add examples to begin.",
"SEARCH_EMPTY_MESSAGE": "No guardrails found for this search.",
"EMPTY_MESSAGE": "Nenhuma proteção encontrada. Crie uma ou adicione exemplos para começar.",
"SEARCH_EMPTY_MESSAGE": "Nenhuma proteção encontrada para essa pesquisa.",
"API": {
"ADD": {
"SUCCESS": "Guardrails added successfully",
"ERROR": "There was an error adding guardrails, please try again."
"SUCCESS": "Proteções adicionadas com sucesso",
"ERROR": "Ocorreu um erro ao adicionar as proteções. Por favor, tente novamente."
},
"UPDATE": {
"SUCCESS": "Guardrails updated successfully",
"ERROR": "There was an error updating guardrails, please try again."
"SUCCESS": "Proteções atualizados com sucesso",
"ERROR": "Ocorreu um erro ao atualizar as proteções. Por favor, tente novamente."
},
"DELETE": {
"SUCCESS": "Guardrails deleted successfully",
"ERROR": "There was an error deleting guardrails, please try again."
"SUCCESS": "Proteções removidas com sucesso",
"ERROR": "Ocorreu um erro ao excluir as proteções, por favor, tente novamente."
}
}
},
"RESPONSE_GUIDELINES": {
"TITLE": "Response Guidelines",
"DESCRIPTION": "The vibe and structure of your assistants replies—clear and friendly? Short and snappy? Detailed and formal?",
"TITLE": "Diretrizes de Resposta",
"DESCRIPTION": "O jeito e a estrutura das respostas do seu assistente — tranquilo e amigável? Curto e ágil? Detalhado e formal?",
"BREADCRUMB": {
"TITLE": "Response Guidelines"
"TITLE": "Diretrizes de Resposta"
},
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECTED": "{count} item selecionado | {count} itens selecionados",
"SELECT_ALL": "Selecionar todos ({count})",
"UNSELECT_ALL": "Desmarcar todos ({count})",
"BULK_DELETE_BUTTON": "Excluir"
},
"ADD": {
"SUGGESTED": {
"TITLE": "Example response guidelines",
"ADD": "Add all",
"ADD_SINGLE": "Add this",
"SAVE": "Add and save (↵)",
"PLACEHOLDER": "Type in another response guideline..."
"TITLE": "Exemplos de diretrizes de resposta",
"ADD": "Adicionar todos",
"ADD_SINGLE": "Adicionar este",
"SAVE": "Adicionar e salvar (↵)",
"PLACEHOLDER": "Escreva uma outra diretriz de resposta..."
},
"NEW": {
"TITLE": "Add a response guideline",
"TITLE": "Adicione uma diretriz de resposta",
"CREATE": "Criar",
"CANCEL": "Cancelar",
"PLACEHOLDER": "Type in another response guideline...",
"TEST_ALL": "Test all"
"PLACEHOLDER": "Escreva uma outra diretriz de resposta...",
"TEST_ALL": "Testar tudo"
}
},
"LIST": {
"SEARCH_PLACEHOLDER": "Pesquisar..."
},
"EMPTY_MESSAGE": "No response guidelines found. Create or add examples to begin.",
"SEARCH_EMPTY_MESSAGE": "No response guidelines found for this search.",
"EMPTY_MESSAGE": "Nenhuma diretriz de resposta encontrada. Crie uma ou adicione exemplos para começar.",
"SEARCH_EMPTY_MESSAGE": "Nenhuma diretriz de resposta encotrada para essa pesquisa.",
"API": {
"ADD": {
"SUCCESS": "Response Guidelines added successfully",
"ERROR": "There was an error adding response guidelines, please try again."
"SUCCESS": "Diretrizes de resposta adicionadas com sucesso",
"ERROR": "Houve um erro ao adicionar diretrizes de resposta, por favor, tente novamente."
},
"UPDATE": {
"SUCCESS": "Response Guidelines updated successfully",
"ERROR": "There was an error updating response guidelines, please try again."
"SUCCESS": "Diretrizes de Resposta atualizadas com sucesso",
"ERROR": "Houve um erro ao atualizar as diretrizes de resposta, por favor, tente novamente."
},
"DELETE": {
"SUCCESS": "Response Guidelines deleted successfully",
"ERROR": "There was an error deleting response guidelines, please try again."
"SUCCESS": "Diretrizes de resposta removidas com sucesso",
"ERROR": "Houve um erro ao excluir as diretrizes de resposta, por favor, tente novamente."
}
}
},
"SCENARIOS": {
"TITLE": "Scenarios",
"DESCRIPTION": "Give your assistant some context—like “what to do when a user is stuck,” or “how to act during a refund request.”",
"TITLE": "Cenários",
"DESCRIPTION": "Dê algum contexto ao seu assistente — como \"o que fazer quando um usuário estiver com problemas\", ou \"como agir durante uma solicitação de reembolso\".",
"BREADCRUMB": {
"TITLE": "Scenarios"
"TITLE": "Cenários"
},
"BULK_ACTION": {
"SELECTED": "{count} item selected | {count} items selected",
"SELECTED": "{count} item selecionado | {count} itens selecionados",
"SELECT_ALL": "Selecionar todos ({count})",
"UNSELECT_ALL": "Desmarcar todos ({count})",
"BULK_DELETE_BUTTON": "Excluir"
},
"ADD": {
"SUGGESTED": {
"TITLE": "Example scenarios",
"ADD": "Add all",
"ADD_SINGLE": "Add this",
"TOOLS_USED": "Tools used :"
"TITLE": "Exemplos de cenários",
"ADD": "Adicionar todos",
"ADD_SINGLE": "Adicionar este",
"TOOLS_USED": "Ferramentas usadas :"
},
"NEW": {
"CREATE": "Add a scenario",
"TITLE": "Create a scenario",
"CREATE": "Adicionar um cenário",
"TITLE": "Criar um cenário",
"FORM": {
"TITLE": {
"LABEL": "Título",
"PLACEHOLDER": "Enter a name for the scenario",
"ERROR": "Scenario name is required"
"PLACEHOLDER": "Digite um nome para o cenário",
"ERROR": "O nome do cenário é obrigatório"
},
"DESCRIPTION": {
"LABEL": "Descrição",
"PLACEHOLDER": "Describe how and where this scenario will be used",
"ERROR": "Scenario description is required"
"PLACEHOLDER": "Descreva como e onde este cenário será utilizado",
"ERROR": "Descrição do cenário é obrigatória"
},
"INSTRUCTION": {
"LABEL": "How to handle",
"PLACEHOLDER": "Describe how and where this scenario will be handled",
"ERROR": "Scenario content is required"
"LABEL": "Como lidar",
"PLACEHOLDER": "Descreva como e onde este cenário será utilizado",
"ERROR": "Conteúdo do cenário é obrigatório"
},
"CREATE": "Criar",
"CANCEL": "Cancelar"
@@ -667,25 +667,25 @@
},
"UPDATE": {
"CANCEL": "Cancelar",
"UPDATE": "Update changes"
"UPDATE": "Atualizar alterações"
},
"LIST": {
"SEARCH_PLACEHOLDER": "Pesquisar..."
},
"EMPTY_MESSAGE": "No scenarios found. Create or add examples to begin.",
"SEARCH_EMPTY_MESSAGE": "No scenarios found for this search.",
"EMPTY_MESSAGE": "Nenhum cenário encontrado. Crie ou adicione exemplos para começar.",
"SEARCH_EMPTY_MESSAGE": "Nenhum cenário encontrado para esta pesquisa.",
"API": {
"ADD": {
"SUCCESS": "Scenarios added successfully",
"ERROR": "There was an error adding scenarios, please try again."
"SUCCESS": "Cenários adicionados com sucesso",
"ERROR": "Ocorreu um erro ao adicionar cenários, por favor tente novamente."
},
"UPDATE": {
"SUCCESS": "Scenarios updated successfully",
"ERROR": "There was an error updating scenarios, please try again."
"SUCCESS": "Cenários atualizados com sucesso",
"ERROR": "Ocorreu um erro ao atualizar cenários, por favor tente novamente."
},
"DELETE": {
"SUCCESS": "Scenarios deleted successfully",
"ERROR": "There was an error deleting scenarios, please try again."
"SUCCESS": "Cenários excluídos com sucesso",
"ERROR": "Ocorreu um erro ao excluir os cenários, por favor tente novamente."
}
}
}
@@ -3,22 +3,22 @@
"MODAL": {
"TITLE": "Templates do Whatsapp",
"SUBTITLE": "Selecione o template do whatsapp que você deseja enviar",
"TEMPLATE_SELECTED_SUBTITLE": "Configure template: {templateName}"
"TEMPLATE_SELECTED_SUBTITLE": "Configurar modelo: {templateName}"
},
"PICKER": {
"SEARCH_PLACEHOLDER": "Pesquisar modelos",
"NO_TEMPLATES_FOUND": "Não há templates encontrados para",
"HEADER": "Header",
"BODY": "Body",
"FOOTER": "Footer",
"BUTTONS": "Buttons",
"HEADER": "Cabeçalho",
"BODY": "Corpo",
"FOOTER": "Rodapé",
"BUTTONS": "Botões",
"CATEGORY": "Categoria",
"MEDIA_CONTENT": "Media Content",
"MEDIA_CONTENT_FALLBACK": "media content",
"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.",
"MEDIA_CONTENT": "Conteúdo de Mídia",
"MEDIA_CONTENT_FALLBACK": "conteúdo de mídia",
"NO_TEMPLATES_AVAILABLE": "Não há modelos disponíveis do WhatsApp. Clique em atualizar para sincronizar os modelos do WhatsApp.",
"REFRESH_BUTTON": "Atualizar modelos",
"REFRESH_SUCCESS": "Atualização de modelos iniciada. Pode levar alguns minutos para atualizar.",
"REFRESH_ERROR": "Falha ao atualizar os modelos. Por favor, tente novamente.",
"LABELS": {
"LANGUAGE": "Idioma",
"TEMPLATE_BODY": "Conteúdo do Template",
@@ -33,14 +33,14 @@
"GO_BACK_LABEL": "Voltar",
"SEND_MESSAGE_LABEL": "Enviar Mensagem",
"FORM_ERROR_MESSAGE": "Por favor, preencha todas as variáveis antes de enviar",
"MEDIA_HEADER_LABEL": "{type} Header",
"OTP_CODE": "Enter 4-8 digit OTP",
"EXPIRY_MINUTES": "Enter expiry minutes",
"BUTTON_PARAMETERS": "Button Parameters",
"BUTTON_LABEL": "Button {index}",
"COUPON_CODE": "Enter coupon code (max 15 chars)",
"MEDIA_URL_LABEL": "Enter {type} URL",
"BUTTON_PARAMETER": "Enter button parameter"
"MEDIA_HEADER_LABEL": "Cabeçalho {type}",
"OTP_CODE": "Digite OTP de 4 a 8 dígitos",
"EXPIRY_MINUTES": "Digite os minutos de expiração",
"BUTTON_PARAMETERS": "Parâmetros do botão",
"BUTTON_LABEL": "Botão {index}",
"COUPON_CODE": "Digite o código do cupom (máx. 15 caracteres)",
"MEDIA_URL_LABEL": "Digite a URL {type}",
"BUTTON_PARAMETER": "Insira o parâmetro do botão"
}
}
}
@@ -11,6 +11,7 @@ import ContactMergeModal from 'dashboard/modules/contact/ContactMergeModal.vue';
import ComposeConversation from 'dashboard/components-next/NewConversation/ComposeConversation.vue';
import { BUS_EVENTS } from 'shared/constants/busEvents';
import NextButton from 'dashboard/components-next/button/Button.vue';
import VoiceCallButton from 'dashboard/components-next/Contacts/VoiceCallButton.vue';
import {
isAConversationRoute,
@@ -28,6 +29,7 @@ export default {
ComposeConversation,
SocialIcons,
ContactMergeModal,
VoiceCallButton,
},
props: {
contact: {
@@ -278,6 +280,14 @@ export default {
/>
</template>
</ComposeConversation>
<VoiceCallButton
:phone="contact.phone_number"
icon="i-ri-phone-fill"
size="sm"
:tooltip-label="$t('CONTACT_PANEL.CALL')"
slate
faded
/>
<NextButton
v-tooltip.top-end="$t('EDIT_CONTACT.BUTTON_LABEL')"
icon="i-ph-pencil-simple"
+4 -3
View File
@@ -60,15 +60,16 @@ const sanitizeURL = url => {
const parsedURL = new URL(url);
// filter out dangerous protocols like `javascript`, `data`, `vbscript`
if (!['https', 'http'].includes(parsedURL.protocol)) {
if (!['https:', 'http:'].includes(parsedURL.protocol)) {
throw new Error('Invalid Protocol');
}
return url; // Return the original valid URL
} catch (e) {
// eslint-disable-next-line no-console
console.error('Invalid URL', e);
return 'about:blank'; // Only return blank for invalid URLs
}
return 'about:blank'; // blank page URL
};
export const IFrameHelper = {
@@ -55,15 +55,8 @@ export default {
emitter.on(BUS_EVENTS.TOGGLE_REPLY_TO_MESSAGE, this.toggleReplyTo);
},
methods: {
...mapActions('conversation', [
'sendMessage',
'sendAttachment',
'clearConversations',
]),
...mapActions('conversationAttributes', [
'getAttributes',
'clearConversationAttributes',
]),
...mapActions('conversation', ['sendMessage', 'sendAttachment']),
...mapActions('conversationAttributes', ['getAttributes']),
async handleSendMessage(content) {
await this.sendMessage({
content,
@@ -84,8 +77,6 @@ export default {
this.inReplyTo = null;
},
startNewConversation() {
this.clearConversations();
this.clearConversationAttributes();
this.replaceRoute('prechat-form');
IFrameHelper.sendMessage({
event: 'onEvent',
+1 -1
View File
@@ -14,7 +14,7 @@
},
"THUMBNAIL": {
"AUTHOR": {
"NOT_AVAILABLE": "Not available"
"NOT_AVAILABLE": "Indisponível"
}
},
"TEAM_AVAILABILITY": {
@@ -1,4 +1,5 @@
<script>
import { mapActions } from 'vuex';
import PreChatForm from '../components/PreChat/Form.vue';
import configMixin from '../mixins/configMixin';
import routerMixin from '../mixins/routerMixin';
@@ -19,6 +20,8 @@ export default {
emitter.off(ON_CONVERSATION_CREATED, this.handleConversationCreated);
},
methods: {
...mapActions('conversation', ['clearConversations']),
...mapActions('conversationAttributes', ['clearConversationAttributes']),
handleConversationCreated() {
// Redirect to messages page after conversation is created
this.replaceRoute('messages');
@@ -48,6 +51,8 @@ export default {
},
});
} else {
this.clearConversations();
this.clearConversationAttributes();
this.$store.dispatch('conversation/createConversation', {
fullName: fullName,
emailAddress: emailAddress,
+15 -15
View File
@@ -20,9 +20,9 @@ pt_BR:
hello: 'Olá, mundo'
inbox:
reauthorization:
success: 'Channel reauthorized successfully'
not_required: 'Reauthorization is not required for this inbox'
invalid_channel: 'Invalid channel type for reauthorization'
success: 'Canal reautenticado com sucesso'
not_required: 'Reautenticação não é necessária para esta caixa de entrada'
invalid_channel: 'Tipo de canal inválido para reautenticar'
messages:
reset_password_success: Legal! A solicitação de alteração de senha foi bem sucedida. Verifique seu e-mail para obter instruções.
reset_password_failure: Uh ho! Não conseguimos encontrar nenhum usuário com o e-mail especificado.
@@ -59,12 +59,12 @@ pt_BR:
slack:
invalid_channel_id: 'Canal de slack inválido. Por favor, tente novamente'
whatsapp:
token_exchange_failed: 'Failed to exchange code for access token. Please try again.'
invalid_token_permissions: 'The access token does not have the required permissions for WhatsApp.'
phone_info_fetch_failed: 'Failed to fetch phone number information. Please try again.'
token_exchange_failed: 'Falha ao trocar o código por um token de acesso. Por favor, tente novamente.'
invalid_token_permissions: 'O token de acesso não tem as permissões necessárias para o WhatsApp.'
phone_info_fetch_failed: 'Falha ao obter a informação do número de telefone. Por favor, tente novamente.'
reauthorization:
generic: 'Failed to reauthorize WhatsApp. Please try again.'
not_supported: 'Reauthorization is not supported for this type of WhatsApp channel.'
generic: 'Falha ao reautenticar o WhatsApp. Por favor, tente novamente.'
not_supported: 'Reautenticação não é suportado por este tipo de canal WhatsApp.'
inboxes:
imap:
socket_error: Por favor, verifique a conexão de rede, endereço IMAP e tente novamente.
@@ -257,8 +257,8 @@ pt_BR:
description: 'Crie issues em Linear diretamente da sua janela de conversa. Alternativamente, vincule as issues lineares existentes para um processo de rastreamento de problemas mais simples e eficiente.'
notion:
name: 'Notion'
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.'
short_description: 'Integre banco de dados, documentos e páginas diretamente com o Capitão.'
description: 'Conecte o seu espaço de trabalho Notion para permitir que o Capitão acesse e gere respostas inteligentes usando o conteúdo de seus bancos de dados, documentos e páginas para fornecer suporte ao cliente mais contextual.'
shopify:
name: 'Shopify'
short_description: 'Acessar detalhes do pedido e dados de clientes da sua loja Shopify.'
@@ -359,9 +359,9 @@ pt_BR:
portals:
send_instructions:
email_required: 'E-mail é obrigatório'
invalid_email_format: 'Invalid email format'
custom_domain_not_configured: 'Custom domain is not configured'
instructions_sent_successfully: 'Instructions sent successfully'
subject: 'Finish setting up %{custom_domain}'
invalid_email_format: 'Formato inválido de e-mail'
custom_domain_not_configured: 'Domínio personalizado não está configurado'
instructions_sent_successfully: 'Instruções enviadas com sucesso'
subject: 'Termine de configurar %{custom_domain}'
ssl_status:
custom_domain_not_configured: 'Custom domain is not configured'
custom_domain_not_configured: 'Domínio personalizado não está configurado'