feat: add reauth flow for wa embedded signup (#11940)
# Pull Request Template ## Description Please include a summary of the change and issue(s) fixed. Also, mention relevant motivation, context, and any dependencies that this change requires. Fixes # (issue) ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration. ## Checklist: - [ ] My code follows the style guidelines of this project - [ ] 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 - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
committed by
GitHub
parent
462ab5241c
commit
d2583d32e9
@@ -9,6 +9,13 @@ class WhatsappChannel extends ApiClient {
|
||||
createEmbeddedSignup(params) {
|
||||
return axios.post(`${this.baseUrl()}/whatsapp/authorization`, params);
|
||||
}
|
||||
|
||||
reauthorizeWhatsApp({ inboxId, ...params }) {
|
||||
return axios.post(`${this.baseUrl()}/whatsapp/authorization`, {
|
||||
...params,
|
||||
inbox_id: inboxId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export default new WhatsappChannel();
|
||||
|
||||
@@ -72,6 +72,24 @@
|
||||
"MARK_ALL_READ": "All notifications marked as read",
|
||||
"DELETE_ALL": "All notifications deleted",
|
||||
"DELETE_ALL_READ": "All read notifications deleted"
|
||||
},
|
||||
"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.",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -598,6 +598,21 @@
|
||||
"WHATSAPP_SECTION_UPDATE_TITLE": "Update API Key",
|
||||
"WHATSAPP_SECTION_UPDATE_PLACEHOLDER": "Enter the new API Key here",
|
||||
"WHATSAPP_SECTION_UPDATE_BUTTON": "Update",
|
||||
"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_CONNECT_BUTTON": "Connect",
|
||||
"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_WEBHOOK_TITLE": "Webhook Verification Token",
|
||||
"WHATSAPP_WEBHOOK_SUBHEADER": "This token is used to verify the authenticity of the webhook endpoint.",
|
||||
"WHATSAPP_TEMPLATES_SYNC_TITLE": "Sync Templates",
|
||||
|
||||
@@ -11,6 +11,7 @@ import InstagramReauthorize from './channels/instagram/Reauthorize.vue';
|
||||
import DuplicateInboxBanner from './channels/instagram/DuplicateInboxBanner.vue';
|
||||
import MicrosoftReauthorize from './channels/microsoft/Reauthorize.vue';
|
||||
import GoogleReauthorize from './channels/google/Reauthorize.vue';
|
||||
import WhatsappReauthorize from './channels/whatsapp/Reauthorize.vue';
|
||||
import PreChatFormSettings from './PreChatForm/Settings.vue';
|
||||
import WeeklyAvailability from './components/WeeklyAvailability.vue';
|
||||
import GreetingsEditor from 'shared/components/GreetingsEditor.vue';
|
||||
@@ -44,6 +45,7 @@ export default {
|
||||
GoogleReauthorize,
|
||||
NextButton,
|
||||
InstagramReauthorize,
|
||||
WhatsappReauthorize,
|
||||
DuplicateInboxBanner,
|
||||
Editor,
|
||||
},
|
||||
@@ -87,10 +89,7 @@ export default {
|
||||
return this.tabs[this.selectedTabIndex]?.key;
|
||||
},
|
||||
shouldShowWhatsAppConfiguration() {
|
||||
return !!(
|
||||
this.isAWhatsAppCloudChannel &&
|
||||
this.inbox.provider_config?.source !== 'embedded_signup'
|
||||
);
|
||||
return this.isAWhatsAppCloudChannel;
|
||||
},
|
||||
whatsAppAPIProviderName() {
|
||||
if (this.isAWhatsAppCloudChannel) {
|
||||
@@ -247,6 +246,14 @@ export default {
|
||||
this.inbox.reauthorization_required
|
||||
);
|
||||
},
|
||||
whatsappUnauthorized() {
|
||||
return (
|
||||
this.isAWhatsAppChannel &&
|
||||
this.inbox.provider === 'whatsapp_cloud' &&
|
||||
this.inbox.provider_config?.source === 'embedded_signup' &&
|
||||
this.inbox.reauthorization_required
|
||||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
$route(to) {
|
||||
@@ -416,6 +423,7 @@ export default {
|
||||
<FacebookReauthorize v-if="facebookUnauthorized" :inbox="inbox" />
|
||||
<GoogleReauthorize v-if="googleUnauthorized" :inbox="inbox" />
|
||||
<InstagramReauthorize v-if="instagramUnauthorized" :inbox="inbox" />
|
||||
<WhatsappReauthorize v-if="whatsappUnauthorized" :inbox="inbox" />
|
||||
<DuplicateInboxBanner
|
||||
v-if="hasDuplicateInstagramInbox"
|
||||
:content="$t('INBOX_MGMT.ADD.INSTAGRAM.DUPLICATE_INBOX_BANNER')"
|
||||
|
||||
@@ -7,8 +7,13 @@ import { useAlert } from 'dashboard/composables';
|
||||
import Icon from 'next/icon/Icon.vue';
|
||||
import NextButton from 'next/button/Button.vue';
|
||||
import LoadingState from 'dashboard/components/widgets/LoadingState.vue';
|
||||
import { loadScript } from 'dashboard/helper/DOMHelpers';
|
||||
import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
|
||||
import {
|
||||
setupFacebookSdk,
|
||||
initWhatsAppEmbeddedSignup,
|
||||
createMessageHandler,
|
||||
isValidBusinessData,
|
||||
} from './whatsapp/utils';
|
||||
|
||||
const store = useStore();
|
||||
const router = useRouter();
|
||||
@@ -120,14 +125,6 @@ const completeSignupFlow = async businessDataParam => {
|
||||
}
|
||||
};
|
||||
|
||||
const isValidBusinessData = businessDataLocal => {
|
||||
return (
|
||||
businessDataLocal &&
|
||||
businessDataLocal.business_id &&
|
||||
businessDataLocal.waba_id
|
||||
);
|
||||
};
|
||||
|
||||
// Message handling
|
||||
const handleEmbeddedSignupData = async data => {
|
||||
if (data.event === 'FINISH') {
|
||||
@@ -162,9 +159,26 @@ const handleEmbeddedSignupData = async data => {
|
||||
}
|
||||
};
|
||||
|
||||
const fbLoginCallback = response => {
|
||||
if (response.authResponse && response.authResponse.code) {
|
||||
authCode.value = response.authResponse.code;
|
||||
const handleSignupMessage = createMessageHandler(handleEmbeddedSignupData);
|
||||
|
||||
const launchEmbeddedSignup = async () => {
|
||||
try {
|
||||
isAuthenticating.value = true;
|
||||
processingMessage.value = t(
|
||||
'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.AUTH_PROCESSING'
|
||||
);
|
||||
|
||||
await setupFacebookSdk(
|
||||
window.chatwootConfig?.whatsappAppId,
|
||||
window.chatwootConfig?.whatsappApiVersion
|
||||
);
|
||||
fbSdkLoaded.value = true;
|
||||
|
||||
const code = await initWhatsAppEmbeddedSignup(
|
||||
window.chatwootConfig?.whatsappConfigurationId
|
||||
);
|
||||
|
||||
authCode.value = code;
|
||||
authCodeReceived.value = true;
|
||||
processingMessage.value = t(
|
||||
'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.WAITING_FOR_BUSINESS_INFO'
|
||||
@@ -173,79 +187,18 @@ const fbLoginCallback = response => {
|
||||
if (businessData.value) {
|
||||
completeSignupFlow(businessData.value);
|
||||
}
|
||||
} else if (response.error) {
|
||||
handleSignupError({ error: response.error });
|
||||
} else {
|
||||
isProcessing.value = false;
|
||||
isAuthenticating.value = false;
|
||||
useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED'));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSignupMessage = event => {
|
||||
// Validate origin for security - following Facebook documentation
|
||||
// https://developers.facebook.com/docs/whatsapp/embedded-signup/implementation#step-3--add-embedded-signup-to-your-website
|
||||
if (!event.origin.endsWith('facebook.com')) return;
|
||||
|
||||
// Parse and handle WhatsApp embedded signup events
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
if (data.type === 'WA_EMBEDDED_SIGNUP') {
|
||||
handleEmbeddedSignupData(data);
|
||||
}
|
||||
} catch {
|
||||
// Ignore non-JSON or irrelevant messages
|
||||
}
|
||||
};
|
||||
|
||||
const runFBInit = () => {
|
||||
window.FB.init({
|
||||
appId: window.chatwootConfig?.whatsappAppId,
|
||||
autoLogAppEvents: true,
|
||||
xfbml: true,
|
||||
version: window.chatwootConfig?.whatsappApiVersion || 'v22.0',
|
||||
});
|
||||
fbSdkLoaded.value = true;
|
||||
};
|
||||
|
||||
const loadFacebookSdk = async () => {
|
||||
return loadScript('https://connect.facebook.net/en_US/sdk.js', {
|
||||
async: true,
|
||||
defer: true,
|
||||
crossOrigin: 'anonymous',
|
||||
});
|
||||
};
|
||||
|
||||
const tryWhatsAppLogin = () => {
|
||||
isAuthenticating.value = true;
|
||||
processingMessage.value = t(
|
||||
'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.AUTH_PROCESSING'
|
||||
);
|
||||
|
||||
window.FB.login(fbLoginCallback, {
|
||||
config_id: window.chatwootConfig?.whatsappConfigurationId,
|
||||
response_type: 'code',
|
||||
override_default_response_type: true,
|
||||
extras: {
|
||||
setup: {},
|
||||
featureType: '',
|
||||
sessionInfoVersion: '3',
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const launchEmbeddedSignup = async () => {
|
||||
try {
|
||||
// Load SDK first if not loaded, following Facebook.vue pattern exactly
|
||||
await loadFacebookSdk();
|
||||
runFBInit(); // Initialize FB after loading
|
||||
|
||||
// Now proceed with login
|
||||
tryWhatsAppLogin();
|
||||
} catch (error) {
|
||||
handleSignupError({
|
||||
error: t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SDK_LOAD_ERROR'),
|
||||
});
|
||||
if (error.message === 'Login cancelled') {
|
||||
isProcessing.value = false;
|
||||
isAuthenticating.value = false;
|
||||
useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED'));
|
||||
} else {
|
||||
handleSignupError({
|
||||
error:
|
||||
error.message ||
|
||||
t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SDK_LOAD_ERROR'),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -259,7 +212,6 @@ const cleanupMessageListener = () => {
|
||||
};
|
||||
|
||||
const initialize = () => {
|
||||
window.fbAsyncInit = runFBInit;
|
||||
setupMessageListener();
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useAlert } from 'dashboard/composables';
|
||||
import InboxReconnectionRequired from '../../components/InboxReconnectionRequired.vue';
|
||||
import whatsappChannel from 'dashboard/api/channel/whatsappChannel';
|
||||
import {
|
||||
setupFacebookSdk,
|
||||
initWhatsAppEmbeddedSignup,
|
||||
createMessageHandler,
|
||||
isValidBusinessData,
|
||||
} from './utils';
|
||||
|
||||
const props = defineProps({
|
||||
inbox: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const isRequestingAuthorization = ref(false);
|
||||
const isLoadingFacebook = ref(true);
|
||||
|
||||
const whatsappAppId = computed(() => window.chatwootConfig.whatsappAppId);
|
||||
const whatsappConfigurationId = computed(
|
||||
() => window.chatwootConfig.whatsappConfigurationId
|
||||
);
|
||||
|
||||
const reauthorizeWhatsApp = async params => {
|
||||
isRequestingAuthorization.value = true;
|
||||
|
||||
try {
|
||||
const response = await whatsappChannel.reauthorizeWhatsApp({
|
||||
inboxId: props.inbox.id,
|
||||
...params,
|
||||
});
|
||||
|
||||
if (response.data.success) {
|
||||
useAlert(t('INBOX.REAUTHORIZE.SUCCESS'));
|
||||
} else {
|
||||
useAlert(response.data.message || t('INBOX.REAUTHORIZE.ERROR'));
|
||||
}
|
||||
} catch (error) {
|
||||
useAlert(error.message || t('INBOX.REAUTHORIZE.ERROR'));
|
||||
} finally {
|
||||
isRequestingAuthorization.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleEmbeddedSignupEvents = async (data, authCode) => {
|
||||
if (!data || typeof data !== 'object') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle different event types
|
||||
if (data.event === 'FINISH') {
|
||||
const businessData = data.data;
|
||||
|
||||
if (isValidBusinessData(businessData) && businessData.phone_number_id) {
|
||||
await reauthorizeWhatsApp({
|
||||
code: authCode,
|
||||
business_id: businessData.business_id,
|
||||
waba_id: businessData.waba_id,
|
||||
phone_number_id: businessData.phone_number_id,
|
||||
});
|
||||
} else {
|
||||
useAlert(
|
||||
t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.INVALID_BUSINESS_DATA')
|
||||
);
|
||||
}
|
||||
} else if (data.event === 'CANCEL') {
|
||||
isRequestingAuthorization.value = false;
|
||||
useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED'));
|
||||
} else if (data.event === 'error') {
|
||||
isRequestingAuthorization.value = false;
|
||||
useAlert(
|
||||
data.error_message ||
|
||||
t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SIGNUP_ERROR')
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const startEmbeddedSignup = authCode => {
|
||||
const messageHandler = createMessageHandler(data =>
|
||||
handleEmbeddedSignupEvents(data, authCode)
|
||||
);
|
||||
window.addEventListener('message', messageHandler);
|
||||
};
|
||||
|
||||
const handleLoginAndReauthorize = async () => {
|
||||
// Validate required configuration
|
||||
if (!whatsappAppId.value) {
|
||||
throw new Error('WhatsApp App ID is required');
|
||||
}
|
||||
if (!whatsappConfigurationId.value) {
|
||||
throw new Error('WhatsApp Configuration ID is required');
|
||||
}
|
||||
|
||||
try {
|
||||
const authCode = await initWhatsAppEmbeddedSignup(
|
||||
whatsappConfigurationId.value
|
||||
);
|
||||
|
||||
// Check if this is a reauthorization scenario where we already have the business data
|
||||
const existingConfig = props.inbox.provider_config;
|
||||
if (
|
||||
existingConfig &&
|
||||
existingConfig.business_account_id &&
|
||||
existingConfig.phone_number_id
|
||||
) {
|
||||
await reauthorizeWhatsApp({
|
||||
code: authCode,
|
||||
business_id: existingConfig.business_account_id,
|
||||
waba_id: existingConfig.business_account_id,
|
||||
phone_number_id: existingConfig.phone_number_id,
|
||||
});
|
||||
} else {
|
||||
startEmbeddedSignup(authCode);
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.message === 'Login cancelled') {
|
||||
useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED'));
|
||||
} else {
|
||||
useAlert(
|
||||
error.message ||
|
||||
t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.AUTH_NOT_COMPLETED')
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
const requestAuthorization = async () => {
|
||||
if (isLoadingFacebook.value) {
|
||||
useAlert(t('INBOX.REAUTHORIZE.LOADING_FACEBOOK'));
|
||||
return;
|
||||
}
|
||||
|
||||
isRequestingAuthorization.value = true;
|
||||
try {
|
||||
await handleLoginAndReauthorize();
|
||||
} catch (error) {
|
||||
useAlert(error.message || t('INBOX.REAUTHORIZE.CONFIGURATION_ERROR'));
|
||||
} finally {
|
||||
// Reset only if not already processing through embedded signup
|
||||
if (!window.FB || !window.FB.getLoginStatus) {
|
||||
isRequestingAuthorization.value = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
// Validate required configuration
|
||||
if (!whatsappAppId.value) {
|
||||
useAlert(t('INBOX.REAUTHORIZE.WHATSAPP_APP_ID_MISSING'));
|
||||
return;
|
||||
}
|
||||
if (!whatsappConfigurationId.value) {
|
||||
useAlert(t('INBOX.REAUTHORIZE.WHATSAPP_CONFIG_ID_MISSING'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Load Facebook SDK and initialize
|
||||
await setupFacebookSdk(
|
||||
whatsappAppId.value,
|
||||
window.chatwootConfig?.whatsappApiVersion
|
||||
);
|
||||
} catch (error) {
|
||||
useAlert(t('INBOX.REAUTHORIZE.FACEBOOK_LOAD_ERROR'));
|
||||
} finally {
|
||||
isLoadingFacebook.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Expose requestAuthorization function for parent components
|
||||
defineExpose({
|
||||
requestAuthorization,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<InboxReconnectionRequired
|
||||
class="mx-8 mt-5"
|
||||
:is-loading="isRequestingAuthorization"
|
||||
@reauthorize="requestAuthorization"
|
||||
/>
|
||||
</template>
|
||||
@@ -0,0 +1,89 @@
|
||||
import { loadScript } from 'dashboard/helper/DOMHelpers';
|
||||
|
||||
export const loadFacebookSdk = async () => {
|
||||
return loadScript('https://connect.facebook.net/en_US/sdk.js', {
|
||||
async: true,
|
||||
defer: true,
|
||||
crossOrigin: 'anonymous',
|
||||
});
|
||||
};
|
||||
|
||||
export const initializeFacebook = (appId, apiVersion) => {
|
||||
const version = apiVersion || 'v22.0';
|
||||
return new Promise(resolve => {
|
||||
const init = () => {
|
||||
window.FB.init({
|
||||
appId,
|
||||
autoLogAppEvents: true,
|
||||
xfbml: true,
|
||||
version,
|
||||
});
|
||||
resolve();
|
||||
};
|
||||
|
||||
if (window.FB) {
|
||||
init();
|
||||
} else {
|
||||
window.fbAsyncInit = init;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const isValidBusinessData = businessData => {
|
||||
return businessData && businessData.business_id && businessData.waba_id;
|
||||
};
|
||||
|
||||
export const createMessageHandler = onEmbeddedSignupData => {
|
||||
return event => {
|
||||
if (!event.origin.endsWith('facebook.com')) return;
|
||||
|
||||
try {
|
||||
let data;
|
||||
if (typeof event.data === 'string') {
|
||||
data = JSON.parse(event.data);
|
||||
} else if (typeof event.data === 'object' && event.data !== null) {
|
||||
data = event.data;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.type === 'WA_EMBEDDED_SIGNUP') {
|
||||
onEmbeddedSignupData(data);
|
||||
}
|
||||
} catch {
|
||||
// Ignore non-JSON or irrelevant messages
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const initWhatsAppEmbeddedSignup = configId => {
|
||||
return new Promise((resolve, reject) => {
|
||||
window.FB.login(
|
||||
response => {
|
||||
if (response.authResponse && response.authResponse.code) {
|
||||
resolve(response.authResponse.code);
|
||||
} else if (response.error) {
|
||||
reject(new Error(response.error));
|
||||
} else {
|
||||
reject(new Error('Login cancelled'));
|
||||
}
|
||||
},
|
||||
{
|
||||
config_id: configId,
|
||||
response_type: 'code',
|
||||
override_default_response_type: true,
|
||||
extras: {
|
||||
setup: {},
|
||||
featureType: '',
|
||||
sessionInfoVersion: '3',
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const setupFacebookSdk = async (appId, apiVersion) => {
|
||||
const version = apiVersion || 'v22.0';
|
||||
await loadFacebookSdk();
|
||||
await initializeFacebook(appId, version);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ 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: {
|
||||
@@ -14,6 +15,7 @@ export default {
|
||||
ImapSettings,
|
||||
SmtpSettings,
|
||||
NextButton,
|
||||
WhatsappReauthorize,
|
||||
},
|
||||
mixins: [inboxMixin],
|
||||
props: {
|
||||
@@ -29,12 +31,21 @@ export default {
|
||||
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();
|
||||
@@ -84,6 +95,11 @@ 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 {
|
||||
@@ -210,45 +226,80 @@ export default {
|
||||
</div>
|
||||
<div v-else-if="isAWhatsAppChannel && !isATwilioChannel">
|
||||
<div v-if="inbox.provider_config" class="mx-8">
|
||||
<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"
|
||||
<!-- 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')
|
||||
"
|
||||
>
|
||||
<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"
|
||||
<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"
|
||||
>
|
||||
{{ $t('INBOX_MGMT.SETTINGS_POPUP.WHATSAPP_SECTION_UPDATE_BUTTON') }}
|
||||
</NextButton>
|
||||
</div>
|
||||
</SettingsSection>
|
||||
<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="
|
||||
@@ -262,6 +313,12 @@ export default {
|
||||
</div>
|
||||
</SettingsSection>
|
||||
</div>
|
||||
<WhatsappReauthorize
|
||||
v-if="isEmbeddedSignupWhatsApp"
|
||||
ref="whatsappReauth"
|
||||
:inbox="inbox"
|
||||
class="hidden"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user