mirror of
				https://github.com/lingble/chatwoot.git
				synced 2025-11-03 20:48:07 +00:00 
			
		
		
		
	chore: Enable flexible whatsapp onboarding (Manual + Embedded Signup) options (#12344)
We recently introduced the WhatsApp Embedded Signup flow in Chatwoot to simplify onboarding. However, we discovered two important limitations: Some customers’ numbers are already linked to an Embedded Signup, which blocks re-use. Tech providers cannot onboard their own numbers via Embedded Signup. As a result, we need to support both Manual and Embedded Signup flows to cover all scenarios. ### Problem - Current UI only offers the Embedded Signup option. - Customers who need to reuse existing numbers (already connected to WABA) or tech providers testing their own numbers get stuck. - Manual flow exists but is no longer exposed in the UX **Current Embedded Signup screen** <img width="2564" height="1250" alt="CleanShot 2025-08-21 at 21 58 07@2x" src="https://github.com/user-attachments/assets/c3de4cf1-cae6-4a0e-aa9c-5fa4e2249c0e" /> **Current Manual Setup screen** <img width="2568" height="1422" alt="CleanShot 2025-08-21 at 22 00 25@2x" src="https://github.com/user-attachments/assets/96408f97-3ffe-42d1-9019-a511e808f5ac" /> ### Solution - Design a dual-path UX in the Create WhatsApp Inbox step that: - Offers Embedded Signup (default/recommended) for new numbers and businesses. - Offers Manual Setup for advanced users, existing linked numbers, and tech providers. <img width="2030" height="1376" alt="CleanShot 2025-09-01 at 14 13 16@2x" src="https://github.com/user-attachments/assets/6f17e5a2-a2fd-40fb-826a-c9ee778be795" /> --------- Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: iamsivin <iamsivin@gmail.com>
This commit is contained in:
		@@ -1,5 +1,4 @@
 | 
				
			|||||||
class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts::BaseController
 | 
					class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts::BaseController
 | 
				
			||||||
  before_action :validate_feature_enabled!
 | 
					 | 
				
			||||||
  before_action :fetch_and_validate_inbox, if: -> { params[:inbox_id].present? }
 | 
					  before_action :fetch_and_validate_inbox, if: -> { params[:inbox_id].present? }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # POST /api/v1/accounts/:account_id/whatsapp/authorization
 | 
					  # POST /api/v1/accounts/:account_id/whatsapp/authorization
 | 
				
			||||||
@@ -65,15 +64,6 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts:
 | 
				
			|||||||
    }, status: :unprocessable_entity
 | 
					    }, status: :unprocessable_entity
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def validate_feature_enabled!
 | 
					 | 
				
			||||||
    return if Current.account.feature_whatsapp_embedded_signup?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    render json: {
 | 
					 | 
				
			||||||
      success: false,
 | 
					 | 
				
			||||||
      error: 'WhatsApp embedded signup is not enabled for this account'
 | 
					 | 
				
			||||||
    }, status: :forbidden
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  def validate_embedded_signup_params!
 | 
					  def validate_embedded_signup_params!
 | 
				
			||||||
    missing_params = []
 | 
					    missing_params = []
 | 
				
			||||||
    missing_params << 'code' if params[:code].blank?
 | 
					    missing_params << 'code' if params[:code].blank?
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,6 +35,8 @@ export default {
 | 
				
			|||||||
  HELP_CENTER_DOCS_URL:
 | 
					  HELP_CENTER_DOCS_URL:
 | 
				
			||||||
    'https://www.chatwoot.com/docs/product/others/help-center',
 | 
					    'https://www.chatwoot.com/docs/product/others/help-center',
 | 
				
			||||||
  TESTIMONIAL_URL: 'https://testimonials.cdn.chatwoot.com/content.json',
 | 
					  TESTIMONIAL_URL: 'https://testimonials.cdn.chatwoot.com/content.json',
 | 
				
			||||||
 | 
					  WHATSAPP_EMBEDDED_SIGNUP_DOCS_URL:
 | 
				
			||||||
 | 
					    'https://developers.facebook.com/docs/whatsapp/embedded-signup/custom-flows/onboarding-business-app-users#limitations',
 | 
				
			||||||
  SMALL_SCREEN_BREAKPOINT: 768,
 | 
					  SMALL_SCREEN_BREAKPOINT: 768,
 | 
				
			||||||
  AVAILABILITY_STATUS_KEYS: ['online', 'busy', 'offline'],
 | 
					  AVAILABILITY_STATUS_KEYS: ['online', 'busy', 'offline'],
 | 
				
			||||||
  SNOOZE_OPTIONS: {
 | 
					  SNOOZE_OPTIONS: {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,6 @@ export const FEATURE_FLAGS = {
 | 
				
			|||||||
  REPORT_V4: 'report_v4',
 | 
					  REPORT_V4: 'report_v4',
 | 
				
			||||||
  CHANNEL_INSTAGRAM: 'channel_instagram',
 | 
					  CHANNEL_INSTAGRAM: 'channel_instagram',
 | 
				
			||||||
  CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team',
 | 
					  CONTACT_CHATWOOT_SUPPORT_TEAM: 'contact_chatwoot_support_team',
 | 
				
			||||||
  WHATSAPP_EMBEDDED_SIGNUP: 'whatsapp_embedded_signup',
 | 
					 | 
				
			||||||
  CAPTAIN_V2: 'captain_integration_v2',
 | 
					  CAPTAIN_V2: 'captain_integration_v2',
 | 
				
			||||||
  SAML: 'saml',
 | 
					  SAML: 'saml',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -272,8 +272,8 @@
 | 
				
			|||||||
        },
 | 
					        },
 | 
				
			||||||
        "SUBMIT_BUTTON": "Create WhatsApp Channel",
 | 
					        "SUBMIT_BUTTON": "Create WhatsApp Channel",
 | 
				
			||||||
        "EMBEDDED_SIGNUP": {
 | 
					        "EMBEDDED_SIGNUP": {
 | 
				
			||||||
          "TITLE": "Quick Setup with Meta",
 | 
					          "TITLE": "Quick setup with Meta",
 | 
				
			||||||
          "DESC": "You will be redirected to Meta to log into your WhatsApp Business account. Having admin access will help make the setup smooth and easy.",
 | 
					          "DESC": "Use the WhatsApp Embedded Signup flow to quickly connect new numbers. You will be redirected to Meta to log into your WhatsApp Business account. Having admin access will help make the setup smooth and easy.",
 | 
				
			||||||
          "BENEFITS": {
 | 
					          "BENEFITS": {
 | 
				
			||||||
            "TITLE": "Benefits of Embedded Signup:",
 | 
					            "TITLE": "Benefits of Embedded Signup:",
 | 
				
			||||||
            "EASY_SETUP": "No manual configuration required",
 | 
					            "EASY_SETUP": "No manual configuration required",
 | 
				
			||||||
@@ -281,9 +281,8 @@
 | 
				
			|||||||
            "AUTO_CONFIG": "Automatic webhook and phone number configuration"
 | 
					            "AUTO_CONFIG": "Automatic webhook and phone number configuration"
 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "LEARN_MORE": {
 | 
					          "LEARN_MORE": {
 | 
				
			||||||
            "TEXT": "To learn more about integrated signup, pricing, and limitations, visit",
 | 
					            "TEXT": "To learn more about integrated signup, pricing, and limitations, visit {link}.",
 | 
				
			||||||
            "LINK_TEXT": "this link.",
 | 
					            "LINK_TEXT": "this link"
 | 
				
			||||||
            "LINK_URL": "https://developers.facebook.com/docs/whatsapp/embedded-signup/custom-flows/onboarding-business-app-users#limitations"
 | 
					 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
          "SUBMIT_BUTTON": "Connect with WhatsApp Business",
 | 
					          "SUBMIT_BUTTON": "Connect with WhatsApp Business",
 | 
				
			||||||
          "AUTH_PROCESSING": "Authenticating with Meta",
 | 
					          "AUTH_PROCESSING": "Authenticating with Meta",
 | 
				
			||||||
@@ -296,7 +295,9 @@
 | 
				
			|||||||
          "INVALID_BUSINESS_DATA": "Invalid business data received from Facebook. Please try again.",
 | 
					          "INVALID_BUSINESS_DATA": "Invalid business data received from Facebook. Please try again.",
 | 
				
			||||||
          "SIGNUP_ERROR": "Signup error occurred",
 | 
					          "SIGNUP_ERROR": "Signup error occurred",
 | 
				
			||||||
          "AUTH_NOT_COMPLETED": "Authentication not completed. Please restart the process.",
 | 
					          "AUTH_NOT_COMPLETED": "Authentication not completed. Please restart the process.",
 | 
				
			||||||
          "SUCCESS_FALLBACK": "WhatsApp Business Account has been successfully configured"
 | 
					          "SUCCESS_FALLBACK": "WhatsApp Business Account has been successfully configured",
 | 
				
			||||||
 | 
					          "MANUAL_FALLBACK": "If your number is already connected to the WhatsApp Business Platform (API), or if you’re a tech provider onboarding your own number, please use the {link} flow",
 | 
				
			||||||
 | 
					          "MANUAL_LINK_TEXT": "manual setup flow"
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        "API": {
 | 
					        "API": {
 | 
				
			||||||
          "ERROR_MESSAGE": "We were not able to save the WhatsApp channel"
 | 
					          "ERROR_MESSAGE": "We were not able to save the WhatsApp channel"
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,25 +1,23 @@
 | 
				
			|||||||
<script setup>
 | 
					<script setup>
 | 
				
			||||||
import { computed } from 'vue';
 | 
					import { computed } from 'vue';
 | 
				
			||||||
import { useRoute, useRouter } from 'vue-router';
 | 
					import { useRoute, useRouter } from 'vue-router';
 | 
				
			||||||
import { useI18n } from 'vue-i18n';
 | 
					import { useI18n, I18nT } from 'vue-i18n';
 | 
				
			||||||
import { useStore } from 'vuex';
 | 
					 | 
				
			||||||
import Twilio from './Twilio.vue';
 | 
					import Twilio from './Twilio.vue';
 | 
				
			||||||
import ThreeSixtyDialogWhatsapp from './360DialogWhatsapp.vue';
 | 
					import ThreeSixtyDialogWhatsapp from './360DialogWhatsapp.vue';
 | 
				
			||||||
import CloudWhatsapp from './CloudWhatsapp.vue';
 | 
					import CloudWhatsapp from './CloudWhatsapp.vue';
 | 
				
			||||||
import WhatsappEmbeddedSignup from './WhatsappEmbeddedSignup.vue';
 | 
					import WhatsappEmbeddedSignup from './WhatsappEmbeddedSignup.vue';
 | 
				
			||||||
import ChannelSelector from 'dashboard/components/ChannelSelector.vue';
 | 
					import ChannelSelector from 'dashboard/components/ChannelSelector.vue';
 | 
				
			||||||
import { FEATURE_FLAGS } from 'dashboard/featureFlags';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute();
 | 
					const route = useRoute();
 | 
				
			||||||
const router = useRouter();
 | 
					const router = useRouter();
 | 
				
			||||||
const { t } = useI18n();
 | 
					const { t } = useI18n();
 | 
				
			||||||
const store = useStore();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PROVIDER_TYPES = {
 | 
					const PROVIDER_TYPES = {
 | 
				
			||||||
  WHATSAPP: 'whatsapp',
 | 
					  WHATSAPP: 'whatsapp',
 | 
				
			||||||
  TWILIO: 'twilio',
 | 
					  TWILIO: 'twilio',
 | 
				
			||||||
  WHATSAPP_CLOUD: 'whatsapp_cloud',
 | 
					  WHATSAPP_CLOUD: 'whatsapp_cloud',
 | 
				
			||||||
  WHATSAPP_EMBEDDED: 'whatsapp_embedded',
 | 
					  WHATSAPP_EMBEDDED: 'whatsapp_embedded',
 | 
				
			||||||
 | 
					  WHATSAPP_MANUAL: 'whatsapp_manual',
 | 
				
			||||||
  THREE_SIXTY_DIALOG: '360dialog',
 | 
					  THREE_SIXTY_DIALOG: '360dialog',
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -30,14 +28,6 @@ const hasWhatsappAppId = computed(() => {
 | 
				
			|||||||
  );
 | 
					  );
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isWhatsappEmbeddedSignupEnabled = computed(() => {
 | 
					 | 
				
			||||||
  const accountId = route.params.accountId;
 | 
					 | 
				
			||||||
  return store.getters['accounts/isFeatureEnabledonAccount'](
 | 
					 | 
				
			||||||
    accountId,
 | 
					 | 
				
			||||||
    FEATURE_FLAGS.WHATSAPP_EMBEDDED_SIGNUP
 | 
					 | 
				
			||||||
  );
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const selectedProvider = computed(() => route.query.provider);
 | 
					const selectedProvider = computed(() => route.query.provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const showProviderSelection = computed(() => !selectedProvider.value);
 | 
					const showProviderSelection = computed(() => !selectedProvider.value);
 | 
				
			||||||
@@ -67,28 +57,15 @@ const selectProvider = providerValue => {
 | 
				
			|||||||
  });
 | 
					  });
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const shouldShowEmbeddedSignup = provider => {
 | 
					const shouldShowCloudWhatsapp = provider => {
 | 
				
			||||||
  // Check if the feature is enabled for the account
 | 
					 | 
				
			||||||
  if (!isWhatsappEmbeddedSignupEnabled.value) {
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  return (
 | 
					  return (
 | 
				
			||||||
    (provider === PROVIDER_TYPES.WHATSAPP && hasWhatsappAppId.value) ||
 | 
					    provider === PROVIDER_TYPES.WHATSAPP_MANUAL ||
 | 
				
			||||||
    provider === PROVIDER_TYPES.WHATSAPP_EMBEDDED
 | 
					    (provider === PROVIDER_TYPES.WHATSAPP && !hasWhatsappAppId.value)
 | 
				
			||||||
  );
 | 
					  );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const shouldShowCloudWhatsapp = provider => {
 | 
					const handleManualLinkClick = () => {
 | 
				
			||||||
  // If embedded signup feature is enabled and app ID is configured, don't show cloud whatsapp
 | 
					  selectProvider(PROVIDER_TYPES.WHATSAPP_MANUAL);
 | 
				
			||||||
  if (isWhatsappEmbeddedSignupEnabled.value && hasWhatsappAppId.value) {
 | 
					 | 
				
			||||||
    return false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  // Show cloud whatsapp when:
 | 
					 | 
				
			||||||
  // 1. Provider is whatsapp AND
 | 
					 | 
				
			||||||
  // 2. Either no app ID is configured OR embedded signup feature is disabled
 | 
					 | 
				
			||||||
  return provider === PROVIDER_TYPES.WHATSAPP;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -117,10 +94,43 @@ const shouldShowCloudWhatsapp = provider => {
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div v-else-if="showConfiguration">
 | 
					    <div v-else-if="showConfiguration">
 | 
				
			||||||
      <WhatsappEmbeddedSignup
 | 
					      <div class="px-6 py-5 rounded-2xl border border-n-weak">
 | 
				
			||||||
        v-if="shouldShowEmbeddedSignup(selectedProvider)"
 | 
					        <!-- Show embedded signup if app ID is configured -->
 | 
				
			||||||
      />
 | 
					        <div
 | 
				
			||||||
 | 
					          v-if="
 | 
				
			||||||
 | 
					            hasWhatsappAppId && selectedProvider === PROVIDER_TYPES.WHATSAPP
 | 
				
			||||||
 | 
					          "
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <WhatsappEmbeddedSignup />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <!-- Manual setup fallback option -->
 | 
				
			||||||
 | 
					          <div class="pt-6 mt-6 border-t border-n-weak">
 | 
				
			||||||
 | 
					            <I18nT
 | 
				
			||||||
 | 
					              keypath="INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.MANUAL_FALLBACK"
 | 
				
			||||||
 | 
					              tag="p"
 | 
				
			||||||
 | 
					              class="text-sm text-n-slate-11"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
 | 
					              <template #link>
 | 
				
			||||||
 | 
					                <a
 | 
				
			||||||
 | 
					                  href="#"
 | 
				
			||||||
 | 
					                  class="underline text-n-brand"
 | 
				
			||||||
 | 
					                  @click.prevent="handleManualLinkClick"
 | 
				
			||||||
 | 
					                >
 | 
				
			||||||
 | 
					                  {{
 | 
				
			||||||
 | 
					                    $t(
 | 
				
			||||||
 | 
					                      'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.MANUAL_LINK_TEXT'
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                  }}
 | 
				
			||||||
 | 
					                </a>
 | 
				
			||||||
 | 
					              </template>
 | 
				
			||||||
 | 
					            </I18nT>
 | 
				
			||||||
 | 
					          </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Show manual setup -->
 | 
				
			||||||
        <CloudWhatsapp v-else-if="shouldShowCloudWhatsapp(selectedProvider)" />
 | 
					        <CloudWhatsapp v-else-if="shouldShowCloudWhatsapp(selectedProvider)" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <!-- Other providers -->
 | 
				
			||||||
        <Twilio
 | 
					        <Twilio
 | 
				
			||||||
          v-else-if="selectedProvider === PROVIDER_TYPES.TWILIO"
 | 
					          v-else-if="selectedProvider === PROVIDER_TYPES.TWILIO"
 | 
				
			||||||
          type="whatsapp"
 | 
					          type="whatsapp"
 | 
				
			||||||
@@ -131,4 +141,5 @@ const shouldShowCloudWhatsapp = provider => {
 | 
				
			|||||||
        <CloudWhatsapp v-else />
 | 
					        <CloudWhatsapp v-else />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,12 +2,13 @@
 | 
				
			|||||||
import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
 | 
					import { ref, computed, onMounted, onBeforeUnmount } from 'vue';
 | 
				
			||||||
import { useStore } from 'vuex';
 | 
					import { useStore } from 'vuex';
 | 
				
			||||||
import { useRouter } from 'vue-router';
 | 
					import { useRouter } from 'vue-router';
 | 
				
			||||||
import { useI18n } from 'vue-i18n';
 | 
					import { useI18n, I18nT } from 'vue-i18n';
 | 
				
			||||||
import { useAlert } from 'dashboard/composables';
 | 
					import { useAlert } from 'dashboard/composables';
 | 
				
			||||||
import Icon from 'next/icon/Icon.vue';
 | 
					import Icon from 'next/icon/Icon.vue';
 | 
				
			||||||
import NextButton from 'next/button/Button.vue';
 | 
					import NextButton from 'next/button/Button.vue';
 | 
				
			||||||
import LoadingState from 'dashboard/components/widgets/LoadingState.vue';
 | 
					import LoadingState from 'dashboard/components/widgets/LoadingState.vue';
 | 
				
			||||||
import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
 | 
					import { parseAPIErrorResponse } from 'dashboard/store/utils/api';
 | 
				
			||||||
 | 
					import globalConstants from 'dashboard/constants/globals.js';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  setupFacebookSdk,
 | 
					  setupFacebookSdk,
 | 
				
			||||||
  initWhatsAppEmbeddedSignup,
 | 
					  initWhatsAppEmbeddedSignup,
 | 
				
			||||||
@@ -28,9 +29,6 @@ const authCode = ref(null);
 | 
				
			|||||||
const businessData = ref(null);
 | 
					const businessData = ref(null);
 | 
				
			||||||
const isAuthenticating = ref(false);
 | 
					const isAuthenticating = ref(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Computed
 | 
					 | 
				
			||||||
const whatsappIconPath = '/assets/images/dashboard/channels/whatsapp.png';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const benefits = computed(() => [
 | 
					const benefits = computed(() => [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
    key: 'EASY_SETUP',
 | 
					    key: 'EASY_SETUP',
 | 
				
			||||||
@@ -235,14 +233,9 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
      <div class="flex flex-col items-start mb-6 text-start">
 | 
					      <div class="flex flex-col items-start mb-6 text-start">
 | 
				
			||||||
        <div class="flex justify-start mb-6">
 | 
					        <div class="flex justify-start mb-6">
 | 
				
			||||||
          <div
 | 
					          <div
 | 
				
			||||||
            class="flex justify-center items-center w-12 h-12 rounded-full bg-n-alpha-2"
 | 
					            class="flex size-11 items-center justify-center rounded-full bg-n-alpha-2"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <img
 | 
					            <Icon icon="i-woot-whatsapp" class="text-n-slate-10 size-6" />
 | 
				
			||||||
              :src="whatsappIconPath"
 | 
					 | 
				
			||||||
              :alt="$t('INBOX_MGMT.ADD.WHATSAPP.PROVIDERS.WHATSAPP_CLOUD')"
 | 
					 | 
				
			||||||
              class="object-contain w-8 h-8"
 | 
					 | 
				
			||||||
              draggable="false"
 | 
					 | 
				
			||||||
            />
 | 
					 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -266,22 +259,26 @@ onBeforeUnmount(() => {
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div class="flex flex-col gap-2 mb-6">
 | 
					      <div class="flex flex-col gap-2 mb-6">
 | 
				
			||||||
        <span class="text-sm text-n-slate-11">
 | 
					        <I18nT
 | 
				
			||||||
          {{ $t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.LEARN_MORE.TEXT') }}
 | 
					          keypath="INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.LEARN_MORE.TEXT"
 | 
				
			||||||
          {{ ' ' }}
 | 
					          tag="span"
 | 
				
			||||||
 | 
					          class="text-sm text-n-slate-11"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					          <template #link>
 | 
				
			||||||
            <a
 | 
					            <a
 | 
				
			||||||
            :href="
 | 
					              :href="globalConstants.WHATSAPP_EMBEDDED_SIGNUP_DOCS_URL"
 | 
				
			||||||
              $t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.LEARN_MORE.LINK_URL')
 | 
					 | 
				
			||||||
            "
 | 
					 | 
				
			||||||
              target="_blank"
 | 
					              target="_blank"
 | 
				
			||||||
              rel="noopener noreferrer"
 | 
					              rel="noopener noreferrer"
 | 
				
			||||||
            class="underline text-primary"
 | 
					              class="underline text-n-brand"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {{
 | 
					              {{
 | 
				
			||||||
              $t('INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.LEARN_MORE.LINK_TEXT')
 | 
					                $t(
 | 
				
			||||||
 | 
					                  'INBOX_MGMT.ADD.WHATSAPP.EMBEDDED_SIGNUP.LEARN_MORE.LINK_TEXT'
 | 
				
			||||||
 | 
					                )
 | 
				
			||||||
              }}
 | 
					              }}
 | 
				
			||||||
            </a>
 | 
					            </a>
 | 
				
			||||||
        </span>
 | 
					          </template>
 | 
				
			||||||
 | 
					        </I18nT>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div class="flex mt-4">
 | 
					      <div class="flex mt-4">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -184,6 +184,7 @@
 | 
				
			|||||||
- name: whatsapp_embedded_signup
 | 
					- name: whatsapp_embedded_signup
 | 
				
			||||||
  display_name: WhatsApp Embedded Signup
 | 
					  display_name: WhatsApp Embedded Signup
 | 
				
			||||||
  enabled: false
 | 
					  enabled: false
 | 
				
			||||||
 | 
					  deprecated: true
 | 
				
			||||||
- name: whatsapp_campaign
 | 
					- name: whatsapp_campaign
 | 
				
			||||||
  display_name: WhatsApp Campaign
 | 
					  display_name: WhatsApp Campaign
 | 
				
			||||||
  enabled: false
 | 
					  enabled: false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,31 +16,7 @@ RSpec.describe 'WhatsApp Authorization API', type: :request do
 | 
				
			|||||||
      let(:agent) { create(:user, account: account, role: :agent) }
 | 
					      let(:agent) { create(:user, account: account, role: :agent) }
 | 
				
			||||||
      let(:administrator) { create(:user, account: account, role: :administrator) }
 | 
					      let(:administrator) { create(:user, account: account, role: :administrator) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'when feature is not enabled' do
 | 
					      context 'when authenticated user makes request' do
 | 
				
			||||||
        before do
 | 
					 | 
				
			||||||
          account.disable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it 'returns forbidden' do
 | 
					 | 
				
			||||||
          post "/api/v1/accounts/#{account.id}/whatsapp/authorization",
 | 
					 | 
				
			||||||
               params: {
 | 
					 | 
				
			||||||
                 code: 'test_code',
 | 
					 | 
				
			||||||
                 business_id: 'test_business_id',
 | 
					 | 
				
			||||||
                 waba_id: 'test_waba_id'
 | 
					 | 
				
			||||||
               },
 | 
					 | 
				
			||||||
               headers: agent.create_new_auth_token,
 | 
					 | 
				
			||||||
               as: :json
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
          expect(response).to have_http_status(:forbidden)
 | 
					 | 
				
			||||||
          expect(response.parsed_body['error']).to eq('WhatsApp embedded signup is not enabled for this account')
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context 'when feature is enabled' do
 | 
					 | 
				
			||||||
        before do
 | 
					 | 
				
			||||||
          account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it 'returns unprocessable entity when code is missing' do
 | 
					        it 'returns unprocessable entity when code is missing' do
 | 
				
			||||||
          post "/api/v1/accounts/#{account.id}/whatsapp/authorization",
 | 
					          post "/api/v1/accounts/#{account.id}/whatsapp/authorization",
 | 
				
			||||||
               params: {
 | 
					               params: {
 | 
				
			||||||
@@ -246,10 +222,6 @@ RSpec.describe 'WhatsApp Authorization API', type: :request do
 | 
				
			|||||||
      context 'when user is not authorized for the account' do
 | 
					      context 'when user is not authorized for the account' do
 | 
				
			||||||
        let(:other_account) { create(:account) }
 | 
					        let(:other_account) { create(:account) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        before do
 | 
					 | 
				
			||||||
          account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it 'returns unauthorized' do
 | 
					        it 'returns unauthorized' do
 | 
				
			||||||
          post "/api/v1/accounts/#{other_account.id}/whatsapp/authorization",
 | 
					          post "/api/v1/accounts/#{other_account.id}/whatsapp/authorization",
 | 
				
			||||||
               params: {
 | 
					               params: {
 | 
				
			||||||
@@ -265,10 +237,6 @@ RSpec.describe 'WhatsApp Authorization API', type: :request do
 | 
				
			|||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      context 'when user is an administrator' do
 | 
					      context 'when user is an administrator' do
 | 
				
			||||||
        before do
 | 
					 | 
				
			||||||
          account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        it 'allows channel creation' do
 | 
					        it 'allows channel creation' do
 | 
				
			||||||
          embedded_signup_service = instance_double(Whatsapp::EmbeddedSignupService)
 | 
					          embedded_signup_service = instance_double(Whatsapp::EmbeddedSignupService)
 | 
				
			||||||
          whatsapp_channel = create(:channel_whatsapp, account: account, validate_provider_config: false, sync_templates: false)
 | 
					          whatsapp_channel = create(:channel_whatsapp, account: account, validate_provider_config: false, sync_templates: false)
 | 
				
			||||||
@@ -321,10 +289,6 @@ RSpec.describe 'WhatsApp Authorization API', type: :request do
 | 
				
			|||||||
    context 'when user is an administrator' do
 | 
					    context 'when user is an administrator' do
 | 
				
			||||||
      let(:administrator) { create(:user, account: account, role: :administrator) }
 | 
					      let(:administrator) { create(:user, account: account, role: :administrator) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      before do
 | 
					 | 
				
			||||||
        account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      context 'with valid parameters' do
 | 
					      context 'with valid parameters' do
 | 
				
			||||||
        let(:valid_params) do
 | 
					        let(:valid_params) do
 | 
				
			||||||
          {
 | 
					          {
 | 
				
			||||||
@@ -489,7 +453,6 @@ RSpec.describe 'WhatsApp Authorization API', type: :request do
 | 
				
			|||||||
      let(:agent) { create(:user, account: account, role: :agent) }
 | 
					      let(:agent) { create(:user, account: account, role: :agent) }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      before do
 | 
					      before do
 | 
				
			||||||
        account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        create(:inbox_member, inbox: whatsapp_inbox, user: agent)
 | 
					        create(:inbox_member, inbox: whatsapp_inbox, user: agent)
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,57 +0,0 @@
 | 
				
			|||||||
require 'rails_helper'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
RSpec.describe Featurable do
 | 
					 | 
				
			||||||
  let(:account) { create(:account) }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  describe 'WhatsApp embedded signup feature' do
 | 
					 | 
				
			||||||
    it 'is disabled by default' do
 | 
					 | 
				
			||||||
      expect(account.feature_whatsapp_embedded_signup?).to be false
 | 
					 | 
				
			||||||
      expect(account.feature_enabled?('whatsapp_embedded_signup')).to be false
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    describe '#enable_features!' do
 | 
					 | 
				
			||||||
      it 'enables the whatsapp embedded signup feature' do
 | 
					 | 
				
			||||||
        account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        expect(account.feature_whatsapp_embedded_signup?).to be true
 | 
					 | 
				
			||||||
        expect(account.feature_enabled?('whatsapp_embedded_signup')).to be true
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it 'enables multiple features at once' do
 | 
					 | 
				
			||||||
        account.enable_features!(:whatsapp_embedded_signup, :help_center)
 | 
					 | 
				
			||||||
        expect(account.feature_whatsapp_embedded_signup?).to be true
 | 
					 | 
				
			||||||
        expect(account.feature_help_center?).to be true
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    describe '#disable_features!' do
 | 
					 | 
				
			||||||
      before do
 | 
					 | 
				
			||||||
        account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it 'disables the whatsapp embedded signup feature' do
 | 
					 | 
				
			||||||
        expect(account.feature_whatsapp_embedded_signup?).to be true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        account.disable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        expect(account.feature_whatsapp_embedded_signup?).to be false
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    describe '#enabled_features' do
 | 
					 | 
				
			||||||
      it 'includes whatsapp_embedded_signup when enabled' do
 | 
					 | 
				
			||||||
        account.enable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        expect(account.enabled_features).to include('whatsapp_embedded_signup' => true)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      it 'does not include whatsapp_embedded_signup when disabled' do
 | 
					 | 
				
			||||||
        account.disable_features!(:whatsapp_embedded_signup)
 | 
					 | 
				
			||||||
        expect(account.enabled_features).not_to include('whatsapp_embedded_signup' => true)
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    describe '#all_features' do
 | 
					 | 
				
			||||||
      it 'includes whatsapp_embedded_signup in all features list' do
 | 
					 | 
				
			||||||
        expect(account.all_features).to have_key('whatsapp_embedded_signup')
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user