feat: allow switching embedded signup whatsapp embedded inboxes to manual setup (#14975)
Since embedded signup has been disabled on production, WhatsApp inboxes that were created through it have no way to be managed going forward. This PR lets admins transfer an embedded signup inbox to a manual Cloud API setup: the inbox settings Configuration tab now shows the webhook verification token and a "Switch to Manual Setup" form (pre-populated with the Phone Number ID, Business Account ID, and API key stored during the embedded signup journey) instead of the old Reconfigure button. Saving the form updates the channel's `provider_config` without the `source: embedded_signup` marker, so the inbox becomes a regular manually-configured WhatsApp Cloud inbox. The backend re-validates the submitted credentials against Meta before accepting the change. ## How to test 1. Open the settings page of a WhatsApp inbox created via embedded signup → Configuration tab. 2. The Reconfigure button is gone; you see the webhook verification token and a Switch to Manual Setup form pre-filled with the stored credentials. 3. Configure the webhook in your own Meta app using the verification token, enter a permanent access token from that app, and click "Switch to Manual Setup". 4. On success the page switches to the standard manual configuration view (verify token, API key update), and messaging continues to work with the new credentials. Invalid credentials are rejected with an error. ## What changed - `ConfigurationPage.vue`: replaced the embedded-signup Reconfigure section (and the hidden reauthorize component) with the manual transfer form. - New `WHATSAPP_MANUAL_TRANSFER_*` translation keys. --------- Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: iamsivin <iamsivin@gmail.com>
This commit is contained in:
co-authored by
Muhsin
Muhsin Keloth
iamsivin
parent
cc87429903
commit
b560720e08
@@ -61,10 +61,10 @@ const triggerAction = () => {
|
||||
<div>
|
||||
<slot />
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex-shrink-0">
|
||||
<button
|
||||
v-if="actionLabel"
|
||||
class="px-3 py-1 w-auto grid place-content-center rounded-lg"
|
||||
class="px-3 py-1 w-auto grid place-content-center rounded-lg whitespace-nowrap"
|
||||
:class="buttonClass"
|
||||
@click="triggerAction"
|
||||
>
|
||||
|
||||
@@ -7,6 +7,7 @@ export const FEATURE_FLAGS = {
|
||||
AUTOMATIONS: 'automations',
|
||||
CAMPAIGNS: 'campaigns',
|
||||
WHATSAPP_CAMPAIGNS: 'whatsapp_campaign',
|
||||
WHATSAPP_MANUAL_TRANSFER: 'whatsapp_manual_transfer',
|
||||
CANNED_RESPONSES: 'canned_responses',
|
||||
CRM: 'crm',
|
||||
CUSTOM_ATTRIBUTES: 'custom_attributes',
|
||||
|
||||
@@ -820,6 +820,15 @@
|
||||
"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_MANUAL_TRANSFER_TITLE": "Switch to Manual Setup",
|
||||
"WHATSAPP_MANUAL_TRANSFER_SUBHEADER": "This inbox was connected through WhatsApp embedded signup, which is no longer supported. Enter the WhatsApp Cloud API credentials from your own Meta app to switch this inbox to a manual setup. Configure the webhook in your Meta app using the verification token above before switching.",
|
||||
"WHATSAPP_MANUAL_TRANSFER_PHONE_NUMBER_ID_LABEL": "Phone Number ID",
|
||||
"WHATSAPP_MANUAL_TRANSFER_BUSINESS_ACCOUNT_ID_LABEL": "Business Account ID",
|
||||
"WHATSAPP_MANUAL_TRANSFER_API_KEY_LABEL": "API Key",
|
||||
"WHATSAPP_MANUAL_TRANSFER_API_KEY_PLACEHOLDER": "Enter a permanent access token from your Meta app",
|
||||
"WHATSAPP_MANUAL_TRANSFER_BUTTON": "Switch to Manual Setup",
|
||||
"WHATSAPP_MANUAL_TRANSFER_SUCCESS": "Inbox switched to manual setup successfully.",
|
||||
"WHATSAPP_MANUAL_TRANSFER_ERROR": "Could not switch to manual setup. Please verify the credentials and try again.",
|
||||
"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.",
|
||||
@@ -837,6 +846,70 @@
|
||||
"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_MANUAL_MIGRATION": {
|
||||
"BANNER": {
|
||||
"TITLE": "WhatsApp setup action required",
|
||||
"DESCRIPTION": "Meta restrictions are affecting WhatsApp setup and management features. Reconnect this inbox manually to keep your WhatsApp configuration up to date.",
|
||||
"START": "Start manual migration",
|
||||
"GUIDE": "View guide"
|
||||
},
|
||||
"DIALOG": {
|
||||
"EYEBROW": "WhatsApp manual migration",
|
||||
"TITLE": "Reconnect WhatsApp inbox",
|
||||
"CLOSE": "Close",
|
||||
"ACTION_REQUIRED_TITLE": "Action required for this WhatsApp inbox",
|
||||
"ACTION_REQUIRED_DESCRIPTION": "Meta restrictions are affecting setup and management features. This guided flow updates the WhatsApp API connection without creating a new inbox.",
|
||||
"GUIDE_LINK": "Open the manual setup guide",
|
||||
"PRESERVED_TITLE": "Preserved",
|
||||
"PRESERVED_DESCRIPTION": "Conversations, contacts, collaborators, routing, business hours, and inbox settings.",
|
||||
"UPDATED_TITLE": "Updated",
|
||||
"UPDATED_DESCRIPTION": "WABA ID, phone number ID, access token, and webhook configuration.",
|
||||
"WABA_ID": "WABA ID",
|
||||
"WABA_PLACEHOLDER": "Enter WABA ID",
|
||||
"WABA_HELP": "The WhatsApp Business Account that owns this phone number.",
|
||||
"PHONE_NUMBER_ID": "Phone Number ID",
|
||||
"PHONE_NUMBER_PLACEHOLDER": "Enter Phone Number ID",
|
||||
"PHONE_NUMBER_HELP": "Meta's unique ID for the WhatsApp number connected to this inbox.",
|
||||
"DISPLAY_PHONE_NUMBER": "Display phone number",
|
||||
"DISPLAY_PHONE_NUMBER_PLACEHOLDER": "Enter display phone number",
|
||||
"DISPLAY_PHONE_NUMBER_HELP": "The customer-facing WhatsApp number. This cannot be changed during migration.",
|
||||
"ACCESS_TOKEN": "Permanent access token or system user token",
|
||||
"ACCESS_TOKEN_PLACEHOLDER": "Paste access token",
|
||||
"TOKEN_HELP_PREFIX": "The token must include",
|
||||
"TOKEN_HELP_MIDDLE": "Add",
|
||||
"TOKEN_HELP_SUFFIX": "for template sync and template management.",
|
||||
"MESSAGING_PERMISSION": "whatsapp_business_messaging.",
|
||||
"MANAGEMENT_PERMISSION": "whatsapp_business_management",
|
||||
"REVIEW_TITLE": "Review before reconnecting",
|
||||
"INBOX": "Inbox",
|
||||
"PHONE_NUMBER": "Phone number",
|
||||
"NOT_ENTERED": "Not entered",
|
||||
"VERIFY_NOTICE": "Chatwoot will verify these credentials with Meta before applying any changes. If verification fails, the current configuration is left untouched.",
|
||||
"BACK": "Back",
|
||||
"CANCEL": "Cancel",
|
||||
"CONTINUE": "Continue",
|
||||
"REVIEW_MIGRATION": "Review migration",
|
||||
"RECONNECT": "Reconnect WhatsApp inbox"
|
||||
},
|
||||
"STEPS": {
|
||||
"BEFORE_YOU_START": {
|
||||
"TITLE": "Before you start",
|
||||
"DESCRIPTION": "This reconnects the WhatsApp API details for this inbox. Conversations, collaborators, routing, business hours, CSAT, and bot settings will be preserved."
|
||||
},
|
||||
"BUSINESS_DETAILS": {
|
||||
"TITLE": "Business details",
|
||||
"DESCRIPTION": "Enter the WhatsApp assets from the customer Meta Business account."
|
||||
},
|
||||
"ACCESS_TOKEN": {
|
||||
"TITLE": "Access token",
|
||||
"DESCRIPTION": "Paste a permanent access token or system user token with WhatsApp permissions."
|
||||
},
|
||||
"REVIEW_MIGRATION": {
|
||||
"TITLE": "Review migration",
|
||||
"DESCRIPTION": "Confirm the connection details before reconnecting this inbox. Chatwoot will verify the token, WABA, and phone number with Meta before applying changes."
|
||||
}
|
||||
}
|
||||
},
|
||||
"WHATSAPP_CALLING_ENABLED": {
|
||||
"LABEL": "Enable voice calling",
|
||||
"DESCRIPTION": "Allow agents to start and receive WhatsApp voice calls on this inbox. Available only on embedded-signup WhatsApp Cloud channels with calling permission granted by Meta."
|
||||
|
||||
@@ -29,6 +29,8 @@ import CustomerSatisfactionPage from './settingsPage/CustomerSatisfactionPage.vu
|
||||
import CollaboratorsPage from './settingsPage/CollaboratorsPage.vue';
|
||||
import BotConfiguration from './components/BotConfiguration.vue';
|
||||
import AccountHealth from './components/AccountHealth.vue';
|
||||
import WhatsappManualMigrationDialog from './components/WhatsappManualMigrationDialog.vue';
|
||||
import WhatsappManualMigrationBanner from './components/WhatsappManualMigrationBanner.vue';
|
||||
import { FEATURE_FLAGS } from '../../../../featureFlags';
|
||||
import SenderNameExamplePreview from './components/SenderNameExamplePreview.vue';
|
||||
import LockToSingleConversationPreview from './components/LockToSingleConversationPreview.vue';
|
||||
@@ -78,6 +80,8 @@ export default {
|
||||
ColorPicker,
|
||||
SelectInput,
|
||||
AccountHealth,
|
||||
WhatsappManualMigrationDialog,
|
||||
WhatsappManualMigrationBanner,
|
||||
Widget,
|
||||
AccessToken,
|
||||
Icon,
|
||||
@@ -112,6 +116,7 @@ export default {
|
||||
isLoadingHealth: false,
|
||||
healthError: null,
|
||||
isRegisteringWebhook: false,
|
||||
isTransferringWhatsAppToManual: false,
|
||||
widgetBubblePosition: 'right',
|
||||
widgetBubbleType: 'standard',
|
||||
widgetBubbleLauncherTitle: '',
|
||||
@@ -382,10 +387,12 @@ export default {
|
||||
return this.inbox.provider_config?.source === 'embedded_signup';
|
||||
},
|
||||
whatsappUnauthorized() {
|
||||
// The manual migration banner supersedes the embedded-signup reauthorize flow when the feature is enabled.
|
||||
return (
|
||||
this.isAWhatsAppCloudChannel &&
|
||||
this.isEmbeddedSignupWhatsApp &&
|
||||
this.inbox.reauthorization_required
|
||||
this.inbox.reauthorization_required &&
|
||||
!this.showWhatsAppManualMigration
|
||||
);
|
||||
},
|
||||
whatsappRegistrationIncomplete() {
|
||||
@@ -402,6 +409,16 @@ export default {
|
||||
this.healthData.throughput?.level === 'NOT_APPLICABLE'
|
||||
);
|
||||
},
|
||||
showWhatsAppManualMigration() {
|
||||
return (
|
||||
this.isAWhatsAppCloudChannel &&
|
||||
this.isEmbeddedSignupWhatsApp &&
|
||||
this.isFeatureEnabledonAccount(
|
||||
this.accountId,
|
||||
FEATURE_FLAGS.WHATSAPP_MANUAL_TRANSFER
|
||||
)
|
||||
);
|
||||
},
|
||||
widgetBuilderStorageKey() {
|
||||
return `${LOCAL_STORAGE_KEYS.WIDGET_BUILDER}${this.inbox.id}`;
|
||||
},
|
||||
@@ -413,6 +430,7 @@ export default {
|
||||
if (inboxChanged) {
|
||||
this.syncInboxData();
|
||||
this.setTabFromRouteParam();
|
||||
this.openWhatsAppManualMigrationIfRequested();
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -423,6 +441,7 @@ export default {
|
||||
this.fetchHealthData();
|
||||
this.$nextTick(() => {
|
||||
this.setTabFromRouteParam();
|
||||
this.openWhatsAppManualMigrationIfRequested();
|
||||
});
|
||||
} else {
|
||||
this.selectedFeatureFlags = newInbox?.selected_feature_flags || [];
|
||||
@@ -433,8 +452,52 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
this.fetchSharedData();
|
||||
this.openWhatsAppManualMigrationIfRequested();
|
||||
},
|
||||
methods: {
|
||||
openWhatsAppManualMigrationDialog() {
|
||||
this.$refs.whatsappManualMigrationDialog?.open();
|
||||
},
|
||||
openWhatsAppManualMigrationIfRequested() {
|
||||
if (
|
||||
this.showWhatsAppManualMigration &&
|
||||
this.$route.query.migration === 'whatsapp_manual'
|
||||
) {
|
||||
this.$nextTick(() => {
|
||||
this.openWhatsAppManualMigrationDialog();
|
||||
});
|
||||
}
|
||||
},
|
||||
async transferWhatsAppToManualSetup(form) {
|
||||
this.isTransferringWhatsAppToManual = true;
|
||||
try {
|
||||
const providerConfig = { ...(this.inbox.provider_config || {}) };
|
||||
delete providerConfig.source;
|
||||
const payload = {
|
||||
id: this.inbox.id,
|
||||
formData: false,
|
||||
channel: {
|
||||
provider_config: {
|
||||
...providerConfig,
|
||||
phone_number_id: form.phoneNumberId,
|
||||
business_account_id: form.wabaId,
|
||||
api_key: form.accessToken,
|
||||
},
|
||||
},
|
||||
};
|
||||
await this.$store.dispatch('inboxes/updateInbox', payload);
|
||||
useAlert(
|
||||
this.$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_TRANSFER_SUCCESS')
|
||||
);
|
||||
this.$refs.whatsappManualMigrationDialog?.close();
|
||||
} catch (error) {
|
||||
useAlert(
|
||||
this.$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_TRANSFER_ERROR')
|
||||
);
|
||||
} finally {
|
||||
this.isTransferringWhatsAppToManual = false;
|
||||
}
|
||||
},
|
||||
async copyWebhookSecret(value) {
|
||||
await copyTextToClipboard(value);
|
||||
useAlert(
|
||||
@@ -748,6 +811,12 @@ export default {
|
||||
class="mx-6 mb-4"
|
||||
:class="bannerMaxWidth"
|
||||
/>
|
||||
<WhatsappManualMigrationBanner
|
||||
v-if="showWhatsAppManualMigration"
|
||||
class="mx-6 mb-6"
|
||||
:class="bannerMaxWidth"
|
||||
@start="openWhatsAppManualMigrationDialog"
|
||||
/>
|
||||
<Banner
|
||||
v-if="showInstagramRestrictionSettingsBanner"
|
||||
color="amber"
|
||||
@@ -1339,6 +1408,13 @@ export default {
|
||||
@register-webhook="registerWebhook"
|
||||
/>
|
||||
</div>
|
||||
<WhatsappManualMigrationDialog
|
||||
v-if="showWhatsAppManualMigration"
|
||||
ref="whatsappManualMigrationDialog"
|
||||
:inbox="inbox"
|
||||
:is-loading="isTransferringWhatsAppToManual"
|
||||
@reconnect="transferWhatsAppToManualSetup"
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Banner from 'dashboard/components-next/banner/Banner.vue';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
|
||||
const emit = defineEmits(['start']);
|
||||
const { t } = useI18n();
|
||||
|
||||
const WHATSAPP_MANUAL_MIGRATION_GUIDE_URL =
|
||||
'https://www.chatwoot.com/hc/user-guide/articles/1756799850-how-to-setup-a-whats_app-channel-manual-flow';
|
||||
|
||||
const copy = computed(() => ({
|
||||
title: t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.BANNER.TITLE'),
|
||||
description: t(
|
||||
'INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.BANNER.DESCRIPTION'
|
||||
),
|
||||
start: t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.BANNER.START'),
|
||||
guide: t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.BANNER.GUIDE'),
|
||||
}));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Banner color="amber" :action-label="copy.start" @action="emit('start')">
|
||||
<div class="flex items-start gap-2">
|
||||
<Icon
|
||||
icon="i-lucide-triangle-alert"
|
||||
class="flex-shrink-0 mt-0.5 size-4 text-n-amber-11"
|
||||
/>
|
||||
<div class="flex flex-col gap-0.5">
|
||||
<span class="font-medium text-n-amber-12">{{ copy.title }}</span>
|
||||
<span>
|
||||
{{ copy.description }}
|
||||
<a
|
||||
:href="WHATSAPP_MANUAL_MIGRATION_GUIDE_URL"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="underline link underline-offset-2"
|
||||
>
|
||||
{{ copy.guide }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Banner>
|
||||
</template>
|
||||
+524
@@ -0,0 +1,524 @@
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useBranding } from 'shared/composables/useBranding';
|
||||
import Dialog from 'dashboard/components-next/dialog/Dialog.vue';
|
||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||
import Input from 'dashboard/components-next/input/Input.vue';
|
||||
import TextArea from 'dashboard/components-next/textarea/TextArea.vue';
|
||||
import Icon from 'dashboard/components-next/icon/Icon.vue';
|
||||
|
||||
const props = defineProps({
|
||||
inbox: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['reconnect']);
|
||||
const { t } = useI18n();
|
||||
const { replaceInstallationName } = useBranding();
|
||||
|
||||
const WHATSAPP_MANUAL_MIGRATION_GUIDE_URL =
|
||||
'https://www.chatwoot.com/hc/user-guide/articles/1756799850-how-to-setup-a-whats_app-channel-manual-flow';
|
||||
|
||||
const dialogRef = ref(null);
|
||||
const currentStep = ref(0);
|
||||
|
||||
const buildForm = () => ({
|
||||
wabaId: props.inbox.provider_config?.business_account_id || '',
|
||||
phoneNumberId: props.inbox.provider_config?.phone_number_id || '',
|
||||
displayPhoneNumber: props.inbox.phone_number || '',
|
||||
accessToken: '',
|
||||
});
|
||||
|
||||
const form = ref(buildForm());
|
||||
|
||||
const copy = computed(() => ({
|
||||
eyebrow: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.EYEBROW`
|
||||
),
|
||||
title: t(`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.TITLE`),
|
||||
close: t(`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.CLOSE`),
|
||||
actionRequiredTitle: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.ACTION_REQUIRED_TITLE`
|
||||
),
|
||||
actionRequiredDescription: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.ACTION_REQUIRED_DESCRIPTION`
|
||||
),
|
||||
guideLink: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.GUIDE_LINK`
|
||||
),
|
||||
preservedTitle: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.PRESERVED_TITLE`
|
||||
),
|
||||
preservedDescription: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.PRESERVED_DESCRIPTION`
|
||||
),
|
||||
updatedTitle: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.UPDATED_TITLE`
|
||||
),
|
||||
updatedDescription: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.UPDATED_DESCRIPTION`
|
||||
),
|
||||
wabaId: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.WABA_ID`
|
||||
),
|
||||
wabaPlaceholder: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.WABA_PLACEHOLDER`
|
||||
),
|
||||
wabaHelp: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.WABA_HELP`
|
||||
),
|
||||
phoneNumberId: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.PHONE_NUMBER_ID`
|
||||
),
|
||||
phoneNumberPlaceholder: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.PHONE_NUMBER_PLACEHOLDER`
|
||||
),
|
||||
phoneNumberHelp: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.PHONE_NUMBER_HELP`
|
||||
),
|
||||
displayPhoneNumber: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.DISPLAY_PHONE_NUMBER`
|
||||
),
|
||||
displayPhoneNumberPlaceholder: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.DISPLAY_PHONE_NUMBER_PLACEHOLDER`
|
||||
),
|
||||
displayPhoneNumberHelp: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.DISPLAY_PHONE_NUMBER_HELP`
|
||||
),
|
||||
accessToken: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.ACCESS_TOKEN`
|
||||
),
|
||||
accessTokenPlaceholder: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.ACCESS_TOKEN_PLACEHOLDER`
|
||||
),
|
||||
tokenHelpPrefix: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.TOKEN_HELP_PREFIX`
|
||||
),
|
||||
tokenHelpMiddle: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.TOKEN_HELP_MIDDLE`
|
||||
),
|
||||
tokenHelpSuffix: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.TOKEN_HELP_SUFFIX`
|
||||
),
|
||||
messagingPermission: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.MESSAGING_PERMISSION`
|
||||
),
|
||||
managementPermission: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.MANAGEMENT_PERMISSION`
|
||||
),
|
||||
reviewTitle: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.REVIEW_TITLE`
|
||||
),
|
||||
inbox: t(`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.INBOX`),
|
||||
phoneNumber: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.PHONE_NUMBER`
|
||||
),
|
||||
notEntered: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.NOT_ENTERED`
|
||||
),
|
||||
verifyNotice: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.VERIFY_NOTICE`
|
||||
),
|
||||
back: t(`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.BACK`),
|
||||
cancel: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.CANCEL`
|
||||
),
|
||||
continue: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.CONTINUE`
|
||||
),
|
||||
reviewMigration: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.REVIEW_MIGRATION`
|
||||
),
|
||||
reconnect: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.DIALOG.RECONNECT`
|
||||
),
|
||||
}));
|
||||
|
||||
const steps = computed(() => [
|
||||
{
|
||||
title: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.BEFORE_YOU_START.TITLE`
|
||||
),
|
||||
description: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.BEFORE_YOU_START.DESCRIPTION`
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.BUSINESS_DETAILS.TITLE`
|
||||
),
|
||||
description: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.BUSINESS_DETAILS.DESCRIPTION`
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.ACCESS_TOKEN.TITLE`
|
||||
),
|
||||
description: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.ACCESS_TOKEN.DESCRIPTION`
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.REVIEW_MIGRATION.TITLE`
|
||||
),
|
||||
description: t(
|
||||
`INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_MANUAL_MIGRATION.STEPS.REVIEW_MIGRATION.DESCRIPTION`
|
||||
),
|
||||
},
|
||||
]);
|
||||
|
||||
const currentStepDetails = computed(() => steps.value[currentStep.value]);
|
||||
const isFirstStep = computed(() => currentStep.value === 0);
|
||||
const isLastStep = computed(() => currentStep.value === steps.value.length - 1);
|
||||
const guideUrl = WHATSAPP_MANUAL_MIGRATION_GUIDE_URL;
|
||||
const hasBusinessDetails = computed(
|
||||
() => form.value.wabaId.trim() && form.value.phoneNumberId.trim()
|
||||
);
|
||||
const hasAccessToken = computed(() => form.value.accessToken.trim());
|
||||
const canContinue = computed(() => {
|
||||
if (currentStep.value === 1) return hasBusinessDetails.value;
|
||||
if (currentStep.value === 2) return hasAccessToken.value;
|
||||
if (isLastStep.value) {
|
||||
return hasBusinessDetails.value && hasAccessToken.value;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
const open = () => {
|
||||
currentStep.value = 0;
|
||||
form.value = buildForm();
|
||||
dialogRef.value?.open();
|
||||
};
|
||||
|
||||
const close = () => dialogRef.value?.close();
|
||||
|
||||
const goBack = () => {
|
||||
if (!isFirstStep.value) currentStep.value -= 1;
|
||||
};
|
||||
|
||||
const goNext = () => {
|
||||
if (!isLastStep.value) currentStep.value += 1;
|
||||
};
|
||||
|
||||
const reconnect = () => {
|
||||
if (!canContinue.value) return;
|
||||
|
||||
emit('reconnect', {
|
||||
wabaId: form.value.wabaId.trim(),
|
||||
phoneNumberId: form.value.phoneNumberId.trim(),
|
||||
accessToken: form.value.accessToken.trim(),
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ open, close });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Dialog
|
||||
ref="dialogRef"
|
||||
width="3xl"
|
||||
position="top"
|
||||
:show-confirm-button="false"
|
||||
:show-cancel-button="false"
|
||||
overflow-y-auto
|
||||
>
|
||||
<div class="flex flex-col gap-5 h-[24rem]">
|
||||
<div class="flex items-start justify-between gap-4">
|
||||
<div class="min-w-0">
|
||||
<p class="mb-1 text-sm font-medium text-n-slate-11">
|
||||
{{ copy.eyebrow }}
|
||||
</p>
|
||||
<h3 class="m-0 text-xl font-semibold text-n-slate-12">
|
||||
{{ copy.title }}
|
||||
</h3>
|
||||
<p class="mt-2 mb-0 text-sm text-n-slate-11 min-h-[2.5rem]">
|
||||
{{ replaceInstallationName(currentStepDetails.description) }}
|
||||
</p>
|
||||
</div>
|
||||
<NextButton
|
||||
v-tooltip="copy.close"
|
||||
type="button"
|
||||
variant="ghost"
|
||||
color="slate"
|
||||
size="sm"
|
||||
icon="i-lucide-x"
|
||||
:aria-label="copy.close"
|
||||
@click="close"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="grid flex-1 gap-6 overflow-y-auto min-h-0 grid-cols-[11rem,1fr]"
|
||||
>
|
||||
<ol class="flex flex-col p-0 m-0 list-none">
|
||||
<li
|
||||
v-for="(step, index) in steps"
|
||||
:key="step.title"
|
||||
class="relative flex gap-3"
|
||||
>
|
||||
<div class="relative flex flex-col items-center">
|
||||
<span
|
||||
class="z-10 grid text-xs font-semibold transition-colors rounded-full size-6 place-content-center"
|
||||
:class="
|
||||
index < currentStep
|
||||
? 'bg-n-teal-9 text-white'
|
||||
: index === currentStep
|
||||
? 'bg-n-blue-9 text-white'
|
||||
: 'bg-n-alpha-2 text-n-slate-11 outline outline-1 outline-n-container -outline-offset-1'
|
||||
"
|
||||
>
|
||||
<Icon
|
||||
v-if="index < currentStep"
|
||||
icon="i-lucide-check"
|
||||
class="size-3.5"
|
||||
/>
|
||||
<span v-else>{{ index + 1 }}</span>
|
||||
</span>
|
||||
<span
|
||||
v-if="index < steps.length - 1"
|
||||
class="flex-1 my-1 rounded-full w-0.5"
|
||||
:class="index < currentStep ? 'bg-n-teal-9' : 'bg-n-slate-4'"
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="text-sm leading-6 truncate min-w-0"
|
||||
:class="[
|
||||
index < steps.length - 1 ? 'pb-6' : '',
|
||||
index === currentStep
|
||||
? 'font-medium text-n-slate-12'
|
||||
: 'text-n-slate-11',
|
||||
]"
|
||||
>
|
||||
{{ step.title }}
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
<div class="min-w-0">
|
||||
<section v-if="currentStep === 0" class="flex flex-col gap-5">
|
||||
<div
|
||||
class="flex gap-3 p-3 border rounded-xl border-n-weak bg-n-alpha-2"
|
||||
>
|
||||
<span
|
||||
class="grid flex-shrink-0 rounded-lg size-8 place-content-center bg-n-amber-3 text-n-amber-11"
|
||||
>
|
||||
<Icon icon="i-lucide-triangle-alert" class="size-4" />
|
||||
</span>
|
||||
<div>
|
||||
<h4 class="mt-0 mb-1 text-base font-medium text-n-slate-12">
|
||||
{{ copy.actionRequiredTitle }}
|
||||
</h4>
|
||||
<p class="m-0 text-sm text-n-slate-11">
|
||||
{{ copy.actionRequiredDescription }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-3 sm:grid-cols-2">
|
||||
<div
|
||||
class="flex flex-col gap-1 p-3 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container -outline-offset-1"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon icon="i-lucide-check" class="size-4 text-n-teal-11" />
|
||||
<p class="m-0 text-sm font-medium text-n-slate-12">
|
||||
{{ copy.preservedTitle }}
|
||||
</p>
|
||||
</div>
|
||||
<p class="m-0 text-sm text-n-slate-11">
|
||||
{{ copy.preservedDescription }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
class="flex flex-col gap-1 p-3 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container -outline-offset-1"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<Icon
|
||||
icon="i-lucide-refresh-cw"
|
||||
class="size-4 text-n-blue-11"
|
||||
/>
|
||||
<p class="m-0 text-sm font-medium text-n-slate-12">
|
||||
{{ copy.updatedTitle }}
|
||||
</p>
|
||||
</div>
|
||||
<p class="m-0 text-sm text-n-slate-11">
|
||||
{{ copy.updatedDescription }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a
|
||||
:href="guideUrl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
class="inline-flex items-center gap-1.5 text-sm font-medium text-n-blue-11 hover:underline"
|
||||
>
|
||||
{{ copy.guideLink }}
|
||||
<Icon icon="i-lucide-external-link" class="size-3.5" />
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section v-else-if="currentStep === 1" class="grid gap-4">
|
||||
<div class="flex flex-col gap-1">
|
||||
<Input
|
||||
v-model="form.wabaId"
|
||||
:label="copy.wabaId"
|
||||
:placeholder="copy.wabaPlaceholder"
|
||||
/>
|
||||
<span class="text-xs leading-5 text-n-slate-11">
|
||||
{{ copy.wabaHelp }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="grid gap-4 sm:grid-cols-2">
|
||||
<div class="flex flex-col gap-1">
|
||||
<Input
|
||||
v-model="form.phoneNumberId"
|
||||
:label="copy.phoneNumberId"
|
||||
:placeholder="copy.phoneNumberPlaceholder"
|
||||
/>
|
||||
<span class="text-xs leading-5 text-n-slate-11">
|
||||
{{ copy.phoneNumberHelp }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-col gap-1">
|
||||
<Input
|
||||
v-model="form.displayPhoneNumber"
|
||||
disabled
|
||||
:label="copy.displayPhoneNumber"
|
||||
:placeholder="copy.displayPhoneNumberPlaceholder"
|
||||
/>
|
||||
<span class="text-xs leading-5 text-n-slate-11">
|
||||
{{ copy.displayPhoneNumberHelp }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section v-else-if="currentStep === 2" class="grid gap-4">
|
||||
<TextArea
|
||||
v-model="form.accessToken"
|
||||
:label="copy.accessToken"
|
||||
:placeholder="copy.accessTokenPlaceholder"
|
||||
auto-height
|
||||
min-height="6rem"
|
||||
max-height="12rem"
|
||||
/>
|
||||
<div
|
||||
class="flex gap-3 p-3 border rounded-xl bg-n-blue-3 border-n-blue-4 text-n-blue-11"
|
||||
>
|
||||
<Icon icon="i-lucide-info" class="flex-shrink-0 size-4 mt-0.5" />
|
||||
<p class="m-0 text-sm">
|
||||
{{ copy.tokenHelpPrefix }}
|
||||
<code>{{ copy.messagingPermission }}</code>
|
||||
{{ copy.tokenHelpMiddle }}
|
||||
<code>{{ copy.managementPermission }}</code>
|
||||
{{ copy.tokenHelpSuffix }}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
v-else
|
||||
class="flex flex-col gap-4 p-4 rounded-xl bg-n-solid-2 outline outline-1 outline-n-container -outline-offset-1"
|
||||
>
|
||||
<h4 class="m-0 text-base font-medium text-n-slate-12">
|
||||
{{ copy.reviewTitle }}
|
||||
</h4>
|
||||
<dl class="grid gap-3 m-0 sm:grid-cols-2">
|
||||
<div>
|
||||
<dt class="text-xs text-n-slate-11">{{ copy.inbox }}</dt>
|
||||
<dd class="m-0 text-sm font-medium text-n-slate-12">
|
||||
{{ inbox.name }}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-xs text-n-slate-11">
|
||||
{{ copy.phoneNumber }}
|
||||
</dt>
|
||||
<dd class="m-0 text-sm font-medium text-n-slate-12">
|
||||
{{ form.displayPhoneNumber || inbox.phone_number }}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-xs text-n-slate-11">{{ copy.wabaId }}</dt>
|
||||
<dd class="m-0 text-sm font-medium text-n-slate-12">
|
||||
{{ form.wabaId || copy.notEntered }}
|
||||
</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt class="text-xs text-n-slate-11">
|
||||
{{ copy.phoneNumberId }}
|
||||
</dt>
|
||||
<dd class="m-0 text-sm font-medium text-n-slate-12">
|
||||
{{ form.phoneNumberId || copy.notEntered }}
|
||||
</dd>
|
||||
</div>
|
||||
</dl>
|
||||
<div
|
||||
class="flex gap-3 p-3 border rounded-lg bg-n-alpha-2 border-n-weak text-n-slate-11"
|
||||
>
|
||||
<Icon
|
||||
icon="i-lucide-shield-check"
|
||||
class="flex-shrink-0 size-4 mt-0.5 text-n-teal-11"
|
||||
/>
|
||||
<p class="m-0 text-sm">
|
||||
{{ replaceInstallationName(copy.verifyNotice) }}
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex items-center justify-between w-full gap-3">
|
||||
<NextButton
|
||||
type="button"
|
||||
variant="faded"
|
||||
color="slate"
|
||||
:disabled="isFirstStep"
|
||||
@click="goBack"
|
||||
>
|
||||
{{ copy.back }}
|
||||
</NextButton>
|
||||
<div class="flex items-center gap-2">
|
||||
<NextButton
|
||||
type="button"
|
||||
variant="ghost"
|
||||
color="slate"
|
||||
@click="close"
|
||||
>
|
||||
{{ copy.cancel }}
|
||||
</NextButton>
|
||||
<NextButton
|
||||
v-if="!isLastStep"
|
||||
type="button"
|
||||
:disabled="!canContinue"
|
||||
@click="goNext"
|
||||
>
|
||||
{{ currentStep === 2 ? copy.reviewMigration : copy.continue }}
|
||||
</NextButton>
|
||||
<NextButton
|
||||
v-else
|
||||
type="button"
|
||||
color="teal"
|
||||
:disabled="!canContinue"
|
||||
:is-loading="isLoading"
|
||||
@click="reconnect"
|
||||
>
|
||||
{{ copy.reconnect }}
|
||||
</NextButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
+5
-27
@@ -10,7 +10,6 @@ import { useVuelidate } from '@vuelidate/core';
|
||||
import { required } from '@vuelidate/validators';
|
||||
import NextButton from 'dashboard/components-next/button/Button.vue';
|
||||
import TextArea from 'next/textarea/TextArea.vue';
|
||||
import WhatsappReauthorize from '../channels/whatsapp/Reauthorize.vue';
|
||||
import { sanitizeAllowedDomains } from 'dashboard/helper/URLHelper';
|
||||
|
||||
export default {
|
||||
@@ -22,7 +21,6 @@ export default {
|
||||
SmtpSettings,
|
||||
NextButton,
|
||||
TextArea,
|
||||
WhatsappReauthorize,
|
||||
},
|
||||
mixins: [inboxMixin],
|
||||
props: {
|
||||
@@ -39,7 +37,6 @@ export default {
|
||||
hmacMandatory: false,
|
||||
allowMobileWebview: false,
|
||||
whatsAppInboxAPIKey: '',
|
||||
isRequestingReauthorization: false,
|
||||
isSyncingTemplates: false,
|
||||
allowedDomains: '',
|
||||
isUpdatingAllowedDomains: false,
|
||||
@@ -53,9 +50,6 @@ export default {
|
||||
isEmbeddedSignupWhatsApp() {
|
||||
return this.inbox.provider_config?.source === 'embedded_signup';
|
||||
},
|
||||
whatsappAppId() {
|
||||
return window.chatwootConfig?.whatsappAppId;
|
||||
},
|
||||
isForwardingEnabled() {
|
||||
return !!this.inbox.forwarding_enabled;
|
||||
},
|
||||
@@ -166,11 +160,6 @@ export default {
|
||||
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 {
|
||||
@@ -362,22 +351,17 @@ export default {
|
||||
<!-- Embedded Signup Section -->
|
||||
<template v-if="isEmbeddedSignupWhatsApp">
|
||||
<SettingsFieldSection
|
||||
v-if="whatsappAppId"
|
||||
:label="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_EMBEDDED_SIGNUP_TITLE')
|
||||
:label="$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_WEBHOOK_TITLE')"
|
||||
:help-text="
|
||||
$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_WEBHOOK_SUBHEADER')
|
||||
"
|
||||
:help-text="`${$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_EMBEDDED_SIGNUP_SUBHEADER')} ${$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_EMBEDDED_SIGNUP_DESCRIPTION')}`"
|
||||
>
|
||||
<div class="flex flex-col gap-1 items-start">
|
||||
<NextButton @click="handleReconfigure">
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_RECONFIGURE_BUTTON') }}
|
||||
</NextButton>
|
||||
</div>
|
||||
<woot-code :script="inbox.provider_config.webhook_verify_token" />
|
||||
</SettingsFieldSection>
|
||||
</template>
|
||||
|
||||
<!-- Manual Setup Section -->
|
||||
<template v-else>
|
||||
<template v-else-if="!isEmbeddedSignupWhatsApp">
|
||||
<SettingsFieldSection
|
||||
:label="$t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_WEBHOOK_TITLE')"
|
||||
:help-text="
|
||||
@@ -435,12 +419,6 @@ export default {
|
||||
</NextButton>
|
||||
</SettingsFieldSection>
|
||||
</div>
|
||||
<WhatsappReauthorize
|
||||
v-if="isEmbeddedSignupWhatsApp"
|
||||
ref="whatsappReauth"
|
||||
:inbox="inbox"
|
||||
class="hidden"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user