From f812ca3b99ed0c72f185eda1890beb0433f44de6 Mon Sep 17 00:00:00 2001 From: Muhsin Keloth Date: Wed, 11 Jun 2025 14:40:16 +0530 Subject: [PATCH] fix: code complexity issues --- .../composables/useWhatsappEmbeddedSignup.js | 312 ++++-------------- .../whatsapp/useWhatsappFacebookSDK.js | 93 ++++++ .../whatsapp/useWhatsappSignupApi.js | 85 +++++ .../whatsapp/useWhatsappSignupHandlers.js | 58 ++++ .../whatsapp/useWhatsappSignupState.js | 34 ++ .../whatsapp/useWhatsappSignupValidation.js | 25 ++ 6 files changed, 359 insertions(+), 248 deletions(-) create mode 100644 app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js create mode 100644 app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js create mode 100644 app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js create mode 100644 app/javascript/dashboard/composables/whatsapp/useWhatsappSignupState.js create mode 100644 app/javascript/dashboard/composables/whatsapp/useWhatsappSignupValidation.js diff --git a/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js b/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js index 6adab5bf6..0cad25f5a 100644 --- a/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js +++ b/app/javascript/dashboard/composables/useWhatsappEmbeddedSignup.js @@ -1,47 +1,74 @@ -import { ref, computed } from 'vue'; +import { computed } from 'vue'; import { useStore } from 'vuex'; import { useRouter } from 'vue-router'; import { useI18n } from 'vue-i18n'; -import { useAlert } from 'dashboard/composables'; -import Auth from 'dashboard/api/auth'; +import { useWhatsappSignupValidation } from './whatsapp/useWhatsappSignupValidation'; +import { useWhatsappSignupState } from './whatsapp/useWhatsappSignupState'; +import { useWhatsappSignupHandlers } from './whatsapp/useWhatsappSignupHandlers'; +import { useWhatsappSignupApi } from './whatsapp/useWhatsappSignupApi'; +import { useWhatsappFacebookSDK } from './whatsapp/useWhatsappFacebookSDK'; export function useWhatsappEmbeddedSignup() { const store = useStore(); const router = useRouter(); const { t } = useI18n(); - // State - const fbSdkLoaded = ref(false); - const isProcessing = ref(false); - const processingMessage = ref(''); - const authCodeReceived = ref(false); - const currentStep = ref('initial'); - const authCode = ref(null); - const businessData = ref(null); - const isAuthenticating = ref(false); - const hasSignupStarted = ref(false); + // Composables + const { isValidBusinessData, normalizeBusinessData } = + useWhatsappSignupValidation(); - // Computed - const authHeaders = computed(() => { - if (Auth.hasAuthCookie()) { - const { - 'access-token': accessToken, - 'token-type': tokenType, - client, - expiry, - uid, - } = Auth.getAuthData(); - return { - 'access-token': accessToken, - 'token-type': tokenType, - client, - expiry, - uid, - }; - } - return {}; + const { + fbSdkLoaded, + isProcessing, + processingMessage, + authCodeReceived, + currentStep, + authCode, + businessData, + isAuthenticating, + hasSignupStarted, + resetState, + } = useWhatsappSignupState(); + + const { handleSignupError, handleSignupCancellation, handleSignupSuccess } = + useWhatsappSignupHandlers({ + currentStep, + isProcessing, + isAuthenticating, + resetState, + store, + router, + t, + }); + + const { completeSignupFlow } = useWhatsappSignupApi({ + authCodeReceived, + authCode, + currentStep, + isProcessing, + processingMessage, + store, + t, + handleSignupError, + handleSignupSuccess, }); + const { loadFacebookSdk, launchEmbeddedSignup } = useWhatsappFacebookSDK({ + fbSdkLoaded, + hasSignupStarted, + processingMessage, + isProcessing, + isAuthenticating, + currentStep, + authCode, + authCodeReceived, + businessData, + completeSignupFlow, + handleSignupError, + t, + }); + + // Computed const benefits = computed(() => [ { key: 'EASY_SETUP', @@ -61,148 +88,16 @@ export function useWhatsappEmbeddedSignup() { () => hasSignupStarted.value || isProcessing.value ); - // Error handling - const handleSignupError = data => { - currentStep.value = 'initial'; - isProcessing.value = false; - authCodeReceived.value = false; - isAuthenticating.value = false; - hasSignupStarted.value = false; - - const errorMessage = - data.error || - data.message || - t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE'); - useAlert(errorMessage); - }; - - const handleSignupCancellation = data => { - currentStep.value = 'initial'; - isProcessing.value = false; - authCodeReceived.value = false; - isAuthenticating.value = false; - hasSignupStarted.value = false; - - let message = t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.CANCELLED'); - if (data.data?.current_step) { - message += ` (Step: ${data.data.current_step})`; - } - - useAlert(message); - }; - - const handleSignupSuccess = inboxData => { - currentStep.value = 'completed'; - isProcessing.value = false; - isAuthenticating.value = false; - - // Update the store with the new inbox data - if (inboxData && inboxData.id) { - // Add the new inbox to the store - 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, - }, - }); - } else { - // Fallback if inbox data is not properly formatted - useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SUCCESS_FALLBACK')); - router.replace({ - name: 'settings_inbox_list', - }); - } - }; - - // Signup flow - const completeSignupFlow = async businessDataParam => { - if (!authCodeReceived.value || !authCode.value) { - 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' - ); - - try { - // Send both auth code and business info together (synchronous flow) - 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) { - // Clear the stored auth code for security - authCode.value = null; - - // Handle synchronous success response - handleSignupSuccess(responseData); - } else { - throw new Error(responseData.message || responseData.error); - } - } catch (error) { - handleSignupError({ error: error.message }); - } - }; - // Message handling const handleEmbeddedSignupData = async data => { - // Handle different embedded signup events per Facebook documentation if (data.event === 'FINISH') { - // Facebook might send business data in different structures - let businessDataLocal = data.data; + const businessDataLocal = + data.data || data.business_data || data.details || data; - // If data.data doesn't exist, try other possible structures - if (!businessDataLocal) { - businessDataLocal = data.business_data || data.details || data; - } - - // Validate we have the required business information - if ( - businessDataLocal && - (businessDataLocal.business_id || businessDataLocal.businessId) && - (businessDataLocal.waba_id || businessDataLocal.wabaId) - ) { - // Normalize the data structure to match our backend expectations - const normalizedData = { - business_id: - businessDataLocal.business_id || businessDataLocal.businessId, - waba_id: businessDataLocal.waba_id || businessDataLocal.wabaId, - phone_number_id: - businessDataLocal.phone_number_id || - businessDataLocal.phoneNumberId || - businessDataLocal.phone_id, - }; - - // Store business data + if (isValidBusinessData(businessDataLocal)) { + const normalizedData = normalizeBusinessData(businessDataLocal); businessData.value = normalizedData; - // Check if we already have auth code and process immediately + if (authCodeReceived.value && authCode.value) { await completeSignupFlow(normalizedData); } else { @@ -231,45 +126,17 @@ export function useWhatsappEmbeddedSignup() { } }; - const fbLoginCallback = response => { - if (response.authResponse && response.authResponse.code) { - // Authorization code received from Facebook - 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' - ); - - // Check if we already have business data and process immediately - 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')); - } - }; - const handleSignupMessage = event => { - // Handle Facebook embedded signup message events try { const originUrl = new URL(event.origin); const allowedHosts = ['facebook.com', 'www.facebook.com']; if (!allowedHosts.includes(originUrl.hostname)) return; } catch (error) { - // Invalid origin URL, reject the event return; } try { const data = JSON.parse(event.data); - if (data.type === 'WA_EMBEDDED_SIGNUP') { handleEmbeddedSignupData(data); } @@ -278,56 +145,6 @@ export function useWhatsappEmbeddedSignup() { } }; - // Facebook SDK - 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); - }; - - const launchEmbeddedSignup = () => { - hasSignupStarted.value = true; - processingMessage.value = t( - 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.AUTH_PROCESSING' - ); - - if (!window.FB) { - loadFacebookSdk(); - setTimeout(() => launchEmbeddedSignup(), 1000); - return; - } - - isAuthenticating.value = true; - currentStep.value = 'auth_processing'; - - // Following Facebook's embedded signup documentation - window.FB.login(fbLoginCallback, { - config_id: window.chatwootConfig?.whatsappConfigurationId, - response_type: 'code', - override_default_response_type: true, - extras: { - setup: {}, - featureType: '', // Leave empty for default flow - sessionInfoVersion: '3', - }, - }); - }; - // Lifecycle const setupMessageListener = () => { window.addEventListener('message', handleSignupMessage); @@ -337,7 +154,6 @@ export function useWhatsappEmbeddedSignup() { window.removeEventListener('message', handleSignupMessage); }; - // Initialize const initialize = () => { loadFacebookSdk(); setupMessageListener(); diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js new file mode 100644 index 000000000..dda13149f --- /dev/null +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappFacebookSDK.js @@ -0,0 +1,93 @@ +import { useAlert } from 'dashboard/composables'; + +export function useWhatsappFacebookSDK({ + fbSdkLoaded, + hasSignupStarted, + processingMessage, + isProcessing, + isAuthenticating, + currentStep, + authCode, + authCodeReceived, + businessData, + completeSignupFlow, + handleSignupError, + t, +}) { + 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); + }; + + 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' + ); + + 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')); + } + }; + + const launchEmbeddedSignup = () => { + hasSignupStarted.value = true; + processingMessage.value = t( + 'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.AUTH_PROCESSING' + ); + + if (!window.FB) { + loadFacebookSdk(); + setTimeout(() => launchEmbeddedSignup(), 1000); + 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', + }, + }); + }; + + return { + loadFacebookSdk, + launchEmbeddedSignup, + }; +} diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js new file mode 100644 index 000000000..9a762d1ec --- /dev/null +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupApi.js @@ -0,0 +1,85 @@ +import { computed } from 'vue'; +import Auth from 'dashboard/api/auth'; + +export function useWhatsappSignupApi({ + authCodeReceived, + authCode, + currentStep, + isProcessing, + processingMessage, + store, + t, + handleSignupError, + handleSignupSuccess, +}) { + const authHeaders = computed(() => { + if (Auth.hasAuthCookie()) { + const { + 'access-token': accessToken, + 'token-type': tokenType, + client, + expiry, + uid, + } = Auth.getAuthData(); + return { + 'access-token': accessToken, + 'token-type': tokenType, + client, + expiry, + uid, + }; + } + return {}; + }); + + const completeSignupFlow = async businessDataParam => { + if (!authCodeReceived.value || !authCode.value) { + 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' + ); + + 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); + } + } catch (error) { + handleSignupError({ error: error.message }); + } + }; + + return { + completeSignupFlow, + }; +} diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js new file mode 100644 index 000000000..3a9b7d202 --- /dev/null +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupHandlers.js @@ -0,0 +1,58 @@ +import { useAlert } from 'dashboard/composables'; + +export function useWhatsappSignupHandlers({ + currentStep, + isProcessing, + isAuthenticating, + resetState, + store, + router, + t, +}) { + const handleSignupError = data => { + resetState(); + const errorMessage = + data.error || + data.message || + t('INBOX_MGMT.ADD.WHATSAPP.API.ERROR_MESSAGE'); + 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})`; + } + useAlert(message); + }; + + 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, + }, + }); + } else { + useAlert(t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.SUCCESS_FALLBACK')); + router.replace({ + name: 'settings_inbox_list', + }); + } + }; + + return { + handleSignupError, + handleSignupCancellation, + handleSignupSuccess, + }; +} diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupState.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupState.js new file mode 100644 index 000000000..32ad3b7b7 --- /dev/null +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupState.js @@ -0,0 +1,34 @@ +import { ref } from 'vue'; + +export function useWhatsappSignupState() { + const fbSdkLoaded = ref(false); + const isProcessing = ref(false); + const processingMessage = ref(''); + const authCodeReceived = ref(false); + const currentStep = ref('initial'); + const authCode = ref(null); + const businessData = ref(null); + const isAuthenticating = ref(false); + const hasSignupStarted = ref(false); + + const resetState = () => { + currentStep.value = 'initial'; + isProcessing.value = false; + authCodeReceived.value = false; + isAuthenticating.value = false; + hasSignupStarted.value = false; + }; + + return { + fbSdkLoaded, + isProcessing, + processingMessage, + authCodeReceived, + currentStep, + authCode, + businessData, + isAuthenticating, + hasSignupStarted, + resetState, + }; +} diff --git a/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupValidation.js b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupValidation.js new file mode 100644 index 000000000..ea9babaa4 --- /dev/null +++ b/app/javascript/dashboard/composables/whatsapp/useWhatsappSignupValidation.js @@ -0,0 +1,25 @@ +export function useWhatsappSignupValidation() { + const isValidBusinessData = businessData => { + return ( + businessData && + (businessData.business_id || businessData.businessId) && + (businessData.waba_id || businessData.wabaId) + ); + }; + + const normalizeBusinessData = businessData => { + return { + business_id: businessData.business_id || businessData.businessId, + waba_id: businessData.waba_id || businessData.wabaId, + phone_number_id: + businessData.phone_number_id || + businessData.phoneNumberId || + businessData.phone_id, + }; + }; + + return { + isValidBusinessData, + normalizeBusinessData, + }; +}