Files
chatwoot/app/javascript/dashboard/routes/dashboard/settings/inbox/settingsPage/ConfigurationPage.vue
T
Sojan JoseandGitHub d48503bdcf feat(voice): Improved voice call creation flow [EE] (#12268)
This PR improves the voice call creation flow by simplifying
configuration and automating setup with Twilio APIs.

references: #11602 , #11481 

## Key changes

- Removed the requirement for twiml_app_sid – provisioning is now
automated through APIs.
- Auto-configured webhook URLs for:
  - Voice number callbacks
  - Status callbacks
  -  twiML callbacks
- Disabled business hours, help center, and related options until voice
inbox is fully supported.
- Added a configuration tab in the voice inbox to display the required
Twilio URLs (to make verification easier in Twilio console).


## Test Cases
- Provisioning
- Create a new voice inbox → verify that Twilio app provisioning happens
automatically.
  - Verify twiML callback 
- Webhook configuration
- Check that both voice number callback and status callback URLs are
auto-populated in Twilio.
- Disabled features
- Confirm that business hours and help center options are
hidden/disabled for voice inbox.
- Configuration tab
- Open the voice inbox configuration tab → verify that the displayed
Twilio URLs match what’s set in Twilio.
2025-08-22 13:38:23 +02:00

351 lines
11 KiB
Vue

<script>
import { useAlert } from 'dashboard/composables';
import inboxMixin from 'shared/mixins/inboxMixin';
import SettingsSection from '../../../../../components/SettingsSection.vue';
import ImapSettings from '../ImapSettings.vue';
import SmtpSettings from '../SmtpSettings.vue';
import { useVuelidate } from '@vuelidate/core';
import { required } from '@vuelidate/validators';
import NextButton from 'dashboard/components-next/button/Button.vue';
import WhatsappReauthorize from '../channels/whatsapp/Reauthorize.vue';
export default {
components: {
SettingsSection,
ImapSettings,
SmtpSettings,
NextButton,
WhatsappReauthorize,
},
mixins: [inboxMixin],
props: {
inbox: {
type: Object,
default: () => ({}),
},
},
setup() {
return { v$: useVuelidate() };
},
data() {
return {
hmacMandatory: false,
whatsAppInboxAPIKey: '',
isRequestingReauthorization: false,
isSyncingTemplates: false,
};
},
validations: {
whatsAppInboxAPIKey: { required },
},
computed: {
isEmbeddedSignupWhatsApp() {
return this.inbox.provider_config?.source === 'embedded_signup';
},
whatsappAppId() {
return window.chatwootConfig?.whatsappAppId;
},
},
watch: {
inbox() {
this.setDefaults();
},
},
mounted() {
this.setDefaults();
},
methods: {
setDefaults() {
this.hmacMandatory = this.inbox.hmac_mandatory || false;
},
handleHmacFlag() {
this.updateInbox();
},
async updateInbox() {
try {
const payload = {
id: this.inbox.id,
formData: false,
channel: {
hmac_mandatory: this.hmacMandatory,
},
};
await this.$store.dispatch('inboxes/updateInbox', payload);
useAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
} catch (error) {
useAlert(this.$t('INBOX_MGMT.EDIT.API.ERROR_MESSAGE'));
}
},
async updateWhatsAppInboxAPIKey() {
try {
const payload = {
id: this.inbox.id,
formData: false,
channel: {},
};
payload.channel.provider_config = {
...this.inbox.provider_config,
api_key: this.whatsAppInboxAPIKey,
};
await this.$store.dispatch('inboxes/updateInbox', payload);
useAlert(this.$t('INBOX_MGMT.EDIT.API.SUCCESS_MESSAGE'));
} catch (error) {
useAlert(this.$t('INBOX_MGMT.EDIT.API.ERROR_MESSAGE'));
}
},
async handleReconfigure() {
if (this.$refs.whatsappReauth) {
await this.$refs.whatsappReauth.requestAuthorization();
}
},
async syncTemplates() {
this.isSyncingTemplates = true;
try {
await this.$store.dispatch('inboxes/syncTemplates', this.inbox.id);
useAlert(
this.$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_SUCCESS')
);
} catch (error) {
useAlert(this.$t('INBOX_MGMT.EDIT.API.ERROR_MESSAGE'));
} finally {
this.isSyncingTemplates = false;
}
},
},
};
</script>
<template>
<div v-if="isATwilioChannel" class="mx-8">
<SettingsSection
:title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.TITLE')"
:sub-title="$t('INBOX_MGMT.ADD.TWILIO.API_CALLBACK.SUBTITLE')"
>
<woot-code :script="inbox.callback_webhook_url" lang="html" />
</SettingsSection>
</div>
<div v-else-if="isAVoiceChannel" class="mx-8">
<SettingsSection
:title="$t('INBOX_MGMT.ADD.VOICE.CONFIGURATION.TWILIO_VOICE_URL_TITLE')"
:sub-title="
$t('INBOX_MGMT.ADD.VOICE.CONFIGURATION.TWILIO_VOICE_URL_SUBTITLE')
"
>
<woot-code :script="inbox.voice_call_webhook_url" lang="html" />
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.ADD.VOICE.CONFIGURATION.TWILIO_STATUS_URL_TITLE')"
:sub-title="
$t('INBOX_MGMT.ADD.VOICE.CONFIGURATION.TWILIO_STATUS_URL_SUBTITLE')
"
>
<woot-code :script="inbox.voice_status_webhook_url" lang="html" />
</SettingsSection>
</div>
<div v-else-if="isALineChannel" class="mx-8">
<SettingsSection
:title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.API_CALLBACK.TITLE')"
:sub-title="$t('INBOX_MGMT.ADD.LINE_CHANNEL.API_CALLBACK.SUBTITLE')"
>
<woot-code :script="inbox.callback_webhook_url" lang="html" />
</SettingsSection>
</div>
<div v-else-if="isAWebWidgetInbox">
<div class="mx-8">
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_HEADING')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.MESSENGER_SUB_HEAD')"
>
<woot-code
:script="inbox.web_widget_script"
lang="html"
:codepen-title="`${inbox.name} - Chatwoot Widget Test`"
enable-code-pen
/>
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_VERIFICATION')"
>
<woot-code :script="inbox.hmac_token" />
<template #subTitle>
{{ $t('INBOX_MGMT.SETTINGS_POPUP.HMAC_DESCRIPTION') }}
<a
target="_blank"
rel="noopener noreferrer"
href="https://www.chatwoot.com/docs/product/channels/live-chat/sdk/identity-validation/"
>
{{ $t('INBOX_MGMT.SETTINGS_POPUP.HMAC_LINK_TO_DOCS') }}
</a>
</template>
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_VERIFICATION')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_DESCRIPTION')"
>
<div class="flex gap-2 items-center">
<input
id="hmacMandatory"
v-model="hmacMandatory"
type="checkbox"
@change="handleHmacFlag"
/>
<label for="hmacMandatory">
{{ $t('INBOX_MGMT.EDIT.ENABLE_HMAC.LABEL') }}
</label>
</div>
</SettingsSection>
</div>
</div>
<div v-else-if="isAPIInbox" class="mx-8">
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_IDENTIFIER')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.INBOX_IDENTIFIER_SUB_TEXT')"
>
<woot-code :script="inbox.inbox_identifier" />
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_VERIFICATION')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_DESCRIPTION')"
>
<woot-code :script="inbox.hmac_token" />
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_VERIFICATION')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.HMAC_MANDATORY_DESCRIPTION')"
>
<div class="flex gap-2 items-center">
<input
id="hmacMandatory"
v-model="hmacMandatory"
type="checkbox"
@change="handleHmacFlag"
/>
<label for="hmacMandatory">
{{ $t('INBOX_MGMT.EDIT.ENABLE_HMAC.LABEL') }}
</label>
</div>
</SettingsSection>
</div>
<div v-else-if="isAnEmailChannel">
<div class="mx-8">
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.FORWARD_EMAIL_TITLE')"
:sub-title="$t('INBOX_MGMT.SETTINGS_POPUP.FORWARD_EMAIL_SUB_TEXT')"
>
<woot-code :script="inbox.forward_to_email" />
</SettingsSection>
</div>
<ImapSettings :inbox="inbox" />
<SmtpSettings v-if="inbox.imap_enabled" :inbox="inbox" />
</div>
<div v-else-if="isAWhatsAppChannel && !isATwilioChannel">
<div v-if="inbox.provider_config" class="mx-8">
<!-- Embedded Signup Section -->
<template v-if="isEmbeddedSignupWhatsApp">
<SettingsSection
v-if="whatsappAppId"
:title="
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_EMBEDDED_SIGNUP_TITLE')
"
:sub-title="
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_EMBEDDED_SIGNUP_SUBHEADER')
"
>
<div class="flex gap-4 items-center">
<p class="text-sm text-slate-600">
{{
$t(
'INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_EMBEDDED_SIGNUP_DESCRIPTION'
)
}}
</p>
<NextButton @click="handleReconfigure">
{{ $t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_RECONFIGURE_BUTTON') }}
</NextButton>
</div>
</SettingsSection>
</template>
<!-- Manual Setup Section -->
<template v-else>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_WEBHOOK_TITLE')"
:sub-title="
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_WEBHOOK_SUBHEADER')
"
>
<woot-code :script="inbox.provider_config.webhook_verify_token" />
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_TITLE')"
:sub-title="
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_SUBHEADER')
"
>
<woot-code :script="inbox.provider_config.api_key" />
</SettingsSection>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_UPDATE_TITLE')"
:sub-title="
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_UPDATE_SUBHEADER')
"
>
<div
class="flex flex-1 justify-between items-center mt-2 whatsapp-settings--content"
>
<woot-input
v-model="whatsAppInboxAPIKey"
type="text"
class="flex-1 mr-2 [&>input]:!mb-0"
:placeholder="
$t(
'INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_UPDATE_PLACEHOLDER'
)
"
/>
<NextButton
:disabled="v$.whatsAppInboxAPIKey.$invalid"
@click="updateWhatsAppInboxAPIKey"
>
{{
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_UPDATE_BUTTON')
}}
</NextButton>
</div>
</SettingsSection>
</template>
<SettingsSection
:title="$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_TITLE')"
:sub-title="
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_SUBHEADER')
"
>
<div class="flex justify-start items-center mt-2">
<NextButton :disabled="isSyncingTemplates" @click="syncTemplates">
{{ $t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_TEMPLATES_SYNC_BUTTON') }}
</NextButton>
</div>
</SettingsSection>
</div>
<WhatsappReauthorize
v-if="isEmbeddedSignupWhatsApp"
ref="whatsappReauth"
:inbox="inbox"
class="hidden"
/>
</div>
</template>
<style lang="scss" scoped>
.whatsapp-settings--content {
::v-deep input {
margin-bottom: 0;
}
}
</style>