diff --git a/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js b/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js index 0cad25f5a..a87c70dfc 100644 --- a/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js +++ b/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js @@ -7,6 +7,7 @@ import { useWhatsappSignupState } from './whatsapp/useWhatsappSignupState'; import { useWhatsappSignupHandlers } from './whatsapp/useWhatsappSignupHandlers'; import { useWhatsappSignupApi } from './whatsapp/useWhatsappSignupApi'; import { useWhatsappFacebookSDK } from './whatsapp/useWhatsappFacebookSDK'; +import { useWhatsappMessageHandler } from './whatsapp/useWhatsappMessageHandler'; export function useWhatsappEmbeddedSignup() { const store = useStore(); @@ -68,6 +69,20 @@ export function useWhatsappEmbeddedSignup() { t, }); + const { handleSignupMessage } = useWhatsappMessageHandler({ + isValidBusinessData, + normalizeBusinessData, + businessData, + authCodeReceived, + authCode, + completeSignupFlow, + currentStep, + processingMessage, + handleSignupError, + handleSignupCancellation, + t, + }); + // Computed const benefits = computed(() => [ { @@ -88,63 +103,6 @@ export function useWhatsappEmbeddedSignup() { () => hasSignupStarted.value || isProcessing.value ); - // Message handling - const handleEmbeddedSignupData = async data => { - if (data.event === 'FINISH') { - const businessDataLocal = - data.data || data.business_data || data.details || data; - - if (isValidBusinessData(businessDataLocal)) { - const normalizedData = normalizeBusinessData(businessDataLocal); - businessData.value = normalizedData; - - if (authCodeReceived.value && authCode.value) { - await completeSignupFlow(normalizedData); - } else { - currentStep.value = 'waiting_for_auth'; - processingMessage.value = t( - 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.WAITING_FOR_AUTH' - ); - } - } else { - handleSignupError({ - error: t( - 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.INVALID_BUSINESS_DATA' - ), - }); - } - } else if (data.event === 'CANCEL') { - handleSignupCancellation(data); - } else if (data.event === 'error') { - handleSignupError({ - error: - data.error_message || - t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SIGNUP_ERROR'), - error_id: data.error_id, - session_id: data.session_id, - }); - } - }; - - const handleSignupMessage = event => { - try { - const originUrl = new URL(event.origin); - const allowedHosts = ['facebook.com', 'www.facebook.com']; - if (!allowedHosts.includes(originUrl.hostname)) return; - } catch (error) { - return; - } - - try { - const data = JSON.parse(event.data); - if (data.type === 'WA_EMBEDDED_SIGNUP') { - handleEmbeddedSignupData(data); - } - } catch (error) { - // Handle non-JSON messages silently - } - }; - // Lifecycle const setupMessageListener = () => { window.addEventListener('message', handleSignupMessage); diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js index dda13149f..4f55452e2 100644 --- a/app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js @@ -14,56 +14,99 @@ export function useWhatsappFacebookSDK({ handleSignupError, t, }) { + const initializeFacebookSDK = () => { + window.FB.init({ + appId: window.chatwootConfig?.whatsappAppId, + status: true, + xfbml: true, + version: window.chatwootConfig?.whatsappApiVersion || 'v22.0', + }); + fbSdkLoaded.value = true; + }; + + const createFacebookScript = () => { + const script = document.createElement('script'); + script.src = 'https://connect.facebook.net/en_US/sdk.js'; + script.async = true; + script.defer = true; + script.onload = initializeFacebookSDK; + document.body.appendChild(script); + }; + const loadFacebookSdk = () => { if (window.FB) { fbSdkLoaded.value = true; return; } - - const script = document.createElement('script'); - script.src = 'https://connect.facebook.net/en_US/sdk.js'; - script.async = true; - script.defer = true; - script.onload = () => { - window.FB.init({ - appId: window.chatwootConfig?.whatsappAppId, - status: true, - xfbml: true, - version: window.chatwootConfig?.whatsappApiVersion || 'v22.0', - }); - fbSdkLoaded.value = true; - }; - document.body.appendChild(script); + createFacebookScript(); }; - const fbLoginCallback = response => { - if (response.authResponse && response.authResponse.code) { - authCode.value = response.authResponse.code; - authCodeReceived.value = true; - currentStep.value = 'auth_received'; - processingMessage.value = t( - 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.WAITING_FOR_BUSINESS_INFO' - ); + const handleSuccessfulAuth = authResponse => { + authCode.value = authResponse.code; + authCodeReceived.value = true; + currentStep.value = 'auth_received'; + processingMessage.value = t( + 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.WAITING_FOR_BUSINESS_INFO' + ); - if (businessData.value) { - completeSignupFlow(businessData.value); - } - } else if (response.error) { - handleSignupError({ error: response.error }); - } else { - currentStep.value = 'initial'; - isProcessing.value = false; - isAuthenticating.value = false; - hasSignupStarted.value = false; - useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED')); + if (businessData.value) { + completeSignupFlow(businessData.value); } }; - const launchEmbeddedSignup = () => { + const handleAuthError = error => { + handleSignupError({ error }); + }; + + const handleAuthCancellation = () => { + currentStep.value = 'initial'; + isProcessing.value = false; + isAuthenticating.value = false; + hasSignupStarted.value = false; + useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED')); + }; + + const fbLoginCallback = response => { + if (response.authResponse?.code) { + handleSuccessfulAuth(response.authResponse); + } else if (response.error) { + handleAuthError(response.error); + } else { + handleAuthCancellation(); + } + }; + + const setSignupProcessingState = () => { hasSignupStarted.value = true; processingMessage.value = t( 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.AUTH_PROCESSING' ); + }; + + const setAuthenticatingState = () => { + isAuthenticating.value = true; + currentStep.value = 'auth_processing'; + }; + + const createLoginOptions = () => ({ + config_id: window.chatwootConfig?.whatsappConfigurationId, + response_type: 'code', + override_default_response_type: true, + extras: { + setup: {}, + featureType: '', + sessionInfoVersion: '3', + }, + }); + + const executeSignup = () => { + setAuthenticatingState(); + const options = createLoginOptions(); + window.FB.login(fbLoginCallback, options); + }; + + const launchEmbeddedSignup = () => { + setSignupProcessingState(); if (!window.FB) { loadFacebookSdk(); @@ -71,19 +114,7 @@ export function useWhatsappFacebookSDK({ return; } - isAuthenticating.value = true; - currentStep.value = 'auth_processing'; - - window.FB.login(fbLoginCallback, { - config_id: window.chatwootConfig?.whatsappConfigurationId, - response_type: 'code', - override_default_response_type: true, - extras: { - setup: {}, - featureType: '', - sessionInfoVersion: '3', - }, - }); + executeSignup(); }; return { diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappMessageHandler.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappMessageHandler.js new file mode 100644 index 000000000..000c0c60e --- /dev/null +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappMessageHandler.js @@ -0,0 +1,96 @@ +export function useWhatsappMessageHandler({ + isValidBusinessData, + normalizeBusinessData, + businessData, + authCodeReceived, + authCode, + completeSignupFlow, + currentStep, + processingMessage, + handleSignupError, + handleSignupCancellation, + t, +}) { + const processFinishEvent = async data => { + const businessDataLocal = + data.data || data.business_data || data.details || data; + + if (isValidBusinessData(businessDataLocal)) { + const normalizedData = normalizeBusinessData(businessDataLocal); + businessData.value = normalizedData; + + if (authCodeReceived.value && authCode.value) { + await completeSignupFlow(normalizedData); + } else { + currentStep.value = 'waiting_for_auth'; + processingMessage.value = t( + 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.WAITING_FOR_AUTH' + ); + } + } else { + handleSignupError({ + error: t( + 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.INVALID_BUSINESS_DATA' + ), + }); + } + }; + + const processErrorEvent = data => { + handleSignupError({ + error: + data.error_message || + t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SIGNUP_ERROR'), + error_id: data.error_id, + session_id: data.session_id, + }); + }; + + const handleEmbeddedSignupData = async data => { + switch (data.event) { + case 'FINISH': + await processFinishEvent(data); + break; + case 'CANCEL': + handleSignupCancellation(data); + break; + case 'error': + processErrorEvent(data); + break; + default: + // Handle unknown events silently + break; + } + }; + + const validateMessageOrigin = origin => { + try { + const originUrl = new URL(origin); + const allowedHosts = ['facebook.com', 'www.facebook.com']; + return allowedHosts.includes(originUrl.hostname); + } catch (error) { + return false; + } + }; + + const parseMessageData = data => { + try { + return JSON.parse(data); + } catch (error) { + return null; + } + }; + + const handleSignupMessage = event => { + if (!validateMessageOrigin(event.origin)) return; + + const data = parseMessageData(event.data); + if (data?.type === 'WA_EMBEDDED_SIGNUP') { + handleEmbeddedSignupData(data); + } + }; + + return { + handleSignupMessage, + }; +} diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js index 9a762d1ec..a93405f27 100644 --- a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js @@ -32,48 +32,69 @@ export function useWhatsappSignupApi({ return {}; }); + const validateAuthRequirements = () => { + return authCodeReceived.value && authCode.value; + }; + + const createSignupPayload = businessDataParam => { + const accountId = store.getters.getCurrentAccountId; + return { + account_id: accountId, + code: authCode.value, + business_id: businessDataParam.business_id, + waba_id: businessDataParam.waba_id, + phone_number_id: businessDataParam.phone_number_id, + }; + }; + + const createFetchOptions = payload => { + return { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRF-Token': document + .querySelector('meta[name="csrf-token"]') + ?.getAttribute('content'), + ...authHeaders.value, + }, + body: JSON.stringify(payload), + }; + }; + + const setProcessingState = () => { + currentStep.value = 'processing'; + isProcessing.value = true; + processingMessage.value = t( + 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.PROCESSING' + ); + }; + + const handleApiResponse = async response => { + const responseData = await response.json(); + + if (response.ok) { + authCode.value = null; + handleSignupSuccess(responseData); + } else { + throw new Error(responseData.message || responseData.error); + } + }; + const completeSignupFlow = async businessDataParam => { - if (!authCodeReceived.value || !authCode.value) { + if (!validateAuthRequirements()) { handleSignupError({ error: t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.AUTH_NOT_COMPLETED'), }); return; } - currentStep.value = 'processing'; - isProcessing.value = true; - processingMessage.value = t( - 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.PROCESSING' - ); + setProcessingState(); try { - const accountId = store.getters.getCurrentAccountId; - const response = await fetch('/whatsapp/embedded_signup', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'X-CSRF-Token': document - .querySelector('meta[name="csrf-token"]') - ?.getAttribute('content'), - ...authHeaders.value, - }, - body: JSON.stringify({ - account_id: accountId, - code: authCode.value, - business_id: businessDataParam.business_id, - waba_id: businessDataParam.waba_id, - phone_number_id: businessDataParam.phone_number_id, - }), - }); - - const responseData = await response.json(); - - if (response.ok) { - authCode.value = null; - handleSignupSuccess(responseData); - } else { - throw new Error(responseData.message || responseData.error); - } + const payload = createSignupPayload(businessDataParam); + const options = createFetchOptions(payload); + const response = await fetch('/whatsapp/embedded_signup', options); + await handleApiResponse(response); } catch (error) { handleSignupError({ error: error.message }); } diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js index 3a9b7d202..9cc4fae06 100644 --- a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js @@ -9,44 +9,74 @@ export function useWhatsappSignupHandlers({ router, t, }) { - const handleSignupError = data => { - resetState(); - const errorMessage = + const getErrorMessage = data => { + return ( data.error || data.message || - t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE'); + t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE') + ); + }; + + const getCancellationMessage = data => { + let message = t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED'); + if (data.data?.current_step) { + message += ` (Step: ${data.data.current_step})`; + } + return message; + }; + + const handleSignupError = data => { + resetState(); + const errorMessage = getErrorMessage(data); useAlert(errorMessage); }; const handleSignupCancellation = data => { resetState(); - let message = t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED'); - if (data.data?.current_step) { - message += ` (Step: ${data.data.current_step})`; - } + const message = getCancellationMessage(data); useAlert(message); }; + const navigateToAgentSelection = inboxId => { + router.replace({ + name: 'settings_inboxes_add_agents', + params: { + page: 'new', + inbox_id: inboxId, + }, + }); + }; + + const navigateToInboxList = () => { + router.replace({ + name: 'settings_inbox_list', + }); + }; + + const updateStoreWithInbox = inboxData => { + store.commit('inboxes/ADD_INBOXES', inboxData); + useAlert(t('INBOX_MGMT.FINISH.MESSAGE')); + }; + + const handleValidInboxData = inboxData => { + updateStoreWithInbox(inboxData); + navigateToAgentSelection(inboxData.id); + }; + + const handleInvalidInboxData = () => { + useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SUCCESS_FALLBACK')); + navigateToInboxList(); + }; + const handleSignupSuccess = inboxData => { currentStep.value = 'completed'; isProcessing.value = false; isAuthenticating.value = false; - if (inboxData && inboxData.id) { - store.commit('inboxes/ADD_INBOXES', inboxData); - useAlert(t('INBOX_MGMT.FINISH.MESSAGE')); - router.replace({ - name: 'settings_inboxes_add_agents', - params: { - page: 'new', - inbox_id: inboxData.id, - }, - }); + if (inboxData?.id) { + handleValidInboxData(inboxData); } else { - useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SUCCESS_FALLBACK')); - router.replace({ - name: 'settings_inbox_list', - }); + handleInvalidInboxData(); } };