From 1535369c24e80d6e47031e60aade49c76731cfc3 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 18 Sep 2024 20:55:16 +0530 Subject: [PATCH 01/91] Initial structure. --- .../connected-google-combo-account-card.js | 57 +++++++++++++++++++ .../google-combo-account-card/index.js | 3 +- 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 js/src/components/google-combo-account-card/connected-google-combo-account-card.js diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js new file mode 100644 index 0000000000..674533122f --- /dev/null +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -0,0 +1,57 @@ + +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import AccountCard, { APPEARANCE } from '../account-card'; +import AppButton from '../app-button'; +import ConnectedIconLabel from '../connected-icon-label'; +import Section from '../../wcdl/section'; +import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; +import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; + +/** + * Renders a Google account card UI with connected account information. + * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. + * + * @param {Object} props React props. + * @param {{ email: string }} props.googleAccount A data payload object containing the user's Google account email. + * + * @fires gla_google_account_connect_different_account_button_click + */ +const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { + const { data: existingMCAccounts, isResolving: MCAccountsResolving } = useExistingGoogleMCAccounts(); + const { existingAccounts: existingAdsAccount, isResolving: AdsAccountsResolving } = useExistingGoogleAdsAccounts(); + + console.log('MCAccountsResolving', MCAccountsResolving); + console.log('existingMCAccount', existingMCAccounts); + //console.log('AdsAccountsResolving', AdsAccountsResolving); + //console.log('existingAdsAccount', existingAdsAccount); + + return ( + } + > + + {} } + /> + + + ); +}; + +export default ConnectedGoogleComboAccountCard; diff --git a/js/src/components/google-combo-account-card/index.js b/js/src/components/google-combo-account-card/index.js index 098fb7b4ef..459234ca60 100644 --- a/js/src/components/google-combo-account-card/index.js +++ b/js/src/components/google-combo-account-card/index.js @@ -7,6 +7,7 @@ import AccountCard from '.~/components/account-card'; import RequestFullAccessGoogleAccountCard from '../google-account-card/request-full-access-google-account-card'; import { ConnectedGoogleAccountCard } from '../google-account-card'; import ConnectGoogleComboAccountCard from './connect-google-combo-account-card'; +import ConnectedGoogleComboAccountCard from './connected-google-combo-account-card'; export default function GoogleComboAccountCard( { disabled = false } ) { const { google, scope, hasFinishedResolution } = useGoogleAccount(); @@ -18,7 +19,7 @@ export default function GoogleComboAccountCard( { disabled = false } ) { const isConnected = google?.active === 'yes'; if ( isConnected && scope.glaRequired ) { - return ; + return ; } if ( isConnected && ! scope.glaRequired ) { From 0d7965c7aa10672c56000a54137f4a6662c595d0 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 19 Sep 2024 16:20:41 +0530 Subject: [PATCH 02/91] Use hooks to determine existing accounts. --- .../connected-google-combo-account-card.js | 56 +++++++++---------- .../create-mc-ads-accounts/index.js | 41 ++++++++++++++ .../google-combo-account-card/index.js | 21 ++++++- .../useCreateMCAccount.js | 2 + js/src/hooks/useApiFetchCallback.js | 2 + 5 files changed, 89 insertions(+), 33 deletions(-) create mode 100644 js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 674533122f..7ef4e3a359 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,55 +1,51 @@ - /** * External dependencies */ +import { createInterpolateElement } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; -import AppButton from '../app-button'; -import ConnectedIconLabel from '../connected-icon-label'; -import Section from '../../wcdl/section'; -import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; -import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; +import CreateMCAdsAccounts from './create-mc-ads-accounts'; + +/** + * Clicking on the "connect to a different Google account" button. + * + * @event gla_google_account_connect_different_account_button_click + */ /** * Renders a Google account card UI with connected account information. * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. * * @param {Object} props React props. - * @param {{ email: string }} props.googleAccount A data payload object containing the user's Google account email. + * @param {{ MCAccount: string }} props.MCAccount The Google Merchant Center account. + * @param {{ AdsAccounts: string }} props.AdsAccounts The Google Ads accounts. * * @fires gla_google_account_connect_different_account_button_click */ -const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { - const { data: existingMCAccounts, isResolving: MCAccountsResolving } = useExistingGoogleMCAccounts(); - const { existingAccounts: existingAdsAccount, isResolving: AdsAccountsResolving } = useExistingGoogleAdsAccounts(); - - console.log('MCAccountsResolving', MCAccountsResolving); - console.log('existingMCAccount', existingMCAccounts); - //console.log('AdsAccountsResolving', AdsAccountsResolving); - //console.log('existingAdsAccount', existingAdsAccount); - +const ConnectedGoogleComboAccountCard = ( { MCAccounts, AdsAccounts } ) => { return ( } + description={ __( + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', + 'google-listings-and-ads' + ) } + helper={ createInterpolateElement( + __( + '

Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.

', + 'google-listings-and-ads' + ), + { + p:

, + } + ) } + indicator={ __( 'Creating…', 'google-listings-and-ads' ) } > - - {} } - /> - + { MCAccounts.length === 0 && AdsAccounts.length === 0 && }
); }; diff --git a/js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js b/js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js new file mode 100644 index 0000000000..b57913af14 --- /dev/null +++ b/js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js @@ -0,0 +1,41 @@ +/** + * External dependencies + */ +import { useEffect, useState } from '@wordpress/element'; +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import useCreateMCAccount from '../../google-mc-account-card/useCreateMCAccount'; +import useUpsertAdsAccount from '../../../hooks/useUpsertAdsAccount'; + +/** + * Create MC and Ads accounts. + */ +const CreateMCAdsAccounts = () => { + const [merchantCenterAccountCreated, setMerchantCenterAccountCreated] = useState( false ); + const [googleAdsAccountCreated, setGoogleAdsAccountCreated] = useState( false ); + + const [ handleCreateMCAccount, { loading, error, response } ] = useCreateMCAccount(); + + useEffect( () => { + if ( ! loading && ! merchantCenterAccountCreated ) { + handleCreateMCAccount(); + setMerchantCenterAccountCreated( true ); + } + + console.log( 'response', response ); + console.log( 'error', error ); + console.log( 'loading', loading ); + }, [ + loading, + response, + error, + merchantCenterAccountCreated, + ]); + + return
Creating MC and Ads account.
+}; + +export default CreateMCAdsAccounts; diff --git a/js/src/components/google-combo-account-card/index.js b/js/src/components/google-combo-account-card/index.js index 459234ca60..ae03d8519d 100644 --- a/js/src/components/google-combo-account-card/index.js +++ b/js/src/components/google-combo-account-card/index.js @@ -5,21 +5,36 @@ import useGoogleAccount from '.~/hooks/useGoogleAccount'; import AppSpinner from '.~/components/app-spinner'; import AccountCard from '.~/components/account-card'; import RequestFullAccessGoogleAccountCard from '../google-account-card/request-full-access-google-account-card'; -import { ConnectedGoogleAccountCard } from '../google-account-card'; import ConnectGoogleComboAccountCard from './connect-google-combo-account-card'; import ConnectedGoogleComboAccountCard from './connected-google-combo-account-card'; +import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; +import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; export default function GoogleComboAccountCard( { disabled = false } ) { const { google, scope, hasFinishedResolution } = useGoogleAccount(); + /* const { data: existingMCAccounts, isResolving: MCAccountsResolving } = + useExistingGoogleMCAccounts(); + const { + existingAccounts: existingAdsAccount, + isResolving: AdsAccountsResolving, + } = useExistingGoogleAdsAccounts(); */ - if ( ! hasFinishedResolution ) { + if ( + ! hasFinishedResolution + ) { return } />; } const isConnected = google?.active === 'yes'; if ( isConnected && scope.glaRequired ) { - return ; + return ( + + ); } if ( isConnected && ! scope.glaRequired ) { diff --git a/js/src/components/google-mc-account-card/useCreateMCAccount.js b/js/src/components/google-mc-account-card/useCreateMCAccount.js index a503f7354d..7af7d4d7e0 100644 --- a/js/src/components/google-mc-account-card/useCreateMCAccount.js +++ b/js/src/components/google-mc-account-card/useCreateMCAccount.js @@ -18,6 +18,8 @@ const useCreateMCAccount = () => { method: 'POST', } ); + console.log( 'result', result ); + const handleCreateAccount = async () => { try { await fetchCreateMCAccount( { diff --git a/js/src/hooks/useApiFetchCallback.js b/js/src/hooks/useApiFetchCallback.js index 433a2ec4f8..886bda107d 100644 --- a/js/src/hooks/useApiFetchCallback.js +++ b/js/src/hooks/useApiFetchCallback.js @@ -143,6 +143,8 @@ const useApiFetchCallback = ( options, initialState = defaultState ) => { parse: false, } ); + console.log( 'useApiFetchCallback response', response ); + const responseClone = response.clone(); const data = responseClone.json && ( await responseClone.json() ); From 9e9b662f6afd26498b54c1f862091ce03819c28c Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 19 Sep 2024 20:35:23 +0530 Subject: [PATCH 03/91] Fix lint. --- .../connected-google-combo-account-card.js | 98 ++++++++++++++----- .../create-accounts/index.js | 55 +++++++++++ .../create-mc-ads-accounts/index.js | 41 -------- .../google-combo-account-card/index.js | 15 ++- .../useCreateMCAccount.js | 2 - js/src/hooks/useApiFetchCallback.js | 2 - tests/e2e/test-snippets/test-snippets.php | 4 + 7 files changed, 139 insertions(+), 78 deletions(-) create mode 100644 js/src/components/google-combo-account-card/create-accounts/index.js delete mode 100644 js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 7ef4e3a359..9cef4da0ea 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,14 +1,18 @@ /** * External dependencies */ -import { createInterpolateElement } from '@wordpress/element'; +import { + createInterpolateElement, + useEffect, + useState, +} from '@wordpress/element'; import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; -import CreateMCAdsAccounts from './create-mc-ads-accounts'; +import CreateAccounts from './create-accounts'; /** * Clicking on the "connect to a different Google account" button. @@ -21,33 +25,77 @@ import CreateMCAdsAccounts from './create-mc-ads-accounts'; * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. * * @param {Object} props React props. - * @param {{ MCAccount: string }} props.MCAccount The Google Merchant Center account. + * @param {{ googleAccount: object }} props.googleAccount The Google account. + * @param {{ MCAccounts: string }} props.MCAccounts The Google Merchant Center account. * @param {{ AdsAccounts: string }} props.AdsAccounts The Google Ads accounts. * * @fires gla_google_account_connect_different_account_button_click */ -const ConnectedGoogleComboAccountCard = ( { MCAccounts, AdsAccounts } ) => { - return ( - Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.

', - 'google-listings-and-ads' - ), - { - p:

, - } - ) } - indicator={ __( 'Creating…', 'google-listings-and-ads' ) } - > - { MCAccounts.length === 0 && AdsAccounts.length === 0 && } -
- ); +const ConnectedGoogleComboAccountCard = ( { + googleAccount, + MCAccounts, + AdsAccounts, +} ) => { + const [ accounts, setAccounts ] = useState( { + MCAccounts, + AdsAccounts, + } ); + + useEffect( () => { + if ( MCAccounts.length ) { + setAccounts( { + ...accounts, + MCAccounts, + } ); + } + + if ( AdsAccounts.length ) { + setAccounts( { + ...accounts, + AdsAccounts, + } ); + } + }, [ MCAccounts, AdsAccounts, accounts ] ); + + const existingAccounts = Object.keys( accounts ).some( + ( account ) => accounts[ account ].length > 0 + ); + + const description = ! existingAccounts + ? createInterpolateElement( + __( + '

You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.

', + 'google-listings-and-ads' + ), + { + p:

, + } + ) + : ''; + + return ( + Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.

', + 'google-listings-and-ads' + ), + { + p:

, + } + ) } + indicator={ 'Creating...' } + > + { ! existingAccounts && ( + + ) } +
+ ); }; export default ConnectedGoogleComboAccountCard; diff --git a/js/src/components/google-combo-account-card/create-accounts/index.js b/js/src/components/google-combo-account-card/create-accounts/index.js new file mode 100644 index 0000000000..ce0950221f --- /dev/null +++ b/js/src/components/google-combo-account-card/create-accounts/index.js @@ -0,0 +1,55 @@ +/** + * External dependencies + */ +import { useEffect } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import useCreateMCAccount from '../../google-mc-account-card/useCreateMCAccount'; +import useUpsertAdsAccount from '../../../hooks/useUpsertAdsAccount'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; + +/** + * Create MC and Ads accounts. + */ +const CreateAccounts = ( { setAccounts } ) => { + const { googleAdsAccount } = useGoogleAdsAccount(); + + const [ handleCreateAccount, { loading, response } ] = useCreateMCAccount(); + const [ , { loading: adsAccountsLoading } ] = useUpsertAdsAccount(); + + useEffect( () => { + console.log( 'googleAdsAccount', googleAdsAccount ); + console.log( 'response', response ); + + if ( + ! loading && + ! adsAccountsLoading && + response && + response.status === 200 + ) { + const createMCAccount = async () => { + await handleCreateAccount(); + }; + + createMCAccount(); + + setAccounts( { + MCAccounts: [ response.data ], + AdsAccounts: [ googleAdsAccount.id ], + } ); + } + }, [ + loading, + adsAccountsLoading, + response, + handleCreateAccount, + googleAdsAccount, + setAccounts, + ] ); + + return null; +}; + +export default CreateAccounts; diff --git a/js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js b/js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js deleted file mode 100644 index b57913af14..0000000000 --- a/js/src/components/google-combo-account-card/create-mc-ads-accounts/index.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * External dependencies - */ -import { useEffect, useState } from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; - -/** - * Internal dependencies - */ -import useCreateMCAccount from '../../google-mc-account-card/useCreateMCAccount'; -import useUpsertAdsAccount from '../../../hooks/useUpsertAdsAccount'; - -/** - * Create MC and Ads accounts. - */ -const CreateMCAdsAccounts = () => { - const [merchantCenterAccountCreated, setMerchantCenterAccountCreated] = useState( false ); - const [googleAdsAccountCreated, setGoogleAdsAccountCreated] = useState( false ); - - const [ handleCreateMCAccount, { loading, error, response } ] = useCreateMCAccount(); - - useEffect( () => { - if ( ! loading && ! merchantCenterAccountCreated ) { - handleCreateMCAccount(); - setMerchantCenterAccountCreated( true ); - } - - console.log( 'response', response ); - console.log( 'error', error ); - console.log( 'loading', loading ); - }, [ - loading, - response, - error, - merchantCenterAccountCreated, - ]); - - return
Creating MC and Ads account.
-}; - -export default CreateMCAdsAccounts; diff --git a/js/src/components/google-combo-account-card/index.js b/js/src/components/google-combo-account-card/index.js index ae03d8519d..c76f2ff5a7 100644 --- a/js/src/components/google-combo-account-card/index.js +++ b/js/src/components/google-combo-account-card/index.js @@ -12,15 +12,14 @@ import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; export default function GoogleComboAccountCard( { disabled = false } ) { const { google, scope, hasFinishedResolution } = useGoogleAccount(); - /* const { data: existingMCAccounts, isResolving: MCAccountsResolving } = - useExistingGoogleMCAccounts(); - const { - existingAccounts: existingAdsAccount, - isResolving: AdsAccountsResolving, - } = useExistingGoogleAdsAccounts(); */ + const { isResolving: MCAccountsResolving } = useExistingGoogleMCAccounts(); + const { isResolving: AdsAccountsResolving } = + useExistingGoogleAdsAccounts(); if ( - ! hasFinishedResolution + ! hasFinishedResolution || + MCAccountsResolving || + AdsAccountsResolving ) { return } />; } @@ -31,7 +30,7 @@ export default function GoogleComboAccountCard( { disabled = false } ) { return ( ); diff --git a/js/src/components/google-mc-account-card/useCreateMCAccount.js b/js/src/components/google-mc-account-card/useCreateMCAccount.js index 7af7d4d7e0..a503f7354d 100644 --- a/js/src/components/google-mc-account-card/useCreateMCAccount.js +++ b/js/src/components/google-mc-account-card/useCreateMCAccount.js @@ -18,8 +18,6 @@ const useCreateMCAccount = () => { method: 'POST', } ); - console.log( 'result', result ); - const handleCreateAccount = async () => { try { await fetchCreateMCAccount( { diff --git a/js/src/hooks/useApiFetchCallback.js b/js/src/hooks/useApiFetchCallback.js index 886bda107d..433a2ec4f8 100644 --- a/js/src/hooks/useApiFetchCallback.js +++ b/js/src/hooks/useApiFetchCallback.js @@ -143,8 +143,6 @@ const useApiFetchCallback = ( options, initialState = defaultState ) => { parse: false, } ); - console.log( 'useApiFetchCallback response', response ); - const responseClone = response.clone(); const data = responseClone.json && ( await responseClone.json() ); diff --git a/tests/e2e/test-snippets/test-snippets.php b/tests/e2e/test-snippets/test-snippets.php index ebb9b0f710..9590895767 100644 --- a/tests/e2e/test-snippets/test-snippets.php +++ b/tests/e2e/test-snippets/test-snippets.php @@ -40,3 +40,7 @@ function ( array $value_options ) { return $value_options; } ); + +add_filter( 'woocommerce_gla_ads_billing_setup_status', function( $status ) { + return 'approved'; +} ); From c5023b6b37874c7bfdb9f123029c99f8079f73e0 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 20 Sep 2024 14:24:50 +0530 Subject: [PATCH 04/91] Fix: CreateAccounts component. Multiple API calls. --- .../connected-google-combo-account-card.js | 108 +++++++++++------- .../create-accounts/index.js | 55 ++++----- .../google-combo-account-card/index.js | 11 +- 3 files changed, 88 insertions(+), 86 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 9cef4da0ea..aa95517b4d 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,18 +1,19 @@ /** * External dependencies */ -import { - createInterpolateElement, - useEffect, - useState, -} from '@wordpress/element'; -import { __ } from '@wordpress/i18n'; +import { createInterpolateElement, useState } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; import CreateAccounts from './create-accounts'; +import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; +import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; +import AppSpinner from '../app-spinner'; /** * Clicking on the "connect to a different Google account" button. @@ -26,43 +27,43 @@ import CreateAccounts from './create-accounts'; * * @param {Object} props React props. * @param {{ googleAccount: object }} props.googleAccount The Google account. - * @param {{ MCAccounts: string }} props.MCAccounts The Google Merchant Center account. - * @param {{ AdsAccounts: string }} props.AdsAccounts The Google Ads accounts. * * @fires gla_google_account_connect_different_account_button_click */ -const ConnectedGoogleComboAccountCard = ( { - googleAccount, - MCAccounts, - AdsAccounts, -} ) => { - const [ accounts, setAccounts ] = useState( { - MCAccounts, - AdsAccounts, - } ); +const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { + const [ isCreatingAccounts, setIsCreatingAccounts ] = useState( false ); - useEffect( () => { - if ( MCAccounts.length ) { - setAccounts( { - ...accounts, - MCAccounts, - } ); - } + const { + data: existingMCAccounts, + hasFinishedResolution: hasFinishedResolutionForExistingMCAccounts, + } = useExistingGoogleMCAccounts(); + const { + existingAccounts: existingAdsAccount, + isResolving: isResolvingExistingAdsAccount, + } = useExistingGoogleAdsAccounts(); - if ( AdsAccounts.length ) { - setAccounts( { - ...accounts, - AdsAccounts, - } ); - } - }, [ MCAccounts, AdsAccounts, accounts ] ); + const { + googleMCAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, + } = useGoogleMCAccount(); + const { + googleAdsAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, + } = useGoogleAdsAccount(); - const existingAccounts = Object.keys( accounts ).some( - ( account ) => accounts[ account ].length > 0 - ); + if ( + ! hasFinishedResolutionForExistingMCAccounts || + isResolvingExistingAdsAccount + ) { + return } />; + } - const description = ! existingAccounts - ? createInterpolateElement( + const existingAccounts = + existingMCAccounts?.length || existingAdsAccount?.length; + + const Description = () => { + if ( isCreatingAccounts ) { + return createInterpolateElement( __( '

You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.

', 'google-listings-and-ads' @@ -70,13 +71,37 @@ const ConnectedGoogleComboAccountCard = ( { { p:

, } - ) - : ''; + ); + } + + return ( + <> +

{ googleAccount?.email }

+

+ { sprintf( + // Translators: %s is the Merchant Center ID + __( + 'Merchant Center ID: %s', + 'google-listings-and-ads' + ), + googleMCAccount?.id + ) } +

+

+ { sprintf( + // Translators: %s is the Google Ads ID + __( 'Google Ads ID: %s', 'google-listings-and-ads' ), + googleAdsAccount?.id + ) } +

+ + ); + }; return ( } helper={ createInterpolateElement( __( '

Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.

', @@ -86,12 +111,11 @@ const ConnectedGoogleComboAccountCard = ( { p:

, } ) } - indicator={ 'Creating...' } + indicator={ isCreatingAccounts ? 'Creating...' : null } > { ! existingAccounts && ( ) }
diff --git a/js/src/components/google-combo-account-card/create-accounts/index.js b/js/src/components/google-combo-account-card/create-accounts/index.js index ce0950221f..d044197834 100644 --- a/js/src/components/google-combo-account-card/create-accounts/index.js +++ b/js/src/components/google-combo-account-card/create-accounts/index.js @@ -7,47 +7,34 @@ import { useEffect } from '@wordpress/element'; * Internal dependencies */ import useCreateMCAccount from '../../google-mc-account-card/useCreateMCAccount'; -import useUpsertAdsAccount from '../../../hooks/useUpsertAdsAccount'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; +import { receiveMCAccount } from '.~/data/actions'; /** * Create MC and Ads accounts. */ -const CreateAccounts = ( { setAccounts } ) => { - const { googleAdsAccount } = useGoogleAdsAccount(); +const CreateAccounts = ( { setIsCreatingAccounts } ) => { + const [ handleCreateAccount, { data: account, response } ] = + useCreateMCAccount(); - const [ handleCreateAccount, { loading, response } ] = useCreateMCAccount(); - const [ , { loading: adsAccountsLoading } ] = useUpsertAdsAccount(); + const [ upsertAdsAccount ] = useUpsertAdsAccount(); + + if ( response?.status === 200 ) { + receiveMCAccount( account ); + setIsCreatingAccounts( false ); + } useEffect( () => { - console.log( 'googleAdsAccount', googleAdsAccount ); - console.log( 'response', response ); - - if ( - ! loading && - ! adsAccountsLoading && - response && - response.status === 200 - ) { - const createMCAccount = async () => { - await handleCreateAccount(); - }; - - createMCAccount(); - - setAccounts( { - MCAccounts: [ response.data ], - AdsAccounts: [ googleAdsAccount.id ], - } ); - } - }, [ - loading, - adsAccountsLoading, - response, - handleCreateAccount, - googleAdsAccount, - setAccounts, - ] ); + setIsCreatingAccounts( true ); + + const createAccounts = async () => { + await handleCreateAccount(); + await upsertAdsAccount(); + }; + + createAccounts(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [] ); return null; }; diff --git a/js/src/components/google-combo-account-card/index.js b/js/src/components/google-combo-account-card/index.js index c76f2ff5a7..cf5219a5f0 100644 --- a/js/src/components/google-combo-account-card/index.js +++ b/js/src/components/google-combo-account-card/index.js @@ -7,20 +7,11 @@ import AccountCard from '.~/components/account-card'; import RequestFullAccessGoogleAccountCard from '../google-account-card/request-full-access-google-account-card'; import ConnectGoogleComboAccountCard from './connect-google-combo-account-card'; import ConnectedGoogleComboAccountCard from './connected-google-combo-account-card'; -import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; -import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; export default function GoogleComboAccountCard( { disabled = false } ) { const { google, scope, hasFinishedResolution } = useGoogleAccount(); - const { isResolving: MCAccountsResolving } = useExistingGoogleMCAccounts(); - const { isResolving: AdsAccountsResolving } = - useExistingGoogleAdsAccounts(); - if ( - ! hasFinishedResolution || - MCAccountsResolving || - AdsAccountsResolving - ) { + if ( ! hasFinishedResolution ) { return } />; } From d41d82508776e01fc903630a2ad5d4999ed9df09 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 20 Sep 2024 14:26:37 +0530 Subject: [PATCH 05/91] Remove redundant props. --- js/src/components/google-combo-account-card/index.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/js/src/components/google-combo-account-card/index.js b/js/src/components/google-combo-account-card/index.js index cf5219a5f0..2bc42e0395 100644 --- a/js/src/components/google-combo-account-card/index.js +++ b/js/src/components/google-combo-account-card/index.js @@ -18,13 +18,7 @@ export default function GoogleComboAccountCard( { disabled = false } ) { const isConnected = google?.active === 'yes'; if ( isConnected && scope.glaRequired ) { - return ( - - ); + return ; } if ( isConnected && ! scope.glaRequired ) { From 41e6d04ea7e2de376a18e2db7115ad59509f4981 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Mon, 23 Sep 2024 13:08:42 +0530 Subject: [PATCH 06/91] Remove redundant code. --- tests/e2e/test-snippets/test-snippets.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/e2e/test-snippets/test-snippets.php b/tests/e2e/test-snippets/test-snippets.php index 9590895767..ebb9b0f710 100644 --- a/tests/e2e/test-snippets/test-snippets.php +++ b/tests/e2e/test-snippets/test-snippets.php @@ -40,7 +40,3 @@ function ( array $value_options ) { return $value_options; } ); - -add_filter( 'woocommerce_gla_ads_billing_setup_status', function( $status ) { - return 'approved'; -} ); From 691733719effdb8f0c8c646f4d82938d4758132f Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Mon, 23 Sep 2024 23:21:43 +0530 Subject: [PATCH 07/91] Introduce hook. --- .../connect-google-combo-account-card.scss | 7 ++ .../connected-google-combo-account-card.js | 37 +++----- .../create-accounts/index.js | 42 --------- .../useCreateAccounts.js | 87 +++++++++++++++++++ 4 files changed, 104 insertions(+), 69 deletions(-) delete mode 100644 js/src/components/google-combo-account-card/create-accounts/index.js create mode 100644 js/src/components/google-combo-account-card/useCreateAccounts.js diff --git a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss index 9260eecaf1..0f29e4ba01 100644 --- a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss @@ -3,4 +3,11 @@ .gla-account-card__helper { font-size: $gla-font-base; } + + &.gla-connected-google-combo-account-card { + + .gla-account-card__description { + gap: 0; + } + } } diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index aa95517b4d..6ef60d03a2 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,19 +1,17 @@ /** * External dependencies */ -import { createInterpolateElement, useState } from '@wordpress/element'; +import { createInterpolateElement } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; /** * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; -import CreateAccounts from './create-accounts'; -import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; -import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import AppSpinner from '../app-spinner'; +import useCreateAccounts from './useCreateAccounts'; /** * Clicking on the "connect to a different Google account" button. @@ -31,36 +29,26 @@ import AppSpinner from '../app-spinner'; * @fires gla_google_account_connect_different_account_button_click */ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { - const [ isCreatingAccounts, setIsCreatingAccounts ] = useState( false ); - - const { - data: existingMCAccounts, - hasFinishedResolution: hasFinishedResolutionForExistingMCAccounts, - } = useExistingGoogleMCAccounts(); - const { - existingAccounts: existingAdsAccount, - isResolving: isResolvingExistingAdsAccount, - } = useExistingGoogleAdsAccounts(); - const { googleMCAccount, hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, } = useGoogleMCAccount(); + const { googleAdsAccount, hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, } = useGoogleAdsAccount(); + const { accountCreationResolved, isCreatingAccounts } = useCreateAccounts(); + if ( - ! hasFinishedResolutionForExistingMCAccounts || - isResolvingExistingAdsAccount + ! hasFinishedResolutionForCurrentMCAccount || + ! hasFinishedResolutionForCurrentAdsAccount || + ! accountCreationResolved ) { return } />; } - const existingAccounts = - existingMCAccounts?.length || existingAdsAccount?.length; - const Description = () => { if ( isCreatingAccounts ) { return createInterpolateElement( @@ -101,6 +89,7 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { return ( } helper={ createInterpolateElement( __( @@ -112,13 +101,7 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { } ) } indicator={ isCreatingAccounts ? 'Creating...' : null } - > - { ! existingAccounts && ( - - ) } - + /> ); }; diff --git a/js/src/components/google-combo-account-card/create-accounts/index.js b/js/src/components/google-combo-account-card/create-accounts/index.js deleted file mode 100644 index d044197834..0000000000 --- a/js/src/components/google-combo-account-card/create-accounts/index.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * External dependencies - */ -import { useEffect } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import useCreateMCAccount from '../../google-mc-account-card/useCreateMCAccount'; -import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; -import { receiveMCAccount } from '.~/data/actions'; - -/** - * Create MC and Ads accounts. - */ -const CreateAccounts = ( { setIsCreatingAccounts } ) => { - const [ handleCreateAccount, { data: account, response } ] = - useCreateMCAccount(); - - const [ upsertAdsAccount ] = useUpsertAdsAccount(); - - if ( response?.status === 200 ) { - receiveMCAccount( account ); - setIsCreatingAccounts( false ); - } - - useEffect( () => { - setIsCreatingAccounts( true ); - - const createAccounts = async () => { - await handleCreateAccount(); - await upsertAdsAccount(); - }; - - createAccounts(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [] ); - - return null; -}; - -export default CreateAccounts; diff --git a/js/src/components/google-combo-account-card/useCreateAccounts.js b/js/src/components/google-combo-account-card/useCreateAccounts.js new file mode 100644 index 0000000000..341e57ec6f --- /dev/null +++ b/js/src/components/google-combo-account-card/useCreateAccounts.js @@ -0,0 +1,87 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +/** + * External dependencies + */ +import { useEffect, useRef } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import useCreateMCAccount from '../google-mc-account-card/useCreateMCAccount'; +import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; +import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; +import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; +import { receiveMCAccount } from '.~/data/actions'; +import { useAppDispatch } from '.~/data'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; + +/** + * Custom hook to handle the creation of MC and Ads accounts. + */ +const useCreateAccounts = () => { + const accountCreationResolvedRef = useRef( false ); + const isCreatingAccountsRef = useRef( false ); + + const { + googleAdsAccount, + hasFinishedResolution: hasFinishedResolutionForExistingAdsccounts, + } = useGoogleAdsAccount(); + + const { + data: existingMCAccounts, + hasFinishedResolution: hasFinishedResolutionForExistingMCAccounts, + } = useExistingGoogleMCAccounts(); + + const { + existingAccounts: existingAdsAccount, + isResolving: isResolvingExistingAdsAccount, + } = useExistingGoogleAdsAccounts(); + + const [ handleCreateAccount, { data: account, response } ] = + useCreateMCAccount(); + + const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); + const { invalidateResolution } = useAppDispatch(); + + // Process account creation completion. + useEffect( () => { + if ( response?.status === 200 && ! loading ) { + receiveMCAccount( account ); + invalidateResolution( 'getExistingGoogleAdsAccounts' ); + isCreatingAccountsRef.current = false; + } + }, [ response, loading ] ); + + useEffect( () => { + if ( + ! isResolvingExistingAdsAccount && + hasFinishedResolutionForExistingMCAccounts && + isCreatingAccountsRef.current === false && + accountCreationResolvedRef.current === false && + account === undefined + ) { + accountCreationResolvedRef.current = true; + const hasExistingAccounts = true; + + if ( ! hasExistingAccounts ) { + const createAccounts = async () => { + await handleCreateAccount(); + await upsertAdsAccount(); + }; + + isCreatingAccountsRef.current = true; + createAccounts(); + } + } + }, [ + isResolvingExistingAdsAccount, + hasFinishedResolutionForExistingMCAccounts, + ] ); + + return { + isCreatingAccounts: isCreatingAccountsRef.current, + accountCreationResolved: accountCreationResolvedRef.current, + }; +}; + +export default useCreateAccounts; From d1b4c7774caf6fd01fb9a944b9e658b1771a2905 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 24 Sep 2024 00:17:08 +0530 Subject: [PATCH 08/91] Fix: Flicker in component due to resolution state. --- .../connected-google-combo-account-card.js | 20 +++++++++++++------ .../useCreateAccounts.js | 12 +++++++++-- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 6ef60d03a2..8cfd132bcc 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -39,18 +39,26 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, } = useGoogleAdsAccount(); - const { accountCreationResolved, isCreatingAccounts } = useCreateAccounts(); + const { accountsCreated, accountCreationResolved, isCreatingAccounts } = + useCreateAccounts(); if ( - ! hasFinishedResolutionForCurrentMCAccount || - ! hasFinishedResolutionForCurrentAdsAccount || - ! accountCreationResolved + ! accountsCreated && + ( ! hasFinishedResolutionForCurrentAdsAccount || + ! hasFinishedResolutionForCurrentMCAccount || + ! accountCreationResolved ) ) { return } />; } + const creatingAccounts = + isCreatingAccounts || + ( accountsCreated && + ( ! hasFinishedResolutionForCurrentMCAccount || + ! hasFinishedResolutionForCurrentAdsAccount ) ); + const Description = () => { - if ( isCreatingAccounts ) { + if ( creatingAccounts ) { return createInterpolateElement( __( '

You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.

', @@ -100,7 +108,7 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { p:

, } ) } - indicator={ isCreatingAccounts ? 'Creating...' : null } + indicator={ creatingAccounts ? 'Creating...' : null } /> ); }; diff --git a/js/src/components/google-combo-account-card/useCreateAccounts.js b/js/src/components/google-combo-account-card/useCreateAccounts.js index 341e57ec6f..bd50116b2f 100644 --- a/js/src/components/google-combo-account-card/useCreateAccounts.js +++ b/js/src/components/google-combo-account-card/useCreateAccounts.js @@ -21,6 +21,7 @@ import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; const useCreateAccounts = () => { const accountCreationResolvedRef = useRef( false ); const isCreatingAccountsRef = useRef( false ); + const accountsCreatedRef = useRef( false ); const { googleAdsAccount, @@ -49,6 +50,7 @@ const useCreateAccounts = () => { receiveMCAccount( account ); invalidateResolution( 'getExistingGoogleAdsAccounts' ); isCreatingAccountsRef.current = false; + accountsCreatedRef.current = true; } }, [ response, loading ] ); @@ -58,10 +60,14 @@ const useCreateAccounts = () => { hasFinishedResolutionForExistingMCAccounts && isCreatingAccountsRef.current === false && accountCreationResolvedRef.current === false && - account === undefined + account === undefined && + ! googleAdsAccount && + ! hasFinishedResolutionForExistingAdsccounts ) { accountCreationResolvedRef.current = true; - const hasExistingAccounts = true; + const hasExistingAccounts = + existingMCAccounts?.length > 0 && + existingAdsAccount?.length > 0; if ( ! hasExistingAccounts ) { const createAccounts = async () => { @@ -70,6 +76,7 @@ const useCreateAccounts = () => { }; isCreatingAccountsRef.current = true; + accountsCreatedRef.current = false; createAccounts(); } } @@ -81,6 +88,7 @@ const useCreateAccounts = () => { return { isCreatingAccounts: isCreatingAccountsRef.current, accountCreationResolved: accountCreationResolvedRef.current, + accountsCreated: accountsCreatedRef.current, }; }; From b9977132234e7843231a621b33df2295fb25d9f3 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 24 Sep 2024 18:53:27 +0530 Subject: [PATCH 09/91] Update account creation checks. --- .../useCreateAccounts.js | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/js/src/components/google-combo-account-card/useCreateAccounts.js b/js/src/components/google-combo-account-card/useCreateAccounts.js index bd50116b2f..db1eaefd5e 100644 --- a/js/src/components/google-combo-account-card/useCreateAccounts.js +++ b/js/src/components/google-combo-account-card/useCreateAccounts.js @@ -12,7 +12,6 @@ import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; import { receiveMCAccount } from '.~/data/actions'; -import { useAppDispatch } from '.~/data'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; /** @@ -25,7 +24,8 @@ const useCreateAccounts = () => { const { googleAdsAccount, - hasFinishedResolution: hasFinishedResolutionForExistingAdsccounts, + hasFinishedResolution: hasFinishedResolutionForExistingAdsccount, + refetchGoogleAdsAccount, } = useGoogleAdsAccount(); const { @@ -42,29 +42,31 @@ const useCreateAccounts = () => { useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - const { invalidateResolution } = useAppDispatch(); // Process account creation completion. useEffect( () => { if ( response?.status === 200 && ! loading ) { receiveMCAccount( account ); - invalidateResolution( 'getExistingGoogleAdsAccounts' ); + refetchGoogleAdsAccount(); isCreatingAccountsRef.current = false; accountsCreatedRef.current = true; } }, [ response, loading ] ); useEffect( () => { - if ( + const existingAccountsResolved = ! isResolvingExistingAdsAccount && - hasFinishedResolutionForExistingMCAccounts && + hasFinishedResolutionForExistingMCAccounts; + + accountCreationResolvedRef.current = existingAccountsResolved; + + if ( + existingAccountsResolved && isCreatingAccountsRef.current === false && - accountCreationResolvedRef.current === false && account === undefined && - ! googleAdsAccount && - ! hasFinishedResolutionForExistingAdsccounts + hasFinishedResolutionForExistingAdsccount && + googleAdsAccount.id === 0 ) { - accountCreationResolvedRef.current = true; const hasExistingAccounts = existingMCAccounts?.length > 0 && existingAdsAccount?.length > 0; From d293f15beae10e6049bbc25bebf46d3ec7e41be6 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 25 Sep 2024 13:09:25 +0530 Subject: [PATCH 10/91] Update name for resolved checks property. --- .../connected-google-combo-account-card.js | 9 ++++++--- .../google-combo-account-card/useCreateAccounts.js | 10 +++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 8cfd132bcc..3332ee83d7 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -39,14 +39,17 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, } = useGoogleAdsAccount(); - const { accountsCreated, accountCreationResolved, isCreatingAccounts } = - useCreateAccounts(); + const { + accountsCreated, + accountCreationChecksResolved, + isCreatingAccounts, + } = useCreateAccounts(); if ( ! accountsCreated && ( ! hasFinishedResolutionForCurrentAdsAccount || ! hasFinishedResolutionForCurrentMCAccount || - ! accountCreationResolved ) + ! accountCreationChecksResolved ) ) { return } />; } diff --git a/js/src/components/google-combo-account-card/useCreateAccounts.js b/js/src/components/google-combo-account-card/useCreateAccounts.js index db1eaefd5e..d58cb93eb8 100644 --- a/js/src/components/google-combo-account-card/useCreateAccounts.js +++ b/js/src/components/google-combo-account-card/useCreateAccounts.js @@ -11,21 +11,19 @@ import useCreateMCAccount from '../google-mc-account-card/useCreateMCAccount'; import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; -import { receiveMCAccount } from '.~/data/actions'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; /** * Custom hook to handle the creation of MC and Ads accounts. */ const useCreateAccounts = () => { - const accountCreationResolvedRef = useRef( false ); + const accountCreationChecksResolvedRef = useRef( false ); const isCreatingAccountsRef = useRef( false ); const accountsCreatedRef = useRef( false ); const { googleAdsAccount, hasFinishedResolution: hasFinishedResolutionForExistingAdsccount, - refetchGoogleAdsAccount, } = useGoogleAdsAccount(); const { @@ -46,8 +44,6 @@ const useCreateAccounts = () => { // Process account creation completion. useEffect( () => { if ( response?.status === 200 && ! loading ) { - receiveMCAccount( account ); - refetchGoogleAdsAccount(); isCreatingAccountsRef.current = false; accountsCreatedRef.current = true; } @@ -58,7 +54,7 @@ const useCreateAccounts = () => { ! isResolvingExistingAdsAccount && hasFinishedResolutionForExistingMCAccounts; - accountCreationResolvedRef.current = existingAccountsResolved; + accountCreationChecksResolvedRef.current = existingAccountsResolved; if ( existingAccountsResolved && @@ -89,7 +85,7 @@ const useCreateAccounts = () => { return { isCreatingAccounts: isCreatingAccountsRef.current, - accountCreationResolved: accountCreationResolvedRef.current, + accountCreationChecksResolved: accountCreationChecksResolvedRef.current, accountsCreated: accountsCreatedRef.current, }; }; From 9ef6c13928e12587acba13e6a5276058d97e2aa4 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 25 Sep 2024 16:54:48 +0530 Subject: [PATCH 11/91] E2E tests. --- .../specs/setup-mc/step-1-accounts.test.js | 62 +++++++++++++++++++ tests/e2e/utils/mock-requests.js | 46 ++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 1e8b0cf552..de4c235120 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -218,6 +218,68 @@ test.describe( 'Set up accounts', () => { expect( page.url() ).toMatch( baseURL + 'google_auth' ); } ); + + test( 'should create merchant center and ads account if does not exist for the user', async () => { + await setUpAccountsPage.mockJetpackConnected(); + await setUpAccountsPage.mockGoogleConnected(); + + await setupAdsAccountPage.fulfillAdsAccountsRequests( [ + { + id: 0, + currency: 'USD', + status: 'disconnected', + symbol: '$', + }, + { + id: 119119119, + currency: 'USD', + status: 'disconnected', + symbol: '$', + }, + ] ); + + await setupAdsAccountPage.fulfillMCAccountsRequests( [ + [], + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ] ); + + await setUpAccountsPage.goto(); + const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); + + await expect( + googleAccountCard.getByText( + /You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you./, + { + exact: true, + } + ) + ).toBeVisible(); + } ); + + test( 'should see the merchant center id and ads account id if connected', async () => { + await setUpAccountsPage.mockGoogleConnected(); + await setUpAccountsPage.mockAdsAccountConnected(); + await setUpAccountsPage.mockMCConnected(); + await setUpAccountsPage.goto(); + + const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); + await expect( + googleAccountCard.getByText( 'Merchant Center ID: 1234', { + exact: true, + } ) + ).toBeVisible(); + + await expect( + googleAccountCard.getByText( 'Google Ads ID: 12345', { + exact: true, + } ) + ).toBeVisible(); + } ); } ); test.describe( 'Continue button', () => { diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index 050da0bc4e..a94caebe59 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -38,6 +38,32 @@ export default class MockRequests { } ); } + /** + * Send the different response for each time the route is called. + * + * @param {RegExp|string} url The url to fulfill. + * @param {Array} payloads The payload to send. + * @param {number} status The HTTP status in the response. + * @return {Promise} + */ + async fulfillRequests( url, payloads = [], status = 200 ) { + let callCount = 0; + await this.page.route( url, ( route ) => { + if ( callCount < payloads.length ) { + route.fulfill( { + status, + contentType: 'application/json', + headers: { 'Access-Control-Allow-Origin': '*' }, + body: JSON.stringify( payloads[ callCount ] ), + } ); + } else { + // Optionally handle additional calls beyond the responses array + route.continue(); + } + callCount += 1; + } ); + } + /** * Fulfill the WC options default country request. * @@ -110,6 +136,16 @@ export default class MockRequests { ); } + /** + * Fulfill the MC accounts requests. + * + * @param {Object} payloads + * @return {Promise} + */ + async fulfillMCAccountsRequests( payloads ) { + await this.fulfillRequests( /\/wc\/gla\/mc\/accounts\b/, payloads ); + } + /** * Fulfill the MC accounts claim-overwrite request. * @@ -222,6 +258,16 @@ export default class MockRequests { await this.fulfillRequest( /\/wc\/gla\/ads\/accounts\b/, payload ); } + /** + * Fulfill the Ads Account requests. + * + * @param {Object} payloads + * @return {Promise} + */ + async fulfillAdsAccountsRequests( payloads ) { + await this.fulfillRequests( /\/wc\/gla\/ads\/accounts\b/, payloads ); + } + /** * Fulfill the Ads Account Status request. * From 767a9066c40f18b8c448c20c6d29f0afb4dab0f5 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 25 Sep 2024 17:30:28 +0530 Subject: [PATCH 12/91] Move hook to hooks directory. --- .../connected-google-combo-account-card.js | 2 +- .../google-combo-account-card => hooks}/useCreateAccounts.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename js/src/{components/google-combo-account-card => hooks}/useCreateAccounts.js (94%) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 3332ee83d7..8cb5fcf9e9 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -11,7 +11,7 @@ import AccountCard, { APPEARANCE } from '../account-card'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import AppSpinner from '../app-spinner'; -import useCreateAccounts from './useCreateAccounts'; +import useCreateAccounts from '../../hooks/useCreateAccounts'; /** * Clicking on the "connect to a different Google account" button. diff --git a/js/src/components/google-combo-account-card/useCreateAccounts.js b/js/src/hooks/useCreateAccounts.js similarity index 94% rename from js/src/components/google-combo-account-card/useCreateAccounts.js rename to js/src/hooks/useCreateAccounts.js index d58cb93eb8..3e7a71d113 100644 --- a/js/src/components/google-combo-account-card/useCreateAccounts.js +++ b/js/src/hooks/useCreateAccounts.js @@ -7,7 +7,7 @@ import { useEffect, useRef } from '@wordpress/element'; /** * Internal dependencies */ -import useCreateMCAccount from '../google-mc-account-card/useCreateMCAccount'; +import useCreateMCAccount from '../components/google-mc-account-card/useCreateMCAccount'; import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; @@ -54,7 +54,7 @@ const useCreateAccounts = () => { ! isResolvingExistingAdsAccount && hasFinishedResolutionForExistingMCAccounts; - accountCreationChecksResolvedRef.current = existingAccountsResolved; + accountCreationChecksResolvedRef.current = existingAccountsResolved; if ( existingAccountsResolved && From 2de300a5ff953eb4013067fbae43ba7f8dd08676 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 25 Sep 2024 18:48:02 +0530 Subject: [PATCH 13/91] Add JS tests for useCreateAccounts hook. --- js/src/hooks/useCreateAccounts.js | 7 ++ js/src/hooks/useCreateAccounts.test.js | 105 +++++++++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 js/src/hooks/useCreateAccounts.test.js diff --git a/js/src/hooks/useCreateAccounts.js b/js/src/hooks/useCreateAccounts.js index 3e7a71d113..272dc69a92 100644 --- a/js/src/hooks/useCreateAccounts.js +++ b/js/src/hooks/useCreateAccounts.js @@ -17,6 +17,13 @@ import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; * Custom hook to handle the creation of MC and Ads accounts. */ const useCreateAccounts = () => { + /** + * Refs are used to avoid the re-render of the parent component. + * + * accountCreationChecksResolvedRef - Indicates if the account creation checks have been resolved. + * isCreatingAccountsRef - Indicates if the accounts are being created. + * accountsCreatedRef - Indicates if the accounts have been created. + */ const accountCreationChecksResolvedRef = useRef( false ); const isCreatingAccountsRef = useRef( false ); const accountsCreatedRef = useRef( false ); diff --git a/js/src/hooks/useCreateAccounts.test.js b/js/src/hooks/useCreateAccounts.test.js new file mode 100644 index 0000000000..955e4c46f6 --- /dev/null +++ b/js/src/hooks/useCreateAccounts.test.js @@ -0,0 +1,105 @@ +/* eslint-disable testing-library/no-unnecessary-act */ +/** + * External dependencies + */ +import { renderHook, act } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import useCreateAccounts from './useCreateAccounts'; +import useCreateMCAccount from '../components/google-mc-account-card/useCreateMCAccount'; +import useUpsertAdsAccount from './useUpsertAdsAccount'; +import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; +import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; +import useGoogleAdsAccount from './useGoogleAdsAccount'; + +jest.mock( '../components/google-mc-account-card/useCreateMCAccount' ); +jest.mock( './useUpsertAdsAccount' ); +jest.mock( './useExistingGoogleAdsAccounts' ); +jest.mock( './useExistingGoogleMCAccounts' ); +jest.mock( './useGoogleAdsAccount' ); + +describe( 'useCreateAccounts hook', () => { + let handleCreateAccount; + let upsertAdsAccount; + + beforeEach( () => { + handleCreateAccount = jest.fn( () => Promise.resolve() ); + upsertAdsAccount = jest.fn( () => Promise.resolve() ); + + useCreateMCAccount.mockReturnValue( [ + handleCreateAccount, + { data: undefined, response: { status: 200 } }, + ] ); + useUpsertAdsAccount.mockReturnValue( [ + upsertAdsAccount, + { loading: false }, + ] ); + useGoogleAdsAccount.mockReturnValue( { + googleAdsAccount: { id: 0 }, + hasFinishedResolution: true, + } ); + useExistingGoogleMCAccounts.mockReturnValue( { + data: [], + hasFinishedResolution: true, + } ); + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [], + isResolving: false, + } ); + } ); + + it( 'should not call "handleCreateAccount" and "upsertAdsAccount" when there are existing accounts', () => { + // Simulate existing accounts + useExistingGoogleMCAccounts.mockReturnValue( { + data: [ { id: 1 } ], + hasFinishedResolution: true, + } ); + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [ { id: 1 } ], + isResolving: false, + } ); + + const { result } = renderHook( () => useCreateAccounts() ); + + expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.accountsCreated ).toBe( false ); + expect( handleCreateAccount ).not.toHaveBeenCalled(); + expect( upsertAdsAccount ).not.toHaveBeenCalled(); + } ); + + it( 'should call "handleCreateAccount" and "upsertAdsAccount" when there are no existing accounts', async () => { + // Simulate the initial state and mock behavior for account creation + const { result, rerender } = renderHook( () => useCreateAccounts() ); + + expect( result.current.isCreatingAccounts ).toBe( false ); + + useCreateMCAccount.mockReturnValueOnce( [ + handleCreateAccount, + { data: {}, response: { status: 200 } }, + ] ); + useUpsertAdsAccount.mockReturnValueOnce( [ + upsertAdsAccount, + { loading: false }, + ] ); + + await act( async () => { + rerender(); // Trigger the effect that begins account creation + } ); + + // At this point, isCreatingAccounts should be true + expect( result.current.isCreatingAccounts ).toBe( true ); + + await act( async () => { + rerender(); // Trigger the effect that begins account creation + } ); + + expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.accountsCreated ).toBe( true ); + + // Finally, check that the functions were called correctly + expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); + expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); + } ); +} ); From 8239b4764022597de69a4e983d47ce1eff108df0 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 25 Sep 2024 21:43:14 +0530 Subject: [PATCH 14/91] Add indicator style. --- .../connect-google-combo-account-card.scss | 10 ++++++++++ .../connected-google-combo-account-card.js | 18 +++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss index 0f29e4ba01..85495cf299 100644 --- a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss @@ -9,5 +9,15 @@ .gla-account-card__description { gap: 0; } + + .gla-account-card__indicator { + color: #007CBA; + display: flex; + vertical-align: middle; + + .components-spinner { + margin-top: 0; + } + } } } diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 8cb5fcf9e9..39e1c8cc2e 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -3,6 +3,7 @@ */ import { createInterpolateElement } from '@wordpress/element'; import { __, sprintf } from '@wordpress/i18n'; +import { Spinner } from '@wordpress/components'; /** * Internal dependencies @@ -97,6 +98,21 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { ); }; + const Indicator = () => { + if ( creatingAccounts ) { + return ( + <> + + + { __( 'Creating…', 'google-listings-and-ads' ) } + + + ); + } + + return null; + }; + return ( { p:

, } ) } - indicator={ creatingAccounts ? 'Creating...' : null } + indicator={ } /> ); }; From 2e16bf4eb755b0b9a91b10c2ff7827efde39d55b Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 25 Sep 2024 21:47:51 +0530 Subject: [PATCH 15/91] Fix css lint error. --- .../connect-google-combo-account-card.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss index 85495cf299..f2dbb97a61 100644 --- a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss @@ -11,7 +11,7 @@ } .gla-account-card__indicator { - color: #007CBA; + color: #007cba; display: flex; vertical-align: middle; From 32b47d53dee8da34923552c51f834f4d69a4dcaf Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 27 Sep 2024 21:17:46 +0530 Subject: [PATCH 16/91] Refactor hook to handle either of the account creation. --- .../account-creation-description.js | 86 +++++++ .../connect-google-combo-account-card.scss | 23 +- .../connected-google-combo-account-card.js | 108 ++++----- ...ounts.js => useAutoCreateAdsMCAccounts.js} | 77 ++++--- .../hooks/useAutoCreateAdsMCAccounts.test.js | 209 ++++++++++++++++++ js/src/hooks/useCreateAccounts.test.js | 105 --------- 6 files changed, 383 insertions(+), 225 deletions(-) create mode 100644 js/src/components/google-combo-account-card/account-creation-description.js rename js/src/hooks/{useCreateAccounts.js => useAutoCreateAdsMCAccounts.js} (54%) create mode 100644 js/src/hooks/useAutoCreateAdsMCAccounts.test.js delete mode 100644 js/src/hooks/useCreateAccounts.test.js diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js new file mode 100644 index 0000000000..ed786b4fa9 --- /dev/null +++ b/js/src/components/google-combo-account-card/account-creation-description.js @@ -0,0 +1,86 @@ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; + +const AccountCreationDescription = ( { + isCreatingAccounts, + isCreatingMCAccount, + isCreatingAdsAccount, + googleAccount = {}, + googleMCAccount = {}, + googleAdsAccount = {}, +} ) => { + if ( isCreatingAccounts ) { + let description; + + if ( isCreatingMCAccount && isCreatingAdsAccount ) { + description = ( +

+ { __( + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', + 'google-listings-and-ads' + ) } +

+ ); + } else if ( isCreatingAdsAccount ) { + description = ( + <> +

+ { __( + 'You don’t have Google Ads account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } + + + ); + } else if ( isCreatingMCAccount ) { + description = ( + <> +

+ { __( + 'You don’t have Merchant Center account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to sync products so they show on Google.', + 'google-listings-and-ads' + ) } + + + ); + } + + return description; + } + + return ( +
+

{ googleAccount?.email }

+

+ { sprintf( + // Translators: %s is the Merchant Center ID + __( 'Merchant Center ID: %s', 'google-listings-and-ads' ), + googleMCAccount.id ?? 0 + ) } +

+

+ { sprintf( + // Translators: %s is the Google Ads ID + __( 'Google Ads ID: %s', 'google-listings-and-ads' ), + googleAdsAccount.id ?? 0 + ) } +

+
+ ); +}; + +export default AccountCreationDescription; diff --git a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss index f2dbb97a61..991927082a 100644 --- a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss @@ -1,23 +1,10 @@ -.gla-connect-google-combo-account-card { +.gla-google-combo-account-card--connected { - .gla-account-card__helper { - font-size: $gla-font-base; + .gla-account-card__icon { + align-self: flex-start; } - &.gla-connected-google-combo-account-card { - - .gla-account-card__description { - gap: 0; - } - - .gla-account-card__indicator { - color: #007cba; - display: flex; - vertical-align: middle; - - .components-spinner { - margin-top: 0; - } - } + .gla-account-card__description p { + margin: 0; } } diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 39e1c8cc2e..16a8436030 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,9 +1,7 @@ /** * External dependencies */ -import { createInterpolateElement } from '@wordpress/element'; -import { __, sprintf } from '@wordpress/i18n'; -import { Spinner } from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; /** * Internal dependencies @@ -12,7 +10,9 @@ import AccountCard, { APPEARANCE } from '../account-card'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import AppSpinner from '../app-spinner'; -import useCreateAccounts from '../../hooks/useCreateAccounts'; +import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; +import LoadingLabel from '../loading-label/loading-label'; +import AccountCreationDescription from './account-creation-description'; /** * Clicking on the "connect to a different Google account" button. @@ -43,8 +43,11 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { const { accountsCreated, accountCreationChecksResolved, - isCreatingAccounts, - } = useCreateAccounts(); + isCreatingAdsAccount, + isCreatingMCAccount, + } = useAutoCreateAdsMCAccounts(); + + const isCreatingAccounts = isCreatingAdsAccount || isCreatingMCAccount; if ( ! accountsCreated && @@ -61,73 +64,38 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { ( ! hasFinishedResolutionForCurrentMCAccount || ! hasFinishedResolutionForCurrentAdsAccount ) ); - const Description = () => { - if ( creatingAccounts ) { - return createInterpolateElement( - __( - '

You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.

', - 'google-listings-and-ads' - ), - { - p:

, - } - ); - } - - return ( - <> -

{ googleAccount?.email }

-

- { sprintf( - // Translators: %s is the Merchant Center ID - __( - 'Merchant Center ID: %s', - 'google-listings-and-ads' - ), - googleMCAccount?.id - ) } -

-

- { sprintf( - // Translators: %s is the Google Ads ID - __( 'Google Ads ID: %s', 'google-listings-and-ads' ), - googleAdsAccount?.id - ) } -

- - ); - }; - - const Indicator = () => { - if ( creatingAccounts ) { - return ( - <> - - - { __( 'Creating…', 'google-listings-and-ads' ) } - - - ); - } - - return null; - }; - return ( } - helper={ createInterpolateElement( - __( - '

Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.

', - 'google-listings-and-ads' - ), - { - p:

, - } - ) } - indicator={ } + className="gla-google-combo-account-card--connected" + description={ + + } + helper={ + isCreatingAdsAccount && + isCreatingMCAccount && ( +

+ { __( + 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } +

+ ) + } + indicator={ + creatingAccounts ? ( + + ) : null + } /> ); }; diff --git a/js/src/hooks/useCreateAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js similarity index 54% rename from js/src/hooks/useCreateAccounts.js rename to js/src/hooks/useAutoCreateAdsMCAccounts.js index 272dc69a92..2d09765362 100644 --- a/js/src/hooks/useCreateAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -1,4 +1,3 @@ -/* eslint-disable react-hooks/exhaustive-deps */ /** * External dependencies */ @@ -11,12 +10,16 @@ import useCreateMCAccount from '../components/google-mc-account-card/useCreateMC import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; /** * Custom hook to handle the creation of MC and Ads accounts. + * + * @return {Object} Object with the following properties: + * - isCreatingAccounts: Indicates if the accounts are being created. + * - accountCreationChecksResolved: Indicates if the account creation checks have been resolved. + * - accountsCreated: Indicates if the accounts have been created */ -const useCreateAccounts = () => { +const useAutoCreateAdsMCAccounts = () => { /** * Refs are used to avoid the re-render of the parent component. * @@ -26,13 +29,10 @@ const useCreateAccounts = () => { */ const accountCreationChecksResolvedRef = useRef( false ); const isCreatingAccountsRef = useRef( false ); + const isCreatingAdsAccountsRef = useRef( false ); + const isCreatingMCAccountsRef = useRef( false ); const accountsCreatedRef = useRef( false ); - const { - googleAdsAccount, - hasFinishedResolution: hasFinishedResolutionForExistingAdsccount, - } = useGoogleAdsAccount(); - const { data: existingMCAccounts, hasFinishedResolution: hasFinishedResolutionForExistingMCAccounts, @@ -43,14 +43,35 @@ const useCreateAccounts = () => { isResolving: isResolvingExistingAdsAccount, } = useExistingGoogleAdsAccounts(); - const [ handleCreateAccount, { data: account, response } ] = - useCreateMCAccount(); - + const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - // Process account creation completion. + const createAccounts = async () => { + const hasExistingMCAccount = existingMCAccounts.length > 0; + const hasExistingAdsAccount = existingAdsAccount.length > 0; + + isCreatingMCAccountsRef.current = ! hasExistingMCAccount; + isCreatingAdsAccountsRef.current = ! hasExistingAdsAccount; + isCreatingAccountsRef.current = + ! hasExistingAdsAccount || ! hasExistingMCAccount; + + if ( ! hasExistingMCAccount ) { + await handleCreateAccount(); + } + + if ( ! hasExistingAdsAccount ) { + await upsertAdsAccount(); + } + }; + useEffect( () => { - if ( response?.status === 200 && ! loading ) { + if ( + isCreatingAccountsRef.current === true && + response?.status === 200 && + ! loading + ) { + isCreatingMCAccountsRef.current = false; + isCreatingAdsAccountsRef.current = false; isCreatingAccountsRef.current = false; accountsCreatedRef.current = true; } @@ -65,36 +86,28 @@ const useCreateAccounts = () => { if ( existingAccountsResolved && - isCreatingAccountsRef.current === false && - account === undefined && - hasFinishedResolutionForExistingAdsccount && - googleAdsAccount.id === 0 + isCreatingAccountsRef.current === false ) { - const hasExistingAccounts = - existingMCAccounts?.length > 0 && - existingAdsAccount?.length > 0; - - if ( ! hasExistingAccounts ) { - const createAccounts = async () => { - await handleCreateAccount(); - await upsertAdsAccount(); - }; - - isCreatingAccountsRef.current = true; - accountsCreatedRef.current = false; + const hasExistingMCAccount = existingMCAccounts?.length > 0; + const hasExistingAdsAccount = existingAdsAccount?.length > 0; + + if ( ! hasExistingMCAccount || ! hasExistingAdsAccount ) { createAccounts(); } } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [ isResolvingExistingAdsAccount, hasFinishedResolutionForExistingMCAccounts, ] ); return { - isCreatingAccounts: isCreatingAccountsRef.current, - accountCreationChecksResolved: accountCreationChecksResolvedRef.current, accountsCreated: accountsCreatedRef.current, + accountCreationChecksResolved: accountCreationChecksResolvedRef.current, + isCreatingAccounts: isCreatingAccountsRef.current, + isCreatingAdsAccount: isCreatingAdsAccountsRef.current, + isCreatingMCAccount: isCreatingMCAccountsRef.current, }; }; -export default useCreateAccounts; +export default useAutoCreateAdsMCAccounts; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js new file mode 100644 index 0000000000..ccd6c779be --- /dev/null +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -0,0 +1,209 @@ +/* eslint-disable testing-library/no-unnecessary-act */ +/** + * External dependencies + */ +import { renderHook, act } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import useCreateAccounts from './useAutoCreateAdsMCAccounts'; +import useCreateMCAccount from '../components/google-mc-account-card/useCreateMCAccount'; +import useUpsertAdsAccount from './useUpsertAdsAccount'; +import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; +import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; + +jest.mock( '../components/google-mc-account-card/useCreateMCAccount' ); +jest.mock( './useUpsertAdsAccount' ); +jest.mock( './useExistingGoogleAdsAccounts' ); +jest.mock( './useExistingGoogleMCAccounts' ); +jest.mock( './useGoogleAdsAccount' ); + +describe( 'useAutoCreateAdsMCAccounts hook', () => { + let handleCreateAccount; + let upsertAdsAccount; + + beforeEach( () => { + handleCreateAccount = jest.fn( () => Promise.resolve() ); + upsertAdsAccount = jest.fn( () => Promise.resolve() ); + + useCreateMCAccount.mockReturnValue( [ + handleCreateAccount, + { response: { status: 200 } }, + ] ); + useUpsertAdsAccount.mockReturnValue( [ + upsertAdsAccount, + { loading: false }, + ] ); + useExistingGoogleMCAccounts.mockReturnValue( { + data: [], + hasFinishedResolution: true, + } ); + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [], + isResolving: false, + } ); + } ); + + it( 'should not call "handleCreateAccount" and "upsertAdsAccount" when there are existing accounts', () => { + // Simulate existing accounts + useExistingGoogleMCAccounts.mockReturnValue( { + data: [ { id: 1 } ], + hasFinishedResolution: true, + } ); + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [ { id: 1 } ], + isResolving: false, + } ); + + const { result } = renderHook( () => useCreateAccounts() ); + + expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.accountsCreated ).toBe( false ); + expect( handleCreateAccount ).not.toHaveBeenCalled(); + expect( upsertAdsAccount ).not.toHaveBeenCalled(); + } ); + + it( 'should call "handleCreateAccount" and "upsertAdsAccount" when there are no existing accounts', async () => { + // Simulate the initial state and mock behavior for account creation + const { result, rerender } = renderHook( () => useCreateAccounts() ); + + expect( result.current.isCreatingAccounts ).toBe( false ); + + useCreateMCAccount.mockReturnValueOnce( [ + handleCreateAccount, + { response: { status: 200 } }, + ] ); + useUpsertAdsAccount.mockReturnValueOnce( [ + upsertAdsAccount, + { loading: false }, + ] ); + + await act( async () => { + rerender(); // Trigger the effect that begins account creation + } ); + + // At this point, isCreatingAccounts should be true + expect( result.current.isCreatingAdsAccount ).toBe( true ); + expect( result.current.isCreatingMCAccount ).toBe( true ); + + await act( async () => { + rerender(); + } ); + + expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.accountsCreated ).toBe( true ); + + // Finally, check that the functions were called correctly + expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); + expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); + } ); + + it( 'should create Merchant Center account only when there is no existing MC account, but there is an existing Ads account', async () => { + // Simulate no existing MC account but an existing Ads account + useExistingGoogleMCAccounts.mockReturnValue( { + data: [], // No existing MC account + hasFinishedResolution: true, + } ); + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [ { id: 1 } ], // Existing Ads account + isResolving: false, + } ); + + // Step 1: Initial render - No response, loading is true + useCreateMCAccount.mockReturnValueOnce( [ + handleCreateAccount, + { response: undefined, loading: true }, // Initially no response, loading is true + ] ); + + const { result, rerender } = renderHook( () => useCreateAccounts() ); + + // Initially, it should not be creating accounts + expect( result.current.isCreatingAccounts ).toBe( false ); + + // Trigger the effect that starts account creation + await act( async () => { + rerender(); // Simulate the effect firing + } ); + + // Step 2: At this point, MC account creation should have started + expect( result.current.isCreatingMCAccount ).toBe( true ); + expect( result.current.isCreatingAdsAccount ).toBe( false ); // Since Ads account exists + expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); + expect( upsertAdsAccount ).not.toHaveBeenCalled(); + + // Step 3: Simulate the response for MC account creation + useCreateMCAccount.mockReturnValueOnce( [ + handleCreateAccount, + { response: { status: 200 }, loading: false }, // Now account creation is complete + ] ); + + // Trigger a rerender to simulate the async function resolving + await act( async () => { + rerender(); // Re-render after response has been updated + } ); + + // Step 4: Final assertions after account creation has completed + expect( result.current.isCreatingAccounts ).toBe( false ); // Account creation should be complete + expect( result.current.accountsCreated ).toBe( true ); // The account has been created + expect( result.current.isCreatingMCAccount ).toBe( false ); // MC account creation finished + + // Finally, verify that only handleCreateAccount was called, not upsertAdsAccount + expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); + expect( upsertAdsAccount ).not.toHaveBeenCalled(); + } ); + + it( 'should create Ads account only when there is no existing Ads account, but there is an existing Merchant Center account', async () => { + // Simulate existing MC account but no existing Ads account + useExistingGoogleMCAccounts.mockReturnValue( { + data: [ { id: 1 } ], // Existing MC account + hasFinishedResolution: true, + } ); + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [], // No existing Ads account + isResolving: false, + } ); + + // Step 1: Initial render - No response, loading is true for Ads account creation + useUpsertAdsAccount.mockReturnValueOnce( [ + upsertAdsAccount, + { response: undefined, loading: true }, // Initially no response, loading is true for Ads account creation + ] ); + + const { result, rerender } = renderHook( () => useCreateAccounts() ); + + // Initially, it should not be creating accounts + expect( result.current.isCreatingAccounts ).toBe( false ); + + // Trigger the effect that starts account creation + await act( async () => { + rerender(); // Simulate the effect firing + } ); + + // Step 2: At this point, Ads account creation should have started + expect( result.current.isCreatingAdsAccount ).toBe( true ); + expect( result.current.isCreatingMCAccount ).toBe( false ); // Since MC account exists + expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); + expect( handleCreateAccount ).not.toHaveBeenCalled(); // MC account creation shouldn't be triggered + + // Step 3: Simulate the response for Ads account creation + useUpsertAdsAccount.mockReturnValueOnce( [ + upsertAdsAccount, + { response: { status: 200 }, loading: false }, // Now Ads account creation is complete + ] ); + + // Trigger a rerender to simulate the async function resolving + await act( async () => { + rerender(); // Re-render after response has been updated + } ); + + // Step 4: Final assertions after Ads account creation has completed + expect( result.current.isCreatingAccounts ).toBe( false ); // Account creation should be complete + expect( result.current.accountsCreated ).toBe( true ); // The account has been created + expect( result.current.isCreatingAdsAccount ).toBe( false ); // Ads account creation finished + + // Finally, verify that only upsertAdsAccount was called, not handleCreateAccount + expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); + expect( handleCreateAccount ).not.toHaveBeenCalled(); + } ); +} ); diff --git a/js/src/hooks/useCreateAccounts.test.js b/js/src/hooks/useCreateAccounts.test.js deleted file mode 100644 index 955e4c46f6..0000000000 --- a/js/src/hooks/useCreateAccounts.test.js +++ /dev/null @@ -1,105 +0,0 @@ -/* eslint-disable testing-library/no-unnecessary-act */ -/** - * External dependencies - */ -import { renderHook, act } from '@testing-library/react'; - -/** - * Internal dependencies - */ -import useCreateAccounts from './useCreateAccounts'; -import useCreateMCAccount from '../components/google-mc-account-card/useCreateMCAccount'; -import useUpsertAdsAccount from './useUpsertAdsAccount'; -import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; -import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; -import useGoogleAdsAccount from './useGoogleAdsAccount'; - -jest.mock( '../components/google-mc-account-card/useCreateMCAccount' ); -jest.mock( './useUpsertAdsAccount' ); -jest.mock( './useExistingGoogleAdsAccounts' ); -jest.mock( './useExistingGoogleMCAccounts' ); -jest.mock( './useGoogleAdsAccount' ); - -describe( 'useCreateAccounts hook', () => { - let handleCreateAccount; - let upsertAdsAccount; - - beforeEach( () => { - handleCreateAccount = jest.fn( () => Promise.resolve() ); - upsertAdsAccount = jest.fn( () => Promise.resolve() ); - - useCreateMCAccount.mockReturnValue( [ - handleCreateAccount, - { data: undefined, response: { status: 200 } }, - ] ); - useUpsertAdsAccount.mockReturnValue( [ - upsertAdsAccount, - { loading: false }, - ] ); - useGoogleAdsAccount.mockReturnValue( { - googleAdsAccount: { id: 0 }, - hasFinishedResolution: true, - } ); - useExistingGoogleMCAccounts.mockReturnValue( { - data: [], - hasFinishedResolution: true, - } ); - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [], - isResolving: false, - } ); - } ); - - it( 'should not call "handleCreateAccount" and "upsertAdsAccount" when there are existing accounts', () => { - // Simulate existing accounts - useExistingGoogleMCAccounts.mockReturnValue( { - data: [ { id: 1 } ], - hasFinishedResolution: true, - } ); - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [ { id: 1 } ], - isResolving: false, - } ); - - const { result } = renderHook( () => useCreateAccounts() ); - - expect( result.current.isCreatingAccounts ).toBe( false ); - expect( result.current.accountsCreated ).toBe( false ); - expect( handleCreateAccount ).not.toHaveBeenCalled(); - expect( upsertAdsAccount ).not.toHaveBeenCalled(); - } ); - - it( 'should call "handleCreateAccount" and "upsertAdsAccount" when there are no existing accounts', async () => { - // Simulate the initial state and mock behavior for account creation - const { result, rerender } = renderHook( () => useCreateAccounts() ); - - expect( result.current.isCreatingAccounts ).toBe( false ); - - useCreateMCAccount.mockReturnValueOnce( [ - handleCreateAccount, - { data: {}, response: { status: 200 } }, - ] ); - useUpsertAdsAccount.mockReturnValueOnce( [ - upsertAdsAccount, - { loading: false }, - ] ); - - await act( async () => { - rerender(); // Trigger the effect that begins account creation - } ); - - // At this point, isCreatingAccounts should be true - expect( result.current.isCreatingAccounts ).toBe( true ); - - await act( async () => { - rerender(); // Trigger the effect that begins account creation - } ); - - expect( result.current.isCreatingAccounts ).toBe( false ); - expect( result.current.accountsCreated ).toBe( true ); - - // Finally, check that the functions were called correctly - expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); - expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); - } ); -} ); From f55fd1dcb78a8d2b29851e0e9ef568926892d52d Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Mon, 30 Sep 2024 19:28:03 +0530 Subject: [PATCH 17/91] CR feedback - round 2. --- .../account-creation-description.js | 138 +++++++++++------- .../connected-google-combo-account-card.js | 45 +++--- js/src/hooks/useAutoCreateAdsMCAccounts.js | 14 +- .../hooks/useAutoCreateAdsMCAccounts.test.js | 21 +-- 4 files changed, 132 insertions(+), 86 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js index ed786b4fa9..7a3a96c6cf 100644 --- a/js/src/components/google-combo-account-card/account-creation-description.js +++ b/js/src/components/google-combo-account-card/account-creation-description.js @@ -3,82 +3,116 @@ */ import { __, sprintf } from '@wordpress/i18n'; +/** + * Internal dependencies + */ +import useGoogleAccount from '.~/hooks/useGoogleAccount'; + +/** + * Renders the description for the account creation card. + * + * @param {*} param0 Props. + * @param {boolean} param0.isCreatingAccounts Whether accounts are being created. + * @param {boolean} param0.isCreatingMCAccount Whether Merchant Center account is being created. + * @param {boolean} param0.isCreatingAdsAccount Whether Google Ads account is being created. + * @param {Object} param0.googleMCAccount Google Merchant Center account. + * @param {Object} param0.googleAdsAccount Google Ads account. + */ const AccountCreationDescription = ( { isCreatingAccounts, isCreatingMCAccount, isCreatingAdsAccount, - googleAccount = {}, googleMCAccount = {}, googleAdsAccount = {}, } ) => { - if ( isCreatingAccounts ) { + const { google } = useGoogleAccount(); + + const getDescription = () => { let description; - if ( isCreatingMCAccount && isCreatingAdsAccount ) { - description = ( -

- { __( - 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', - 'google-listings-and-ads' - ) } -

- ); - } else if ( isCreatingAdsAccount ) { - description = ( - <> + if ( isCreatingAccounts ) { + if ( isCreatingMCAccount && isCreatingAdsAccount ) { + description = (

{ __( - 'You don’t have Google Ads account, so we’re creating one for you.', + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', 'google-listings-and-ads' ) }

- - { __( - 'Required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } - - - ); - } else if ( isCreatingMCAccount ) { + ); + } else if ( isCreatingAdsAccount ) { + description = ( + <> +

+ { __( + 'You don’t have Google Ads account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } + + + ); + } else if ( isCreatingMCAccount ) { + description = ( + <> +

+ { __( + 'You don’t have Merchant Center account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to sync products so they show on Google.', + 'google-listings-and-ads' + ) } + + + ); + } + } else { description = ( <> -

- { __( - 'You don’t have Merchant Center account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to sync products so they show on Google.', - 'google-listings-and-ads' - ) } - +

{ google?.email }

+ { googleMCAccount?.id && ( +

+ { sprintf( + // Translators: %s is the Merchant Center ID + __( + 'Merchant Center ID: %s', + 'google-listings-and-ads' + ), + googleMCAccount.id + ) } +

+ ) } + { googleAdsAccount?.id && ( +

+ { sprintf( + // Translators: %s is the Google Ads ID + __( + 'Google Ads ID: %s', + 'google-listings-and-ads' + ), + googleAdsAccount.id + ) } +

+ ) } ); } return description; - } + }; return (
-

{ googleAccount?.email }

-

- { sprintf( - // Translators: %s is the Merchant Center ID - __( 'Merchant Center ID: %s', 'google-listings-and-ads' ), - googleMCAccount.id ?? 0 - ) } -

-

- { sprintf( - // Translators: %s is the Google Ads ID - __( 'Google Ads ID: %s', 'google-listings-and-ads' ), - googleAdsAccount.id ?? 0 - ) } -

+ { getDescription() }
); }; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 16a8436030..618549ac3c 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -64,13 +64,36 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { ( ! hasFinishedResolutionForCurrentMCAccount || ! hasFinishedResolutionForCurrentAdsAccount ) ); + const getHelper = () => + isCreatingAdsAccount && + isCreatingMCAccount && ( +

+ { __( + 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } +

+ ); + + const getIndicator = () => { + if ( creatingAccounts ) { + return ( + + ); + } + + return null; + }; + return ( { googleAdsAccount={ googleAdsAccount } /> } - helper={ - isCreatingAdsAccount && - isCreatingMCAccount && ( -

- { __( - 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } -

- ) - } - indicator={ - creatingAccounts ? ( - - ) : null - } + helper={ getHelper() } + indicator={ getIndicator() } /> ); }; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 2d09765362..d5e21de5c7 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -12,12 +12,15 @@ import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts' import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; /** - * Custom hook to handle the creation of MC and Ads accounts. + * Custom hook to handle the creation of Google Merchant Center (MC) and Google Ads accounts. * - * @return {Object} Object with the following properties: - * - isCreatingAccounts: Indicates if the accounts are being created. - * - accountCreationChecksResolved: Indicates if the account creation checks have been resolved. - * - accountsCreated: Indicates if the accounts have been created + * @typedef {Object} AutoCreateAccountsStatus + * @property {boolean} isCreatingAdsAccount Indicates if the Google Ads account is currently being created. + * @property {boolean} isCreatingMCAccount Indicates if the Google Merchant Center account is currently being created. + * @property {boolean} accountCreationChecksResolved Indicates if the account creation checks (for existing accounts) have been resolved. + * @property {boolean} accountsCreated Indicates if both the Google Ads and Google Merchant Center accounts have been successfully created. + * + * @return {AutoCreateAccountsStatus} Object containing properties related to the account creation status. */ const useAutoCreateAdsMCAccounts = () => { /** @@ -104,7 +107,6 @@ const useAutoCreateAdsMCAccounts = () => { return { accountsCreated: accountsCreatedRef.current, accountCreationChecksResolved: accountCreationChecksResolvedRef.current, - isCreatingAccounts: isCreatingAccountsRef.current, isCreatingAdsAccount: isCreatingAdsAccountsRef.current, isCreatingMCAccount: isCreatingMCAccountsRef.current, }; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index ccd6c779be..844b968ae8 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -58,7 +58,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useCreateAccounts() ); - expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.isCreatingAdsAccount ).toBe( false ); + expect( result.current.isCreatingMCAccount ).toBe( false ); expect( result.current.accountsCreated ).toBe( false ); expect( handleCreateAccount ).not.toHaveBeenCalled(); expect( upsertAdsAccount ).not.toHaveBeenCalled(); @@ -68,7 +69,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { // Simulate the initial state and mock behavior for account creation const { result, rerender } = renderHook( () => useCreateAccounts() ); - expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.isCreatingAdsAccount ).toBe( false ); + expect( result.current.isCreatingMCAccount ).toBe( false ); useCreateMCAccount.mockReturnValueOnce( [ handleCreateAccount, @@ -83,7 +85,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { rerender(); // Trigger the effect that begins account creation } ); - // At this point, isCreatingAccounts should be true expect( result.current.isCreatingAdsAccount ).toBe( true ); expect( result.current.isCreatingMCAccount ).toBe( true ); @@ -91,7 +92,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { rerender(); } ); - expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.isCreatingAdsAccount ).toBe( false ); + expect( result.current.isCreatingMCAccount ).toBe( false ); expect( result.current.accountsCreated ).toBe( true ); // Finally, check that the functions were called correctly @@ -119,7 +121,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result, rerender } = renderHook( () => useCreateAccounts() ); // Initially, it should not be creating accounts - expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.isCreatingAdsAccount ).toBe( false ); + expect( result.current.isCreatingMCAccount ).toBe( false ); // Trigger the effect that starts account creation await act( async () => { @@ -144,9 +147,9 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); // Step 4: Final assertions after account creation has completed - expect( result.current.isCreatingAccounts ).toBe( false ); // Account creation should be complete + expect( result.current.isCreatingAdsAccount ).toBe( false ); + expect( result.current.isCreatingMCAccount ).toBe( false ); expect( result.current.accountsCreated ).toBe( true ); // The account has been created - expect( result.current.isCreatingMCAccount ).toBe( false ); // MC account creation finished // Finally, verify that only handleCreateAccount was called, not upsertAdsAccount expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); @@ -173,7 +176,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result, rerender } = renderHook( () => useCreateAccounts() ); // Initially, it should not be creating accounts - expect( result.current.isCreatingAccounts ).toBe( false ); + expect( result.current.isCreatingAdsAccount ).toBe( false ); + expect( result.current.isCreatingMCAccount ).toBe( false ); // Trigger the effect that starts account creation await act( async () => { @@ -198,7 +202,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); // Step 4: Final assertions after Ads account creation has completed - expect( result.current.isCreatingAccounts ).toBe( false ); // Account creation should be complete expect( result.current.accountsCreated ).toBe( true ); // The account has been created expect( result.current.isCreatingAdsAccount ).toBe( false ); // Ads account creation finished From 95fe0cb4831f9076799a3833a84fc398f0764c62 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 1 Oct 2024 23:50:15 +0530 Subject: [PATCH 18/91] Add CR feedback changes. --- .../account-creation-description.js | 78 +++++++++---------- .../connected-google-combo-account-card.js | 1 - js/src/hooks/useAutoCreateAdsMCAccounts.js | 6 +- js/src/hooks/useExistingGoogleAdsAccounts.js | 5 +- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js index 7a3a96c6cf..78c75005d9 100644 --- a/js/src/components/google-combo-account-card/account-creation-description.js +++ b/js/src/components/google-combo-account-card/account-creation-description.js @@ -11,12 +11,12 @@ import useGoogleAccount from '.~/hooks/useGoogleAccount'; /** * Renders the description for the account creation card. * - * @param {*} param0 Props. - * @param {boolean} param0.isCreatingAccounts Whether accounts are being created. - * @param {boolean} param0.isCreatingMCAccount Whether Merchant Center account is being created. - * @param {boolean} param0.isCreatingAdsAccount Whether Google Ads account is being created. - * @param {Object} param0.googleMCAccount Google Merchant Center account. - * @param {Object} param0.googleAdsAccount Google Ads account. + * @param {Object} props Props. + * @param {boolean} props.isCreatingAccounts Whether accounts are being created. + * @param {boolean} props.isCreatingMCAccount Whether Merchant Center account is being created. + * @param {boolean} props.isCreatingAdsAccount Whether Google Ads account is being created. + * @param {Object} props.googleMCAccount Google Merchant Center account. + * @param {Object} props.googleAdsAccount Google Ads account. */ const AccountCreationDescription = ( { isCreatingAccounts, @@ -32,7 +32,7 @@ const AccountCreationDescription = ( { if ( isCreatingAccounts ) { if ( isCreatingMCAccount && isCreatingAdsAccount ) { - description = ( + return (

{ __( 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', @@ -41,7 +41,7 @@ const AccountCreationDescription = ( {

); } else if ( isCreatingAdsAccount ) { - description = ( + return ( <>

{ __( @@ -58,7 +58,7 @@ const AccountCreationDescription = ( { ); } else if ( isCreatingMCAccount ) { - description = ( + return ( <>

{ __( @@ -75,39 +75,37 @@ const AccountCreationDescription = ( { ); } - } else { - description = ( - <> -

{ google?.email }

- { googleMCAccount?.id && ( -

- { sprintf( - // Translators: %s is the Merchant Center ID - __( - 'Merchant Center ID: %s', - 'google-listings-and-ads' - ), - googleMCAccount.id - ) } -

- ) } - { googleAdsAccount?.id && ( -

- { sprintf( - // Translators: %s is the Google Ads ID - __( - 'Google Ads ID: %s', - 'google-listings-and-ads' - ), - googleAdsAccount.id - ) } -

- ) } - - ); } - return description; + return ( + <> +

{ google?.email }

+ { googleMCAccount?.id && ( +

+ { sprintf( + // Translators: %s is the Merchant Center ID + __( + 'Merchant Center ID: %s', + 'google-listings-and-ads' + ), + googleMCAccount.id + ) } +

+ ) } + { googleAdsAccount?.id && ( +

+ { sprintf( + // Translators: %s is the Google Ads ID + __( + 'Google Ads ID: %s', + 'google-listings-and-ads' + ), + googleAdsAccount.id + ) } +

+ ) } + + ); }; return ( diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 618549ac3c..0bee8a26e0 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -96,7 +96,6 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { isCreatingAccounts={ creatingAccounts } isCreatingAdsAccount={ isCreatingAdsAccount } isCreatingMCAccount={ isCreatingMCAccount } - googleAccount={ googleAccount } googleMCAccount={ googleMCAccount } googleAdsAccount={ googleAdsAccount } /> diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index d5e21de5c7..f41fb79058 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -43,7 +43,7 @@ const useAutoCreateAdsMCAccounts = () => { const { existingAccounts: existingAdsAccount, - isResolving: isResolvingExistingAdsAccount, + hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount, } = useExistingGoogleAdsAccounts(); const [ handleCreateAccount, { response } ] = useCreateMCAccount(); @@ -82,7 +82,7 @@ const useAutoCreateAdsMCAccounts = () => { useEffect( () => { const existingAccountsResolved = - ! isResolvingExistingAdsAccount && + hasFinishedResolutionForExistingAdsAccount && hasFinishedResolutionForExistingMCAccounts; accountCreationChecksResolvedRef.current = existingAccountsResolved; @@ -100,7 +100,7 @@ const useAutoCreateAdsMCAccounts = () => { } // eslint-disable-next-line react-hooks/exhaustive-deps }, [ - isResolvingExistingAdsAccount, + hasFinishedResolutionForExistingAdsAccount, hasFinishedResolutionForExistingMCAccounts, ] ); diff --git a/js/src/hooks/useExistingGoogleAdsAccounts.js b/js/src/hooks/useExistingGoogleAdsAccounts.js index 8eda3b9a2f..1e84516710 100644 --- a/js/src/hooks/useExistingGoogleAdsAccounts.js +++ b/js/src/hooks/useExistingGoogleAdsAccounts.js @@ -15,8 +15,11 @@ const useExistingGoogleAdsAccounts = () => { const isResolving = select( STORE_KEY ).isResolving( 'getExistingGoogleAdsAccounts' ); + const hasFinishedResolution = select( STORE_KEY ).hasFinishedResolution( + 'getExistingGoogleAdsAccounts' + ); - return { existingAccounts, isResolving }; + return { existingAccounts, hasFinishedResolution, isResolving }; }, [] ); }; From 1a24f0dbb9877653e9776ed634b0cb3bb7733c7d Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 10:15:12 +0530 Subject: [PATCH 19/91] Remove unwanted props. --- .../account-creation-description.js | 92 +++++++++---------- .../connected-google-combo-account-card.js | 10 +- .../google-combo-account-card/index.js | 2 +- 3 files changed, 52 insertions(+), 52 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js index 78c75005d9..86756c8a77 100644 --- a/js/src/components/google-combo-account-card/account-creation-description.js +++ b/js/src/components/google-combo-account-card/account-creation-description.js @@ -12,75 +12,75 @@ import useGoogleAccount from '.~/hooks/useGoogleAccount'; * Renders the description for the account creation card. * * @param {Object} props Props. - * @param {boolean} props.isCreatingAccounts Whether accounts are being created. * @param {boolean} props.isCreatingMCAccount Whether Merchant Center account is being created. * @param {boolean} props.isCreatingAdsAccount Whether Google Ads account is being created. + * @param {boolean} props.isLoading Whether the data is loading. * @param {Object} props.googleMCAccount Google Merchant Center account. * @param {Object} props.googleAdsAccount Google Ads account. */ const AccountCreationDescription = ( { - isCreatingAccounts, isCreatingMCAccount, isCreatingAdsAccount, + isLoading = false, googleMCAccount = {}, googleAdsAccount = {}, } ) => { const { google } = useGoogleAccount(); const getDescription = () => { - let description; - - if ( isCreatingAccounts ) { - if ( isCreatingMCAccount && isCreatingAdsAccount ) { - return ( + if ( isCreatingMCAccount && isCreatingAdsAccount ) { + return ( +

+ { __( + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', + 'google-listings-and-ads' + ) } +

+ ); + } else if ( isCreatingAdsAccount ) { + return ( + <>

{ __( - 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', + 'You don’t have Google Ads account, so we’re creating one for you.', 'google-listings-and-ads' ) }

- ); - } else if ( isCreatingAdsAccount ) { - return ( - <> -

- { __( - 'You don’t have Google Ads account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } - - - ); - } else if ( isCreatingMCAccount ) { - return ( - <> -

- { __( - 'You don’t have Merchant Center account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to sync products so they show on Google.', - 'google-listings-and-ads' - ) } - - - ); - } + + { __( + 'Required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } + + + ); + } else if ( isCreatingMCAccount ) { + return ( + <> +

+ { __( + 'You don’t have Merchant Center account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to sync products so they show on Google.', + 'google-listings-and-ads' + ) } + + + ); + } + + if ( isLoading ) { + return null; } return ( <>

{ google?.email }

- { googleMCAccount?.id && ( + { googleMCAccount?.id && googleMCAccount.id !== 0 && (

{ sprintf( // Translators: %s is the Merchant Center ID @@ -92,7 +92,7 @@ const AccountCreationDescription = ( { ) }

) } - { googleAdsAccount?.id && ( + { googleAdsAccount?.id && googleAdsAccount.id !== 0 && (

{ sprintf( // Translators: %s is the Google Ads ID diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 0bee8a26e0..eab37bc936 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -24,12 +24,9 @@ import AccountCreationDescription from './account-creation-description'; * Renders a Google account card UI with connected account information. * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. * - * @param {Object} props React props. - * @param {{ googleAccount: object }} props.googleAccount The Google account. - * * @fires gla_google_account_connect_different_account_button_click */ -const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { +const ConnectedGoogleComboAccountCard = () => { const { googleMCAccount, hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, @@ -93,7 +90,10 @@ const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => { className="gla-google-combo-account-card--connected" description={ ; + return ; } if ( isConnected && ! scope.glaRequired ) { From 2325d7a275bcb057a23acd31222aa241e0ed9bdf Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 11:20:19 +0530 Subject: [PATCH 20/91] Use refs to remove no-deps eslint rule. --- .../account-creation-description.js | 51 +++--- .../connected-google-combo-account-card.js | 42 +++-- js/src/hooks/useAutoCreateAdsMCAccounts.js | 147 +++++++++++++----- 3 files changed, 154 insertions(+), 86 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js index 86756c8a77..ba85d0fdc6 100644 --- a/js/src/components/google-combo-account-card/account-creation-description.js +++ b/js/src/components/google-combo-account-card/account-creation-description.js @@ -73,6 +73,14 @@ const AccountCreationDescription = ( { ); } + const DisplayAccountInfo = ( { account, text } ) => { + if ( account?.id === undefined || account.id === 0 ) { + return null; + } + + return

{ text }

; + }; + if ( isLoading ) { return null; } @@ -80,30 +88,25 @@ const AccountCreationDescription = ( { return ( <>

{ google?.email }

- { googleMCAccount?.id && googleMCAccount.id !== 0 && ( -

- { sprintf( - // Translators: %s is the Merchant Center ID - __( - 'Merchant Center ID: %s', - 'google-listings-and-ads' - ), - googleMCAccount.id - ) } -

- ) } - { googleAdsAccount?.id && googleAdsAccount.id !== 0 && ( -

- { sprintf( - // Translators: %s is the Google Ads ID - __( - 'Google Ads ID: %s', - 'google-listings-and-ads' - ), - googleAdsAccount.id - ) } -

- ) } + + ); }; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index eab37bc936..22c1937239 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -38,14 +38,14 @@ const ConnectedGoogleComboAccountCard = () => { } = useGoogleAdsAccount(); const { - accountsCreated, - accountCreationChecksResolved, + isCreatingAccounts, + isCreatingBothAccounts, isCreatingAdsAccount, isCreatingMCAccount, + accountCreationChecksResolved, + accountsCreated, } = useAutoCreateAdsMCAccounts(); - const isCreatingAccounts = isCreatingAdsAccount || isCreatingMCAccount; - if ( ! accountsCreated && ( ! hasFinishedResolutionForCurrentAdsAccount || @@ -55,25 +55,23 @@ const ConnectedGoogleComboAccountCard = () => { return } />; } - const creatingAccounts = - isCreatingAccounts || - ( accountsCreated && - ( ! hasFinishedResolutionForCurrentMCAccount || - ! hasFinishedResolutionForCurrentAdsAccount ) ); + const getHelper = () => { + if ( isCreatingBothAccounts ) { + return ( +

+ { __( + 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } +

+ ); + } - const getHelper = () => - isCreatingAdsAccount && - isCreatingMCAccount && ( -

- { __( - 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } -

- ); + return null; + }; const getIndicator = () => { - if ( creatingAccounts ) { + if ( isCreatingAccounts ) { return ( { description={ { * isCreatingAccountsRef - Indicates if the accounts are being created. * accountsCreatedRef - Indicates if the accounts have been created. */ - const accountCreationChecksResolvedRef = useRef( false ); - const isCreatingAccountsRef = useRef( false ); + const isCreatingBothAccountsRef = useRef( false ); const isCreatingAdsAccountsRef = useRef( false ); const isCreatingMCAccountsRef = useRef( false ); + const initHasExistingMCAAccountsRef = useRef( null ); + const initHasExistingAdsAccountsRef = useRef( null ); const accountsCreatedRef = useRef( false ); const { @@ -43,72 +44,138 @@ const useAutoCreateAdsMCAccounts = () => { const { existingAccounts: existingAdsAccount, - hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount, + isResolving: isResolvingExistingAdsAccount, } = useExistingGoogleAdsAccounts(); const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - const createAccounts = async () => { - const hasExistingMCAccount = existingMCAccounts.length > 0; - const hasExistingAdsAccount = existingAdsAccount.length > 0; + const hasExistingMCAccount = existingMCAccounts?.length > 0; + const hasExistingAdsAccount = existingAdsAccount?.length > 0; + + if ( + initHasExistingMCAAccountsRef.current === null && + hasFinishedResolutionForExistingMCAccounts + ) { + initHasExistingMCAAccountsRef.current = hasExistingMCAccount; + } + + if ( + initHasExistingAdsAccountsRef.current === null && + ! isResolvingExistingAdsAccount + ) { + initHasExistingAdsAccountsRef.current = hasExistingAdsAccount; + } + + const createMCAccount = useCallback( async () => { + await handleCreateAccount(); + }, [ handleCreateAccount ] ); + + const createAdsAccount = useCallback( async () => { + await upsertAdsAccount(); + }, [ upsertAdsAccount ] ); + + const createBothAccounts = useCallback( async () => { + await createMCAccount(); + await createAdsAccount(); + }, [ createMCAccount, createAdsAccount ] ); + + const accountCreationChecksResolved = + initHasExistingAdsAccountsRef.current !== null && + initHasExistingMCAAccountsRef.current !== null; + + const shouldCreateAdsAccount = + initHasExistingAdsAccountsRef.current === false && + initHasExistingMCAAccountsRef.current === true; + + const shouldCreateMCAccount = + initHasExistingAdsAccountsRef.current === true && + initHasExistingMCAAccountsRef.current === false; + + const shouldCreateBothAccounts = + ! initHasExistingAdsAccountsRef.current && + ! initHasExistingMCAAccountsRef.current; + + const isCreatingAccounts = + isCreatingAdsAccountsRef.current || + isCreatingMCAccountsRef.current || + isCreatingBothAccountsRef.current; - isCreatingMCAccountsRef.current = ! hasExistingMCAccount; - isCreatingAdsAccountsRef.current = ! hasExistingAdsAccount; - isCreatingAccountsRef.current = - ! hasExistingAdsAccount || ! hasExistingMCAccount; - - if ( ! hasExistingMCAccount ) { - await handleCreateAccount(); + useEffect( () => { + // Ads account check + if ( isCreatingAdsAccountsRef.current === true && ! loading ) { + isCreatingAdsAccountsRef.current = false; + accountsCreatedRef.current = true; } - if ( ! hasExistingAdsAccount ) { - await upsertAdsAccount(); + // MC account check + if ( + isCreatingMCAccountsRef.current === true && + response?.status === 200 + ) { + isCreatingMCAccountsRef.current = false; + accountsCreatedRef.current = true; } - }; - useEffect( () => { + // both accounts check if ( - isCreatingAccountsRef.current === true && + isCreatingBothAccountsRef.current === true && response?.status === 200 && ! loading ) { - isCreatingMCAccountsRef.current = false; - isCreatingAdsAccountsRef.current = false; - isCreatingAccountsRef.current = false; + isCreatingBothAccountsRef.current = false; accountsCreatedRef.current = true; } }, [ response, loading ] ); useEffect( () => { - const existingAccountsResolved = - hasFinishedResolutionForExistingAdsAccount && - hasFinishedResolutionForExistingMCAccounts; + const handleCreation = async () => { + // Bail out if we haven't resolved the existing accounts checks yet or there's a creation in progress or the accounts have been created. + if ( + ! accountCreationChecksResolved || + isCreatingAccounts || + accountsCreatedRef.current + ) { + return; + } - accountCreationChecksResolvedRef.current = existingAccountsResolved; + if ( shouldCreateAdsAccount ) { + isCreatingAdsAccountsRef.current = true; + await createAdsAccount(); + return; + } - if ( - existingAccountsResolved && - isCreatingAccountsRef.current === false - ) { - const hasExistingMCAccount = existingMCAccounts?.length > 0; - const hasExistingAdsAccount = existingAdsAccount?.length > 0; + if ( shouldCreateMCAccount ) { + isCreatingMCAccountsRef.current = true; + await createMCAccount(); + return; + } - if ( ! hasExistingMCAccount || ! hasExistingAdsAccount ) { - createAccounts(); + if ( shouldCreateBothAccounts ) { + isCreatingBothAccountsRef.current = true; + await createBothAccounts(); } - } - // eslint-disable-next-line react-hooks/exhaustive-deps + }; + + handleCreation(); }, [ - hasFinishedResolutionForExistingAdsAccount, - hasFinishedResolutionForExistingMCAccounts, + accountCreationChecksResolved, + createBothAccounts, + createAdsAccount, + createMCAccount, + isCreatingAccounts, + shouldCreateAdsAccount, + shouldCreateMCAccount, + shouldCreateBothAccounts, ] ); return { - accountsCreated: accountsCreatedRef.current, - accountCreationChecksResolved: accountCreationChecksResolvedRef.current, + accountCreationChecksResolved, isCreatingAdsAccount: isCreatingAdsAccountsRef.current, isCreatingMCAccount: isCreatingMCAccountsRef.current, + isCreatingBothAccounts: isCreatingBothAccountsRef.current, + isCreatingAccounts, + accountsCreated: accountsCreatedRef.current, }; }; From a0dcb9a8b23f5a04660262e4b0f36a6ed4f0a4ea Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 13:59:43 +0530 Subject: [PATCH 21/91] Fix: e2e tests. --- .../account-creation-description.js | 3 +- .../connected-google-combo-account-card.js | 1 + js/src/hooks/useAutoCreateAdsMCAccounts.js | 18 +-- .../setup-stepper/setup-accounts/index.js | 3 + .../specs/setup-mc/step-1-accounts.test.js | 147 ++++++++++++++++-- tests/e2e/utils/mock-requests.js | 86 ++++------ 6 files changed, 182 insertions(+), 76 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js index ba85d0fdc6..91c845fe39 100644 --- a/js/src/components/google-combo-account-card/account-creation-description.js +++ b/js/src/components/google-combo-account-card/account-creation-description.js @@ -19,6 +19,7 @@ import useGoogleAccount from '.~/hooks/useGoogleAccount'; * @param {Object} props.googleAdsAccount Google Ads account. */ const AccountCreationDescription = ( { + isCreatingBothAccounts, isCreatingMCAccount, isCreatingAdsAccount, isLoading = false, @@ -28,7 +29,7 @@ const AccountCreationDescription = ( { const { google } = useGoogleAccount(); const getDescription = () => { - if ( isCreatingMCAccount && isCreatingAdsAccount ) { + if ( isCreatingBothAccounts ) { return (

{ __( diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 22c1937239..d58944cd63 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -92,6 +92,7 @@ const ConnectedGoogleComboAccountCard = () => { ! hasFinishedResolutionForCurrentAdsAccount || ! hasFinishedResolutionForCurrentMCAccount } + isCreatingBothAccounts={ isCreatingBothAccounts } isCreatingAdsAccount={ isCreatingAdsAccount } isCreatingMCAccount={ isCreatingMCAccount } googleMCAccount={ googleMCAccount } diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 06935d2589..4a1ea0932a 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -33,7 +33,7 @@ const useAutoCreateAdsMCAccounts = () => { const isCreatingBothAccountsRef = useRef( false ); const isCreatingAdsAccountsRef = useRef( false ); const isCreatingMCAccountsRef = useRef( false ); - const initHasExistingMCAAccountsRef = useRef( null ); + const initHasExistingMCAccountsRef = useRef( null ); const initHasExistingAdsAccountsRef = useRef( null ); const accountsCreatedRef = useRef( false ); @@ -44,7 +44,7 @@ const useAutoCreateAdsMCAccounts = () => { const { existingAccounts: existingAdsAccount, - isResolving: isResolvingExistingAdsAccount, + hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount, } = useExistingGoogleAdsAccounts(); const [ handleCreateAccount, { response } ] = useCreateMCAccount(); @@ -54,15 +54,15 @@ const useAutoCreateAdsMCAccounts = () => { const hasExistingAdsAccount = existingAdsAccount?.length > 0; if ( - initHasExistingMCAAccountsRef.current === null && + initHasExistingMCAccountsRef.current === null && hasFinishedResolutionForExistingMCAccounts ) { - initHasExistingMCAAccountsRef.current = hasExistingMCAccount; + initHasExistingMCAccountsRef.current = hasExistingMCAccount; } if ( initHasExistingAdsAccountsRef.current === null && - ! isResolvingExistingAdsAccount + hasFinishedResolutionForExistingAdsAccount ) { initHasExistingAdsAccountsRef.current = hasExistingAdsAccount; } @@ -82,19 +82,19 @@ const useAutoCreateAdsMCAccounts = () => { const accountCreationChecksResolved = initHasExistingAdsAccountsRef.current !== null && - initHasExistingMCAAccountsRef.current !== null; + initHasExistingMCAccountsRef.current !== null; const shouldCreateAdsAccount = initHasExistingAdsAccountsRef.current === false && - initHasExistingMCAAccountsRef.current === true; + initHasExistingMCAccountsRef.current === true; const shouldCreateMCAccount = initHasExistingAdsAccountsRef.current === true && - initHasExistingMCAAccountsRef.current === false; + initHasExistingMCAccountsRef.current === false; const shouldCreateBothAccounts = ! initHasExistingAdsAccountsRef.current && - ! initHasExistingMCAAccountsRef.current; + ! initHasExistingMCAccountsRef.current; const isCreatingAccounts = isCreatingAdsAccountsRef.current || diff --git a/js/src/setup-mc/setup-stepper/setup-accounts/index.js b/js/src/setup-mc/setup-stepper/setup-accounts/index.js index d4bfc68f86..3288e46f61 100644 --- a/js/src/setup-mc/setup-stepper/setup-accounts/index.js +++ b/js/src/setup-mc/setup-stepper/setup-accounts/index.js @@ -127,6 +127,9 @@ const SetupAccounts = ( props ) => { ( googleMCAccount?.status === 'incomplete' && googleMCAccount?.step === 'link_ads' ) ); + console.log('isGoogleAdsReady', isGoogleAdsReady); + console.log('isGoogleMCReady', isGoogleMCReady); + const isContinueButtonDisabled = ! ( hasFinishedResolution && isGoogleAdsReady && diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index de4c235120..432b159729 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -223,23 +223,70 @@ test.describe( 'Set up accounts', () => { await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); - await setupAdsAccountPage.fulfillAdsAccountsRequests( [ + await page.route( /\/wc\/gla\/mc\/accounts\b/, ( route ) => { + if ( route.request().method() === 'POST' ) { + // Do nothing. + } else { + route.continue(); + } + } ); + + await page.route( /\/wc\/gla\/ads\/accounts\b/, ( route ) => { + if ( route.request().method() === 'POST' ) { + // Do nothing. + } else { + route.continue(); + } + } ); + + await setupAdsAccountPage.fulfillAdsAccounts( + [ + [], + { + id: 78787878, + name: 'gla', + }, + ], + 200, + [ 'GET' ] + ); + + await setupAdsAccountPage.fulfillMCAccounts( + [ + [], + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ], + 200, + 'GET' + ); + + await setUpAccountsPage.fulfillAdsConnection( [ { id: 0, currency: 'USD', - status: 'disconnected', + status: 'approved', symbol: '$', }, { - id: 119119119, + id: 78787878, currency: 'USD', - status: 'disconnected', + status: 'approved', symbol: '$', }, ] ); - await setupAdsAccountPage.fulfillMCAccountsRequests( [ - [], + await setUpAccountsPage.fulfillMCConnection( [ + { + id: 0, + name: null, + subaccount: null, + domain: null, + }, { id: 5432178, name: null, @@ -262,20 +309,98 @@ test.describe( 'Set up accounts', () => { } ); test( 'should see the merchant center id and ads account id if connected', async () => { + await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); - await setUpAccountsPage.mockAdsAccountConnected(); - await setUpAccountsPage.mockMCConnected(); await setUpAccountsPage.goto(); + await setupAdsAccountPage.fulfillAdsAccounts( + { + message: + 'Account must be accepted before completing setup.', + has_access: false, + step: 'account_access', + invite_link: 'https://ads.google.com/nav/', + }, + 428, + [ 'POST' ] + ); + + await setupAdsAccountPage.fulfillMCAccounts( + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + 200, + [ 'POST' ] + ); + + await setupAdsAccountPage.fulfillAdsAccounts( + [ + [], + { + id: 78787878, + name: 'gla', + }, + ], + 200, + [ 'GET' ] + ); + + await setupAdsAccountPage.fulfillMCAccounts( + [ + [], + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ], + 200, + 'GET' + ); + + await setUpAccountsPage.fulfillAdsConnection( [ + { + id: 0, + currency: 'USD', + status: 'approved', + symbol: '$', + }, + { + id: 78787878, + currency: 'USD', + status: 'approved', + symbol: '$', + }, + ] ); + + await setUpAccountsPage.fulfillMCConnection( [ + { + id: 0, + name: null, + subaccount: null, + domain: null, + }, + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ] ); + const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); await expect( - googleAccountCard.getByText( 'Merchant Center ID: 1234', { + googleAccountCard.getByText( 'Merchant Center ID: 5432178', { exact: true, } ) ).toBeVisible(); await expect( - googleAccountCard.getByText( 'Google Ads ID: 12345', { + googleAccountCard.getByText( 'Google Ads ID: 78787878', { exact: true, } ) ).toBeVisible(); @@ -326,6 +451,8 @@ test.describe( 'Set up accounts', () => { test.describe( 'When all accounts are connected', async () => { test.beforeAll( async () => { + await setupAdsAccountPage.mockJetpackConnected(); + await setUpAccountsPage.mockGoogleConnected(); await setupAdsAccountPage.mockAdsAccountConnected(); await setupAdsAccountPage.mockAdsStatusClaimed(); await setUpAccountsPage.mockMCConnected(); diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index a94caebe59..477c608057 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -21,49 +21,38 @@ export default class MockRequests { * @return {Promise} */ async fulfillRequest( url, payload, status = 200, methods = [] ) { + let callCount = 0; + await this.page.route( url, ( route ) => { if ( - methods.length === 0 || - methods.includes( route.request().method() ) + ( Array.isArray( payload ) && callCount < payload.length ) || // Ensure there are payloads to fulfill + ( ! Array.isArray( payload ) && callCount === 0 ) // For single payload scenario ) { - route.fulfill( { - status, - content: 'application/json', - headers: { 'Access-Control-Allow-Origin': '*' }, - body: JSON.stringify( payload ), - } ); + if ( + methods.length === 0 || + methods.includes( route.request().method() ) + ) { + // Handle single or multiple payloads + const currentPayload = Array.isArray( payload ) + ? payload[ callCount ] + : payload; + + route.fulfill( { + status, + contentType: 'application/json', + headers: { 'Access-Control-Allow-Origin': '*' }, + body: JSON.stringify( currentPayload ), + } ); + callCount += 1; + } else { + route.fallback(); + } } else { route.fallback(); } } ); } - /** - * Send the different response for each time the route is called. - * - * @param {RegExp|string} url The url to fulfill. - * @param {Array} payloads The payload to send. - * @param {number} status The HTTP status in the response. - * @return {Promise} - */ - async fulfillRequests( url, payloads = [], status = 200 ) { - let callCount = 0; - await this.page.route( url, ( route ) => { - if ( callCount < payloads.length ) { - route.fulfill( { - status, - contentType: 'application/json', - headers: { 'Access-Control-Allow-Origin': '*' }, - body: JSON.stringify( payloads[ callCount ] ), - } ); - } else { - // Optionally handle additional calls beyond the responses array - route.continue(); - } - callCount += 1; - } ); - } - /** * Fulfill the WC options default country request. * @@ -136,16 +125,6 @@ export default class MockRequests { ); } - /** - * Fulfill the MC accounts requests. - * - * @param {Object} payloads - * @return {Promise} - */ - async fulfillMCAccountsRequests( payloads ) { - await this.fulfillRequests( /\/wc\/gla\/mc\/accounts\b/, payloads ); - } - /** * Fulfill the MC accounts claim-overwrite request. * @@ -254,18 +233,13 @@ export default class MockRequests { * @param {Object} payload * @return {Promise} */ - async fulfillAdsAccounts( payload ) { - await this.fulfillRequest( /\/wc\/gla\/ads\/accounts\b/, payload ); - } - - /** - * Fulfill the Ads Account requests. - * - * @param {Object} payloads - * @return {Promise} - */ - async fulfillAdsAccountsRequests( payloads ) { - await this.fulfillRequests( /\/wc\/gla\/ads\/accounts\b/, payloads ); + async fulfillAdsAccounts( payload, status = 200, methods = [] ) { + await this.fulfillRequest( + /\/wc\/gla\/ads\/accounts\b/, + payload, + status, + methods + ); } /** From ea3a30f83d6be08e2b1b0b42eb0a476324dd8542 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 15:50:33 +0530 Subject: [PATCH 22/91] Fix: hook tests. --- .../hooks/useAutoCreateAdsMCAccounts.test.js | 19 +++++-------------- .../setup-stepper/setup-accounts/index.js | 3 --- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 844b968ae8..152bd20f1e 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -41,7 +41,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); useExistingGoogleAdsAccounts.mockReturnValue( { existingAccounts: [], - isResolving: false, + hasFinishedResolution: true, } ); } ); @@ -53,7 +53,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); useExistingGoogleAdsAccounts.mockReturnValue( { existingAccounts: [ { id: 1 } ], - isResolving: false, + hasFinishedResolution: false, } ); const { result } = renderHook( () => useCreateAccounts() ); @@ -85,8 +85,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { rerender(); // Trigger the effect that begins account creation } ); - expect( result.current.isCreatingAdsAccount ).toBe( true ); - expect( result.current.isCreatingMCAccount ).toBe( true ); + expect( result.current.isCreatingAdsAccount ).toBe( false ); + expect( result.current.isCreatingMCAccount ).toBe( false ); await act( async () => { rerender(); @@ -102,14 +102,9 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); it( 'should create Merchant Center account only when there is no existing MC account, but there is an existing Ads account', async () => { - // Simulate no existing MC account but an existing Ads account - useExistingGoogleMCAccounts.mockReturnValue( { - data: [], // No existing MC account - hasFinishedResolution: true, - } ); useExistingGoogleAdsAccounts.mockReturnValue( { existingAccounts: [ { id: 1 } ], // Existing Ads account - isResolving: false, + hasFinishedResolution: true, } ); // Step 1: Initial render - No response, loading is true @@ -162,10 +157,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { data: [ { id: 1 } ], // Existing MC account hasFinishedResolution: true, } ); - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [], // No existing Ads account - isResolving: false, - } ); // Step 1: Initial render - No response, loading is true for Ads account creation useUpsertAdsAccount.mockReturnValueOnce( [ diff --git a/js/src/setup-mc/setup-stepper/setup-accounts/index.js b/js/src/setup-mc/setup-stepper/setup-accounts/index.js index 3288e46f61..d4bfc68f86 100644 --- a/js/src/setup-mc/setup-stepper/setup-accounts/index.js +++ b/js/src/setup-mc/setup-stepper/setup-accounts/index.js @@ -127,9 +127,6 @@ const SetupAccounts = ( props ) => { ( googleMCAccount?.status === 'incomplete' && googleMCAccount?.step === 'link_ads' ) ); - console.log('isGoogleAdsReady', isGoogleAdsReady); - console.log('isGoogleMCReady', isGoogleMCReady); - const isContinueButtonDisabled = ! ( hasFinishedResolution && isGoogleAdsReady && From 58738f81840efddac41580bb82089c5203c34e08 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 15:54:54 +0530 Subject: [PATCH 23/91] Lint fix. --- .../google-combo-account-card/account-creation-description.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js index 91c845fe39..a6b53d6354 100644 --- a/js/src/components/google-combo-account-card/account-creation-description.js +++ b/js/src/components/google-combo-account-card/account-creation-description.js @@ -12,6 +12,7 @@ import useGoogleAccount from '.~/hooks/useGoogleAccount'; * Renders the description for the account creation card. * * @param {Object} props Props. + * @param {boolean} props.isCreatingBothAccounts Whether both, MC and Ads accounts are being created. * @param {boolean} props.isCreatingMCAccount Whether Merchant Center account is being created. * @param {boolean} props.isCreatingAdsAccount Whether Google Ads account is being created. * @param {boolean} props.isLoading Whether the data is loading. From a2b5f196e13da1ed98fad6e2f15753bec53225ed Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 16:05:35 +0530 Subject: [PATCH 24/91] Remove unnecessary act in tests. --- .../hooks/useAutoCreateAdsMCAccounts.test.js | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 152bd20f1e..2fdc806d34 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -1,4 +1,3 @@ -/* eslint-disable testing-library/no-unnecessary-act */ /** * External dependencies */ @@ -81,13 +80,12 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { { loading: false }, ] ); - await act( async () => { - rerender(); // Trigger the effect that begins account creation - } ); + rerender(); expect( result.current.isCreatingAdsAccount ).toBe( false ); expect( result.current.isCreatingMCAccount ).toBe( false ); + // eslint-disable-next-line testing-library/no-unnecessary-act await act( async () => { rerender(); } ); @@ -119,10 +117,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { expect( result.current.isCreatingAdsAccount ).toBe( false ); expect( result.current.isCreatingMCAccount ).toBe( false ); - // Trigger the effect that starts account creation - await act( async () => { - rerender(); // Simulate the effect firing - } ); + // Trigger the effect that starts account creation. + rerender(); // Step 2: At this point, MC account creation should have started expect( result.current.isCreatingMCAccount ).toBe( true ); @@ -136,10 +132,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { { response: { status: 200 }, loading: false }, // Now account creation is complete ] ); - // Trigger a rerender to simulate the async function resolving - await act( async () => { - rerender(); // Re-render after response has been updated - } ); + // Trigger a rerender to simulate the async function resolving. + rerender(); // Step 4: Final assertions after account creation has completed expect( result.current.isCreatingAdsAccount ).toBe( false ); @@ -170,10 +164,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { expect( result.current.isCreatingAdsAccount ).toBe( false ); expect( result.current.isCreatingMCAccount ).toBe( false ); - // Trigger the effect that starts account creation - await act( async () => { - rerender(); // Simulate the effect firing - } ); + rerender(); // Simulate the effect firing. // Step 2: At this point, Ads account creation should have started expect( result.current.isCreatingAdsAccount ).toBe( true ); @@ -187,10 +178,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { { response: { status: 200 }, loading: false }, // Now Ads account creation is complete ] ); - // Trigger a rerender to simulate the async function resolving - await act( async () => { - rerender(); // Re-render after response has been updated - } ); + // Trigger a rerender to simulate the async function resolving. + rerender(); // Step 4: Final assertions after Ads account creation has completed expect( result.current.accountsCreated ).toBe( true ); // The account has been created From c4f0d2b73f5a1d56c626ad821548b73c8a013e59 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 21:13:21 +0530 Subject: [PATCH 25/91] Move hooks to relevant component. --- .../account-creation-description.js | 123 ---------------- .../account-info.js | 16 +++ .../account-creation-description/index.js | 131 ++++++++++++++++++ .../connected-google-combo-account-card.js | 24 +--- 4 files changed, 149 insertions(+), 145 deletions(-) delete mode 100644 js/src/components/google-combo-account-card/account-creation-description.js create mode 100644 js/src/components/google-combo-account-card/account-creation-description/account-info.js create mode 100644 js/src/components/google-combo-account-card/account-creation-description/index.js diff --git a/js/src/components/google-combo-account-card/account-creation-description.js b/js/src/components/google-combo-account-card/account-creation-description.js deleted file mode 100644 index a6b53d6354..0000000000 --- a/js/src/components/google-combo-account-card/account-creation-description.js +++ /dev/null @@ -1,123 +0,0 @@ -/** - * External dependencies - */ -import { __, sprintf } from '@wordpress/i18n'; - -/** - * Internal dependencies - */ -import useGoogleAccount from '.~/hooks/useGoogleAccount'; - -/** - * Renders the description for the account creation card. - * - * @param {Object} props Props. - * @param {boolean} props.isCreatingBothAccounts Whether both, MC and Ads accounts are being created. - * @param {boolean} props.isCreatingMCAccount Whether Merchant Center account is being created. - * @param {boolean} props.isCreatingAdsAccount Whether Google Ads account is being created. - * @param {boolean} props.isLoading Whether the data is loading. - * @param {Object} props.googleMCAccount Google Merchant Center account. - * @param {Object} props.googleAdsAccount Google Ads account. - */ -const AccountCreationDescription = ( { - isCreatingBothAccounts, - isCreatingMCAccount, - isCreatingAdsAccount, - isLoading = false, - googleMCAccount = {}, - googleAdsAccount = {}, -} ) => { - const { google } = useGoogleAccount(); - - const getDescription = () => { - if ( isCreatingBothAccounts ) { - return ( -

- { __( - 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', - 'google-listings-and-ads' - ) } -

- ); - } else if ( isCreatingAdsAccount ) { - return ( - <> -

- { __( - 'You don’t have Google Ads account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } - - - ); - } else if ( isCreatingMCAccount ) { - return ( - <> -

- { __( - 'You don’t have Merchant Center account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to sync products so they show on Google.', - 'google-listings-and-ads' - ) } - - - ); - } - - const DisplayAccountInfo = ( { account, text } ) => { - if ( account?.id === undefined || account.id === 0 ) { - return null; - } - - return

{ text }

; - }; - - if ( isLoading ) { - return null; - } - - return ( - <> -

{ google?.email }

- - - - ); - }; - - return ( -
- { getDescription() } -
- ); -}; - -export default AccountCreationDescription; diff --git a/js/src/components/google-combo-account-card/account-creation-description/account-info.js b/js/src/components/google-combo-account-card/account-creation-description/account-info.js new file mode 100644 index 0000000000..673c16a1d4 --- /dev/null +++ b/js/src/components/google-combo-account-card/account-creation-description/account-info.js @@ -0,0 +1,16 @@ +/** + * Display account info. + * + * @param {Object} props Props. + * @param {Object} props.account Account object. + * @param {string} props.text Text to display. + */ +const AccountInfo = ( { account, text } ) => { + if ( ! account?.id ) { + return null; + } + + return

{ text }

; +}; + +export default AccountInfo; diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js new file mode 100644 index 0000000000..bb5a7ec23d --- /dev/null +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -0,0 +1,131 @@ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import useGoogleAccount from '.~/hooks/useGoogleAccount'; +import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import AccountInfo from './account-info'; + +/** + * Renders the description for the account creation card. + * + * @param {Object} props Props. + * @param {Object} props.accountsCreated Whether accounts have been created. + * @param {boolean} props.isCreatingBothAccounts Whether both, MC and Ads accounts are being created. + * @param {boolean} props.isCreatingMCAccount Whether Merchant Center account is being created. + * @param {boolean} props.isCreatingAdsAccount Whether Google Ads account is being created. + */ +const AccountCreationDescription = ( { + accountsCreated, + isCreatingBothAccounts, + isCreatingMCAccount, + isCreatingAdsAccount, +} ) => { + const { google } = useGoogleAccount(); + const { + googleMCAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, + } = useGoogleMCAccount(); + + const { + googleAdsAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, + } = useGoogleAdsAccount(); + + const isLoadingData = + accountsCreated && + ( ! hasFinishedResolutionForCurrentMCAccount || + ! hasFinishedResolutionForCurrentAdsAccount ); + + const getDescription = () => { + if ( + isLoadingData || + isCreatingBothAccounts || + isCreatingMCAccount || + isCreatingAdsAccount + ) { + if ( isCreatingBothAccounts ) { + return ( +

+ { __( + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', + 'google-listings-and-ads' + ) } +

+ ); + } else if ( isCreatingAdsAccount ) { + return ( + <> +

+ { __( + 'You don’t have Google Ads account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } + + + ); + } else if ( isCreatingMCAccount ) { + return ( + <> +

+ { __( + 'You don’t have Merchant Center account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to sync products so they show on Google.', + 'google-listings-and-ads' + ) } + + + ); + } + } + + return ( + <> +

{ google?.email }

+ + + + ); + }; + + return ( +
+ { getDescription() } +
+ ); +}; + +export default AccountCreationDescription; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index d58944cd63..00135cae14 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -27,16 +27,6 @@ import AccountCreationDescription from './account-creation-description'; * @fires gla_google_account_connect_different_account_button_click */ const ConnectedGoogleComboAccountCard = () => { - const { - googleMCAccount, - hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, - } = useGoogleMCAccount(); - - const { - googleAdsAccount, - hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, - } = useGoogleAdsAccount(); - const { isCreatingAccounts, isCreatingBothAccounts, @@ -46,12 +36,7 @@ const ConnectedGoogleComboAccountCard = () => { accountsCreated, } = useAutoCreateAdsMCAccounts(); - if ( - ! accountsCreated && - ( ! hasFinishedResolutionForCurrentAdsAccount || - ! hasFinishedResolutionForCurrentMCAccount || - ! accountCreationChecksResolved ) - ) { + if ( ! accountCreationChecksResolved ) { return } />; } @@ -88,15 +73,10 @@ const ConnectedGoogleComboAccountCard = () => { className="gla-google-combo-account-card--connected" description={ } helper={ getHelper() } From 0d5130f8bc1083fc79087ca2ea65d324542d49fb Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 3 Oct 2024 21:24:56 +0530 Subject: [PATCH 26/91] Fix js linting. --- .../connected-google-combo-account-card.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 00135cae14..bc554cfa8f 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -7,8 +7,6 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import AppSpinner from '../app-spinner'; import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; import LoadingLabel from '../loading-label/loading-label'; From 896c681e2d730282536ca014b54bb7264eebd26f Mon Sep 17 00:00:00 2001 From: asvinb Date: Thu, 3 Oct 2024 20:30:10 +0400 Subject: [PATCH 27/91] Load correct scss file in appropriate component. --- .../connect-google-combo-account-card.js | 1 - .../connected-google-combo-account-card.js | 1 + ...ccount-card.scss => connected-google-combo-account-card.scss} | 0 3 files changed, 1 insertion(+), 1 deletion(-) rename js/src/components/google-combo-account-card/{connect-google-combo-account-card.scss => connected-google-combo-account-card.scss} (100%) diff --git a/js/src/components/google-combo-account-card/connect-google-combo-account-card.js b/js/src/components/google-combo-account-card/connect-google-combo-account-card.js index dfff4dd2c9..2537700494 100644 --- a/js/src/components/google-combo-account-card/connect-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connect-google-combo-account-card.js @@ -14,7 +14,6 @@ import AppButton from '.~/components/app-button'; import readMoreLink from '../google-account-card/read-more-link'; import useGoogleConnectFlow from '../google-account-card/use-google-connect-flow'; import AppDocumentationLink from '../app-documentation-link'; -import './connect-google-combo-account-card.scss'; /** * @param {Object} props React props diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index bc554cfa8f..f0a752de2b 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -11,6 +11,7 @@ import AppSpinner from '../app-spinner'; import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; import LoadingLabel from '../loading-label/loading-label'; import AccountCreationDescription from './account-creation-description'; +import './connected-google-combo-account-card.scss'; /** * Clicking on the "connect to a different Google account" button. diff --git a/js/src/components/google-combo-account-card/connect-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss similarity index 100% rename from js/src/components/google-combo-account-card/connect-google-combo-account-card.scss rename to js/src/components/google-combo-account-card/connected-google-combo-account-card.scss From 1252ac95a119df09ce48ff275f8fff87296cd530 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 8 Oct 2024 10:54:57 +0530 Subject: [PATCH 28/91] Add connected icon label. --- .../connected-google-combo-account-card.js | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index f0a752de2b..df39b7eda2 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -12,6 +12,9 @@ import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; import LoadingLabel from '../loading-label/loading-label'; import AccountCreationDescription from './account-creation-description'; import './connected-google-combo-account-card.scss'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; +import ConnectedIconLabel from '../connected-icon-label'; /** * Clicking on the "connect to a different Google account" button. @@ -26,6 +29,16 @@ import './connected-google-combo-account-card.scss'; * @fires gla_google_account_connect_different_account_button_click */ const ConnectedGoogleComboAccountCard = () => { + const { + googleAdsAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, + } = useGoogleAdsAccount(); + + const { + googleMCAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, + } = useGoogleMCAccount(); + const { isCreatingAccounts, isCreatingBothAccounts, @@ -35,10 +48,25 @@ const ConnectedGoogleComboAccountCard = () => { accountsCreated, } = useAutoCreateAdsMCAccounts(); - if ( ! accountCreationChecksResolved ) { + if ( + ! accountCreationChecksResolved || + ! hasFinishedResolutionForCurrentAdsAccount || + ! hasFinishedResolutionForCurrentMCAccount + ) { return } />; } + const isGoogleAdsAccountConnected = + googleAdsAccount?.status === 'approved' || + ( googleAdsAccount?.status === 'incomplete' && + googleAdsAccount?.step === 'link_merchant' ); + + const isGoogleMCAccountConnected = + googleMCAccount?.id || + googleMCAccount?.status === 'connected' || + ( googleMCAccount?.status === 'incomplete' && + googleMCAccount?.step === 'link_ads' ); + const getHelper = () => { if ( isCreatingBothAccounts ) { return ( @@ -63,6 +91,14 @@ const ConnectedGoogleComboAccountCard = () => { ); } + if ( isGoogleAdsAccountConnected && isGoogleMCAccountConnected ) { + return ( + + ); + } + return null; }; From 6d46a02513746e37675cfda1c0b318e52c875952 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 8 Oct 2024 11:52:25 +0530 Subject: [PATCH 29/91] Fix: E2E tests. --- .../specs/setup-mc/step-1-accounts.test.js | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 432b159729..5da3868d70 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -242,10 +242,12 @@ test.describe( 'Set up accounts', () => { await setupAdsAccountPage.fulfillAdsAccounts( [ [], - { - id: 78787878, - name: 'gla', - }, + [ + { + id: 78787878, + name: 'gla', + }, + ], ], 200, [ 'GET' ] @@ -254,12 +256,14 @@ test.describe( 'Set up accounts', () => { await setupAdsAccountPage.fulfillMCAccounts( [ [], - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - }, + [ + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ], ], 200, 'GET' @@ -339,10 +343,12 @@ test.describe( 'Set up accounts', () => { await setupAdsAccountPage.fulfillAdsAccounts( [ [], - { - id: 78787878, - name: 'gla', - }, + [ + { + id: 78787878, + name: 'gla', + }, + ], ], 200, [ 'GET' ] @@ -351,12 +357,14 @@ test.describe( 'Set up accounts', () => { await setupAdsAccountPage.fulfillMCAccounts( [ [], - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - }, + [ + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ], ], 200, 'GET' From 2466e3cf0f8b99ea0291bbd2b03eee4a3ed95e82 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 8 Oct 2024 15:47:26 +0530 Subject: [PATCH 30/91] Fix: Creating account message showing up constantly. --- .../connected-google-combo-account-card.js | 16 +++++++---- js/src/constants.js | 7 +++++ js/src/hooks/useAutoCreateAdsMCAccounts.js | 28 ++++++++++++++++--- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index df39b7eda2..83dba43a58 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -15,6 +15,10 @@ import './connected-google-combo-account-card.scss'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import ConnectedIconLabel from '../connected-icon-label'; +import { + GOOGLE_ADS_ACCOUNT_STATUS, + GOOGLE_MC_ACCOUNT_STATUS, +} from '.~/constants'; /** * Clicking on the "connect to a different Google account" button. @@ -57,14 +61,16 @@ const ConnectedGoogleComboAccountCard = () => { } const isGoogleAdsAccountConnected = - googleAdsAccount?.status === 'approved' || - ( googleAdsAccount?.status === 'incomplete' && - googleAdsAccount?.step === 'link_merchant' ); + googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED || + ( googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.INCOMPLETE && + [ 'link_merchant', 'account_access' ].includes( + googleAdsAccount?.step + ) ); const isGoogleMCAccountConnected = googleMCAccount?.id || - googleMCAccount?.status === 'connected' || - ( googleMCAccount?.status === 'incomplete' && + googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || + ( googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && googleMCAccount?.step === 'link_ads' ); const getHelper = () => { diff --git a/js/src/constants.js b/js/src/constants.js index de28ac0544..e66e9476f6 100644 --- a/js/src/constants.js +++ b/js/src/constants.js @@ -70,6 +70,13 @@ export const GOOGLE_ADS_ACCOUNT_STATUS = { INCOMPLETE: 'incomplete', }; +// Account status related +export const GOOGLE_MC_ACCOUNT_STATUS = { + CONNECTED: 'connected', + DISCONNECTED: 'disconnected', + INCOMPLETE: 'incomplete', +}; + export const GOOGLE_ADS_BILLING_STATUS = { UNKNOWN: 'unknown', PENDING: 'pending', diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 4a1ea0932a..ab9951a2dc 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -10,6 +10,9 @@ import useCreateMCAccount from '../components/google-mc-account-card/useCreateMC import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; +import useGoogleAdsAccount from './useGoogleAdsAccount'; +import useGoogleMCAccount from './useGoogleMCAccount'; +import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; /** * Custom hook to handle the creation of Google Merchant Center (MC) and Google Ads accounts. @@ -47,22 +50,39 @@ const useAutoCreateAdsMCAccounts = () => { hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount, } = useExistingGoogleAdsAccounts(); + const { + hasFinishedResolution: hasFinishedResolutionForGoogleAdsAccount, + hasGoogleAdsConnection, + } = useGoogleAdsAccount(); + + const { + googleMCAccount, + hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount, + } = useGoogleMCAccount(); + const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); + const isGoogleMCConnected = + googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || + googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE; - const hasExistingMCAccount = existingMCAccounts?.length > 0; - const hasExistingAdsAccount = existingAdsAccount?.length > 0; + const hasExistingMCAccount = + isGoogleMCConnected || existingMCAccounts?.length > 0; + const hasExistingAdsAccount = + hasGoogleAdsConnection || existingAdsAccount?.length > 0; if ( initHasExistingMCAccountsRef.current === null && - hasFinishedResolutionForExistingMCAccounts + hasFinishedResolutionForExistingMCAccounts && + hasFinishedResolutionForGoogleMCAccount ) { initHasExistingMCAccountsRef.current = hasExistingMCAccount; } if ( initHasExistingAdsAccountsRef.current === null && - hasFinishedResolutionForExistingAdsAccount + hasFinishedResolutionForExistingAdsAccount && + hasFinishedResolutionForGoogleAdsAccount ) { initHasExistingAdsAccountsRef.current = hasExistingAdsAccount; } From 11eba1ba53316615270a7a3e0ea747a9f61387ea Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 8 Oct 2024 16:50:27 +0530 Subject: [PATCH 31/91] Update filfilrequest utility. --- .../specs/setup-mc/step-1-accounts.test.js | 144 ++++++++++-------- tests/e2e/utils/mock-requests.js | 119 +++++++++++---- 2 files changed, 173 insertions(+), 90 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 5da3868d70..931a6a1d21 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -250,7 +250,8 @@ test.describe( 'Set up accounts', () => { ], ], 200, - [ 'GET' ] + [ 'GET' ], + true ); await setupAdsAccountPage.fulfillMCAccounts( @@ -266,38 +267,49 @@ test.describe( 'Set up accounts', () => { ], ], 200, - 'GET' + 'GET', + true ); - await setUpAccountsPage.fulfillAdsConnection( [ - { - id: 0, - currency: 'USD', - status: 'approved', - symbol: '$', - }, - { - id: 78787878, - currency: 'USD', - status: 'approved', - symbol: '$', - }, - ] ); + await setUpAccountsPage.fulfillAdsConnection( + [ + { + id: 0, + currency: 'USD', + status: 'approved', + symbol: '$', + }, + { + id: 78787878, + currency: 'USD', + status: 'approved', + symbol: '$', + }, + ], + 200, + 'GET', + true + ); - await setUpAccountsPage.fulfillMCConnection( [ - { - id: 0, - name: null, - subaccount: null, - domain: null, - }, - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - }, - ] ); + await setUpAccountsPage.fulfillMCConnection( + [ + { + id: 0, + name: null, + subaccount: null, + domain: null, + }, + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ], + 200, + 'GET', + true + ); await setUpAccountsPage.goto(); const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); @@ -351,7 +363,8 @@ test.describe( 'Set up accounts', () => { ], ], 200, - [ 'GET' ] + [ 'GET' ], + true ); await setupAdsAccountPage.fulfillMCAccounts( @@ -367,38 +380,49 @@ test.describe( 'Set up accounts', () => { ], ], 200, - 'GET' + 'GET', + true ); - await setUpAccountsPage.fulfillAdsConnection( [ - { - id: 0, - currency: 'USD', - status: 'approved', - symbol: '$', - }, - { - id: 78787878, - currency: 'USD', - status: 'approved', - symbol: '$', - }, - ] ); + await setUpAccountsPage.fulfillAdsConnection( + [ + { + id: 0, + currency: 'USD', + status: 'approved', + symbol: '$', + }, + { + id: 78787878, + currency: 'USD', + status: 'approved', + symbol: '$', + }, + ], + 200, + 'GET', + true + ); - await setUpAccountsPage.fulfillMCConnection( [ - { - id: 0, - name: null, - subaccount: null, - domain: null, - }, - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - }, - ] ); + await setUpAccountsPage.fulfillMCConnection( + [ + { + id: 0, + name: null, + subaccount: null, + domain: null, + }, + { + id: 5432178, + name: null, + subaccount: null, + domain: null, + }, + ], + 200, + 'GET', + true + ); const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); await expect( diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index 477c608057..bf1f2e5dfb 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -18,35 +18,50 @@ export default class MockRequests { * @param {Object} payload The payload to send. * @param {number} status The HTTP status in the response. * @param {Array} methods The HTTP methods in the request to be fulfill. + * @param {boolean} multiRequestMock Whether to mock multiple requests. * @return {Promise} */ - async fulfillRequest( url, payload, status = 200, methods = [] ) { + async fulfillRequest( + url, + payload, + status = 200, + methods = [], + multiRequestMock = false + ) { let callCount = 0; await this.page.route( url, ( route ) => { - if ( - ( Array.isArray( payload ) && callCount < payload.length ) || // Ensure there are payloads to fulfill - ( ! Array.isArray( payload ) && callCount === 0 ) // For single payload scenario - ) { - if ( - methods.length === 0 || - methods.includes( route.request().method() ) - ) { - // Handle single or multiple payloads - const currentPayload = Array.isArray( payload ) - ? payload[ callCount ] - : payload; - - route.fulfill( { - status, - contentType: 'application/json', - headers: { 'Access-Control-Allow-Origin': '*' }, - body: JSON.stringify( currentPayload ), - } ); - callCount += 1; + const requestMethod = route.request().method(); + + if ( methods.length === 0 || methods.includes( requestMethod ) ) { + let currentPayload; + + if ( multiRequestMock ) { + // Handle multiple requests scenario + if ( + Array.isArray( payload ) && + callCount < payload.length + ) { + currentPayload = payload[ callCount ]; + callCount += 1; + } else if ( ! Array.isArray( payload ) ) { + currentPayload = payload; + } else { + // Fallback if all payloads are fulfilled + route.fallback(); + return; + } } else { - route.fallback(); + // Handle single response scenario + currentPayload = payload; } + + route.fulfill( { + status, + contentType: 'application/json', + headers: { 'Access-Control-Allow-Origin': '*' }, + body: JSON.stringify( currentPayload ), + } ); } else { route.fallback(); } @@ -114,14 +129,21 @@ export default class MockRequests { * @param {Object} payload * @param {number} status * @param {string[]} [methods] + * @param {boolean} multiRequestMock * @return {Promise} */ - async fulfillMCAccounts( payload, status = 200, methods ) { + async fulfillMCAccounts( + payload, + status = 200, + methods, + multiRequestMock = false + ) { await this.fulfillRequest( /\/wc\/gla\/mc\/accounts\b/, payload, status, - methods + methods, + multiRequestMock ); } @@ -144,10 +166,24 @@ export default class MockRequests { * Fulfill the MC connection request. * * @param {Object} payload + * @param {number} status + * @param {Array} methods + * @param {boolean} multiRequestMock * @return {Promise} */ - async fulfillMCConnection( payload ) { - await this.fulfillRequest( /\/wc\/gla\/mc\/connection\b/, payload ); + async fulfillMCConnection( + payload, + status = 200, + methods = [], + multiRequestMock = false + ) { + await this.fulfillRequest( + /\/wc\/gla\/mc\/connection\b/, + payload, + status, + methods, + multiRequestMock + ); } /** @@ -204,10 +240,24 @@ export default class MockRequests { * Fulfill the Ads Connection request. * * @param {Object} payload + * @param {number} status + * @param {Array} methods + * @param {boolean} multiRequestMock * @return {Promise} */ - async fulfillAdsConnection( payload ) { - await this.fulfillRequest( /\/wc\/gla\/ads\/connection\b/, payload ); + async fulfillAdsConnection( + payload, + status = 200, + methods = [], + multiRequestMock = false + ) { + await this.fulfillRequest( + /\/wc\/gla\/ads\/connection\b/, + payload, + status, + methods, + multiRequestMock + ); } /** @@ -231,14 +281,23 @@ export default class MockRequests { * Fulfill the Ads Account request. * * @param {Object} payload + * @param {number} status + * @param {Array} methods + * @param {boolean} multiRequestMock * @return {Promise} */ - async fulfillAdsAccounts( payload, status = 200, methods = [] ) { + async fulfillAdsAccounts( + payload, + status = 200, + methods = [], + multiRequestMock = false + ) { await this.fulfillRequest( /\/wc\/gla\/ads\/accounts\b/, payload, status, - methods + methods, + multiRequestMock ); } From 0df9699336b49595b38b8ebe59efdde960e0ad3c Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 8 Oct 2024 18:08:45 +0530 Subject: [PATCH 32/91] Fix: unit test errors. --- .../hooks/useAutoCreateAdsMCAccounts.test.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 2fdc806d34..86b904ae13 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -11,12 +11,15 @@ import useCreateMCAccount from '../components/google-mc-account-card/useCreateMC import useUpsertAdsAccount from './useUpsertAdsAccount'; import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; +import useGoogleAdsAccount from './useGoogleAdsAccount'; +import useGoogleMCAccount from './useGoogleMCAccount'; jest.mock( '../components/google-mc-account-card/useCreateMCAccount' ); jest.mock( './useUpsertAdsAccount' ); jest.mock( './useExistingGoogleAdsAccounts' ); jest.mock( './useExistingGoogleMCAccounts' ); jest.mock( './useGoogleAdsAccount' ); +jest.mock( './useGoogleMCAccount' ); describe( 'useAutoCreateAdsMCAccounts hook', () => { let handleCreateAccount; @@ -42,6 +45,21 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { existingAccounts: [], hasFinishedResolution: true, } ); + + useGoogleAdsAccount.mockReturnValue( { + hasFinishedResolution: true, + hasGoogleAdsConnection: false, + } ); + + useGoogleAdsAccount.mockReturnValue( { + hasFinishedResolution: true, + hasGoogleAdsConnection: false, + } ); + + useGoogleMCAccount.mockReturnValue( { + hasFinishedResolution: true, + googleMCAccount: undefined, + } ); } ); it( 'should not call "handleCreateAccount" and "upsertAdsAccount" when there are existing accounts', () => { From ab0d80df9cabf20e6b40ed8be0e0af87c3acefd3 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 8 Oct 2024 18:48:42 +0530 Subject: [PATCH 33/91] Add E2E test case for connected label. --- .../connected-google-combo-account-card.js | 2 +- .../specs/setup-mc/step-1-accounts.test.js | 157 +++++++----------- 2 files changed, 62 insertions(+), 97 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 83dba43a58..c92f2b4597 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -71,7 +71,7 @@ const ConnectedGoogleComboAccountCard = () => { googleMCAccount?.id || googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || ( googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && - googleMCAccount?.step === 'link_ads' ); + [ 'link_ads', 'claim' ].includes( googleMCAccount?.step ) ); const getHelper = () => { if ( isCreatingBothAccounts ) { diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 931a6a1d21..7e7e7fcca5 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -276,13 +276,15 @@ test.describe( 'Set up accounts', () => { { id: 0, currency: 'USD', - status: 'approved', + status: 'disconnected', symbol: '$', }, { id: 78787878, currency: 'USD', - status: 'approved', + status: 'incomplete', + step: 'account_access', + sub_account: true, symbol: '$', }, ], @@ -324,118 +326,81 @@ test.describe( 'Set up accounts', () => { ).toBeVisible(); } ); - test( 'should see the merchant center id and ads account id if connected', async () => { - await setUpAccountsPage.mockJetpackConnected(); - await setUpAccountsPage.mockGoogleConnected(); - await setUpAccountsPage.goto(); - - await setupAdsAccountPage.fulfillAdsAccounts( - { - message: - 'Account must be accepted before completing setup.', - has_access: false, - step: 'account_access', - invite_link: 'https://ads.google.com/nav/', - }, - 428, - [ 'POST' ] - ); + test.describe( 'After connecting Google account', () => { + test.beforeEach( async () => { + await setUpAccountsPage.mockJetpackConnected(); + await setUpAccountsPage.mockGoogleConnected(); - await setupAdsAccountPage.fulfillMCAccounts( - { + await setUpAccountsPage.fulfillMCConnection( { id: 5432178, name: null, subaccount: null, domain: null, - }, - 200, - [ 'POST' ] - ); - - await setupAdsAccountPage.fulfillAdsAccounts( - [ - [], - [ - { - id: 78787878, - name: 'gla', - }, - ], - ], - 200, - [ 'GET' ], - true - ); + status: 'incomplete', + step: 'claim', + } ); + + await setUpAccountsPage.fulfillAdsConnection( { + id: 78787878, + currency: 'USD', + status: 'incomplete', + step: 'account_access', + sub_account: true, + symbol: '$', + } ); - await setupAdsAccountPage.fulfillMCAccounts( - [ - [], - [ - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - }, - ], - ], - 200, - 'GET', - true - ); + await setUpAccountsPage.goto(); + } ); - await setUpAccountsPage.fulfillAdsConnection( - [ + test( 'should see the merchant center id and ads account id if connected', async () => { + await setupAdsAccountPage.fulfillAdsAccounts( { - id: 0, - currency: 'USD', - status: 'approved', - symbol: '$', + message: + 'Account must be accepted before completing setup.', + has_access: false, + step: 'account_access', + invite_link: 'https://ads.google.com/nav/', }, - { - id: 78787878, - currency: 'USD', - status: 'approved', - symbol: '$', - }, - ], - 200, - 'GET', - true - ); + 428, + [ 'POST' ] + ); - await setUpAccountsPage.fulfillMCConnection( - [ - { - id: 0, - name: null, - subaccount: null, - domain: null, - }, + await setupAdsAccountPage.fulfillMCAccounts( { id: 5432178, name: null, subaccount: null, domain: null, }, - ], - 200, - 'GET', - true - ); + 200, + [ 'POST' ] + ); + + const googleAccountCard = + setUpAccountsPage.getGoogleAccountCard(); + await expect( + googleAccountCard.getByText( + 'Merchant Center ID: 5432178', + { + exact: true, + } + ) + ).toBeVisible(); - const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); - await expect( - googleAccountCard.getByText( 'Merchant Center ID: 5432178', { - exact: true, - } ) - ).toBeVisible(); + await expect( + googleAccountCard.getByText( 'Google Ads ID: 78787878', { + exact: true, + } ) + ).toBeVisible(); + } ); - await expect( - googleAccountCard.getByText( 'Google Ads ID: 78787878', { - exact: true, - } ) - ).toBeVisible(); + test( 'should see the connected label', async () => { + const googleAccountCard = + setUpAccountsPage.getGoogleAccountCard(); + await expect( + googleAccountCard.getByText( 'Connected', { exact: true } ) + ).toBeVisible(); + } ); } ); } ); From f2b3c2173aaa75ec0d991cbe1a4b70cbf2e3d41a Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 8 Oct 2024 19:18:19 +0530 Subject: [PATCH 34/91] Remove ambiguous request mocking. --- tests/e2e/specs/setup-mc/step-1-accounts.test.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 7e7e7fcca5..03e655a14e 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -223,22 +223,6 @@ test.describe( 'Set up accounts', () => { await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); - await page.route( /\/wc\/gla\/mc\/accounts\b/, ( route ) => { - if ( route.request().method() === 'POST' ) { - // Do nothing. - } else { - route.continue(); - } - } ); - - await page.route( /\/wc\/gla\/ads\/accounts\b/, ( route ) => { - if ( route.request().method() === 'POST' ) { - // Do nothing. - } else { - route.continue(); - } - } ); - await setupAdsAccountPage.fulfillAdsAccounts( [ [], From b1023b65b1e361382b63c53a3ba11a1335be5bd0 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Mon, 14 Oct 2024 20:29:48 +0530 Subject: [PATCH 35/91] Remove use of useCallback and redundant code. --- .../account-creation-description/index.js | 6 +-- .../connect-google-combo-account-card.js | 1 - .../connected-google-combo-account-card.js | 15 +----- .../connected-google-combo-account-card.scss | 4 -- .../connect-mc/index.js | 2 +- .../google-mc-account-card/create-account.js | 2 +- js/src/constants.js | 2 - js/src/hooks/useAutoCreateAdsMCAccounts.js | 53 +++++++++---------- .../hooks/useAutoCreateAdsMCAccounts.test.js | 19 +++---- .../useCreateMCAccount.js | 0 10 files changed, 38 insertions(+), 66 deletions(-) rename js/src/{components/google-mc-account-card => hooks}/useCreateMCAccount.js (100%) diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index bb5a7ec23d..5270358248 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -15,7 +15,7 @@ import AccountInfo from './account-info'; * Renders the description for the account creation card. * * @param {Object} props Props. - * @param {Object} props.accountsCreated Whether accounts have been created. + * @param {boolean} props.accountsCreated Whether accounts have been created. * @param {boolean} props.isCreatingBothAccounts Whether both, MC and Ads accounts are being created. * @param {boolean} props.isCreatingMCAccount Whether Merchant Center account is being created. * @param {boolean} props.isCreatingAdsAccount Whether Google Ads account is being created. @@ -37,14 +37,14 @@ const AccountCreationDescription = ( { hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, } = useGoogleAdsAccount(); - const isLoadingData = + const isLoadingAccountsData = accountsCreated && ( ! hasFinishedResolutionForCurrentMCAccount || ! hasFinishedResolutionForCurrentAdsAccount ); const getDescription = () => { if ( - isLoadingData || + isLoadingAccountsData || isCreatingBothAccounts || isCreatingMCAccount || isCreatingAdsAccount diff --git a/js/src/components/google-combo-account-card/connect-google-combo-account-card.js b/js/src/components/google-combo-account-card/connect-google-combo-account-card.js index 2537700494..a20c0c3de8 100644 --- a/js/src/components/google-combo-account-card/connect-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connect-google-combo-account-card.js @@ -33,7 +33,6 @@ const ConnectGoogleComboAccountCard = ( { disabled } ) => { return ( { const { @@ -98,11 +90,7 @@ const ConnectedGoogleComboAccountCard = () => { } if ( isGoogleAdsAccountConnected && isGoogleMCAccountConnected ) { - return ( - - ); + return ; } return null; @@ -111,6 +99,7 @@ const ConnectedGoogleComboAccountCard = () => { return ( { - /** - * Refs are used to avoid the re-render of the parent component. - * - * accountCreationChecksResolvedRef - Indicates if the account creation checks have been resolved. - * isCreatingAccountsRef - Indicates if the accounts are being created. - * accountsCreatedRef - Indicates if the accounts have been created. - */ + // Refs are used to avoid the re-render of the parent component. const isCreatingBothAccountsRef = useRef( false ); const isCreatingAdsAccountsRef = useRef( false ); const isCreatingMCAccountsRef = useRef( false ); @@ -46,7 +42,7 @@ const useAutoCreateAdsMCAccounts = () => { } = useExistingGoogleMCAccounts(); const { - existingAccounts: existingAdsAccount, + existingAccounts: existingAdsAccounts, hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount, } = useExistingGoogleAdsAccounts(); @@ -69,7 +65,7 @@ const useAutoCreateAdsMCAccounts = () => { const hasExistingMCAccount = isGoogleMCConnected || existingMCAccounts?.length > 0; const hasExistingAdsAccount = - hasGoogleAdsConnection || existingAdsAccount?.length > 0; + hasGoogleAdsConnection || existingAdsAccounts?.length > 0; if ( initHasExistingMCAccountsRef.current === null && @@ -87,19 +83,6 @@ const useAutoCreateAdsMCAccounts = () => { initHasExistingAdsAccountsRef.current = hasExistingAdsAccount; } - const createMCAccount = useCallback( async () => { - await handleCreateAccount(); - }, [ handleCreateAccount ] ); - - const createAdsAccount = useCallback( async () => { - await upsertAdsAccount(); - }, [ upsertAdsAccount ] ); - - const createBothAccounts = useCallback( async () => { - await createMCAccount(); - await createAdsAccount(); - }, [ createMCAccount, createAdsAccount ] ); - const accountCreationChecksResolved = initHasExistingAdsAccountsRef.current !== null && initHasExistingMCAccountsRef.current !== null; @@ -149,6 +132,19 @@ const useAutoCreateAdsMCAccounts = () => { }, [ response, loading ] ); useEffect( () => { + const createMCAccount = async () => { + await handleCreateAccount(); + }; + + const createAdsAccount = async () => { + await upsertAdsAccount(); + }; + + const createBothAccounts = async () => { + await createMCAccount(); + await createAdsAccount(); + }; + const handleCreation = async () => { // Bail out if we haven't resolved the existing accounts checks yet or there's a creation in progress or the accounts have been created. if ( @@ -180,13 +176,12 @@ const useAutoCreateAdsMCAccounts = () => { handleCreation(); }, [ accountCreationChecksResolved, - createBothAccounts, - createAdsAccount, - createMCAccount, isCreatingAccounts, shouldCreateAdsAccount, shouldCreateMCAccount, shouldCreateBothAccounts, + handleCreateAccount, + upsertAdsAccount, ] ); return { diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 86b904ae13..82b2e24165 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -6,15 +6,15 @@ import { renderHook, act } from '@testing-library/react'; /** * Internal dependencies */ -import useCreateAccounts from './useAutoCreateAdsMCAccounts'; -import useCreateMCAccount from '../components/google-mc-account-card/useCreateMCAccount'; +import useAutoCreateAdsMCAccounts from './useAutoCreateAdsMCAccounts'; +import useCreateMCAccount from './useCreateMCAccount'; import useUpsertAdsAccount from './useUpsertAdsAccount'; import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; import useGoogleAdsAccount from './useGoogleAdsAccount'; import useGoogleMCAccount from './useGoogleMCAccount'; -jest.mock( '../components/google-mc-account-card/useCreateMCAccount' ); +jest.mock( './useCreateMCAccount' ); jest.mock( './useUpsertAdsAccount' ); jest.mock( './useExistingGoogleAdsAccounts' ); jest.mock( './useExistingGoogleMCAccounts' ); @@ -51,11 +51,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { hasGoogleAdsConnection: false, } ); - useGoogleAdsAccount.mockReturnValue( { - hasFinishedResolution: true, - hasGoogleAdsConnection: false, - } ); - useGoogleMCAccount.mockReturnValue( { hasFinishedResolution: true, googleMCAccount: undefined, @@ -73,7 +68,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { hasFinishedResolution: false, } ); - const { result } = renderHook( () => useCreateAccounts() ); + const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); expect( result.current.isCreatingAdsAccount ).toBe( false ); expect( result.current.isCreatingMCAccount ).toBe( false ); @@ -84,7 +79,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { it( 'should call "handleCreateAccount" and "upsertAdsAccount" when there are no existing accounts', async () => { // Simulate the initial state and mock behavior for account creation - const { result, rerender } = renderHook( () => useCreateAccounts() ); + const { result, rerender } = renderHook( () => useAutoCreateAdsMCAccounts() ); expect( result.current.isCreatingAdsAccount ).toBe( false ); expect( result.current.isCreatingMCAccount ).toBe( false ); @@ -129,7 +124,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { { response: undefined, loading: true }, // Initially no response, loading is true ] ); - const { result, rerender } = renderHook( () => useCreateAccounts() ); + const { result, rerender } = renderHook( () => useAutoCreateAdsMCAccounts() ); // Initially, it should not be creating accounts expect( result.current.isCreatingAdsAccount ).toBe( false ); @@ -176,7 +171,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { { response: undefined, loading: true }, // Initially no response, loading is true for Ads account creation ] ); - const { result, rerender } = renderHook( () => useCreateAccounts() ); + const { result, rerender } = renderHook( () => useAutoCreateAdsMCAccounts() ); // Initially, it should not be creating accounts expect( result.current.isCreatingAdsAccount ).toBe( false ); diff --git a/js/src/components/google-mc-account-card/useCreateMCAccount.js b/js/src/hooks/useCreateMCAccount.js similarity index 100% rename from js/src/components/google-mc-account-card/useCreateMCAccount.js rename to js/src/hooks/useCreateMCAccount.js From 7d343cd5a807d204a60cb30f6f57ab40aa212fee Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Mon, 14 Oct 2024 21:32:15 +0530 Subject: [PATCH 36/91] Update conditions for rendering. --- .../account-creation-description/index.js | 45 +++++++++++-------- .../connected-google-combo-account-card.scss | 7 +++ js/src/hooks/useAutoCreateAdsMCAccounts.js | 44 +++++++----------- 3 files changed, 49 insertions(+), 47 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index 5270358248..d93f5fd26a 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -98,25 +98,32 @@ const AccountCreationDescription = ( { return ( <>

{ google?.email }

- - + { googleMCAccount.id > 0 && ( + + ) } + { googleAdsAccount.id > 0 && ( + + ) } ); }; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss index 5b3d70cdb2..b0646ef6e5 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss @@ -3,4 +3,11 @@ .gla-account-card__description p { margin: 0; } + + .gla-connected-google-combo-account-card__description { + + em { + color: #757575; + } + } } diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index db629a5b84..8271833089 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -30,8 +30,8 @@ import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; const useAutoCreateAdsMCAccounts = () => { // Refs are used to avoid the re-render of the parent component. const isCreatingBothAccountsRef = useRef( false ); - const isCreatingAdsAccountsRef = useRef( false ); - const isCreatingMCAccountsRef = useRef( false ); + const isCreatingAdsAccountRef = useRef( false ); + const isCreatingMCAccountRef = useRef( false ); const initHasExistingMCAccountsRef = useRef( null ); const initHasExistingAdsAccountsRef = useRef( null ); const accountsCreatedRef = useRef( false ); @@ -100,23 +100,23 @@ const useAutoCreateAdsMCAccounts = () => { ! initHasExistingMCAccountsRef.current; const isCreatingAccounts = - isCreatingAdsAccountsRef.current || - isCreatingMCAccountsRef.current || + isCreatingAdsAccountRef.current || + isCreatingMCAccountRef.current || isCreatingBothAccountsRef.current; useEffect( () => { // Ads account check - if ( isCreatingAdsAccountsRef.current === true && ! loading ) { - isCreatingAdsAccountsRef.current = false; + if ( isCreatingAdsAccountRef.current === true && ! loading ) { + isCreatingAdsAccountRef.current = false; accountsCreatedRef.current = true; } // MC account check if ( - isCreatingMCAccountsRef.current === true && + isCreatingMCAccountRef.current === true && response?.status === 200 ) { - isCreatingMCAccountsRef.current = false; + isCreatingMCAccountRef.current = false; accountsCreatedRef.current = true; } @@ -132,19 +132,6 @@ const useAutoCreateAdsMCAccounts = () => { }, [ response, loading ] ); useEffect( () => { - const createMCAccount = async () => { - await handleCreateAccount(); - }; - - const createAdsAccount = async () => { - await upsertAdsAccount(); - }; - - const createBothAccounts = async () => { - await createMCAccount(); - await createAdsAccount(); - }; - const handleCreation = async () => { // Bail out if we haven't resolved the existing accounts checks yet or there's a creation in progress or the accounts have been created. if ( @@ -156,20 +143,21 @@ const useAutoCreateAdsMCAccounts = () => { } if ( shouldCreateAdsAccount ) { - isCreatingAdsAccountsRef.current = true; - await createAdsAccount(); + isCreatingAdsAccountRef.current = true; + await upsertAdsAccount(); return; } if ( shouldCreateMCAccount ) { - isCreatingMCAccountsRef.current = true; - await createMCAccount(); + isCreatingMCAccountRef.current = true; + await handleCreateAccount(); return; } if ( shouldCreateBothAccounts ) { isCreatingBothAccountsRef.current = true; - await createBothAccounts(); + await handleCreateAccount(); + await upsertAdsAccount(); } }; @@ -186,8 +174,8 @@ const useAutoCreateAdsMCAccounts = () => { return { accountCreationChecksResolved, - isCreatingAdsAccount: isCreatingAdsAccountsRef.current, - isCreatingMCAccount: isCreatingMCAccountsRef.current, + isCreatingAdsAccount: isCreatingAdsAccountRef.current, + isCreatingMCAccount: isCreatingMCAccountRef.current, isCreatingBothAccounts: isCreatingBothAccountsRef.current, isCreatingAccounts, accountsCreated: accountsCreatedRef.current, From 37859b3b60b6f7867ad361c216e2f8c7806f8e59 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Mon, 14 Oct 2024 21:43:01 +0530 Subject: [PATCH 37/91] Formatting updates. --- js/src/hooks/useAutoCreateAdsMCAccounts.test.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 82b2e24165..f8e8af521a 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -79,7 +79,9 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { it( 'should call "handleCreateAccount" and "upsertAdsAccount" when there are no existing accounts', async () => { // Simulate the initial state and mock behavior for account creation - const { result, rerender } = renderHook( () => useAutoCreateAdsMCAccounts() ); + const { result, rerender } = renderHook( () => + useAutoCreateAdsMCAccounts() + ); expect( result.current.isCreatingAdsAccount ).toBe( false ); expect( result.current.isCreatingMCAccount ).toBe( false ); @@ -124,7 +126,9 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { { response: undefined, loading: true }, // Initially no response, loading is true ] ); - const { result, rerender } = renderHook( () => useAutoCreateAdsMCAccounts() ); + const { result, rerender } = renderHook( () => + useAutoCreateAdsMCAccounts() + ); // Initially, it should not be creating accounts expect( result.current.isCreatingAdsAccount ).toBe( false ); @@ -171,7 +175,9 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { { response: undefined, loading: true }, // Initially no response, loading is true for Ads account creation ] ); - const { result, rerender } = renderHook( () => useAutoCreateAdsMCAccounts() ); + const { result, rerender } = renderHook( () => + useAutoCreateAdsMCAccounts() + ); // Initially, it should not be creating accounts expect( result.current.isCreatingAdsAccount ).toBe( false ); From 298c0f4b247ef3386719da9f8436ccacefacb74c Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 15 Oct 2024 11:41:45 +0530 Subject: [PATCH 38/91] Remove unused component. --- .../account-info.js | 16 --------------- .../account-creation-description/index.js | 20 ++++++++----------- .../hooks/useAutoCreateAdsMCAccounts.test.js | 3 ++- 3 files changed, 10 insertions(+), 29 deletions(-) delete mode 100644 js/src/components/google-combo-account-card/account-creation-description/account-info.js diff --git a/js/src/components/google-combo-account-card/account-creation-description/account-info.js b/js/src/components/google-combo-account-card/account-creation-description/account-info.js deleted file mode 100644 index 673c16a1d4..0000000000 --- a/js/src/components/google-combo-account-card/account-creation-description/account-info.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Display account info. - * - * @param {Object} props Props. - * @param {Object} props.account Account object. - * @param {string} props.text Text to display. - */ -const AccountInfo = ( { account, text } ) => { - if ( ! account?.id ) { - return null; - } - - return

{ text }

; -}; - -export default AccountInfo; diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index d93f5fd26a..886c6cbe55 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -9,7 +9,6 @@ import { __, sprintf } from '@wordpress/i18n'; import useGoogleAccount from '.~/hooks/useGoogleAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import AccountInfo from './account-info'; /** * Renders the description for the account creation card. @@ -44,7 +43,6 @@ const AccountCreationDescription = ( { const getDescription = () => { if ( - isLoadingAccountsData || isCreatingBothAccounts || isCreatingMCAccount || isCreatingAdsAccount @@ -98,10 +96,9 @@ const AccountCreationDescription = ( { return ( <>

{ google?.email }

- { googleMCAccount.id > 0 && ( - 0 && ( +

+ { sprintf( // Translators: %s is the Merchant Center ID __( 'Merchant Center ID: %s', @@ -109,12 +106,11 @@ const AccountCreationDescription = ( { ), googleMCAccount.id ) } - /> +

) } - { googleAdsAccount.id > 0 && ( - 0 && ( +

+ { sprintf( // Translators: %s is the Google Ads ID __( 'Google Ads ID: %s', @@ -122,7 +118,7 @@ const AccountCreationDescription = ( { ), googleAdsAccount.id ) } - /> +

) } ); diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index f8e8af521a..73eb28944c 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -63,9 +63,10 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { data: [ { id: 1 } ], hasFinishedResolution: true, } ); + useExistingGoogleAdsAccounts.mockReturnValue( { existingAccounts: [ { id: 1 } ], - hasFinishedResolution: false, + hasFinishedResolution: true, } ); const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); From 5ac6cf102c6ae1a679635347365429e26356eab4 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 15 Oct 2024 12:18:54 +0530 Subject: [PATCH 39/91] Update property names and description. --- .../account-creation-description/index.js | 16 ++++---- .../connected-google-combo-account-card.js | 8 ++-- js/src/hooks/useAutoCreateAdsMCAccounts.js | 10 ++--- .../hooks/useAutoCreateAdsMCAccounts.test.js | 38 +++++++++---------- 4 files changed, 36 insertions(+), 36 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index 886c6cbe55..61bdfca544 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -16,14 +16,14 @@ import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; * @param {Object} props Props. * @param {boolean} props.accountsCreated Whether accounts have been created. * @param {boolean} props.isCreatingBothAccounts Whether both, MC and Ads accounts are being created. - * @param {boolean} props.isCreatingMCAccount Whether Merchant Center account is being created. - * @param {boolean} props.isCreatingAdsAccount Whether Google Ads account is being created. + * @param {boolean} props.isCreatingOnlyMCAccount Whether only the Merchant Center account is being created. + * @param {boolean} props.isCreatingOnlyAdsAccount Whether only Google Ads account is being created. */ const AccountCreationDescription = ( { accountsCreated, isCreatingBothAccounts, - isCreatingMCAccount, - isCreatingAdsAccount, + isCreatingOnlyMCAccount, + isCreatingOnlyAdsAccount, } ) => { const { google } = useGoogleAccount(); const { @@ -44,8 +44,8 @@ const AccountCreationDescription = ( { const getDescription = () => { if ( isCreatingBothAccounts || - isCreatingMCAccount || - isCreatingAdsAccount + isCreatingOnlyMCAccount || + isCreatingOnlyAdsAccount ) { if ( isCreatingBothAccounts ) { return ( @@ -56,7 +56,7 @@ const AccountCreationDescription = ( { ) }

); - } else if ( isCreatingAdsAccount ) { + } else if ( isCreatingOnlyAdsAccount ) { return ( <>

@@ -73,7 +73,7 @@ const AccountCreationDescription = ( { ); - } else if ( isCreatingMCAccount ) { + } else if ( isCreatingOnlyMCAccount ) { return ( <>

diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 6ef37ab844..1d0b28123d 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -38,8 +38,8 @@ const ConnectedGoogleComboAccountCard = () => { const { isCreatingAccounts, isCreatingBothAccounts, - isCreatingAdsAccount, - isCreatingMCAccount, + isCreatingOnlyAdsAccount, + isCreatingOnlyMCAccount, accountCreationChecksResolved, accountsCreated, } = useAutoCreateAdsMCAccounts(); @@ -104,8 +104,8 @@ const ConnectedGoogleComboAccountCard = () => { description={ } diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 8271833089..7cc25f168b 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -20,10 +20,10 @@ import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; * @typedef {Object} AutoCreateAccountsStatus * @property {boolean} accountsCreated Indicates if both the Google Ads and Google Merchant Center accounts have been successfully created. * @property {boolean} accountCreationChecksResolved Indicates if the account creation checks (for existing accounts) have been resolved. - * @property {boolean} isCreatingAccounts Indicates if the Google Ads and Google Merchant Center accounts are currently being created. - * @property {boolean} isCreatingAdsAccount Indicates if the Google Ads account is currently being created. + * @property {boolean} isCreatingAccounts Indicates if the Google Ads and/or Google Merchant Center account(s) are being created. + * @property {boolean} isCreatingOnlyAdsAccount Indicates if only the Google Ads account is currently being created. * @property {boolean} isCreatingBothAccounts Indicates if both the Google Ads and Google Merchant Center accounts are currently being created. - * @property {boolean} isCreatingMCAccount Indicates if the Google Merchant Center account is currently being created. + * @property {boolean} isCreatingOnlyMCAccount Indicates if only the Google Merchant Center account is currently being created. * * @return {AutoCreateAccountsStatus} Object containing properties related to the account creation status. */ @@ -174,8 +174,8 @@ const useAutoCreateAdsMCAccounts = () => { return { accountCreationChecksResolved, - isCreatingAdsAccount: isCreatingAdsAccountRef.current, - isCreatingMCAccount: isCreatingMCAccountRef.current, + isCreatingOnlyAdsAccount: isCreatingAdsAccountRef.current, + isCreatingOnlyMCAccount: isCreatingMCAccountRef.current, isCreatingBothAccounts: isCreatingBothAccountsRef.current, isCreatingAccounts, accountsCreated: accountsCreatedRef.current, diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 73eb28944c..5bdaa8c262 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -71,8 +71,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - expect( result.current.isCreatingAdsAccount ).toBe( false ); - expect( result.current.isCreatingMCAccount ).toBe( false ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); expect( result.current.accountsCreated ).toBe( false ); expect( handleCreateAccount ).not.toHaveBeenCalled(); expect( upsertAdsAccount ).not.toHaveBeenCalled(); @@ -84,8 +84,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { useAutoCreateAdsMCAccounts() ); - expect( result.current.isCreatingAdsAccount ).toBe( false ); - expect( result.current.isCreatingMCAccount ).toBe( false ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); useCreateMCAccount.mockReturnValueOnce( [ handleCreateAccount, @@ -98,16 +98,16 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { rerender(); - expect( result.current.isCreatingAdsAccount ).toBe( false ); - expect( result.current.isCreatingMCAccount ).toBe( false ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); // eslint-disable-next-line testing-library/no-unnecessary-act await act( async () => { rerender(); } ); - expect( result.current.isCreatingAdsAccount ).toBe( false ); - expect( result.current.isCreatingMCAccount ).toBe( false ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); expect( result.current.accountsCreated ).toBe( true ); // Finally, check that the functions were called correctly @@ -132,15 +132,15 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { ); // Initially, it should not be creating accounts - expect( result.current.isCreatingAdsAccount ).toBe( false ); - expect( result.current.isCreatingMCAccount ).toBe( false ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); // Trigger the effect that starts account creation. rerender(); // Step 2: At this point, MC account creation should have started - expect( result.current.isCreatingMCAccount ).toBe( true ); - expect( result.current.isCreatingAdsAccount ).toBe( false ); // Since Ads account exists + expect( result.current.isCreatingOnlyMCAccount ).toBe( true ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); // Since Ads account exists expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); expect( upsertAdsAccount ).not.toHaveBeenCalled(); @@ -154,8 +154,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { rerender(); // Step 4: Final assertions after account creation has completed - expect( result.current.isCreatingAdsAccount ).toBe( false ); - expect( result.current.isCreatingMCAccount ).toBe( false ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); expect( result.current.accountsCreated ).toBe( true ); // The account has been created // Finally, verify that only handleCreateAccount was called, not upsertAdsAccount @@ -181,14 +181,14 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { ); // Initially, it should not be creating accounts - expect( result.current.isCreatingAdsAccount ).toBe( false ); - expect( result.current.isCreatingMCAccount ).toBe( false ); + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); rerender(); // Simulate the effect firing. // Step 2: At this point, Ads account creation should have started - expect( result.current.isCreatingAdsAccount ).toBe( true ); - expect( result.current.isCreatingMCAccount ).toBe( false ); // Since MC account exists + expect( result.current.isCreatingOnlyAdsAccount ).toBe( true ); + expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); // Since MC account exists expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); expect( handleCreateAccount ).not.toHaveBeenCalled(); // MC account creation shouldn't be triggered @@ -203,7 +203,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { // Step 4: Final assertions after Ads account creation has completed expect( result.current.accountsCreated ).toBe( true ); // The account has been created - expect( result.current.isCreatingAdsAccount ).toBe( false ); // Ads account creation finished + expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); // Ads account creation finished // Finally, verify that only upsertAdsAccount was called, not handleCreateAccount expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); From d3f4f6ff1f4d2cc3eb24b4019f01b0a26d6e4df3 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 15 Oct 2024 13:14:05 +0530 Subject: [PATCH 40/91] Add status for MC account mock. --- tests/e2e/specs/setup-mc/step-1-accounts.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 03e655a14e..7f3df66cd7 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -290,6 +290,8 @@ test.describe( 'Set up accounts', () => { name: null, subaccount: null, domain: null, + status: 'incomplete', + step: 'claim', }, ], 200, From 60eff85021fe48698eeb5e5da1cdcdbef6242bd5 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 12:24:45 +0530 Subject: [PATCH 41/91] Rename constants. --- .../account-creation-description/index.js | 16 ++++---- .../connected-google-combo-account-card.js | 8 ++-- js/src/hooks/useAutoCreateAdsMCAccounts.js | 8 ++-- .../hooks/useAutoCreateAdsMCAccounts.test.js | 38 +++++++++---------- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index 61bdfca544..38d44fb408 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -16,14 +16,14 @@ import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; * @param {Object} props Props. * @param {boolean} props.accountsCreated Whether accounts have been created. * @param {boolean} props.isCreatingBothAccounts Whether both, MC and Ads accounts are being created. - * @param {boolean} props.isCreatingOnlyMCAccount Whether only the Merchant Center account is being created. - * @param {boolean} props.isCreatingOnlyAdsAccount Whether only Google Ads account is being created. + * @param {boolean} props.isCreatingMCAccountOnly Whether only the Merchant Center account is being created. + * @param {boolean} props.isCreatingAdsAccountOnly Whether only Google Ads account is being created. */ const AccountCreationDescription = ( { accountsCreated, isCreatingBothAccounts, - isCreatingOnlyMCAccount, - isCreatingOnlyAdsAccount, + isCreatingMCAccountOnly, + isCreatingAdsAccountOnly, } ) => { const { google } = useGoogleAccount(); const { @@ -44,8 +44,8 @@ const AccountCreationDescription = ( { const getDescription = () => { if ( isCreatingBothAccounts || - isCreatingOnlyMCAccount || - isCreatingOnlyAdsAccount + isCreatingMCAccountOnly || + isCreatingAdsAccountOnly ) { if ( isCreatingBothAccounts ) { return ( @@ -56,7 +56,7 @@ const AccountCreationDescription = ( { ) }

); - } else if ( isCreatingOnlyAdsAccount ) { + } else if ( isCreatingAdsAccountOnly ) { return ( <>

@@ -73,7 +73,7 @@ const AccountCreationDescription = ( { ); - } else if ( isCreatingOnlyMCAccount ) { + } else if ( isCreatingMCAccountOnly ) { return ( <>

diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 1d0b28123d..f198f50929 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -38,8 +38,8 @@ const ConnectedGoogleComboAccountCard = () => { const { isCreatingAccounts, isCreatingBothAccounts, - isCreatingOnlyAdsAccount, - isCreatingOnlyMCAccount, + isCreatingAdsAccountOnly, + isCreatingMCAccountOnly, accountCreationChecksResolved, accountsCreated, } = useAutoCreateAdsMCAccounts(); @@ -104,8 +104,8 @@ const ConnectedGoogleComboAccountCard = () => { description={ } diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 7cc25f168b..bfa23b0a05 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -21,9 +21,9 @@ import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; * @property {boolean} accountsCreated Indicates if both the Google Ads and Google Merchant Center accounts have been successfully created. * @property {boolean} accountCreationChecksResolved Indicates if the account creation checks (for existing accounts) have been resolved. * @property {boolean} isCreatingAccounts Indicates if the Google Ads and/or Google Merchant Center account(s) are being created. - * @property {boolean} isCreatingOnlyAdsAccount Indicates if only the Google Ads account is currently being created. + * @property {boolean} isCreatingAdsAccountOnly Indicates if only the Google Ads account is currently being created. * @property {boolean} isCreatingBothAccounts Indicates if both the Google Ads and Google Merchant Center accounts are currently being created. - * @property {boolean} isCreatingOnlyMCAccount Indicates if only the Google Merchant Center account is currently being created. + * @property {boolean} isCreatingMCAccountOnly Indicates if only the Google Merchant Center account is currently being created. * * @return {AutoCreateAccountsStatus} Object containing properties related to the account creation status. */ @@ -174,8 +174,8 @@ const useAutoCreateAdsMCAccounts = () => { return { accountCreationChecksResolved, - isCreatingOnlyAdsAccount: isCreatingAdsAccountRef.current, - isCreatingOnlyMCAccount: isCreatingMCAccountRef.current, + isCreatingAdsAccountOnly: isCreatingAdsAccountRef.current, + isCreatingMCAccountOnly: isCreatingMCAccountRef.current, isCreatingBothAccounts: isCreatingBothAccountsRef.current, isCreatingAccounts, accountsCreated: accountsCreatedRef.current, diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 5bdaa8c262..ff99a885cf 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -71,8 +71,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); expect( result.current.accountsCreated ).toBe( false ); expect( handleCreateAccount ).not.toHaveBeenCalled(); expect( upsertAdsAccount ).not.toHaveBeenCalled(); @@ -84,8 +84,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { useAutoCreateAdsMCAccounts() ); - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); useCreateMCAccount.mockReturnValueOnce( [ handleCreateAccount, @@ -98,16 +98,16 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { rerender(); - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); // eslint-disable-next-line testing-library/no-unnecessary-act await act( async () => { rerender(); } ); - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); expect( result.current.accountsCreated ).toBe( true ); // Finally, check that the functions were called correctly @@ -132,15 +132,15 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { ); // Initially, it should not be creating accounts - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); // Trigger the effect that starts account creation. rerender(); // Step 2: At this point, MC account creation should have started - expect( result.current.isCreatingOnlyMCAccount ).toBe( true ); - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); // Since Ads account exists + expect( result.current.isCreatingMCAccountOnly ).toBe( true ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); // Since Ads account exists expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); expect( upsertAdsAccount ).not.toHaveBeenCalled(); @@ -154,8 +154,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { rerender(); // Step 4: Final assertions after account creation has completed - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); expect( result.current.accountsCreated ).toBe( true ); // The account has been created // Finally, verify that only handleCreateAccount was called, not upsertAdsAccount @@ -181,14 +181,14 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { ); // Initially, it should not be creating accounts - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); rerender(); // Simulate the effect firing. // Step 2: At this point, Ads account creation should have started - expect( result.current.isCreatingOnlyAdsAccount ).toBe( true ); - expect( result.current.isCreatingOnlyMCAccount ).toBe( false ); // Since MC account exists + expect( result.current.isCreatingAdsAccountOnly ).toBe( true ); + expect( result.current.isCreatingMCAccountOnly ).toBe( false ); // Since MC account exists expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); expect( handleCreateAccount ).not.toHaveBeenCalled(); // MC account creation shouldn't be triggered @@ -203,7 +203,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { // Step 4: Final assertions after Ads account creation has completed expect( result.current.accountsCreated ).toBe( true ); // The account has been created - expect( result.current.isCreatingOnlyAdsAccount ).toBe( false ); // Ads account creation finished + expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); // Ads account creation finished // Finally, verify that only upsertAdsAccount was called, not handleCreateAccount expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); From bd98116837c252dc742f9c8dd445fd1b10d3db20 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 17:21:02 +0530 Subject: [PATCH 42/91] Simplify the auto creation hook. --- .../account-creation-description/index.js | 124 +++++----- .../connected-google-combo-account-card.js | 37 +-- .../connected-google-combo-account-card.scss | 2 +- .../google-combo-account-card/constants.js | 0 .../connect-mc/index.js | 2 +- js/src/constants.js | 4 + js/src/hooks/useAutoCreateAdsMCAccounts.js | 118 ++++++---- .../hooks/useAutoCreateAdsMCAccounts.test.js | 217 +++++------------- 8 files changed, 201 insertions(+), 303 deletions(-) create mode 100644 js/src/components/google-combo-account-card/constants.js diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index 38d44fb408..dcff531b25 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -9,94 +9,84 @@ import { __, sprintf } from '@wordpress/i18n'; import useGoogleAccount from '.~/hooks/useGoogleAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import { + CREATING_ADS_ACCOUNT, + CREATING_BOTH_ACCOUNTS, + CREATING_MC_ACCOUNT, +} from '.~/constants'; /** * Renders the description for the account creation card. * * @param {Object} props Props. - * @param {boolean} props.accountsCreated Whether accounts have been created. - * @param {boolean} props.isCreatingBothAccounts Whether both, MC and Ads accounts are being created. - * @param {boolean} props.isCreatingMCAccountOnly Whether only the Merchant Center account is being created. - * @param {boolean} props.isCreatingAdsAccountOnly Whether only Google Ads account is being created. + * @param {string} props.isCreatingWhichAccount The type of account that is being created. + * @param {number} props.isGoogleAdsReady Whether the Google Ads account is ready. + * @param {number} props.isGoogleMCReady Whether the Merchant Center account is ready. */ const AccountCreationDescription = ( { - accountsCreated, - isCreatingBothAccounts, - isCreatingMCAccountOnly, - isCreatingAdsAccountOnly, + isCreatingWhichAccount, + isGoogleAdsReady, + isGoogleMCReady, } ) => { const { google } = useGoogleAccount(); - const { - googleMCAccount, - hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, - } = useGoogleMCAccount(); - - const { - googleAdsAccount, - hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, - } = useGoogleAdsAccount(); - - const isLoadingAccountsData = - accountsCreated && - ( ! hasFinishedResolutionForCurrentMCAccount || - ! hasFinishedResolutionForCurrentAdsAccount ); + const { googleMCAccount } = useGoogleMCAccount(); + const { googleAdsAccount } = useGoogleAdsAccount(); const getDescription = () => { - if ( - isCreatingBothAccounts || - isCreatingMCAccountOnly || - isCreatingAdsAccountOnly - ) { - if ( isCreatingBothAccounts ) { - return ( -

- { __( - 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', - 'google-listings-and-ads' - ) } -

- ); - } else if ( isCreatingAdsAccountOnly ) { - return ( - <> -

- { __( - 'You don’t have Google Ads account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } - - - ); - } else if ( isCreatingMCAccountOnly ) { - return ( - <> + if ( isCreatingWhichAccount ) { + switch ( isCreatingWhichAccount ) { + case CREATING_BOTH_ACCOUNTS: + return (

{ __( - 'You don’t have Merchant Center account, so we’re creating one for you.', + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', 'google-listings-and-ads' ) }

- - { __( - 'Required to sync products so they show on Google.', - 'google-listings-and-ads' - ) } - - - ); + ); + + case CREATING_ADS_ACCOUNT: + return ( + <> +

+ { __( + 'You don’t have Google Ads account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ) } + + + ); + + case CREATING_MC_ACCOUNT: + return ( + <> +

+ { __( + 'You don’t have Merchant Center account, so we’re creating one for you.', + 'google-listings-and-ads' + ) } +

+ + { __( + 'Required to sync products so they show on Google.', + 'google-listings-and-ads' + ) } + + + ); } } return ( <>

{ google?.email }

- { ! isLoadingAccountsData && googleMCAccount.id > 0 && ( + { isGoogleMCReady > 0 && (

{ sprintf( // Translators: %s is the Merchant Center ID @@ -108,7 +98,7 @@ const AccountCreationDescription = ( { ) }

) } - { ! isLoadingAccountsData && googleAdsAccount.id > 0 && ( + { isGoogleAdsReady > 0 && (

{ sprintf( // Translators: %s is the Google Ads ID diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index f198f50929..9a0f7c26f4 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -15,10 +15,7 @@ import './connected-google-combo-account-card.scss'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import ConnectedIconLabel from '../connected-icon-label'; -import { - GOOGLE_ADS_ACCOUNT_STATUS, - GOOGLE_MC_ACCOUNT_STATUS, -} from '.~/constants'; +import { CREATING_BOTH_ACCOUNTS } from '.~/constants'; /** * Renders a Google account card UI with connected account information. @@ -36,12 +33,9 @@ const ConnectedGoogleComboAccountCard = () => { } = useGoogleMCAccount(); const { - isCreatingAccounts, - isCreatingBothAccounts, - isCreatingAdsAccountOnly, - isCreatingMCAccountOnly, accountCreationChecksResolved, - accountsCreated, + isCreatingAccounts, + isCreatingWhichAccount, } = useAutoCreateAdsMCAccounts(); if ( @@ -52,21 +46,11 @@ const ConnectedGoogleComboAccountCard = () => { return } />; } - const isGoogleAdsAccountConnected = - googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED || - ( googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.INCOMPLETE && - [ 'link_merchant', 'account_access' ].includes( - googleAdsAccount?.step - ) ); - - const isGoogleMCAccountConnected = - googleMCAccount?.id || - googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || - ( googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && - [ 'link_ads', 'claim' ].includes( googleMCAccount?.step ) ); + const isGoogleAdsReady = ! isCreatingAccounts && googleAdsAccount.id > 0; + const isGoogleMCReady = ! isCreatingAccounts && googleMCAccount.id > 0; const getHelper = () => { - if ( isCreatingBothAccounts ) { + if ( isCreatingWhichAccount === CREATING_BOTH_ACCOUNTS ) { return (

{ __( @@ -89,7 +73,7 @@ const ConnectedGoogleComboAccountCard = () => { ); } - if ( isGoogleAdsAccountConnected && isGoogleMCAccountConnected ) { + if ( isGoogleAdsReady && isGoogleMCReady ) { return ; } @@ -103,10 +87,9 @@ const ConnectedGoogleComboAccountCard = () => { className="gla-google-combo-account-card--connected" description={ } helper={ getHelper() } diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss index b0646ef6e5..f7e57ce16e 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss @@ -7,7 +7,7 @@ .gla-connected-google-combo-account-card__description { em { - color: #757575; + color: $gray-700; } } } diff --git a/js/src/components/google-combo-account-card/constants.js b/js/src/components/google-combo-account-card/constants.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/src/components/google-mc-account-card/connect-mc/index.js b/js/src/components/google-mc-account-card/connect-mc/index.js index d02c628a37..658bc245f3 100644 --- a/js/src/components/google-mc-account-card/connect-mc/index.js +++ b/js/src/components/google-mc-account-card/connect-mc/index.js @@ -18,7 +18,7 @@ import ReclaimUrlCard from '../reclaim-url-card'; import AccountCard, { APPEARANCE } from '.~/components/account-card'; import CreateAccountButton from '../create-account-button'; import useConnectMCAccount from '../useConnectMCAccount'; -import useCreateMCAccount from '../../../hooks/useCreateMCAccount'; +import useCreateMCAccount from '.~/hooks/useCreateMCAccount'; import CreatingCard from '../creating-card'; import './index.scss'; diff --git a/js/src/constants.js b/js/src/constants.js index 3a34ea00f7..cdea5e560f 100644 --- a/js/src/constants.js +++ b/js/src/constants.js @@ -123,3 +123,7 @@ export const GOOGLE_WPCOM_APP_CONNECTED_STATUS = { ERROR: 'error', DISABLED: 'disabled', }; + +export const CREATING_BOTH_ACCOUNTS = 'both'; +export const CREATING_ADS_ACCOUNT = 'ads'; +export const CREATING_MC_ACCOUNT = 'mc'; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index bfa23b0a05..3893c142a4 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { useEffect, useRef } from '@wordpress/element'; +import { useEffect, useRef, useState } from '@wordpress/element'; /** * Internal dependencies @@ -12,29 +12,32 @@ import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts' import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; import useGoogleAdsAccount from './useGoogleAdsAccount'; import useGoogleMCAccount from './useGoogleMCAccount'; -import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; +import { + CREATING_ADS_ACCOUNT, + CREATING_BOTH_ACCOUNTS, + CREATING_MC_ACCOUNT, + GOOGLE_MC_ACCOUNT_STATUS, +} from '.~/constants'; /** * Custom hook to handle the creation of Google Merchant Center (MC) and Google Ads accounts. * * @typedef {Object} AutoCreateAccountsStatus - * @property {boolean} accountsCreated Indicates if both the Google Ads and Google Merchant Center accounts have been successfully created. - * @property {boolean} accountCreationChecksResolved Indicates if the account creation checks (for existing accounts) have been resolved. - * @property {boolean} isCreatingAccounts Indicates if the Google Ads and/or Google Merchant Center account(s) are being created. - * @property {boolean} isCreatingAdsAccountOnly Indicates if only the Google Ads account is currently being created. - * @property {boolean} isCreatingBothAccounts Indicates if both the Google Ads and Google Merchant Center accounts are currently being created. - * @property {boolean} isCreatingMCAccountOnly Indicates if only the Google Merchant Center account is currently being created. + * @property {boolean} accountCreationChecksResolved Whether the checks for account creation have been resolved. + * @property {boolean} isCreatingAccounts Whether the accounts are being created. + * @property {string|null} isCreatingWhichAccount The type of account that is being created. * * @return {AutoCreateAccountsStatus} Object containing properties related to the account creation status. */ const useAutoCreateAdsMCAccounts = () => { - // Refs are used to avoid the re-render of the parent component. - const isCreatingBothAccountsRef = useRef( false ); - const isCreatingAdsAccountRef = useRef( false ); - const isCreatingMCAccountRef = useRef( false ); + const [ accountsState, setAccountsState ] = useState( { + accountsCreated: false, + isCreatingWhichAccount: null, + } ); + + const { accountsCreated, isCreatingWhichAccount } = accountsState; const initHasExistingMCAccountsRef = useRef( null ); const initHasExistingAdsAccountsRef = useRef( null ); - const accountsCreatedRef = useRef( false ); const { data: existingMCAccounts, @@ -58,9 +61,11 @@ const useAutoCreateAdsMCAccounts = () => { const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - const isGoogleMCConnected = - googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || - googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE; + + const isGoogleMCConnected = [ + GOOGLE_MC_ACCOUNT_STATUS.CONNECTED, + GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE, + ].includes( googleMCAccount?.status ); const hasExistingMCAccount = isGoogleMCConnected || existingMCAccounts?.length > 0; @@ -99,63 +104,86 @@ const useAutoCreateAdsMCAccounts = () => { ! initHasExistingAdsAccountsRef.current && ! initHasExistingMCAccountsRef.current; - const isCreatingAccounts = - isCreatingAdsAccountRef.current || - isCreatingMCAccountRef.current || - isCreatingBothAccountsRef.current; + const isCreatingAccounts = !! isCreatingWhichAccount; useEffect( () => { - // Ads account check - if ( isCreatingAdsAccountRef.current === true && ! loading ) { - isCreatingAdsAccountRef.current = false; - accountsCreatedRef.current = true; + if ( ! response && loading ) { + return; + } + + console.debug( 'isCreatingWhichAccount', isCreatingWhichAccount ); + + if ( isCreatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) { + setAccountsState( ( prevState ) => ( { + ...prevState, + isCreatingWhichAccount: null, + accountsCreated: true, + } ) ); + return; } - // MC account check + const mcAccountCreated = [ 200, 403, 406, 503 ].includes( + response?.status + ); + if ( - isCreatingMCAccountRef.current === true && - response?.status === 200 + isCreatingWhichAccount === CREATING_MC_ACCOUNT && + mcAccountCreated ) { - isCreatingMCAccountRef.current = false; - accountsCreatedRef.current = true; + setAccountsState( ( prevState ) => ( { + ...prevState, + isCreatingWhichAccount: null, + accountsCreated: true, + } ) ); + return; } - // both accounts check if ( - isCreatingBothAccountsRef.current === true && - response?.status === 200 && + isCreatingWhichAccount === CREATING_BOTH_ACCOUNTS && + mcAccountCreated && ! loading ) { - isCreatingBothAccountsRef.current = false; - accountsCreatedRef.current = true; + setAccountsState( ( prevState ) => ( { + ...prevState, + isCreatingWhichAccount: null, + accountsCreated: true, + } ) ); } - }, [ response, loading ] ); + }, [ response, loading, isCreatingWhichAccount ] ); useEffect( () => { const handleCreation = async () => { - // Bail out if we haven't resolved the existing accounts checks yet or there's a creation in progress or the accounts have been created. if ( ! accountCreationChecksResolved || isCreatingAccounts || - accountsCreatedRef.current + accountsCreated ) { return; } if ( shouldCreateAdsAccount ) { - isCreatingAdsAccountRef.current = true; + setAccountsState( ( prevState ) => ( { + ...prevState, + isCreatingWhichAccount: CREATING_ADS_ACCOUNT, + } ) ); await upsertAdsAccount(); return; } if ( shouldCreateMCAccount ) { - isCreatingMCAccountRef.current = true; + setAccountsState( ( prevState ) => ( { + ...prevState, + isCreatingWhichAccount: CREATING_MC_ACCOUNT, + } ) ); await handleCreateAccount(); return; } if ( shouldCreateBothAccounts ) { - isCreatingBothAccountsRef.current = true; + setAccountsState( ( prevState ) => ( { + ...prevState, + isCreatingWhichAccount: CREATING_BOTH_ACCOUNTS, + } ) ); await handleCreateAccount(); await upsertAdsAccount(); } @@ -164,21 +192,19 @@ const useAutoCreateAdsMCAccounts = () => { handleCreation(); }, [ accountCreationChecksResolved, + accountsCreated, + handleCreateAccount, isCreatingAccounts, shouldCreateAdsAccount, - shouldCreateMCAccount, shouldCreateBothAccounts, - handleCreateAccount, + shouldCreateMCAccount, upsertAdsAccount, ] ); return { accountCreationChecksResolved, - isCreatingAdsAccountOnly: isCreatingAdsAccountRef.current, - isCreatingMCAccountOnly: isCreatingMCAccountRef.current, - isCreatingBothAccounts: isCreatingBothAccountsRef.current, isCreatingAccounts, - accountsCreated: accountsCreatedRef.current, + isCreatingWhichAccount, }; }; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index ff99a885cf..b0839f7a8f 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { renderHook, act } from '@testing-library/react'; +import { renderHook } from '@testing-library/react'; /** * Internal dependencies @@ -29,23 +29,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { handleCreateAccount = jest.fn( () => Promise.resolve() ); upsertAdsAccount = jest.fn( () => Promise.resolve() ); - useCreateMCAccount.mockReturnValue( [ - handleCreateAccount, - { response: { status: 200 } }, - ] ); - useUpsertAdsAccount.mockReturnValue( [ - upsertAdsAccount, - { loading: false }, - ] ); - useExistingGoogleMCAccounts.mockReturnValue( { - data: [], - hasFinishedResolution: true, - } ); - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [], - hasFinishedResolution: true, - } ); - useGoogleAdsAccount.mockReturnValue( { hasFinishedResolution: true, hasGoogleAdsConnection: false, @@ -57,156 +40,68 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); } ); - it( 'should not call "handleCreateAccount" and "upsertAdsAccount" when there are existing accounts', () => { - // Simulate existing accounts - useExistingGoogleMCAccounts.mockReturnValue( { - data: [ { id: 1 } ], - hasFinishedResolution: true, + describe( 'Automatic account creation', () => { + beforeEach( () => { + useCreateMCAccount.mockReturnValue( [ + handleCreateAccount, + { response: undefined }, + ] ); + useUpsertAdsAccount.mockReturnValue( [ + upsertAdsAccount, + { loading: true }, + ] ); + useExistingGoogleMCAccounts.mockReturnValue( { + data: [], + hasFinishedResolution: true, + } ); + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [], + hasFinishedResolution: true, + } ); } ); - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [ { id: 1 } ], - hasFinishedResolution: true, - } ); - - const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); - expect( result.current.accountsCreated ).toBe( false ); - expect( handleCreateAccount ).not.toHaveBeenCalled(); - expect( upsertAdsAccount ).not.toHaveBeenCalled(); - } ); - - it( 'should call "handleCreateAccount" and "upsertAdsAccount" when there are no existing accounts', async () => { - // Simulate the initial state and mock behavior for account creation - const { result, rerender } = renderHook( () => - useAutoCreateAdsMCAccounts() - ); - - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); - - useCreateMCAccount.mockReturnValueOnce( [ - handleCreateAccount, - { response: { status: 200 } }, - ] ); - useUpsertAdsAccount.mockReturnValueOnce( [ - upsertAdsAccount, - { loading: false }, - ] ); - - rerender(); + it( 'should create both accounts', () => { + const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); - - // eslint-disable-next-line testing-library/no-unnecessary-act - await act( async () => { - rerender(); + // It should create both accounts. + expect( result.current.isCreatingWhichAccount ).toBe( 'both' ); + expect( result.current.isCreatingAccounts ).toBe( true ); } ); - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); - expect( result.current.accountsCreated ).toBe( true ); - - // Finally, check that the functions were called correctly - expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); - expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); - } ); - - it( 'should create Merchant Center account only when there is no existing MC account, but there is an existing Ads account', async () => { - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [ { id: 1 } ], // Existing Ads account - hasFinishedResolution: true, + it( 'should create only the Merchant Center account', () => { + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [ + { + id: 1, + name: 'Test Ads Account', + }, + ], + hasFinishedResolution: true, + } ); + + const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); + + // It should create only the Merchant Center account. + expect( result.current.isCreatingWhichAccount ).toBe( 'mc' ); + expect( result.current.isCreatingAccounts ).toBe( true ); } ); - // Step 1: Initial render - No response, loading is true - useCreateMCAccount.mockReturnValueOnce( [ - handleCreateAccount, - { response: undefined, loading: true }, // Initially no response, loading is true - ] ); - - const { result, rerender } = renderHook( () => - useAutoCreateAdsMCAccounts() - ); - - // Initially, it should not be creating accounts - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); - - // Trigger the effect that starts account creation. - rerender(); - - // Step 2: At this point, MC account creation should have started - expect( result.current.isCreatingMCAccountOnly ).toBe( true ); - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); // Since Ads account exists - expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); - expect( upsertAdsAccount ).not.toHaveBeenCalled(); - - // Step 3: Simulate the response for MC account creation - useCreateMCAccount.mockReturnValueOnce( [ - handleCreateAccount, - { response: { status: 200 }, loading: false }, // Now account creation is complete - ] ); - - // Trigger a rerender to simulate the async function resolving. - rerender(); - - // Step 4: Final assertions after account creation has completed - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); - expect( result.current.accountsCreated ).toBe( true ); // The account has been created - - // Finally, verify that only handleCreateAccount was called, not upsertAdsAccount - expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); - expect( upsertAdsAccount ).not.toHaveBeenCalled(); - } ); - - it( 'should create Ads account only when there is no existing Ads account, but there is an existing Merchant Center account', async () => { - // Simulate existing MC account but no existing Ads account - useExistingGoogleMCAccounts.mockReturnValue( { - data: [ { id: 1 } ], // Existing MC account - hasFinishedResolution: true, + it( 'should create only the Google Ads account', () => { + useExistingGoogleMCAccounts.mockReturnValue( { + data: [ + { + id: 1, + name: 'Test MC Account', + }, + ], + hasFinishedResolution: true, + } ); + + const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); + + // It should create only the Google Ads account. + expect( result.current.isCreatingWhichAccount ).toBe( 'ads' ); + expect( result.current.isCreatingAccounts ).toBe( true ); } ); - - // Step 1: Initial render - No response, loading is true for Ads account creation - useUpsertAdsAccount.mockReturnValueOnce( [ - upsertAdsAccount, - { response: undefined, loading: true }, // Initially no response, loading is true for Ads account creation - ] ); - - const { result, rerender } = renderHook( () => - useAutoCreateAdsMCAccounts() - ); - - // Initially, it should not be creating accounts - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); - - rerender(); // Simulate the effect firing. - - // Step 2: At this point, Ads account creation should have started - expect( result.current.isCreatingAdsAccountOnly ).toBe( true ); - expect( result.current.isCreatingMCAccountOnly ).toBe( false ); // Since MC account exists - expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); - expect( handleCreateAccount ).not.toHaveBeenCalled(); // MC account creation shouldn't be triggered - - // Step 3: Simulate the response for Ads account creation - useUpsertAdsAccount.mockReturnValueOnce( [ - upsertAdsAccount, - { response: { status: 200 }, loading: false }, // Now Ads account creation is complete - ] ); - - // Trigger a rerender to simulate the async function resolving. - rerender(); - - // Step 4: Final assertions after Ads account creation has completed - expect( result.current.accountsCreated ).toBe( true ); // The account has been created - expect( result.current.isCreatingAdsAccountOnly ).toBe( false ); // Ads account creation finished - - // Finally, verify that only upsertAdsAccount was called, not handleCreateAccount - expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); - expect( handleCreateAccount ).not.toHaveBeenCalled(); } ); } ); From cb382e832e139bbe46fd0f51d63785153a0306fb Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 17:29:09 +0530 Subject: [PATCH 43/91] Fix: js lint. --- js/src/hooks/useAutoCreateAdsMCAccounts.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 3893c142a4..72d327117c 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -111,8 +111,6 @@ const useAutoCreateAdsMCAccounts = () => { return; } - console.debug( 'isCreatingWhichAccount', isCreatingWhichAccount ); - if ( isCreatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) { setAccountsState( ( prevState ) => ( { ...prevState, From 747097d6f171afdc10dad1f1cf93d1e4fb9069ac Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 17:42:30 +0530 Subject: [PATCH 44/91] Update existing MC accounts check. --- js/src/hooks/useAutoCreateAdsMCAccounts.js | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 72d327117c..61a2ba4ab5 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -16,7 +16,6 @@ import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, - GOOGLE_MC_ACCOUNT_STATUS, } from '.~/constants'; /** @@ -54,21 +53,13 @@ const useAutoCreateAdsMCAccounts = () => { hasGoogleAdsConnection, } = useGoogleAdsAccount(); - const { - googleMCAccount, - hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount, - } = useGoogleMCAccount(); + const { hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount } = + useGoogleMCAccount(); const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - const isGoogleMCConnected = [ - GOOGLE_MC_ACCOUNT_STATUS.CONNECTED, - GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE, - ].includes( googleMCAccount?.status ); - - const hasExistingMCAccount = - isGoogleMCConnected || existingMCAccounts?.length > 0; + const hasExistingMCAccount = existingMCAccounts?.length > 0; const hasExistingAdsAccount = hasGoogleAdsConnection || existingAdsAccounts?.length > 0; From 79eddb94091c3fe2ed09831209213a5ca536529d Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 18:54:32 +0530 Subject: [PATCH 45/91] Add tests for existing accounts. --- js/src/hooks/useAutoCreateAdsMCAccounts.js | 77 ++++++++++--------- .../hooks/useAutoCreateAdsMCAccounts.test.js | 45 +++++++++++ 2 files changed, 86 insertions(+), 36 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 61a2ba4ab5..2cf4a7ffb2 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -37,6 +37,7 @@ const useAutoCreateAdsMCAccounts = () => { const { accountsCreated, isCreatingWhichAccount } = accountsState; const initHasExistingMCAccountsRef = useRef( null ); const initHasExistingAdsAccountsRef = useRef( null ); + const shouldCreateAccounts = useRef(); const { data: existingMCAccounts, @@ -79,24 +80,35 @@ const useAutoCreateAdsMCAccounts = () => { initHasExistingAdsAccountsRef.current = hasExistingAdsAccount; } - const accountCreationChecksResolved = - initHasExistingAdsAccountsRef.current !== null && - initHasExistingMCAccountsRef.current !== null; - - const shouldCreateAdsAccount = - initHasExistingAdsAccountsRef.current === false && - initHasExistingMCAccountsRef.current === true; + const googleAdsAccountChecksResolved = + hasFinishedResolutionForExistingAdsAccount && + hasFinishedResolutionForGoogleAdsAccount; - const shouldCreateMCAccount = - initHasExistingAdsAccountsRef.current === true && - initHasExistingMCAccountsRef.current === false; + const googleMCAccountChecksResolved = + hasFinishedResolutionForGoogleMCAccount && + hasFinishedResolutionForExistingMCAccounts; - const shouldCreateBothAccounts = - ! initHasExistingAdsAccountsRef.current && - ! initHasExistingMCAccountsRef.current; + const accountCreationChecksResolved = + googleAdsAccountChecksResolved && googleMCAccountChecksResolved; const isCreatingAccounts = !! isCreatingWhichAccount; + if ( googleAdsAccountChecksResolved && googleMCAccountChecksResolved ) { + if ( ! hasExistingAdsAccount || ! hasExistingMCAccount ) { + // Based on which accounts to create, set shouldCreateAccounts to 'ads, 'mc', or 'both'. + const createBothAccounts = + ! hasExistingAdsAccount && ! hasExistingMCAccount; + + if ( createBothAccounts ) { + shouldCreateAccounts.current = CREATING_BOTH_ACCOUNTS; + } else if ( ! hasExistingAdsAccount ) { + shouldCreateAccounts.current = CREATING_ADS_ACCOUNT; + } else { + shouldCreateAccounts.current = CREATING_MC_ACCOUNT; + } + } + } + useEffect( () => { if ( ! response && loading ) { return; @@ -108,6 +120,7 @@ const useAutoCreateAdsMCAccounts = () => { isCreatingWhichAccount: null, accountsCreated: true, } ) ); + shouldCreateAccounts.current = null; return; } @@ -124,6 +137,7 @@ const useAutoCreateAdsMCAccounts = () => { isCreatingWhichAccount: null, accountsCreated: true, } ) ); + shouldCreateAccounts.current = null; return; } @@ -137,6 +151,7 @@ const useAutoCreateAdsMCAccounts = () => { isCreatingWhichAccount: null, accountsCreated: true, } ) ); + shouldCreateAccounts.current = null; } }, [ response, loading, isCreatingWhichAccount ] ); @@ -150,43 +165,33 @@ const useAutoCreateAdsMCAccounts = () => { return; } - if ( shouldCreateAdsAccount ) { + if ( shouldCreateAccounts.current ) { setAccountsState( ( prevState ) => ( { ...prevState, - isCreatingWhichAccount: CREATING_ADS_ACCOUNT, + isCreatingWhichAccount: shouldCreateAccounts.current, } ) ); - await upsertAdsAccount(); - return; - } - if ( shouldCreateMCAccount ) { - setAccountsState( ( prevState ) => ( { - ...prevState, - isCreatingWhichAccount: CREATING_MC_ACCOUNT, - } ) ); - await handleCreateAccount(); - return; - } + if ( shouldCreateAccounts.current === CREATING_BOTH_ACCOUNTS ) { + await handleCreateAccount(); + await upsertAdsAccount(); + return; + } + + if ( shouldCreateAccounts.current === CREATING_ADS_ACCOUNT ) { + await upsertAdsAccount(); + return; + } - if ( shouldCreateBothAccounts ) { - setAccountsState( ( prevState ) => ( { - ...prevState, - isCreatingWhichAccount: CREATING_BOTH_ACCOUNTS, - } ) ); await handleCreateAccount(); - await upsertAdsAccount(); } }; handleCreation(); }, [ accountCreationChecksResolved, + isCreatingAccounts, accountsCreated, handleCreateAccount, - isCreatingAccounts, - shouldCreateAdsAccount, - shouldCreateBothAccounts, - shouldCreateMCAccount, upsertAdsAccount, ] ); diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index b0839f7a8f..9f7deb0154 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -104,4 +104,49 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { expect( result.current.isCreatingAccounts ).toBe( true ); } ); } ); + + describe( 'Existing accounts', () => { + beforeEach( () => { + useCreateMCAccount.mockReturnValue( [ + handleCreateAccount, + { response: { status: 200 } }, + ] ); + useUpsertAdsAccount.mockReturnValue( [ + upsertAdsAccount, + { loading: false }, + ] ); + } ); + + it( 'should not create accounts if they already exist', () => { + useExistingGoogleMCAccounts.mockReturnValue( { + data: [ + { + id: 1, + name: 'Test MC Account', + }, + ], + hasFinishedResolution: true, + } ); + + useExistingGoogleAdsAccounts.mockReturnValue( { + existingAccounts: [ + { + id: 1, + name: 'Test Ads Account', + }, + ], + hasFinishedResolution: true, + } ); + + const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); + + // It should not create any accounts. + expect( result.current.isCreatingWhichAccount ).toBe( null ); + expect( result.current.isCreatingAccounts ).toBe( false ); + + // make sure functions are not called. + expect( handleCreateAccount ).not.toHaveBeenCalled(); + expect( upsertAdsAccount ).not.toHaveBeenCalled(); + } ); + } ); } ); From e03d4790face07f0ed4486abd45845b8ae03dfc6 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 19:18:59 +0530 Subject: [PATCH 46/91] Remove unnecessary refs. --- .../google-mc-account-card/create-account.js | 2 +- js/src/hooks/useAutoCreateAdsMCAccounts.js | 18 ------------------ 2 files changed, 1 insertion(+), 19 deletions(-) diff --git a/js/src/components/google-mc-account-card/create-account.js b/js/src/components/google-mc-account-card/create-account.js index 28e2b084d4..9bf5831ad0 100644 --- a/js/src/components/google-mc-account-card/create-account.js +++ b/js/src/components/google-mc-account-card/create-account.js @@ -4,7 +4,7 @@ import CreateAccountCard from './create-account-card'; import CreatingCard from './creating-card'; import ReclaimUrlCard from './reclaim-url-card'; -import useCreateMCAccount from '../../hooks/useCreateMCAccount'; +import useCreateMCAccount from '.~/hooks/useCreateMCAccount'; /** * Create Account flow. diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 2cf4a7ffb2..2b7692c8ab 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -35,8 +35,6 @@ const useAutoCreateAdsMCAccounts = () => { } ); const { accountsCreated, isCreatingWhichAccount } = accountsState; - const initHasExistingMCAccountsRef = useRef( null ); - const initHasExistingAdsAccountsRef = useRef( null ); const shouldCreateAccounts = useRef(); const { @@ -64,22 +62,6 @@ const useAutoCreateAdsMCAccounts = () => { const hasExistingAdsAccount = hasGoogleAdsConnection || existingAdsAccounts?.length > 0; - if ( - initHasExistingMCAccountsRef.current === null && - hasFinishedResolutionForExistingMCAccounts && - hasFinishedResolutionForGoogleMCAccount - ) { - initHasExistingMCAccountsRef.current = hasExistingMCAccount; - } - - if ( - initHasExistingAdsAccountsRef.current === null && - hasFinishedResolutionForExistingAdsAccount && - hasFinishedResolutionForGoogleAdsAccount - ) { - initHasExistingAdsAccountsRef.current = hasExistingAdsAccount; - } - const googleAdsAccountChecksResolved = hasFinishedResolutionForExistingAdsAccount && hasFinishedResolutionForGoogleAdsAccount; From 3230a8bd3fa98c22de142d937b099e5da093699e Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 19:39:42 +0530 Subject: [PATCH 47/91] Consolidate useEffect hook into one. --- js/src/hooks/useAutoCreateAdsMCAccounts.js | 25 ++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 2b7692c8ab..3601100005 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -92,6 +92,23 @@ const useAutoCreateAdsMCAccounts = () => { } useEffect( () => { + // Set shouldCreateAccounts when all checks are resolved and accounts need to be created + if ( accountCreationChecksResolved && ! shouldCreateAccounts.current ) { + if ( ! hasExistingAdsAccount || ! hasExistingMCAccount ) { + const createBothAccounts = + ! hasExistingAdsAccount && ! hasExistingMCAccount; + + if ( createBothAccounts ) { + shouldCreateAccounts.current = CREATING_BOTH_ACCOUNTS; + } else if ( ! hasExistingAdsAccount ) { + shouldCreateAccounts.current = CREATING_ADS_ACCOUNT; + } else { + shouldCreateAccounts.current = CREATING_MC_ACCOUNT; + } + } + } + + // Handle account creation and updating the state when responses are resolved if ( ! response && loading ) { return; } @@ -135,9 +152,8 @@ const useAutoCreateAdsMCAccounts = () => { } ) ); shouldCreateAccounts.current = null; } - }, [ response, loading, isCreatingWhichAccount ] ); - useEffect( () => { + // Trigger account creation when appropriate const handleCreation = async () => { if ( ! accountCreationChecksResolved || @@ -175,6 +191,11 @@ const useAutoCreateAdsMCAccounts = () => { accountsCreated, handleCreateAccount, upsertAdsAccount, + response, + loading, + isCreatingWhichAccount, + hasExistingMCAccount, + hasExistingAdsAccount, ] ); return { From b5e23ff51918353505d81b052a05ab9bb1eff2b0 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 22:43:31 +0530 Subject: [PATCH 48/91] Optimize hook to use limited refs. --- .../connected-google-combo-account-card.js | 9 +- js/src/hooks/useAutoCreateAdsMCAccounts.js | 132 ++++++------------ .../hooks/useAutoCreateAdsMCAccounts.test.js | 4 - 3 files changed, 44 insertions(+), 101 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 9a0f7c26f4..a2656ea9ce 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -32,11 +32,10 @@ const ConnectedGoogleComboAccountCard = () => { hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, } = useGoogleMCAccount(); - const { - accountCreationChecksResolved, - isCreatingAccounts, - isCreatingWhichAccount, - } = useAutoCreateAdsMCAccounts(); + const { accountCreationChecksResolved, isCreatingWhichAccount } = + useAutoCreateAdsMCAccounts(); + + const isCreatingAccounts = !! isCreatingWhichAccount; if ( ! accountCreationChecksResolved || diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 3601100005..f5a4720e5b 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { useEffect, useRef, useState } from '@wordpress/element'; +import { useEffect, useState, useRef, useCallback } from '@wordpress/element'; /** * Internal dependencies @@ -18,16 +18,6 @@ import { CREATING_MC_ACCOUNT, } from '.~/constants'; -/** - * Custom hook to handle the creation of Google Merchant Center (MC) and Google Ads accounts. - * - * @typedef {Object} AutoCreateAccountsStatus - * @property {boolean} accountCreationChecksResolved Whether the checks for account creation have been resolved. - * @property {boolean} isCreatingAccounts Whether the accounts are being created. - * @property {string|null} isCreatingWhichAccount The type of account that is being created. - * - * @return {AutoCreateAccountsStatus} Object containing properties related to the account creation status. - */ const useAutoCreateAdsMCAccounts = () => { const [ accountsState, setAccountsState ] = useState( { accountsCreated: false, @@ -73,11 +63,8 @@ const useAutoCreateAdsMCAccounts = () => { const accountCreationChecksResolved = googleAdsAccountChecksResolved && googleMCAccountChecksResolved; - const isCreatingAccounts = !! isCreatingWhichAccount; - if ( googleAdsAccountChecksResolved && googleMCAccountChecksResolved ) { if ( ! hasExistingAdsAccount || ! hasExistingMCAccount ) { - // Based on which accounts to create, set shouldCreateAccounts to 'ads, 'mc', or 'both'. const createBothAccounts = ! hasExistingAdsAccount && ! hasExistingMCAccount; @@ -91,35 +78,8 @@ const useAutoCreateAdsMCAccounts = () => { } } - useEffect( () => { - // Set shouldCreateAccounts when all checks are resolved and accounts need to be created - if ( accountCreationChecksResolved && ! shouldCreateAccounts.current ) { - if ( ! hasExistingAdsAccount || ! hasExistingMCAccount ) { - const createBothAccounts = - ! hasExistingAdsAccount && ! hasExistingMCAccount; - - if ( createBothAccounts ) { - shouldCreateAccounts.current = CREATING_BOTH_ACCOUNTS; - } else if ( ! hasExistingAdsAccount ) { - shouldCreateAccounts.current = CREATING_ADS_ACCOUNT; - } else { - shouldCreateAccounts.current = CREATING_MC_ACCOUNT; - } - } - } - - // Handle account creation and updating the state when responses are resolved - if ( ! response && loading ) { - return; - } - - if ( isCreatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) { - setAccountsState( ( prevState ) => ( { - ...prevState, - isCreatingWhichAccount: null, - accountsCreated: true, - } ) ); - shouldCreateAccounts.current = null; + const handlePostAccountCreation = useCallback( () => { + if ( ! isCreatingWhichAccount ) { return; } @@ -127,80 +87,68 @@ const useAutoCreateAdsMCAccounts = () => { response?.status ); - if ( - isCreatingWhichAccount === CREATING_MC_ACCOUNT && - mcAccountCreated - ) { + const resetState = + ( isCreatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) || + ( isCreatingWhichAccount === CREATING_MC_ACCOUNT && + mcAccountCreated ) || + ( isCreatingWhichAccount === CREATING_BOTH_ACCOUNTS && + mcAccountCreated && + ! loading ); + + if ( resetState ) { + shouldCreateAccounts.current = null; setAccountsState( ( prevState ) => ( { ...prevState, isCreatingWhichAccount: null, accountsCreated: true, } ) ); - shouldCreateAccounts.current = null; - return; } + }, [ response, loading, isCreatingWhichAccount ] ); + const handleAccountCreation = useCallback( async () => { if ( - isCreatingWhichAccount === CREATING_BOTH_ACCOUNTS && - mcAccountCreated && - ! loading + ! accountCreationChecksResolved || + isCreatingWhichAccount || + accountsCreated ) { + return; + } + + if ( shouldCreateAccounts.current ) { setAccountsState( ( prevState ) => ( { ...prevState, - isCreatingWhichAccount: null, - accountsCreated: true, + isCreatingWhichAccount: shouldCreateAccounts.current, } ) ); - shouldCreateAccounts.current = null; - } - // Trigger account creation when appropriate - const handleCreation = async () => { - if ( - ! accountCreationChecksResolved || - isCreatingAccounts || - accountsCreated + if ( shouldCreateAccounts.current === CREATING_BOTH_ACCOUNTS ) { + await handleCreateAccount(); + await upsertAdsAccount(); + } else if ( + shouldCreateAccounts.current === CREATING_ADS_ACCOUNT ) { - return; - } - - if ( shouldCreateAccounts.current ) { - setAccountsState( ( prevState ) => ( { - ...prevState, - isCreatingWhichAccount: shouldCreateAccounts.current, - } ) ); - - if ( shouldCreateAccounts.current === CREATING_BOTH_ACCOUNTS ) { - await handleCreateAccount(); - await upsertAdsAccount(); - return; - } - - if ( shouldCreateAccounts.current === CREATING_ADS_ACCOUNT ) { - await upsertAdsAccount(); - return; - } - + await upsertAdsAccount(); + } else { await handleCreateAccount(); } - }; - - handleCreation(); + } }, [ accountCreationChecksResolved, - isCreatingAccounts, + isCreatingWhichAccount, accountsCreated, handleCreateAccount, upsertAdsAccount, - response, - loading, - isCreatingWhichAccount, - hasExistingMCAccount, - hasExistingAdsAccount, ] ); + useEffect( () => { + handlePostAccountCreation(); + }, [ response, loading, handlePostAccountCreation ] ); + + useEffect( () => { + handleAccountCreation(); + }, [ handleAccountCreation ] ); + return { accountCreationChecksResolved, - isCreatingAccounts, isCreatingWhichAccount, }; }; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 9f7deb0154..6586a6a941 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -65,7 +65,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { // It should create both accounts. expect( result.current.isCreatingWhichAccount ).toBe( 'both' ); - expect( result.current.isCreatingAccounts ).toBe( true ); } ); it( 'should create only the Merchant Center account', () => { @@ -83,7 +82,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { // It should create only the Merchant Center account. expect( result.current.isCreatingWhichAccount ).toBe( 'mc' ); - expect( result.current.isCreatingAccounts ).toBe( true ); } ); it( 'should create only the Google Ads account', () => { @@ -101,7 +99,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { // It should create only the Google Ads account. expect( result.current.isCreatingWhichAccount ).toBe( 'ads' ); - expect( result.current.isCreatingAccounts ).toBe( true ); } ); } ); @@ -142,7 +139,6 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { // It should not create any accounts. expect( result.current.isCreatingWhichAccount ).toBe( null ); - expect( result.current.isCreatingAccounts ).toBe( false ); // make sure functions are not called. expect( handleCreateAccount ).not.toHaveBeenCalled(); From 40bd01c590df65153d4baa1d9f539425ae4b9447 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 17 Oct 2024 22:49:24 +0530 Subject: [PATCH 49/91] Remove unused constants. --- js/src/components/google-combo-account-card/constants.js | 0 js/src/constants.js | 6 ------ 2 files changed, 6 deletions(-) delete mode 100644 js/src/components/google-combo-account-card/constants.js diff --git a/js/src/components/google-combo-account-card/constants.js b/js/src/components/google-combo-account-card/constants.js deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/js/src/constants.js b/js/src/constants.js index cdea5e560f..b147f243da 100644 --- a/js/src/constants.js +++ b/js/src/constants.js @@ -69,12 +69,6 @@ export const GOOGLE_ADS_ACCOUNT_STATUS = { INCOMPLETE: 'incomplete', }; -export const GOOGLE_MC_ACCOUNT_STATUS = { - CONNECTED: 'connected', - DISCONNECTED: 'disconnected', - INCOMPLETE: 'incomplete', -}; - export const GOOGLE_ADS_BILLING_STATUS = { UNKNOWN: 'unknown', PENDING: 'pending', From 4e65cd7dca552efd165d6a3c3614c524d748a3c2 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 18 Oct 2024 00:38:55 +0530 Subject: [PATCH 50/91] Fix: E2E tests. --- .../account-creation-description/index.js | 27 +++++++------ .../connected-google-combo-account-card.js | 40 ++++++++++++------- .../google-combo-account-card/constants.js | 3 ++ js/src/constants.js | 4 -- js/src/hooks/useAutoCreateAdsMCAccounts.js | 14 +++++-- .../specs/setup-mc/step-1-accounts.test.js | 9 ++++- 6 files changed, 63 insertions(+), 34 deletions(-) create mode 100644 js/src/components/google-combo-account-card/constants.js diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index dcff531b25..ff3ea78b4f 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -13,25 +13,23 @@ import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, -} from '.~/constants'; +} from '../constants'; /** * Renders the description for the account creation card. * * @param {Object} props Props. - * @param {string} props.isCreatingWhichAccount The type of account that is being created. - * @param {number} props.isGoogleAdsReady Whether the Google Ads account is ready. - * @param {number} props.isGoogleMCReady Whether the Merchant Center account is ready. + * @param {string} props.isCreatingWhichAccount The type of account that is being created. Possible values are 'ads', 'mc', or 'both'. */ -const AccountCreationDescription = ( { - isCreatingWhichAccount, - isGoogleAdsReady, - isGoogleMCReady, -} ) => { - const { google } = useGoogleAccount(); +const AccountCreationDescription = ( { isCreatingWhichAccount } ) => { + const { google, hasFinishedResolution } = useGoogleAccount(); const { googleMCAccount } = useGoogleMCAccount(); const { googleAdsAccount } = useGoogleAdsAccount(); + if ( ! hasFinishedResolution ) { + return null; + } + const getDescription = () => { if ( isCreatingWhichAccount ) { switch ( isCreatingWhichAccount ) { @@ -83,10 +81,15 @@ const AccountCreationDescription = ( { } } + const isCreatingAccounts = !! isCreatingWhichAccount; + const isGoogleAdsReady = + ! isCreatingAccounts && googleAdsAccount.id > 0; + const isGoogleMCReady = ! isCreatingAccounts && googleMCAccount.id > 0; + return ( <>

{ google?.email }

- { isGoogleMCReady > 0 && ( + { isGoogleMCReady && (

{ sprintf( // Translators: %s is the Merchant Center ID @@ -98,7 +101,7 @@ const AccountCreationDescription = ( { ) }

) } - { isGoogleAdsReady > 0 && ( + { isGoogleAdsReady && (

{ sprintf( // Translators: %s is the Google Ads ID diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index a2656ea9ce..cc7011c915 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -7,15 +7,16 @@ import { __ } from '@wordpress/i18n'; * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; +import AccountCreationDescription from './account-creation-description'; import AppSpinner from '../app-spinner'; -import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; +import ConnectedIconLabel from '../connected-icon-label'; +import { CREATING_BOTH_ACCOUNTS } from './constants'; import LoadingLabel from '../loading-label/loading-label'; -import AccountCreationDescription from './account-creation-description'; -import './connected-google-combo-account-card.scss'; +import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; -import ConnectedIconLabel from '../connected-icon-label'; -import { CREATING_BOTH_ACCOUNTS } from '.~/constants'; +import './connected-google-combo-account-card.scss'; /** * Renders a Google account card UI with connected account information. @@ -23,30 +24,43 @@ import { CREATING_BOTH_ACCOUNTS } from '.~/constants'; */ const ConnectedGoogleComboAccountCard = () => { const { - googleAdsAccount, + hasGoogleAdsConnection, hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, } = useGoogleAdsAccount(); const { googleMCAccount, + isPreconditionReady, hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, } = useGoogleMCAccount(); - const { accountCreationChecksResolved, isCreatingWhichAccount } = - useAutoCreateAdsMCAccounts(); + const { + hasFinishedResolutionForExistingAdsMCAccounts, + isCreatingWhichAccount, + } = useAutoCreateAdsMCAccounts(); + + const { hasAccess, step } = useGoogleAdsAccountStatus(); const isCreatingAccounts = !! isCreatingWhichAccount; if ( - ! accountCreationChecksResolved || + ! hasFinishedResolutionForExistingAdsMCAccounts || ! hasFinishedResolutionForCurrentAdsAccount || ! hasFinishedResolutionForCurrentMCAccount ) { return } />; } - const isGoogleAdsReady = ! isCreatingAccounts && googleAdsAccount.id > 0; - const isGoogleMCReady = ! isCreatingAccounts && googleMCAccount.id > 0; + const isGoogleAdsConnected = + hasGoogleAdsConnection && + hasAccess && + [ '', 'billing', 'link_merchant' ].includes( step ); + + const isGoogleMCConnected = + isPreconditionReady && + ( googleMCAccount?.status === 'connected' || + ( googleMCAccount?.status === 'incomplete' && + googleMCAccount?.step === 'link_ads' ) ); const getHelper = () => { if ( isCreatingWhichAccount === CREATING_BOTH_ACCOUNTS ) { @@ -72,7 +86,7 @@ const ConnectedGoogleComboAccountCard = () => { ); } - if ( isGoogleAdsReady && isGoogleMCReady ) { + if ( isGoogleAdsConnected && isGoogleMCConnected ) { return ; } @@ -87,8 +101,6 @@ const ConnectedGoogleComboAccountCard = () => { description={ } helper={ getHelper() } diff --git a/js/src/components/google-combo-account-card/constants.js b/js/src/components/google-combo-account-card/constants.js new file mode 100644 index 0000000000..3086a154d8 --- /dev/null +++ b/js/src/components/google-combo-account-card/constants.js @@ -0,0 +1,3 @@ +export const CREATING_BOTH_ACCOUNTS = 'both'; +export const CREATING_ADS_ACCOUNT = 'ads'; +export const CREATING_MC_ACCOUNT = 'mc'; diff --git a/js/src/constants.js b/js/src/constants.js index b147f243da..6e430384d4 100644 --- a/js/src/constants.js +++ b/js/src/constants.js @@ -117,7 +117,3 @@ export const GOOGLE_WPCOM_APP_CONNECTED_STATUS = { ERROR: 'error', DISABLED: 'disabled', }; - -export const CREATING_BOTH_ACCOUNTS = 'both'; -export const CREATING_ADS_ACCOUNT = 'ads'; -export const CREATING_MC_ACCOUNT = 'mc'; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index f5a4720e5b..f011f24dbd 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -16,8 +16,15 @@ import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, -} from '.~/constants'; +} from '.~/components/google-combo-account-card/constants'; +/** + * Hook to automatically create Ads and Merchant Center accounts if they do not exist. + * + * @return {Object} Object containing the state of the account creation process. + * @property {boolean} hasFinishedResolutionForExistingAdsMCAccounts Indicates whether the checks for existing Merchant Center (MC) and Google Ads accounts have been completed. + * @property {string|null} isCreatingWhichAccount The type of account that is being created. Possible values are 'ads', 'mc', or 'both'. + */ const useAutoCreateAdsMCAccounts = () => { const [ accountsState, setAccountsState ] = useState( { accountsCreated: false, @@ -63,7 +70,7 @@ const useAutoCreateAdsMCAccounts = () => { const accountCreationChecksResolved = googleAdsAccountChecksResolved && googleMCAccountChecksResolved; - if ( googleAdsAccountChecksResolved && googleMCAccountChecksResolved ) { + if ( accountCreationChecksResolved ) { if ( ! hasExistingAdsAccount || ! hasExistingMCAccount ) { const createBothAccounts = ! hasExistingAdsAccount && ! hasExistingMCAccount; @@ -148,7 +155,8 @@ const useAutoCreateAdsMCAccounts = () => { }, [ handleAccountCreation ] ); return { - accountCreationChecksResolved, + hasFinishedResolutionForExistingAdsMCAccounts: + accountCreationChecksResolved, isCreatingWhichAccount, }; }; diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 7f3df66cd7..f86be1c3e5 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -323,7 +323,7 @@ test.describe( 'Set up accounts', () => { subaccount: null, domain: null, status: 'incomplete', - step: 'claim', + step: 'link_ads', } ); await setUpAccountsPage.fulfillAdsConnection( { @@ -383,6 +383,13 @@ test.describe( 'Set up accounts', () => { test( 'should see the connected label', async () => { const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); + + await setUpAccountsPage.fulfillAdsAccountStatus( { + has_access: true, + invite_link: '', + step: 'link_merchant', + } ); + await expect( googleAccountCard.getByText( 'Connected', { exact: true } ) ).toBeVisible(); From 63c2f7f949753042749b53225a3a2754782aeedb Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 18 Oct 2024 01:24:26 +0530 Subject: [PATCH 51/91] Add hasGoogleMCConnection property in useGoogleMCAccount hook. --- js/src/constants.js | 6 ++++++ js/src/hooks/useAutoCreateAdsMCAccounts.js | 9 ++++++--- js/src/hooks/useGoogleMCAccount.js | 19 +++++++++++++++++-- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/js/src/constants.js b/js/src/constants.js index 6e430384d4..3a34ea00f7 100644 --- a/js/src/constants.js +++ b/js/src/constants.js @@ -69,6 +69,12 @@ export const GOOGLE_ADS_ACCOUNT_STATUS = { INCOMPLETE: 'incomplete', }; +export const GOOGLE_MC_ACCOUNT_STATUS = { + CONNECTED: 'connected', + DISCONNECTED: 'disconnected', + INCOMPLETE: 'incomplete', +}; + export const GOOGLE_ADS_BILLING_STATUS = { UNKNOWN: 'unknown', PENDING: 'pending', diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index f011f24dbd..40605f2299 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -49,13 +49,16 @@ const useAutoCreateAdsMCAccounts = () => { hasGoogleAdsConnection, } = useGoogleAdsAccount(); - const { hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount } = - useGoogleMCAccount(); + const { + hasGoogleMCConnection, + hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount, + } = useGoogleMCAccount(); const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - const hasExistingMCAccount = existingMCAccounts?.length > 0; + const hasExistingMCAccount = + hasGoogleMCConnection || existingMCAccounts?.length > 0; const hasExistingAdsAccount = hasGoogleAdsConnection || existingAdsAccounts?.length > 0; diff --git a/js/src/hooks/useGoogleMCAccount.js b/js/src/hooks/useGoogleMCAccount.js index 76958ea1d9..a5a2a0dbaa 100644 --- a/js/src/hooks/useGoogleMCAccount.js +++ b/js/src/hooks/useGoogleMCAccount.js @@ -8,6 +8,7 @@ import { useSelect } from '@wordpress/data'; */ import { STORE_KEY } from '.~/data/constants'; import useGoogleAccount from './useGoogleAccount'; +import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; /** * @typedef {import('.~/data/selectors').GoogleMCAccount} GoogleMCAccount @@ -19,6 +20,8 @@ import useGoogleAccount from './useGoogleAccount'; * @property {boolean} isPreconditionReady Whether the precondition of continued connection processing is fulfilled. */ +const googleMCAccountSelector = 'getGoogleMCAccount'; + /** * A hook to load the connection data of Google Merchant Center account. * @@ -46,15 +49,27 @@ const useGoogleMCAccount = () => { }; } - const { getGoogleMCAccount, isResolving, hasFinishedResolution } = + const { getGoogleMCAccount, hasFinishedResolution } = select( STORE_KEY ); + const selector = select( STORE_KEY ); + const acc = selector[ googleMCAccountSelector ](); + const isResolvingGoogleMCAccount = selector.isResolving( + googleMCAccountSelector + ); + + const hasGoogleMCConnection = [ + GOOGLE_MC_ACCOUNT_STATUS.CONNECTED, + GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE, + ].includes( acc?.status ); + return { googleMCAccount: getGoogleMCAccount(), - isResolving: isResolving( 'getGoogleMCAccount' ), + isResolving: isResolvingGoogleMCAccount, hasFinishedResolution: hasFinishedResolution( 'getGoogleMCAccount' ), isPreconditionReady: true, + hasGoogleMCConnection, }; }, [ From 2da86e67698c43ea964440cc86dce62a6778f99e Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 18 Oct 2024 10:53:59 +0530 Subject: [PATCH 52/91] Update doc block. --- .../account-creation-description/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js index ff3ea78b4f..ca051df7e7 100644 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ b/js/src/components/google-combo-account-card/account-creation-description/index.js @@ -19,7 +19,7 @@ import { * Renders the description for the account creation card. * * @param {Object} props Props. - * @param {string} props.isCreatingWhichAccount The type of account that is being created. Possible values are 'ads', 'mc', or 'both'. + * @param {string|null} props.isCreatingWhichAccount The type of account that is being created. Possible values are 'ads', 'mc', or 'both'. */ const AccountCreationDescription = ( { isCreatingWhichAccount } ) => { const { google, hasFinishedResolution } = useGoogleAccount(); From 1180ca8e0024f0893e1910da2afd4652c1b59150 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 08:10:32 +0530 Subject: [PATCH 53/91] Refactor to account creation description components. --- .../account-card-description.js | 16 +++ .../account-details.js | 46 +++++++ .../creating-accounts.js | 77 +++++++++++ .../account-card-description/index.js | 4 + .../account-card-description/indicator.js | 49 +++++++ .../account-creation-context.js | 18 +++ .../account-creation-description/index.js | 127 ------------------ .../connected-google-combo-account-card.js | 100 +++----------- .../connected-google-combo-account-card.scss | 16 ++- js/src/constants.js | 1 + js/src/hooks/useAutoCreateAdsMCAccounts.js | 16 +-- 11 files changed, 249 insertions(+), 221 deletions(-) create mode 100644 js/src/components/google-combo-account-card/account-card-description/account-card-description.js create mode 100644 js/src/components/google-combo-account-card/account-card-description/account-details.js create mode 100644 js/src/components/google-combo-account-card/account-card-description/creating-accounts.js create mode 100644 js/src/components/google-combo-account-card/account-card-description/index.js create mode 100644 js/src/components/google-combo-account-card/account-card-description/indicator.js create mode 100644 js/src/components/google-combo-account-card/account-creation-context.js delete mode 100644 js/src/components/google-combo-account-card/account-creation-description/index.js diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js new file mode 100644 index 0000000000..1f6e98f3a9 --- /dev/null +++ b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js @@ -0,0 +1,16 @@ +/** + * Internal dependencies + */ +import AccountDetails from './account-details'; +import CreatingAccounts from './creating-accounts'; +import { useAccountCreationContext } from '../account-creation-context'; + +const AccountCardDescription = () => { + const creatingAccounts = useAccountCreationContext(); + + return ( + <>{ creatingAccounts ? : } + ); +}; + +export default AccountCardDescription; diff --git a/js/src/components/google-combo-account-card/account-card-description/account-details.js b/js/src/components/google-combo-account-card/account-card-description/account-details.js new file mode 100644 index 0000000000..a163a41039 --- /dev/null +++ b/js/src/components/google-combo-account-card/account-card-description/account-details.js @@ -0,0 +1,46 @@ +/** + * External dependencies + */ +import { __, sprintf } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import useGoogleAccount from '.~/hooks/useGoogleAccount'; +import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; + +const AccountDetails = () => { + const { google } = useGoogleAccount(); + const { googleMCAccount } = useGoogleMCAccount(); + const { googleAdsAccount } = useGoogleAdsAccount(); + + return ( +

+ { google?.email } + { googleMCAccount.id > 0 && ( + + { sprintf( + // Translators: %s is the Merchant Center ID + __( + 'Merchant Center ID: %s', + 'google-listings-and-ads' + ), + googleMCAccount.id + ) } + + ) } + { googleAdsAccount.id > 0 && ( + + { sprintf( + // Translators: %s is the Google Ads ID + __( 'Google Ads ID: %s', 'google-listings-and-ads' ), + googleAdsAccount.id + ) } + + ) } +
+ ); +}; + +export default AccountDetails; diff --git a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js new file mode 100644 index 0000000000..8a90cc039c --- /dev/null +++ b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js @@ -0,0 +1,77 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { useAccountCreationContext } from '../account-creation-context'; +import { + CREATING_ADS_ACCOUNT, + CREATING_BOTH_ACCOUNTS, + CREATING_MC_ACCOUNT, +} from '../constants'; + +/** + * Account creation in progress description. + * @return {JSX.Element|null} JSX markup. + */ +const CreatingAccounts = () => { + const creatingAccounts = useAccountCreationContext(); + + if ( ! creatingAccounts ) { + return null; + } + + const helperText = { + text: null, + subText: null, + }; + + switch ( creatingAccounts ) { + case CREATING_BOTH_ACCOUNTS: + helperText.text = __( + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', + 'google-listings-and-ads' + ); + helperText.subText = __( + 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ); + break; + + case CREATING_ADS_ACCOUNT: + helperText.text = __( + 'You don’t have Google Ads account, so we’re creating one for you.', + 'google-listings-and-ads' + ); + helperText.subText = __( + 'Required to set up conversion measurement for your store.', + 'google-listings-and-ads' + ); + break; + + case CREATING_MC_ACCOUNT: + helperText.text = __( + 'You don’t have Merchant Center account, so we’re creating one for you.', + 'google-listings-and-ads' + ); + helperText.subText = __( + 'Required to sync products so they show on Google.', + 'google-listings-and-ads' + ); + break; + } + + const { text, subText } = helperText; + + return ( + <> +

{ text }

+ { subText } + + ); +}; + +export default CreatingAccounts; diff --git a/js/src/components/google-combo-account-card/account-card-description/index.js b/js/src/components/google-combo-account-card/account-card-description/index.js new file mode 100644 index 0000000000..ab3c6c78ba --- /dev/null +++ b/js/src/components/google-combo-account-card/account-card-description/index.js @@ -0,0 +1,4 @@ +export { default } from './account-card-description'; +export { default as CreatingAccounts } from './creating-accounts.js'; +export { default as AccountDetails } from './account-details'; +export { default as Indicator } from './indicator.js'; diff --git a/js/src/components/google-combo-account-card/account-card-description/indicator.js b/js/src/components/google-combo-account-card/account-card-description/indicator.js new file mode 100644 index 0000000000..82d448cde7 --- /dev/null +++ b/js/src/components/google-combo-account-card/account-card-description/indicator.js @@ -0,0 +1,49 @@ +/** + * External dependencies + */ +import { __ } from '@wordpress/i18n'; + +/** + * Internal dependencies + */ +import { useAccountCreationContext } from '../account-creation-context'; +import ConnectedIconLabel from '.~/components/connected-icon-label'; +import LoadingLabel from '.~/components/loading-label/loading-label'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; +import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; + +const Indicator = () => { + const creatingAccounts = useAccountCreationContext(); + + const { hasGoogleAdsConnection } = useGoogleAdsAccount(); + const { googleMCAccount, isPreconditionReady } = useGoogleMCAccount(); + const { hasAccess, step } = useGoogleAdsAccountStatus(); + + const isGoogleAdsConnected = + hasGoogleAdsConnection && + hasAccess && + [ '', 'billing', 'link_merchant' ].includes( step ); + + const isGoogleMCConnected = + isPreconditionReady && + ( googleMCAccount?.status === 'connected' || + ( googleMCAccount?.status === 'incomplete' && + googleMCAccount?.step === 'link_ads' ) ); + + if ( creatingAccounts ) { + return ( + + ); + } + + if ( isGoogleAdsConnected && isGoogleMCConnected ) { + return ; + } + + return null; +}; + +export default Indicator; diff --git a/js/src/components/google-combo-account-card/account-creation-context.js b/js/src/components/google-combo-account-card/account-creation-context.js new file mode 100644 index 0000000000..b4205f4a5b --- /dev/null +++ b/js/src/components/google-combo-account-card/account-creation-context.js @@ -0,0 +1,18 @@ +/** + * External dependencies + */ +import { createContext, useContext } from '@wordpress/element'; + +export const AccountCreationContext = createContext( false ); + +export function useAccountCreationContext() { + const adaptiveFormContext = useContext( AccountCreationContext ); + + if ( adaptiveFormContext === false ) { + throw new Error( + 'useAccountCreationContext was used outside of its context provider.' + ); + } + + return adaptiveFormContext; +} diff --git a/js/src/components/google-combo-account-card/account-creation-description/index.js b/js/src/components/google-combo-account-card/account-creation-description/index.js deleted file mode 100644 index ca051df7e7..0000000000 --- a/js/src/components/google-combo-account-card/account-creation-description/index.js +++ /dev/null @@ -1,127 +0,0 @@ -/** - * External dependencies - */ -import { __, sprintf } from '@wordpress/i18n'; - -/** - * Internal dependencies - */ -import useGoogleAccount from '.~/hooks/useGoogleAccount'; -import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import { - CREATING_ADS_ACCOUNT, - CREATING_BOTH_ACCOUNTS, - CREATING_MC_ACCOUNT, -} from '../constants'; - -/** - * Renders the description for the account creation card. - * - * @param {Object} props Props. - * @param {string|null} props.isCreatingWhichAccount The type of account that is being created. Possible values are 'ads', 'mc', or 'both'. - */ -const AccountCreationDescription = ( { isCreatingWhichAccount } ) => { - const { google, hasFinishedResolution } = useGoogleAccount(); - const { googleMCAccount } = useGoogleMCAccount(); - const { googleAdsAccount } = useGoogleAdsAccount(); - - if ( ! hasFinishedResolution ) { - return null; - } - - const getDescription = () => { - if ( isCreatingWhichAccount ) { - switch ( isCreatingWhichAccount ) { - case CREATING_BOTH_ACCOUNTS: - return ( -

- { __( - 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', - 'google-listings-and-ads' - ) } -

- ); - - case CREATING_ADS_ACCOUNT: - return ( - <> -

- { __( - 'You don’t have Google Ads account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } - - - ); - - case CREATING_MC_ACCOUNT: - return ( - <> -

- { __( - 'You don’t have Merchant Center account, so we’re creating one for you.', - 'google-listings-and-ads' - ) } -

- - { __( - 'Required to sync products so they show on Google.', - 'google-listings-and-ads' - ) } - - - ); - } - } - - const isCreatingAccounts = !! isCreatingWhichAccount; - const isGoogleAdsReady = - ! isCreatingAccounts && googleAdsAccount.id > 0; - const isGoogleMCReady = ! isCreatingAccounts && googleMCAccount.id > 0; - - return ( - <> -

{ google?.email }

- { isGoogleMCReady && ( -

- { sprintf( - // Translators: %s is the Merchant Center ID - __( - 'Merchant Center ID: %s', - 'google-listings-and-ads' - ), - googleMCAccount.id - ) } -

- ) } - { isGoogleAdsReady && ( -

- { sprintf( - // Translators: %s is the Google Ads ID - __( - 'Google Ads ID: %s', - 'google-listings-and-ads' - ), - googleAdsAccount.id - ) } -

- ) } - - ); - }; - - return ( -
- { getDescription() } -
- ); -}; - -export default AccountCreationDescription; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index cc7011c915..03a3cb37af 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,20 +1,12 @@ -/** - * External dependencies - */ -import { __ } from '@wordpress/i18n'; - /** * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; -import AccountCreationDescription from './account-creation-description'; +import AccountCardDescription, { Indicator } from './account-card-description'; +import { AccountCreationContext } from './account-creation-context'; import AppSpinner from '../app-spinner'; -import ConnectedIconLabel from '../connected-icon-label'; -import { CREATING_BOTH_ACCOUNTS } from './constants'; -import LoadingLabel from '../loading-label/loading-label'; import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import './connected-google-combo-account-card.scss'; @@ -23,89 +15,37 @@ import './connected-google-combo-account-card.scss'; * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. */ const ConnectedGoogleComboAccountCard = () => { - const { - hasGoogleAdsConnection, - hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, - } = useGoogleAdsAccount(); + const { hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount } = + useGoogleAdsAccount(); - const { - googleMCAccount, - isPreconditionReady, - hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, - } = useGoogleMCAccount(); + const { hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount } = + useGoogleMCAccount(); const { + accountsCreated, hasFinishedResolutionForExistingAdsMCAccounts, isCreatingWhichAccount, } = useAutoCreateAdsMCAccounts(); - const { hasAccess, step } = useGoogleAdsAccountStatus(); - - const isCreatingAccounts = !! isCreatingWhichAccount; - if ( - ! hasFinishedResolutionForExistingAdsMCAccounts || - ! hasFinishedResolutionForCurrentAdsAccount || - ! hasFinishedResolutionForCurrentMCAccount + ! accountsCreated && + ( ! hasFinishedResolutionForExistingAdsMCAccounts || + ! hasFinishedResolutionForCurrentAdsAccount || + ! hasFinishedResolutionForCurrentMCAccount ) ) { return } />; } - const isGoogleAdsConnected = - hasGoogleAdsConnection && - hasAccess && - [ '', 'billing', 'link_merchant' ].includes( step ); - - const isGoogleMCConnected = - isPreconditionReady && - ( googleMCAccount?.status === 'connected' || - ( googleMCAccount?.status === 'incomplete' && - googleMCAccount?.step === 'link_ads' ) ); - - const getHelper = () => { - if ( isCreatingWhichAccount === CREATING_BOTH_ACCOUNTS ) { - return ( -

- { __( - 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', - 'google-listings-and-ads' - ) } -

- ); - } - - return null; - }; - - const getIndicator = () => { - if ( isCreatingAccounts ) { - return ( - - ); - } - - if ( isGoogleAdsConnected && isGoogleMCConnected ) { - return ; - } - - return null; - }; - return ( - - } - helper={ getHelper() } - indicator={ getIndicator() } - /> + + } + indicator={ } + /> + ); }; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss index f7e57ce16e..ecbad738bb 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss @@ -1,13 +1,19 @@ .gla-google-combo-account-card--connected { - .gla-account-card__description p { - margin: 0; - } - - .gla-connected-google-combo-account-card__description { + .gla-account-card__helper { + font-style: normal; + font-size: $gla-font-base; + color: $black; em { + font-style: italic; color: $gray-700; } } + + .gla-account-card__account_details { + display: flex; + flex-direction: column; + gap: $grid-unit; + } } diff --git a/js/src/constants.js b/js/src/constants.js index 3a34ea00f7..ad0ae6d99d 100644 --- a/js/src/constants.js +++ b/js/src/constants.js @@ -63,6 +63,7 @@ export const ISSUE_TYPE_ACCOUNT = 'account'; export const REQUEST_REVIEW = 'request-review'; export const ISSUE_TABLE_PER_PAGE = 5; +// Account status related export const GOOGLE_ADS_ACCOUNT_STATUS = { CONNECTED: 'connected', DISCONNECTED: 'disconnected', diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 40605f2299..7ca678438c 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -21,9 +21,9 @@ import { /** * Hook to automatically create Ads and Merchant Center accounts if they do not exist. * - * @return {Object} Object containing the state of the account creation process. + * @return {Object} The state of the account creation process. * @property {boolean} hasFinishedResolutionForExistingAdsMCAccounts Indicates whether the checks for existing Merchant Center (MC) and Google Ads accounts have been completed. - * @property {string|null} isCreatingWhichAccount The type of account that is being created. Possible values are 'ads', 'mc', or 'both'. + * @property {'ads'|'mc'|'both'|null} isCreatingWhichAccount The type of account that is being created. */ const useAutoCreateAdsMCAccounts = () => { const [ accountsState, setAccountsState ] = useState( { @@ -41,7 +41,7 @@ const useAutoCreateAdsMCAccounts = () => { const { existingAccounts: existingAdsAccounts, - hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount, + hasFinishedResolution: hasFinishedResolutionForExistingAdsAccounts, } = useExistingGoogleAdsAccounts(); const { @@ -63,7 +63,7 @@ const useAutoCreateAdsMCAccounts = () => { hasGoogleAdsConnection || existingAdsAccounts?.length > 0; const googleAdsAccountChecksResolved = - hasFinishedResolutionForExistingAdsAccount && + hasFinishedResolutionForExistingAdsAccounts && hasFinishedResolutionForGoogleAdsAccount; const googleMCAccountChecksResolved = @@ -93,9 +93,7 @@ const useAutoCreateAdsMCAccounts = () => { return; } - const mcAccountCreated = [ 200, 403, 406, 503 ].includes( - response?.status - ); + const mcAccountCreated = response?.status; const resetState = ( isCreatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) || @@ -107,8 +105,7 @@ const useAutoCreateAdsMCAccounts = () => { if ( resetState ) { shouldCreateAccounts.current = null; - setAccountsState( ( prevState ) => ( { - ...prevState, + setAccountsState( () => ( { isCreatingWhichAccount: null, accountsCreated: true, } ) ); @@ -160,6 +157,7 @@ const useAutoCreateAdsMCAccounts = () => { return { hasFinishedResolutionForExistingAdsMCAccounts: accountCreationChecksResolved, + accountsCreated, isCreatingWhichAccount, }; }; From 839363019c57f56e713eb70868fbdc54b4633bcc Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 11:56:40 +0530 Subject: [PATCH 54/91] Add account creation data hook. --- .../account-card-description.js | 17 ++++- .../account-details.js | 28 ++++---- .../creating-accounts.js | 7 +- .../account-card-description/indicator.js | 5 +- .../account-creation-context.js | 6 +- .../connected-google-combo-account-card.js | 7 +- js/src/hooks/useAccountCreationData.js | 71 +++++++++++++++++++ js/src/hooks/useAutoCreateAdsMCAccounts.js | 2 +- 8 files changed, 113 insertions(+), 30 deletions(-) create mode 100644 js/src/hooks/useAccountCreationData.js diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js index 1f6e98f3a9..64d70ff209 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js @@ -3,13 +3,24 @@ */ import AccountDetails from './account-details'; import CreatingAccounts from './creating-accounts'; -import { useAccountCreationContext } from '../account-creation-context'; +import useAccountCreationData from '.~/hooks/useAccountCreationData'; const AccountCardDescription = () => { - const creatingAccounts = useAccountCreationContext(); + const { creatingAccounts, email, googleAdsAccount, googleMCAccount } = + useAccountCreationData(); return ( - <>{ creatingAccounts ? : } + <> + { creatingAccounts ? ( + + ) : ( + + ) } + ); }; diff --git a/js/src/components/google-combo-account-card/account-card-description/account-details.js b/js/src/components/google-combo-account-card/account-card-description/account-details.js index a163a41039..e8f48fe44d 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-details.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-details.js @@ -4,21 +4,19 @@ import { __, sprintf } from '@wordpress/i18n'; /** - * Internal dependencies + * Account details. + * + * @param {Object} props Component props. + * @param {string} props.email Account email. + * @param {number} props.googleAdsID Google Ads ID. + * @param {number} props.googleMerchantCenterID Google Merchant Center ID. + * @return {JSX.Element} JSX markup. */ -import useGoogleAccount from '.~/hooks/useGoogleAccount'; -import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; - -const AccountDetails = () => { - const { google } = useGoogleAccount(); - const { googleMCAccount } = useGoogleMCAccount(); - const { googleAdsAccount } = useGoogleAdsAccount(); - +const AccountDetails = ( { email, googleAdsID, googleMerchantCenterID } ) => { return (
- { google?.email } - { googleMCAccount.id > 0 && ( + { email } + { Number( googleMerchantCenterID ) > 0 && ( { sprintf( // Translators: %s is the Merchant Center ID @@ -26,16 +24,16 @@ const AccountDetails = () => { 'Merchant Center ID: %s', 'google-listings-and-ads' ), - googleMCAccount.id + googleMerchantCenterID ) } ) } - { googleAdsAccount.id > 0 && ( + { Number( googleAdsID ) > 0 && ( { sprintf( // Translators: %s is the Google Ads ID __( 'Google Ads ID: %s', 'google-listings-and-ads' ), - googleAdsAccount.id + googleAdsID ) } ) } diff --git a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js index 8a90cc039c..b08c87f1d1 100644 --- a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js +++ b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js @@ -6,7 +6,6 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { useAccountCreationContext } from '../account-creation-context'; import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, @@ -15,11 +14,11 @@ import { /** * Account creation in progress description. + * @param {Object} props Component props. + * @param {string|null} props.creatingAccounts Whether the accounts are being created. Possible values are: 'both', 'ads', 'mc'. * @return {JSX.Element|null} JSX markup. */ -const CreatingAccounts = () => { - const creatingAccounts = useAccountCreationContext(); - +const CreatingAccounts = ( { creatingAccounts } ) => { if ( ! creatingAccounts ) { return null; } diff --git a/js/src/components/google-combo-account-card/account-card-description/indicator.js b/js/src/components/google-combo-account-card/account-card-description/indicator.js index 82d448cde7..7bb2b374b6 100644 --- a/js/src/components/google-combo-account-card/account-card-description/indicator.js +++ b/js/src/components/google-combo-account-card/account-card-description/indicator.js @@ -6,16 +6,15 @@ import { __ } from '@wordpress/i18n'; /** * Internal dependencies */ -import { useAccountCreationContext } from '../account-creation-context'; import ConnectedIconLabel from '.~/components/connected-icon-label'; import LoadingLabel from '.~/components/loading-label/loading-label'; +import useAccountCreationData from '.~/hooks/useAccountCreationData'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; const Indicator = () => { - const creatingAccounts = useAccountCreationContext(); - + const { creatingAccounts } = useAccountCreationData(); const { hasGoogleAdsConnection } = useGoogleAdsAccount(); const { googleMCAccount, isPreconditionReady } = useGoogleMCAccount(); const { hasAccess, step } = useGoogleAdsAccountStatus(); diff --git a/js/src/components/google-combo-account-card/account-creation-context.js b/js/src/components/google-combo-account-card/account-creation-context.js index b4205f4a5b..45656632ff 100644 --- a/js/src/components/google-combo-account-card/account-creation-context.js +++ b/js/src/components/google-combo-account-card/account-creation-context.js @@ -3,14 +3,14 @@ */ import { createContext, useContext } from '@wordpress/element'; -export const AccountCreationContext = createContext( false ); +export const AccountCreationContext = createContext( {} ); export function useAccountCreationContext() { const adaptiveFormContext = useContext( AccountCreationContext ); - if ( adaptiveFormContext === false ) { + if ( Object.keys( adaptiveFormContext ).length === 0 ) { throw new Error( - 'useAccountCreationContext was used outside of its context provider.' + 'useAccountCreationContext was used outside of its context provider ConnectedGoogleComboAccountCard.' ); } diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 03a3cb37af..6b4c1835bf 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -36,8 +36,13 @@ const ConnectedGoogleComboAccountCard = () => { return } />; } + const accountCreationData = { + accountsCreated, + creatingAccounts: isCreatingWhichAccount, + }; + return ( - + { + const { + google, + hasFinishedResolution: hasFinishedResolutionForGoogleAccount, + } = useGoogleAccount(); + const { + googleAdsAccount, + hasFinishedResolution: hasFinishedResolutionForGoogleAdsAccount, + } = useGoogleAdsAccount(); + const { + googleMCAccount, + hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount, + } = useGoogleMCAccount(); + + const accountCreationContext = useAccountCreationContext(); + const wasCreatingAccounts = useRef( null ); + const { creatingAccounts, accountsCreated } = accountCreationContext; + + const accountDetailsResolved = + hasFinishedResolutionForGoogleAccount && + hasFinishedResolutionForGoogleAdsAccount && + hasFinishedResolutionForGoogleMCAccount; + + useEffect( () => { + if ( creatingAccounts ) { + wasCreatingAccounts.current = creatingAccounts; + } + + if ( + wasCreatingAccounts.current && + accountsCreated && + accountDetailsResolved + ) { + const accountsReady = + google.email && !! googleAdsAccount.id && !! googleMCAccount.id; + + if ( accountsReady ) { + wasCreatingAccounts.current = null; + } + } + }, [ + creatingAccounts, + accountsCreated, + accountDetailsResolved, + google.email, + googleAdsAccount.id, + googleMCAccount.id, + ] ); + + return { + creatingAccounts: wasCreatingAccounts.current, + email: google.email, + googleAdsAccount, + googleMCAccount, + }; +}; + +export default useAccountCreationData; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 7ca678438c..2a7a94bbef 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -93,7 +93,7 @@ const useAutoCreateAdsMCAccounts = () => { return; } - const mcAccountCreated = response?.status; + const mcAccountCreated = !! response?.status; const resetState = ( isCreatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) || From 971497a39d71316a00b3bce02dabb70d8e581dc5 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 12:13:44 +0530 Subject: [PATCH 55/91] Improve code readability. --- .../connected-google-combo-account-card.js | 2 +- js/src/hooks/useAutoCreateAdsMCAccounts.js | 17 ++++++++++------- js/src/hooks/useGoogleMCAccount.js | 10 ++++------ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 6b4c1835bf..e274830a64 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -5,7 +5,7 @@ import AccountCard, { APPEARANCE } from '../account-card'; import AccountCardDescription, { Indicator } from './account-card-description'; import { AccountCreationContext } from './account-creation-context'; import AppSpinner from '../app-spinner'; -import useAutoCreateAdsMCAccounts from '../../hooks/useAutoCreateAdsMCAccounts'; +import useAutoCreateAdsMCAccounts from '.~/hooks/useAutoCreateAdsMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import './connected-google-combo-account-card.scss'; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 2a7a94bbef..77fdf6b2f7 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -57,10 +57,13 @@ const useAutoCreateAdsMCAccounts = () => { const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - const hasExistingMCAccount = - hasGoogleMCConnection || existingMCAccounts?.length > 0; - const hasExistingAdsAccount = - hasGoogleAdsConnection || existingAdsAccounts?.length > 0; + const hasExistingMCAccount = existingMCAccounts?.length > 0; + const hasExistingAdsAccount = existingAdsAccounts?.length > 0; + + const adsAccountCreationRequired = + ! hasGoogleAdsConnection && ! hasExistingAdsAccount; + const MCAccountCreationRequired = + ! hasGoogleMCConnection && ! hasExistingMCAccount; const googleAdsAccountChecksResolved = hasFinishedResolutionForExistingAdsAccounts && @@ -74,13 +77,13 @@ const useAutoCreateAdsMCAccounts = () => { googleAdsAccountChecksResolved && googleMCAccountChecksResolved; if ( accountCreationChecksResolved ) { - if ( ! hasExistingAdsAccount || ! hasExistingMCAccount ) { + if ( ! adsAccountCreationRequired || ! MCAccountCreationRequired ) { const createBothAccounts = - ! hasExistingAdsAccount && ! hasExistingMCAccount; + adsAccountCreationRequired && MCAccountCreationRequired; if ( createBothAccounts ) { shouldCreateAccounts.current = CREATING_BOTH_ACCOUNTS; - } else if ( ! hasExistingAdsAccount ) { + } else if ( adsAccountCreationRequired ) { shouldCreateAccounts.current = CREATING_ADS_ACCOUNT; } else { shouldCreateAccounts.current = CREATING_MC_ACCOUNT; diff --git a/js/src/hooks/useGoogleMCAccount.js b/js/src/hooks/useGoogleMCAccount.js index a5a2a0dbaa..255943f1a3 100644 --- a/js/src/hooks/useGoogleMCAccount.js +++ b/js/src/hooks/useGoogleMCAccount.js @@ -49,9 +49,6 @@ const useGoogleMCAccount = () => { }; } - const { getGoogleMCAccount, hasFinishedResolution } = - select( STORE_KEY ); - const selector = select( STORE_KEY ); const acc = selector[ googleMCAccountSelector ](); const isResolvingGoogleMCAccount = selector.isResolving( @@ -64,10 +61,11 @@ const useGoogleMCAccount = () => { ].includes( acc?.status ); return { - googleMCAccount: getGoogleMCAccount(), + googleMCAccount: acc, isResolving: isResolvingGoogleMCAccount, - hasFinishedResolution: - hasFinishedResolution( 'getGoogleMCAccount' ), + hasFinishedResolution: selector.hasFinishedResolution( + googleMCAccountSelector + ), isPreconditionReady: true, hasGoogleMCConnection, }; From 5d1048c1a40ab83ed36fd05d3804306e8c4b57db Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 12:46:24 +0530 Subject: [PATCH 56/91] Fix: hook tests. --- js/src/hooks/useAutoCreateAdsMCAccounts.js | 2 +- js/src/hooks/useAutoCreateAdsMCAccounts.test.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 77fdf6b2f7..a2ea525935 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -77,7 +77,7 @@ const useAutoCreateAdsMCAccounts = () => { googleAdsAccountChecksResolved && googleMCAccountChecksResolved; if ( accountCreationChecksResolved ) { - if ( ! adsAccountCreationRequired || ! MCAccountCreationRequired ) { + if ( adsAccountCreationRequired || MCAccountCreationRequired ) { const createBothAccounts = adsAccountCreationRequired && MCAccountCreationRequired; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 6586a6a941..c93b6ae1c1 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -36,7 +36,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { useGoogleMCAccount.mockReturnValue( { hasFinishedResolution: true, - googleMCAccount: undefined, + hasGoogleMCConnection: false, } ); } ); From 1b4cae2d4fd8cdd5ba8761fe173f89b7bb58ac69 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 14:26:17 +0530 Subject: [PATCH 57/91] Replace isCreatingWhichAccount with creatingWhichAccount. --- .../connected-google-combo-account-card.js | 4 +-- js/src/hooks/useAutoCreateAdsMCAccounts.js | 26 +++++++++---------- .../hooks/useAutoCreateAdsMCAccounts.test.js | 8 +++--- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index e274830a64..e6f7b66846 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -24,7 +24,7 @@ const ConnectedGoogleComboAccountCard = () => { const { accountsCreated, hasFinishedResolutionForExistingAdsMCAccounts, - isCreatingWhichAccount, + creatingWhichAccount, } = useAutoCreateAdsMCAccounts(); if ( @@ -38,7 +38,7 @@ const ConnectedGoogleComboAccountCard = () => { const accountCreationData = { accountsCreated, - creatingAccounts: isCreatingWhichAccount, + creatingAccounts: creatingWhichAccount, }; return ( diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index a2ea525935..7a18d8bca9 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -23,15 +23,15 @@ import { * * @return {Object} The state of the account creation process. * @property {boolean} hasFinishedResolutionForExistingAdsMCAccounts Indicates whether the checks for existing Merchant Center (MC) and Google Ads accounts have been completed. - * @property {'ads'|'mc'|'both'|null} isCreatingWhichAccount The type of account that is being created. + * @property {'ads'|'mc'|'both'|null} creatingWhichAccount The type of account that is being created. */ const useAutoCreateAdsMCAccounts = () => { const [ accountsState, setAccountsState ] = useState( { accountsCreated: false, - isCreatingWhichAccount: null, + creatingWhichAccount: null, } ); - const { accountsCreated, isCreatingWhichAccount } = accountsState; + const { accountsCreated, creatingWhichAccount } = accountsState; const shouldCreateAccounts = useRef(); const { @@ -92,33 +92,33 @@ const useAutoCreateAdsMCAccounts = () => { } const handlePostAccountCreation = useCallback( () => { - if ( ! isCreatingWhichAccount ) { + if ( ! creatingWhichAccount ) { return; } const mcAccountCreated = !! response?.status; const resetState = - ( isCreatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) || - ( isCreatingWhichAccount === CREATING_MC_ACCOUNT && + ( creatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) || + ( creatingWhichAccount === CREATING_MC_ACCOUNT && mcAccountCreated ) || - ( isCreatingWhichAccount === CREATING_BOTH_ACCOUNTS && + ( creatingWhichAccount === CREATING_BOTH_ACCOUNTS && mcAccountCreated && ! loading ); if ( resetState ) { shouldCreateAccounts.current = null; setAccountsState( () => ( { - isCreatingWhichAccount: null, + creatingWhichAccount: null, accountsCreated: true, } ) ); } - }, [ response, loading, isCreatingWhichAccount ] ); + }, [ response, loading, creatingWhichAccount ] ); const handleAccountCreation = useCallback( async () => { if ( ! accountCreationChecksResolved || - isCreatingWhichAccount || + creatingWhichAccount || accountsCreated ) { return; @@ -127,7 +127,7 @@ const useAutoCreateAdsMCAccounts = () => { if ( shouldCreateAccounts.current ) { setAccountsState( ( prevState ) => ( { ...prevState, - isCreatingWhichAccount: shouldCreateAccounts.current, + creatingWhichAccount: shouldCreateAccounts.current, } ) ); if ( shouldCreateAccounts.current === CREATING_BOTH_ACCOUNTS ) { @@ -143,7 +143,7 @@ const useAutoCreateAdsMCAccounts = () => { } }, [ accountCreationChecksResolved, - isCreatingWhichAccount, + creatingWhichAccount, accountsCreated, handleCreateAccount, upsertAdsAccount, @@ -161,7 +161,7 @@ const useAutoCreateAdsMCAccounts = () => { hasFinishedResolutionForExistingAdsMCAccounts: accountCreationChecksResolved, accountsCreated, - isCreatingWhichAccount, + creatingWhichAccount, }; }; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index c93b6ae1c1..36e00a5a0b 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -64,7 +64,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should create both accounts. - expect( result.current.isCreatingWhichAccount ).toBe( 'both' ); + expect( result.current.creatingWhichAccount ).toBe( 'both' ); } ); it( 'should create only the Merchant Center account', () => { @@ -81,7 +81,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should create only the Merchant Center account. - expect( result.current.isCreatingWhichAccount ).toBe( 'mc' ); + expect( result.current.creatingWhichAccount ).toBe( 'mc' ); } ); it( 'should create only the Google Ads account', () => { @@ -98,7 +98,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should create only the Google Ads account. - expect( result.current.isCreatingWhichAccount ).toBe( 'ads' ); + expect( result.current.creatingWhichAccount ).toBe( 'ads' ); } ); } ); @@ -138,7 +138,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should not create any accounts. - expect( result.current.isCreatingWhichAccount ).toBe( null ); + expect( result.current.creatingWhichAccount ).toBe( null ); // make sure functions are not called. expect( handleCreateAccount ).not.toHaveBeenCalled(); From e74287c3448226d31571afd51604c2897b7ecacd Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 14:33:26 +0530 Subject: [PATCH 58/91] Use separate state variables. --- js/src/hooks/useAutoCreateAdsMCAccounts.js | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 7a18d8bca9..cc4f8d36ee 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -26,12 +26,9 @@ import { * @property {'ads'|'mc'|'both'|null} creatingWhichAccount The type of account that is being created. */ const useAutoCreateAdsMCAccounts = () => { - const [ accountsState, setAccountsState ] = useState( { - accountsCreated: false, - creatingWhichAccount: null, - } ); - - const { accountsCreated, creatingWhichAccount } = accountsState; + // Create separate states. + const [ accountsCreated, setAccountsCreated ] = useState( false ); + const [ creatingWhichAccount, setCreatingWhichAccount ] = useState( null ); const shouldCreateAccounts = useRef(); const { @@ -107,11 +104,8 @@ const useAutoCreateAdsMCAccounts = () => { ! loading ); if ( resetState ) { - shouldCreateAccounts.current = null; - setAccountsState( () => ( { - creatingWhichAccount: null, - accountsCreated: true, - } ) ); + setAccountsCreated( true ); + setCreatingWhichAccount( null ); } }, [ response, loading, creatingWhichAccount ] ); @@ -125,10 +119,7 @@ const useAutoCreateAdsMCAccounts = () => { } if ( shouldCreateAccounts.current ) { - setAccountsState( ( prevState ) => ( { - ...prevState, - creatingWhichAccount: shouldCreateAccounts.current, - } ) ); + setCreatingWhichAccount( shouldCreateAccounts.current ); if ( shouldCreateAccounts.current === CREATING_BOTH_ACCOUNTS ) { await handleCreateAccount(); From 0cc906ea1d2ccd381d248a55cff097b5f340b4cd Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 15:12:50 +0530 Subject: [PATCH 59/91] Add doc blocks. --- .../account-card-description.js | 4 ++++ .../account-details.js | 6 ++--- .../creating-accounts.js | 22 ++++++++----------- .../account-card-description/indicator.js | 5 +++++ .../account-creation-context.js | 11 ++++++++++ 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js index 64d70ff209..505e6d3ae5 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js @@ -5,6 +5,10 @@ import AccountDetails from './account-details'; import CreatingAccounts from './creating-accounts'; import useAccountCreationData from '.~/hooks/useAccountCreationData'; +/** + * AccountCardDescription component + * @return {JSX.Element} AccountCardDescription component. + */ const AccountCardDescription = () => { const { creatingAccounts, email, googleAdsAccount, googleMCAccount } = useAccountCreationData(); diff --git a/js/src/components/google-combo-account-card/account-card-description/account-details.js b/js/src/components/google-combo-account-card/account-card-description/account-details.js index e8f48fe44d..14f4819312 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-details.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-details.js @@ -7,9 +7,9 @@ import { __, sprintf } from '@wordpress/i18n'; * Account details. * * @param {Object} props Component props. - * @param {string} props.email Account email. - * @param {number} props.googleAdsID Google Ads ID. - * @param {number} props.googleMerchantCenterID Google Merchant Center ID. + * @param {string} props.email Google account email address. + * @param {number} props.googleAdsID Google Ads account ID. + * @param {number} props.googleMerchantCenterID Google Merchant Center account ID. * @return {JSX.Element} JSX markup. */ const AccountDetails = ( { email, googleAdsID, googleMerchantCenterID } ) => { diff --git a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js index b08c87f1d1..057c07fb70 100644 --- a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js +++ b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js @@ -19,52 +19,48 @@ import { * @return {JSX.Element|null} JSX markup. */ const CreatingAccounts = ( { creatingAccounts } ) => { + let text = null; + let subText = null; + if ( ! creatingAccounts ) { return null; } - const helperText = { - text: null, - subText: null, - }; - switch ( creatingAccounts ) { case CREATING_BOTH_ACCOUNTS: - helperText.text = __( + text = __( 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', 'google-listings-and-ads' ); - helperText.subText = __( + subText = __( 'Merchant Center is required to sync products so they show on Google. Google Ads is required to set up conversion measurement for your store.', 'google-listings-and-ads' ); break; case CREATING_ADS_ACCOUNT: - helperText.text = __( + text = __( 'You don’t have Google Ads account, so we’re creating one for you.', 'google-listings-and-ads' ); - helperText.subText = __( + subText = __( 'Required to set up conversion measurement for your store.', 'google-listings-and-ads' ); break; case CREATING_MC_ACCOUNT: - helperText.text = __( + text = __( 'You don’t have Merchant Center account, so we’re creating one for you.', 'google-listings-and-ads' ); - helperText.subText = __( + subText = __( 'Required to sync products so they show on Google.', 'google-listings-and-ads' ); break; } - const { text, subText } = helperText; - return ( <>

{ text }

diff --git a/js/src/components/google-combo-account-card/account-card-description/indicator.js b/js/src/components/google-combo-account-card/account-card-description/indicator.js index 7bb2b374b6..1db3da5493 100644 --- a/js/src/components/google-combo-account-card/account-card-description/indicator.js +++ b/js/src/components/google-combo-account-card/account-card-description/indicator.js @@ -13,6 +13,11 @@ import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; +/** + * Account creation indicator. + * Displays a loading indicator when accounts are being created or a connected icon when accounts are connected. + * @return {JSX.Element|null} Indicator component. + */ const Indicator = () => { const { creatingAccounts } = useAccountCreationData(); const { hasGoogleAdsConnection } = useGoogleAdsAccount(); diff --git a/js/src/components/google-combo-account-card/account-creation-context.js b/js/src/components/google-combo-account-card/account-creation-context.js index 45656632ff..337178a56d 100644 --- a/js/src/components/google-combo-account-card/account-creation-context.js +++ b/js/src/components/google-combo-account-card/account-creation-context.js @@ -3,8 +3,19 @@ */ import { createContext, useContext } from '@wordpress/element'; +/** + * @typedef {Object} AccountCreationContext + * @property {boolean} accountsCreated `true` if the accounts have been created. + * @property {string|null} creatingAccounts The accounts that are being created. It can be 'ads', 'mc', or 'both'. + */ + export const AccountCreationContext = createContext( {} ); +/** + * AccountCreation's context hook. + * @return {Object} AccountCreation's context. + * @throws Will throw an error if its context provider is not existing in its parents. + */ export function useAccountCreationContext() { const adaptiveFormContext = useContext( AccountCreationContext ); From 19a3a3480f2eff20eea088b29e935144e2d5fda1 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 16:00:42 +0530 Subject: [PATCH 60/91] Add hooks for account creation determination. --- js/src/hooks/useShouldCreateAdsAccount.js | 32 +++++++++++++++++++++++ js/src/hooks/useShouldCreateMCAccount.js | 32 +++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 js/src/hooks/useShouldCreateAdsAccount.js create mode 100644 js/src/hooks/useShouldCreateMCAccount.js diff --git a/js/src/hooks/useShouldCreateAdsAccount.js b/js/src/hooks/useShouldCreateAdsAccount.js new file mode 100644 index 0000000000..789981274b --- /dev/null +++ b/js/src/hooks/useShouldCreateAdsAccount.js @@ -0,0 +1,32 @@ +/** + * Internal dependencies + */ +import useGoogleAdsAccount from './useGoogleMCAccount'; +import useExistingGoogleAdsAccounts from './useExistingGoogleMCAccounts'; + +/** + * Hook to determine if a Google Ads account should be created. + * This is based on whether the user has any existing Google Ads accounts and if they have a connection to Google Ads. + * If the user has no existing accounts and no connection, a new ads account should be created. + * @return {boolean} Whether a new Google Ads account should be created. + */ +const useShouldCreateAdsAccount = () => { + const { + hasFinishedResolution: hasResolvedAccount, + hasGoogleAdsConnection: hasConnection, + } = useGoogleAdsAccount(); + + const { + hasFinishedResolution: hasResolvedExistingAccounts, + data: accounts, + } = useExistingGoogleAdsAccounts(); + + // Return null if the account hasn't been resolved or the existing accounts haven't been resolved + if ( ! hasResolvedAccount || ! hasResolvedExistingAccounts ) { + return null; + } + + return ! hasConnection && accounts.length === 0; +}; + +export default useShouldCreateAdsAccount; diff --git a/js/src/hooks/useShouldCreateMCAccount.js b/js/src/hooks/useShouldCreateMCAccount.js new file mode 100644 index 0000000000..8a76279268 --- /dev/null +++ b/js/src/hooks/useShouldCreateMCAccount.js @@ -0,0 +1,32 @@ +/** + * Internal dependencies + */ +import useGoogleMCAccount from './useGoogleMCAccount'; +import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; + +/** + * Hook to determine if a Merchant Center account should be created. + * This is based on whether the user has any existing Merchant Center accounts and if they have a connection to Merchant Center. + * If the user has no existing accounts and no connection, a new account should be created. + * @return {boolean} Whether a new Merchant Center account should be created. + */ +const useShouldCreateMCAccount = () => { + const { + hasFinishedResolution: hasResolvedAccount, + hasGoogleMCConnection: hasConnection, + } = useGoogleMCAccount(); + + const { + hasFinishedResolution: hasResolvedExistingAccounts, + data: accounts, + } = useExistingGoogleMCAccounts(); + + // Return null if the account hasn't been resolved or the existing accounts haven't been resolved + if ( ! hasResolvedAccount || ! hasResolvedExistingAccounts ) { + return null; + } + + return ! hasConnection && accounts.length === 0; +}; + +export default useShouldCreateMCAccount; From d3e380e0222d1619f6d32f4338ee9fe459c1205e Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 16:52:39 +0530 Subject: [PATCH 61/91] Refactor useAutoCreateAdsMCAccounts hook. --- .../connected-google-combo-account-card.js | 11 +- js/src/hooks/useAutoCreateAdsMCAccounts.js | 171 ++++++------------ 2 files changed, 64 insertions(+), 118 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index e6f7b66846..7ada6a4b94 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -21,15 +21,12 @@ const ConnectedGoogleComboAccountCard = () => { const { hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount } = useGoogleMCAccount(); - const { - accountsCreated, - hasFinishedResolutionForExistingAdsMCAccounts, - creatingWhichAccount, - } = useAutoCreateAdsMCAccounts(); + const { accountsCreated, hasDetermined, creatingWhich } = + useAutoCreateAdsMCAccounts(); if ( ! accountsCreated && - ( ! hasFinishedResolutionForExistingAdsMCAccounts || + ( ! hasDetermined || ! hasFinishedResolutionForCurrentAdsAccount || ! hasFinishedResolutionForCurrentMCAccount ) ) { @@ -38,7 +35,7 @@ const ConnectedGoogleComboAccountCard = () => { const accountCreationData = { accountsCreated, - creatingAccounts: creatingWhichAccount, + creatingAccounts: creatingWhich, }; return ( diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index cc4f8d36ee..4f2965ece4 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -1,158 +1,107 @@ /** * External dependencies */ -import { useEffect, useState, useRef, useCallback } from '@wordpress/element'; +import { useEffect, useState, useRef } from '@wordpress/element'; /** * Internal dependencies */ import useCreateMCAccount from './useCreateMCAccount'; import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; -import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts'; -import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts'; -import useGoogleAdsAccount from './useGoogleAdsAccount'; -import useGoogleMCAccount from './useGoogleMCAccount'; +import useShouldCreateAdsAccount from './useShouldCreateAdsAccount'; +import useShouldCreateMCAccount from './useShouldCreateMCAccount'; import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, } from '.~/components/google-combo-account-card/constants'; -/** - * Hook to automatically create Ads and Merchant Center accounts if they do not exist. - * - * @return {Object} The state of the account creation process. - * @property {boolean} hasFinishedResolutionForExistingAdsMCAccounts Indicates whether the checks for existing Merchant Center (MC) and Google Ads accounts have been completed. - * @property {'ads'|'mc'|'both'|null} creatingWhichAccount The type of account that is being created. - */ const useAutoCreateAdsMCAccounts = () => { + const lockedRef = useRef( false ); // Create separate states. const [ accountsCreated, setAccountsCreated ] = useState( false ); - const [ creatingWhichAccount, setCreatingWhichAccount ] = useState( null ); - const shouldCreateAccounts = useRef(); - - const { - data: existingMCAccounts, - hasFinishedResolution: hasFinishedResolutionForExistingMCAccounts, - } = useExistingGoogleMCAccounts(); - - const { - existingAccounts: existingAdsAccounts, - hasFinishedResolution: hasFinishedResolutionForExistingAdsAccounts, - } = useExistingGoogleAdsAccounts(); + const [ creatingWhich, setCreatingWhich ] = useState( null ); + const [ hasDetermined, setDetermined ] = useState( false ); - const { - hasFinishedResolution: hasFinishedResolutionForGoogleAdsAccount, - hasGoogleAdsConnection, - } = useGoogleAdsAccount(); - - const { - hasGoogleMCConnection, - hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount, - } = useGoogleMCAccount(); + const shouldCreateAds = useShouldCreateAdsAccount(); + const shouldCreateMC = useShouldCreateMCAccount(); const [ handleCreateAccount, { response } ] = useCreateMCAccount(); const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); - const hasExistingMCAccount = existingMCAccounts?.length > 0; - const hasExistingAdsAccount = existingAdsAccounts?.length > 0; - - const adsAccountCreationRequired = - ! hasGoogleAdsConnection && ! hasExistingAdsAccount; - const MCAccountCreationRequired = - ! hasGoogleMCConnection && ! hasExistingMCAccount; - - const googleAdsAccountChecksResolved = - hasFinishedResolutionForExistingAdsAccounts && - hasFinishedResolutionForGoogleAdsAccount; - - const googleMCAccountChecksResolved = - hasFinishedResolutionForGoogleMCAccount && - hasFinishedResolutionForExistingMCAccounts; + useEffect( () => { + if ( + shouldCreateMC === null || + shouldCreateAds === null || + accountsCreated + ) { + return; + } - const accountCreationChecksResolved = - googleAdsAccountChecksResolved && googleMCAccountChecksResolved; + if ( lockedRef.current && !! creatingWhich ) { + const mcAccountCreated = !! response?.status; - if ( accountCreationChecksResolved ) { - if ( adsAccountCreationRequired || MCAccountCreationRequired ) { - const createBothAccounts = - adsAccountCreationRequired && MCAccountCreationRequired; + const resetState = + ( creatingWhich === CREATING_ADS_ACCOUNT && ! loading ) || + ( creatingWhich === CREATING_MC_ACCOUNT && mcAccountCreated ) || + ( creatingWhich === CREATING_BOTH_ACCOUNTS && + mcAccountCreated && + ! loading ); - if ( createBothAccounts ) { - shouldCreateAccounts.current = CREATING_BOTH_ACCOUNTS; - } else if ( adsAccountCreationRequired ) { - shouldCreateAccounts.current = CREATING_ADS_ACCOUNT; - } else { - shouldCreateAccounts.current = CREATING_MC_ACCOUNT; + if ( resetState ) { + lockedRef.current = false; + setAccountsCreated( true ); + setCreatingWhich( null ); } - } - } - const handlePostAccountCreation = useCallback( () => { - if ( ! creatingWhichAccount ) { return; } - const mcAccountCreated = !! response?.status; + let which = null; - const resetState = - ( creatingWhichAccount === CREATING_ADS_ACCOUNT && ! loading ) || - ( creatingWhichAccount === CREATING_MC_ACCOUNT && - mcAccountCreated ) || - ( creatingWhichAccount === CREATING_BOTH_ACCOUNTS && - mcAccountCreated && - ! loading ); + lockedRef.current = true; - if ( resetState ) { - setAccountsCreated( true ); - setCreatingWhichAccount( null ); + if ( shouldCreateMC && shouldCreateAds ) { + which = CREATING_BOTH_ACCOUNTS; + } else if ( shouldCreateMC ) { + which = CREATING_MC_ACCOUNT; + } else if ( shouldCreateAds ) { + which = CREATING_ADS_ACCOUNT; } - }, [ response, loading, creatingWhichAccount ] ); - const handleAccountCreation = useCallback( async () => { - if ( - ! accountCreationChecksResolved || - creatingWhichAccount || - accountsCreated - ) { - return; - } - - if ( shouldCreateAccounts.current ) { - setCreatingWhichAccount( shouldCreateAccounts.current ); - - if ( shouldCreateAccounts.current === CREATING_BOTH_ACCOUNTS ) { - await handleCreateAccount(); - await upsertAdsAccount(); - } else if ( - shouldCreateAccounts.current === CREATING_ADS_ACCOUNT - ) { - await upsertAdsAccount(); - } else { - await handleCreateAccount(); - } + setCreatingWhich( which ); + setDetermined( true ); + + if ( which ) { + const handleCreateAccountCallback = async () => { + if ( which === CREATING_BOTH_ACCOUNTS ) { + await handleCreateAccount(); + await upsertAdsAccount(); + } else if ( which === CREATING_MC_ACCOUNT ) { + await handleCreateAccount(); + } else if ( which === CREATING_ADS_ACCOUNT ) { + await upsertAdsAccount(); + } + }; + + handleCreateAccountCallback(); + setCreatingWhich( which ); } }, [ - accountCreationChecksResolved, - creatingWhichAccount, accountsCreated, + creatingWhich, handleCreateAccount, + loading, + response?.status, + shouldCreateAds, + shouldCreateMC, upsertAdsAccount, ] ); - useEffect( () => { - handlePostAccountCreation(); - }, [ response, loading, handlePostAccountCreation ] ); - - useEffect( () => { - handleAccountCreation(); - }, [ handleAccountCreation ] ); - return { - hasFinishedResolutionForExistingAdsMCAccounts: - accountCreationChecksResolved, accountsCreated, - creatingWhichAccount, + hasDetermined, + creatingWhich, }; }; From 3561c05e61eb5af2411d0bd697e0f83a144c600e Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 17:15:08 +0530 Subject: [PATCH 62/91] Rename useAccountCreationData hook to useAccountsData. --- .../account-card-description.js | 12 +++---- .../account-card-description/indicator.js | 6 ++-- .../account-creation-context.js | 2 +- .../connected-google-combo-account-card.js | 2 +- ...ountCreationData.js => useAccountsData.js} | 32 ++++++++++++------- 5 files changed, 32 insertions(+), 22 deletions(-) rename js/src/hooks/{useAccountCreationData.js => useAccountsData.js} (66%) diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js index 505e6d3ae5..a94ab82b08 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js @@ -3,23 +3,23 @@ */ import AccountDetails from './account-details'; import CreatingAccounts from './creating-accounts'; -import useAccountCreationData from '.~/hooks/useAccountCreationData'; +import useAccountsData from '.~/hooks/useAccountsData'; /** * AccountCardDescription component * @return {JSX.Element} AccountCardDescription component. */ const AccountCardDescription = () => { - const { creatingAccounts, email, googleAdsAccount, googleMCAccount } = - useAccountCreationData(); + const { creatingWhich, google, googleAdsAccount, googleMCAccount } = + useAccountsData(); return ( <> - { creatingAccounts ? ( - + { creatingWhich ? ( + ) : ( diff --git a/js/src/components/google-combo-account-card/account-card-description/indicator.js b/js/src/components/google-combo-account-card/account-card-description/indicator.js index 1db3da5493..9de748b479 100644 --- a/js/src/components/google-combo-account-card/account-card-description/indicator.js +++ b/js/src/components/google-combo-account-card/account-card-description/indicator.js @@ -8,7 +8,7 @@ import { __ } from '@wordpress/i18n'; */ import ConnectedIconLabel from '.~/components/connected-icon-label'; import LoadingLabel from '.~/components/loading-label/loading-label'; -import useAccountCreationData from '.~/hooks/useAccountCreationData'; +import useAccountsData from '.~/hooks/useAccountsData'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; @@ -19,7 +19,7 @@ import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; * @return {JSX.Element|null} Indicator component. */ const Indicator = () => { - const { creatingAccounts } = useAccountCreationData(); + const { creatingWhich } = useAccountsData(); const { hasGoogleAdsConnection } = useGoogleAdsAccount(); const { googleMCAccount, isPreconditionReady } = useGoogleMCAccount(); const { hasAccess, step } = useGoogleAdsAccountStatus(); @@ -35,7 +35,7 @@ const Indicator = () => { ( googleMCAccount?.status === 'incomplete' && googleMCAccount?.step === 'link_ads' ) ); - if ( creatingAccounts ) { + if ( creatingWhich ) { return ( { const accountCreationData = { accountsCreated, - creatingAccounts: creatingWhich, + creatingWhich, }; return ( diff --git a/js/src/hooks/useAccountCreationData.js b/js/src/hooks/useAccountsData.js similarity index 66% rename from js/src/hooks/useAccountCreationData.js rename to js/src/hooks/useAccountsData.js index 104da17248..f57802c28b 100644 --- a/js/src/hooks/useAccountCreationData.js +++ b/js/src/hooks/useAccountsData.js @@ -11,7 +11,17 @@ import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import { useAccountCreationContext } from '.~/components/google-combo-account-card/account-creation-context'; -const useAccountCreationData = () => { +/** + * useAccountsData hook. + * + * Checks if accounts are being created and if they are ready. + * @return {Object} Object with account data. + * @property {boolean} creatingAccounts - Whether accounts are being created. + * @property {Object} google - Google account data. + * @property {Object} googleAdsAccount - Google Ads account data. + * @property {Object} googleMCAccount - Google Merchant Center account data. + */ +const useAccountsData = () => { const { google, hasFinishedResolution: hasFinishedResolutionForGoogleAccount, @@ -27,7 +37,7 @@ const useAccountCreationData = () => { const accountCreationContext = useAccountCreationContext(); const wasCreatingAccounts = useRef( null ); - const { creatingAccounts, accountsCreated } = accountCreationContext; + const { creatingWhich, accountsCreated } = accountCreationContext; const accountDetailsResolved = hasFinishedResolutionForGoogleAccount && @@ -35,8 +45,8 @@ const useAccountCreationData = () => { hasFinishedResolutionForGoogleMCAccount; useEffect( () => { - if ( creatingAccounts ) { - wasCreatingAccounts.current = creatingAccounts; + if ( creatingWhich ) { + wasCreatingAccounts.current = creatingWhich; } if ( @@ -52,20 +62,20 @@ const useAccountCreationData = () => { } } }, [ - creatingAccounts, + creatingWhich, accountsCreated, accountDetailsResolved, - google.email, - googleAdsAccount.id, - googleMCAccount.id, + google, + googleAdsAccount, + googleMCAccount, ] ); return { - creatingAccounts: wasCreatingAccounts.current, - email: google.email, + creatingWhich: wasCreatingAccounts.current, + google, googleAdsAccount, googleMCAccount, }; }; -export default useAccountCreationData; +export default useAccountsData; From 88138209c81427b16d7263e5c82fbc1870607324 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 17:22:20 +0530 Subject: [PATCH 63/91] Fix: tests. --- .../hooks/useAutoCreateAdsMCAccounts.test.js | 89 +++---------------- 1 file changed, 14 insertions(+), 75 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 36e00a5a0b..9af9a14382 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -13,13 +13,13 @@ import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; import useGoogleAdsAccount from './useGoogleAdsAccount'; import useGoogleMCAccount from './useGoogleMCAccount'; +import useShouldCreateAdsAccount from './useShouldCreateAdsAccount'; +import useShouldCreateMCAccount from './useShouldCreateMCAccount'; jest.mock( './useCreateMCAccount' ); jest.mock( './useUpsertAdsAccount' ); -jest.mock( './useExistingGoogleAdsAccounts' ); -jest.mock( './useExistingGoogleMCAccounts' ); -jest.mock( './useGoogleAdsAccount' ); -jest.mock( './useGoogleMCAccount' ); +jest.mock( './useShouldCreateAdsAccount' ); +jest.mock( './useShouldCreateMCAccount' ); describe( 'useAutoCreateAdsMCAccounts hook', () => { let handleCreateAccount; @@ -29,15 +29,8 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { handleCreateAccount = jest.fn( () => Promise.resolve() ); upsertAdsAccount = jest.fn( () => Promise.resolve() ); - useGoogleAdsAccount.mockReturnValue( { - hasFinishedResolution: true, - hasGoogleAdsConnection: false, - } ); - - useGoogleMCAccount.mockReturnValue( { - hasFinishedResolution: true, - hasGoogleMCConnection: false, - } ); + useShouldCreateAdsAccount.mockReturnValue( true ); + useShouldCreateMCAccount.mockReturnValue( true ); } ); describe( 'Automatic account creation', () => { @@ -50,95 +43,41 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { upsertAdsAccount, { loading: true }, ] ); - useExistingGoogleMCAccounts.mockReturnValue( { - data: [], - hasFinishedResolution: true, - } ); - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [], - hasFinishedResolution: true, - } ); } ); it( 'should create both accounts', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should create both accounts. - expect( result.current.creatingWhichAccount ).toBe( 'both' ); + expect( result.current.creatingWhich ).toBe( 'both' ); } ); it( 'should create only the Merchant Center account', () => { - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [ - { - id: 1, - name: 'Test Ads Account', - }, - ], - hasFinishedResolution: true, - } ); - + useShouldCreateAdsAccount.mockReturnValue( false ); const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - // It should create only the Merchant Center account. - expect( result.current.creatingWhichAccount ).toBe( 'mc' ); + expect( result.current.creatingWhich ).toBe( 'mc' ); } ); it( 'should create only the Google Ads account', () => { - useExistingGoogleMCAccounts.mockReturnValue( { - data: [ - { - id: 1, - name: 'Test MC Account', - }, - ], - hasFinishedResolution: true, - } ); - + useShouldCreateMCAccount.mockReturnValue( false ); const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - // It should create only the Google Ads account. - expect( result.current.creatingWhichAccount ).toBe( 'ads' ); + expect( result.current.creatingWhich ).toBe( 'ads' ); } ); } ); describe( 'Existing accounts', () => { beforeEach( () => { - useCreateMCAccount.mockReturnValue( [ - handleCreateAccount, - { response: { status: 200 } }, - ] ); - useUpsertAdsAccount.mockReturnValue( [ - upsertAdsAccount, - { loading: false }, - ] ); + useShouldCreateAdsAccount.mockReturnValue( false ); + useShouldCreateMCAccount.mockReturnValue( false ); } ); it( 'should not create accounts if they already exist', () => { - useExistingGoogleMCAccounts.mockReturnValue( { - data: [ - { - id: 1, - name: 'Test MC Account', - }, - ], - hasFinishedResolution: true, - } ); - - useExistingGoogleAdsAccounts.mockReturnValue( { - existingAccounts: [ - { - id: 1, - name: 'Test Ads Account', - }, - ], - hasFinishedResolution: true, - } ); - const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should not create any accounts. - expect( result.current.creatingWhichAccount ).toBe( null ); + expect( result.current.creatingWhich ).toBe( null ); // make sure functions are not called. expect( handleCreateAccount ).not.toHaveBeenCalled(); From c9b9f2f3655271c4e165baad75d726e4a41ca51c Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 17:24:46 +0530 Subject: [PATCH 64/91] Remove redundant code. --- js/src/hooks/useAutoCreateAdsMCAccounts.test.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 9af9a14382..7c44710362 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -9,10 +9,6 @@ import { renderHook } from '@testing-library/react'; import useAutoCreateAdsMCAccounts from './useAutoCreateAdsMCAccounts'; import useCreateMCAccount from './useCreateMCAccount'; import useUpsertAdsAccount from './useUpsertAdsAccount'; -import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; -import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; -import useGoogleAdsAccount from './useGoogleAdsAccount'; -import useGoogleMCAccount from './useGoogleMCAccount'; import useShouldCreateAdsAccount from './useShouldCreateAdsAccount'; import useShouldCreateMCAccount from './useShouldCreateMCAccount'; From 85cc699eeb5c81cd700917e54249bec0eefbdc86 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 17:45:14 +0530 Subject: [PATCH 65/91] Fix: TypeError. --- js/src/hooks/useShouldCreateAdsAccount.js | 2 +- js/src/hooks/useShouldCreateMCAccount.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/hooks/useShouldCreateAdsAccount.js b/js/src/hooks/useShouldCreateAdsAccount.js index 789981274b..6b390d9f23 100644 --- a/js/src/hooks/useShouldCreateAdsAccount.js +++ b/js/src/hooks/useShouldCreateAdsAccount.js @@ -26,7 +26,7 @@ const useShouldCreateAdsAccount = () => { return null; } - return ! hasConnection && accounts.length === 0; + return ! hasConnection && accounts?.length === 0; }; export default useShouldCreateAdsAccount; diff --git a/js/src/hooks/useShouldCreateMCAccount.js b/js/src/hooks/useShouldCreateMCAccount.js index 8a76279268..9c0673eaea 100644 --- a/js/src/hooks/useShouldCreateMCAccount.js +++ b/js/src/hooks/useShouldCreateMCAccount.js @@ -26,7 +26,7 @@ const useShouldCreateMCAccount = () => { return null; } - return ! hasConnection && accounts.length === 0; + return ! hasConnection && accounts?.length === 0; }; export default useShouldCreateMCAccount; From b62199d1f17ad3f2f5d3b9cce148e053b1942dc3 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 19:56:12 +0530 Subject: [PATCH 66/91] Update doc blocks. --- .../account-card-description.js | 2 +- .../account-details.js | 35 ++++++++----------- .../creating-accounts.js | 4 --- .../account-creation-context.js | 23 ++++++++---- js/src/hooks/useAccountsData.js | 17 ++++++--- js/src/hooks/useAutoCreateAdsMCAccounts.js | 13 +++++++ 6 files changed, 57 insertions(+), 37 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js index a94ab82b08..8a6770bf9e 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js @@ -6,7 +6,7 @@ import CreatingAccounts from './creating-accounts'; import useAccountsData from '.~/hooks/useAccountsData'; /** - * AccountCardDescription component + * AccountCardDescription component. * @return {JSX.Element} AccountCardDescription component. */ const AccountCardDescription = () => { diff --git a/js/src/components/google-combo-account-card/account-card-description/account-details.js b/js/src/components/google-combo-account-card/account-card-description/account-details.js index 14f4819312..a9696acb0b 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-details.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-details.js @@ -16,27 +16,20 @@ const AccountDetails = ( { email, googleAdsID, googleMerchantCenterID } ) => { return (
{ email } - { Number( googleMerchantCenterID ) > 0 && ( - - { sprintf( - // Translators: %s is the Merchant Center ID - __( - 'Merchant Center ID: %s', - 'google-listings-and-ads' - ), - googleMerchantCenterID - ) } - - ) } - { Number( googleAdsID ) > 0 && ( - - { sprintf( - // Translators: %s is the Google Ads ID - __( 'Google Ads ID: %s', 'google-listings-and-ads' ), - googleAdsID - ) } - - ) } + + { sprintf( + // Translators: %s is the Merchant Center ID + __( 'Merchant Center ID: %s', 'google-listings-and-ads' ), + googleMerchantCenterID + ) } + + + { sprintf( + // Translators: %s is the Google Ads ID + __( 'Google Ads ID: %s', 'google-listings-and-ads' ), + googleAdsID + ) } +
); }; diff --git a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js index 057c07fb70..d0e8d380bf 100644 --- a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js +++ b/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js @@ -22,10 +22,6 @@ const CreatingAccounts = ( { creatingAccounts } ) => { let text = null; let subText = null; - if ( ! creatingAccounts ) { - return null; - } - switch ( creatingAccounts ) { case CREATING_BOTH_ACCOUNTS: text = __( diff --git a/js/src/components/google-combo-account-card/account-creation-context.js b/js/src/components/google-combo-account-card/account-creation-context.js index c628363554..a1b20b28f6 100644 --- a/js/src/components/google-combo-account-card/account-creation-context.js +++ b/js/src/components/google-combo-account-card/account-creation-context.js @@ -5,21 +5,32 @@ import { createContext, useContext } from '@wordpress/element'; /** * @typedef {Object} AccountCreationContext - * @property {boolean} accountsCreated `true` if the accounts have been created. - * @property {string|null} creatingWhich The accounts that are being created. It can be 'ads', 'mc', or 'both'. + * @property {boolean} accountsCreated - `true` if the accounts have been created, `false` otherwise. + * @property {('ads'|'mc'|'both'|null)} creatingWhich - The accounts that are being created. */ -export const AccountCreationContext = createContext( {} ); +/** + * @type {AccountCreationContext} + */ +const defaultContext = { + accountsCreated: undefined, + creatingWhich: undefined, +}; + +export const AccountCreationContext = createContext( defaultContext ); /** * AccountCreation's context hook. - * @return {Object} AccountCreation's context. - * @throws Will throw an error if its context provider is not existing in its parents. + * @return {AccountCreationContext} The current context value for AccountCreation. + * @throws Will throw an error if the context provider is missing in the component's ancestors. */ export function useAccountCreationContext() { const adaptiveFormContext = useContext( AccountCreationContext ); - if ( Object.keys( adaptiveFormContext ).length === 0 ) { + if ( + adaptiveFormContext.accountsCreated === undefined || + adaptiveFormContext.creatingWhich === undefined + ) { throw new Error( 'useAccountCreationContext was used outside of its context provider ConnectedGoogleComboAccountCard.' ); diff --git a/js/src/hooks/useAccountsData.js b/js/src/hooks/useAccountsData.js index f57802c28b..4ad91dea35 100644 --- a/js/src/hooks/useAccountsData.js +++ b/js/src/hooks/useAccountsData.js @@ -12,14 +12,21 @@ import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import { useAccountCreationContext } from '.~/components/google-combo-account-card/account-creation-context'; /** - * useAccountsData hook. - * - * Checks if accounts are being created and if they are ready. - * @return {Object} Object with account data. - * @property {boolean} creatingAccounts - Whether accounts are being created. + * @typedef {Object} AccountsData + * @property {('ads'|'mc'|'both'|null)} creatingWhich - The type of accounts being created, or `null` if none. * @property {Object} google - Google account data. + * @property {string} google.email - Google account email. * @property {Object} googleAdsAccount - Google Ads account data. + * @property {number} googleAdsAccount.id - Google Ads account ID. * @property {Object} googleMCAccount - Google Merchant Center account data. + * @property {number} googleMCAccount.id - Google Merchant Center account ID. + */ + +/** + * useAccountsData hook. + * + * Checks if accounts are being created and if they are ready. + * @return {AccountsData} Object with account data. */ const useAccountsData = () => { const { diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 4f2965ece4..71e69a2e3d 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -16,6 +16,19 @@ import { CREATING_MC_ACCOUNT, } from '.~/components/google-combo-account-card/constants'; +/** + * @typedef {Object} AutoCreateAdsMCAccountsData + * @property {boolean} accountsCreated - Whether the accounts have been successfully created. + * @property {boolean} hasDetermined - Whether the checks to determine if accounts should be created are finished. + * @property {('ads'|'mc'|'both'|null)} creatingWhich - Which accounts are being created ('ads', 'mc', 'both'), or `null` if none. + */ + +/** + * useAutoCreateAdsMCAccounts hook. + * Creates Google Ads and Merchant Center accounts if the user doesn't have any existing and connected accounts. + * + * @return {AutoCreateAdsMCAccountsData} Object containing account creation data. + */ const useAutoCreateAdsMCAccounts = () => { const lockedRef = useRef( false ); // Create separate states. From 3c938407673b21444c112dc128f9f799c23c984c Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 21:21:58 +0530 Subject: [PATCH 67/91] Fix: E2E tests. --- tests/e2e/specs/setup-mc/step-1-accounts.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index f86be1c3e5..a84098bf3c 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -222,6 +222,8 @@ test.describe( 'Set up accounts', () => { test( 'should create merchant center and ads account if does not exist for the user', async () => { await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); + await setupAdsAccountPage.mockAdsAccountDisconnected(); + await setUpAccountsPage.mockMCNotConnected(); await setupAdsAccountPage.fulfillAdsAccounts( [ From 47af5ada8b9dce5aa972b0938b7d499dbab6e33d Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Tue, 22 Oct 2024 22:03:15 +0530 Subject: [PATCH 68/91] Fix: E2E. --- .../specs/setup-mc/step-1-accounts.test.js | 54 +++---------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index a84098bf3c..9ea9a0b866 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -318,65 +318,23 @@ test.describe( 'Set up accounts', () => { test.beforeEach( async () => { await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); - - await setUpAccountsPage.fulfillMCConnection( { - id: 5432178, - name: null, - subaccount: null, - domain: null, - status: 'incomplete', - step: 'link_ads', - } ); - - await setUpAccountsPage.fulfillAdsConnection( { - id: 78787878, - currency: 'USD', - status: 'incomplete', - step: 'account_access', - sub_account: true, - symbol: '$', - } ); + await setUpAccountsPage.mockMCConnected(); + await setupAdsAccountPage.mockAdsAccountConnected(); await setUpAccountsPage.goto(); } ); test( 'should see the merchant center id and ads account id if connected', async () => { - await setupAdsAccountPage.fulfillAdsAccounts( - { - message: - 'Account must be accepted before completing setup.', - has_access: false, - step: 'account_access', - invite_link: 'https://ads.google.com/nav/', - }, - 428, - [ 'POST' ] - ); - - await setupAdsAccountPage.fulfillMCAccounts( - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - }, - 200, - [ 'POST' ] - ); - const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); await expect( - googleAccountCard.getByText( - 'Merchant Center ID: 5432178', - { - exact: true, - } - ) + googleAccountCard.getByText( 'Merchant Center ID: 1234', { + exact: true, + } ) ).toBeVisible(); await expect( - googleAccountCard.getByText( 'Google Ads ID: 78787878', { + googleAccountCard.getByText( 'Google Ads ID: 12345', { exact: true, } ) ).toBeVisible(); From 7937784777ccfc7cb16ef93f0230ca3231435cd9 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 12:20:41 +0530 Subject: [PATCH 69/91] Add useGoogleAdsAccountReady hook. --- .../account-card-description.js | 20 ++++++++---------- .../account-card-description/indicator.js | 11 ++-------- .../account-creation-context.js | 8 +++---- js/src/hooks/useGoogleAdsAccountReady.js | 21 +++++++++++++++++++ .../ads-stepper/setup-accounts/index.js | 14 +++---------- .../setup-stepper/setup-accounts/index.js | 15 +++---------- 6 files changed, 42 insertions(+), 47 deletions(-) create mode 100644 js/src/hooks/useGoogleAdsAccountReady.js diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js index 8a6770bf9e..69938190ea 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js @@ -13,18 +13,16 @@ const AccountCardDescription = () => { const { creatingWhich, google, googleAdsAccount, googleMCAccount } = useAccountsData(); + if ( creatingWhich ) { + return ; + } + return ( - <> - { creatingWhich ? ( - - ) : ( - - ) } - + ); }; diff --git a/js/src/components/google-combo-account-card/account-card-description/indicator.js b/js/src/components/google-combo-account-card/account-card-description/indicator.js index 9de748b479..b52b1e85e0 100644 --- a/js/src/components/google-combo-account-card/account-card-description/indicator.js +++ b/js/src/components/google-combo-account-card/account-card-description/indicator.js @@ -9,9 +9,8 @@ import { __ } from '@wordpress/i18n'; import ConnectedIconLabel from '.~/components/connected-icon-label'; import LoadingLabel from '.~/components/loading-label/loading-label'; import useAccountsData from '.~/hooks/useAccountsData'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; +import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; /** * Account creation indicator. @@ -20,14 +19,8 @@ import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; */ const Indicator = () => { const { creatingWhich } = useAccountsData(); - const { hasGoogleAdsConnection } = useGoogleAdsAccount(); const { googleMCAccount, isPreconditionReady } = useGoogleMCAccount(); - const { hasAccess, step } = useGoogleAdsAccountStatus(); - - const isGoogleAdsConnected = - hasGoogleAdsConnection && - hasAccess && - [ '', 'billing', 'link_merchant' ].includes( step ); + const isGoogleAdsConnected = useGoogleAdsAccountReady(); const isGoogleMCConnected = isPreconditionReady && diff --git a/js/src/components/google-combo-account-card/account-creation-context.js b/js/src/components/google-combo-account-card/account-creation-context.js index a1b20b28f6..622fc80beb 100644 --- a/js/src/components/google-combo-account-card/account-creation-context.js +++ b/js/src/components/google-combo-account-card/account-creation-context.js @@ -25,16 +25,16 @@ export const AccountCreationContext = createContext( defaultContext ); * @throws Will throw an error if the context provider is missing in the component's ancestors. */ export function useAccountCreationContext() { - const adaptiveFormContext = useContext( AccountCreationContext ); + const accountCreationContext = useContext( AccountCreationContext ); if ( - adaptiveFormContext.accountsCreated === undefined || - adaptiveFormContext.creatingWhich === undefined + accountCreationContext.accountsCreated === undefined || + accountCreationContext.creatingWhich === undefined ) { throw new Error( 'useAccountCreationContext was used outside of its context provider ConnectedGoogleComboAccountCard.' ); } - return adaptiveFormContext; + return accountCreationContext; } diff --git a/js/src/hooks/useGoogleAdsAccountReady.js b/js/src/hooks/useGoogleAdsAccountReady.js new file mode 100644 index 0000000000..0b6de9cd4a --- /dev/null +++ b/js/src/hooks/useGoogleAdsAccountReady.js @@ -0,0 +1,21 @@ +/** + * Internal dependencies + */ +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; + +const useGoogleAdsAccountReady = () => { + const { hasGoogleAdsConnection } = useGoogleAdsAccount(); + const { hasAccess, step } = useGoogleAdsAccountStatus(); + + // Ads is ready when we have a connection and verified and verified access. + // Billing is not required, and the 'link_merchant' step will be resolved + // when the MC the account is connected. + return ( + hasGoogleAdsConnection && + hasAccess && + [ '', 'billing', 'link_merchant' ].includes( step ) + ); +}; + +export default useGoogleAdsAccountReady; diff --git a/js/src/setup-ads/ads-stepper/setup-accounts/index.js b/js/src/setup-ads/ads-stepper/setup-accounts/index.js index bab89e5cc1..d9f1c3b6a3 100644 --- a/js/src/setup-ads/ads-stepper/setup-accounts/index.js +++ b/js/src/setup-ads/ads-stepper/setup-accounts/index.js @@ -16,31 +16,23 @@ import { ConnectedGoogleAccountCard } from '.~/components/google-account-card'; import GoogleAdsAccountCard from '.~/components/google-ads-account-card'; import FreeAdCredit from './free-ad-credit'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; import useGoogleAccount from '.~/hooks/useGoogleAccount'; import useFreeAdCredit from '.~/hooks/useFreeAdCredit'; import AppSpinner from '.~/components/app-spinner'; import Section from '.~/wcdl/section'; +import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; const SetupAccounts = ( props ) => { const { onContinue = () => {} } = props; const { google } = useGoogleAccount(); - const { googleAdsAccount, hasGoogleAdsConnection } = useGoogleAdsAccount(); - const { hasAccess, step } = useGoogleAdsAccountStatus(); + const { googleAdsAccount } = useGoogleAdsAccount(); const hasFreeAdCredit = useFreeAdCredit(); + const isGoogleAdsReady = useGoogleAdsAccountReady(); if ( ! google || ( google.active === 'yes' && ! googleAdsAccount ) ) { return ; } - // Ads is ready when we have a connection and verified and verified access. - // Billing is not required, and the 'link_merchant' step will be resolved - // when the MC the account is connected. - const isGoogleAdsReady = - hasGoogleAdsConnection && - hasAccess && - [ '', 'billing', 'link_merchant' ].includes( step ); - const isContinueButtonDisabled = ! isGoogleAdsReady; return ( diff --git a/js/src/setup-mc/setup-stepper/setup-accounts/index.js b/js/src/setup-mc/setup-stepper/setup-accounts/index.js index d4bfc68f86..534b4de7f5 100644 --- a/js/src/setup-mc/setup-stepper/setup-accounts/index.js +++ b/js/src/setup-mc/setup-stepper/setup-accounts/index.js @@ -24,7 +24,7 @@ import GoogleComboAccountCard from '.~/components/google-combo-account-card'; import Faqs from './faqs'; import './index.scss'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; +import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; /** * Renders the disclaimer of Comparison Shopping Service (CSS). @@ -85,9 +85,8 @@ const SetupAccounts = ( props ) => { const { google, scope } = useGoogleAccount(); const { googleMCAccount, isPreconditionReady: isGMCPreconditionReady } = useGoogleMCAccount(); - const { hasFinishedResolution, hasGoogleAdsConnection } = - useGoogleAdsAccount(); - const { hasAccess, step } = useGoogleAdsAccountStatus(); + const { hasFinishedResolution } = useGoogleAdsAccount(); + const isGoogleAdsReady = useGoogleAdsAccountReady(); /** * When jetpack is loading, or when google account is loading, @@ -110,14 +109,6 @@ const SetupAccounts = ( props ) => { return ; } - // Ads is ready when we have a connection and verified and verified access. - // Billing is not required, and the 'link_merchant' step will be resolved - // when the MC the account is connected. - const isGoogleAdsReady = - hasGoogleAdsConnection && - hasAccess && - [ '', 'billing', 'link_merchant' ].includes( step ); - // MC is ready when we have a connection and preconditions are met. // The `link_ads` step will be resolved when the Ads account is connected // since these can be connected in any order. From 1d86086aa899d950d71a3b4649781d0ee27114b6 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 12:52:39 +0530 Subject: [PATCH 70/91] Remove use of context. --- .../account-card-description.js | 18 +--- .../account-details.js | 24 +++-- .../account-card-description/indicator.js | 8 +- .../account-creation-context.js | 40 --------- .../connected-google-combo-account-card.js | 75 ++++++++++++---- js/src/hooks/useAccountsData.js | 88 ------------------- 6 files changed, 79 insertions(+), 174 deletions(-) delete mode 100644 js/src/components/google-combo-account-card/account-creation-context.js delete mode 100644 js/src/hooks/useAccountsData.js diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js index 69938190ea..cd755a8520 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js @@ -3,27 +3,17 @@ */ import AccountDetails from './account-details'; import CreatingAccounts from './creating-accounts'; -import useAccountsData from '.~/hooks/useAccountsData'; /** * AccountCardDescription component. * @return {JSX.Element} AccountCardDescription component. */ -const AccountCardDescription = () => { - const { creatingWhich, google, googleAdsAccount, googleMCAccount } = - useAccountsData(); - - if ( creatingWhich ) { - return ; +const AccountCardDescription = ( { creatingAccounts } ) => { + if ( creatingAccounts ) { + return ; } - return ( - - ); + return ; }; export default AccountCardDescription; diff --git a/js/src/components/google-combo-account-card/account-card-description/account-details.js b/js/src/components/google-combo-account-card/account-card-description/account-details.js index a9696acb0b..5c2c4b131b 100644 --- a/js/src/components/google-combo-account-card/account-card-description/account-details.js +++ b/js/src/components/google-combo-account-card/account-card-description/account-details.js @@ -3,31 +3,37 @@ */ import { __, sprintf } from '@wordpress/i18n'; +/** + * Internal dependencies + */ +import useGoogleAccount from '.~/hooks/useGoogleAccount'; +import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; +import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; + /** * Account details. - * - * @param {Object} props Component props. - * @param {string} props.email Google account email address. - * @param {number} props.googleAdsID Google Ads account ID. - * @param {number} props.googleMerchantCenterID Google Merchant Center account ID. * @return {JSX.Element} JSX markup. */ -const AccountDetails = ( { email, googleAdsID, googleMerchantCenterID } ) => { +const AccountDetails = () => { + const { google } = useGoogleAccount(); + const { googleAdsAccount } = useGoogleAdsAccount(); + const { googleMCAccount } = useGoogleMCAccount(); + return (
- { email } + { google.email } { sprintf( // Translators: %s is the Merchant Center ID __( 'Merchant Center ID: %s', 'google-listings-and-ads' ), - googleMerchantCenterID + googleMCAccount.id ) } { sprintf( // Translators: %s is the Google Ads ID __( 'Google Ads ID: %s', 'google-listings-and-ads' ), - googleAdsID + googleAdsAccount.id ) }
diff --git a/js/src/components/google-combo-account-card/account-card-description/indicator.js b/js/src/components/google-combo-account-card/account-card-description/indicator.js index b52b1e85e0..35e089b96c 100644 --- a/js/src/components/google-combo-account-card/account-card-description/indicator.js +++ b/js/src/components/google-combo-account-card/account-card-description/indicator.js @@ -8,17 +8,17 @@ import { __ } from '@wordpress/i18n'; */ import ConnectedIconLabel from '.~/components/connected-icon-label'; import LoadingLabel from '.~/components/loading-label/loading-label'; -import useAccountsData from '.~/hooks/useAccountsData'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; /** * Account creation indicator. * Displays a loading indicator when accounts are being created or a connected icon when accounts are connected. + * @param {Object} props Component props. + * @param {boolean} props.creatingAccounts Whether the accounts are being created. * @return {JSX.Element|null} Indicator component. */ -const Indicator = () => { - const { creatingWhich } = useAccountsData(); +const Indicator = ( { creatingAccounts } ) => { const { googleMCAccount, isPreconditionReady } = useGoogleMCAccount(); const isGoogleAdsConnected = useGoogleAdsAccountReady(); @@ -28,7 +28,7 @@ const Indicator = () => { ( googleMCAccount?.status === 'incomplete' && googleMCAccount?.step === 'link_ads' ) ); - if ( creatingWhich ) { + if ( creatingAccounts ) { return ( { - const { hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount } = - useGoogleAdsAccount(); + const { + googleAdsAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, + } = useGoogleAdsAccount(); - const { hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount } = - useGoogleMCAccount(); + const { + googleMCAccount, + hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, + } = useGoogleMCAccount(); const { accountsCreated, hasDetermined, creatingWhich } = useAutoCreateAdsMCAccounts(); + const wasCreatingAccounts = useRef( null ); + const accountDetailsResolved = + hasFinishedResolutionForCurrentAdsAccount && + hasFinishedResolutionForCurrentMCAccount; + + useEffect( () => { + if ( creatingWhich ) { + wasCreatingAccounts.current = creatingWhich; + } + + if ( + wasCreatingAccounts.current && + accountsCreated && + accountDetailsResolved + ) { + const accountsReady = + !! googleAdsAccount?.id && !! googleMCAccount?.id; + + if ( accountsReady ) { + wasCreatingAccounts.current = null; + } + } + }, [ + accountDetailsResolved, + accountsCreated, + creatingWhich, + googleAdsAccount, + googleMCAccount, + ] ); + if ( ! accountsCreated && ( ! hasDetermined || @@ -33,21 +71,20 @@ const ConnectedGoogleComboAccountCard = () => { return } />; } - const accountCreationData = { - accountsCreated, - creatingWhich, - }; - return ( - - } - indicator={ } - /> - + + } + indicator={ + + } + /> ); }; diff --git a/js/src/hooks/useAccountsData.js b/js/src/hooks/useAccountsData.js deleted file mode 100644 index 4ad91dea35..0000000000 --- a/js/src/hooks/useAccountsData.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * External dependencies - */ -import { useEffect, useRef } from '@wordpress/element'; - -/** - * Internal dependencies - */ -import useGoogleAccount from '.~/hooks/useGoogleAccount'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; -import { useAccountCreationContext } from '.~/components/google-combo-account-card/account-creation-context'; - -/** - * @typedef {Object} AccountsData - * @property {('ads'|'mc'|'both'|null)} creatingWhich - The type of accounts being created, or `null` if none. - * @property {Object} google - Google account data. - * @property {string} google.email - Google account email. - * @property {Object} googleAdsAccount - Google Ads account data. - * @property {number} googleAdsAccount.id - Google Ads account ID. - * @property {Object} googleMCAccount - Google Merchant Center account data. - * @property {number} googleMCAccount.id - Google Merchant Center account ID. - */ - -/** - * useAccountsData hook. - * - * Checks if accounts are being created and if they are ready. - * @return {AccountsData} Object with account data. - */ -const useAccountsData = () => { - const { - google, - hasFinishedResolution: hasFinishedResolutionForGoogleAccount, - } = useGoogleAccount(); - const { - googleAdsAccount, - hasFinishedResolution: hasFinishedResolutionForGoogleAdsAccount, - } = useGoogleAdsAccount(); - const { - googleMCAccount, - hasFinishedResolution: hasFinishedResolutionForGoogleMCAccount, - } = useGoogleMCAccount(); - - const accountCreationContext = useAccountCreationContext(); - const wasCreatingAccounts = useRef( null ); - const { creatingWhich, accountsCreated } = accountCreationContext; - - const accountDetailsResolved = - hasFinishedResolutionForGoogleAccount && - hasFinishedResolutionForGoogleAdsAccount && - hasFinishedResolutionForGoogleMCAccount; - - useEffect( () => { - if ( creatingWhich ) { - wasCreatingAccounts.current = creatingWhich; - } - - if ( - wasCreatingAccounts.current && - accountsCreated && - accountDetailsResolved - ) { - const accountsReady = - google.email && !! googleAdsAccount.id && !! googleMCAccount.id; - - if ( accountsReady ) { - wasCreatingAccounts.current = null; - } - } - }, [ - creatingWhich, - accountsCreated, - accountDetailsResolved, - google, - googleAdsAccount, - googleMCAccount, - ] ); - - return { - creatingWhich: wasCreatingAccounts.current, - google, - googleAdsAccount, - googleMCAccount, - }; -}; - -export default useAccountsData; From 0be881e41e5521f16799a7a6bc1ba5060bbd0573 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 14:27:17 +0530 Subject: [PATCH 71/91] Remove unwanted components. --- .../account-card-description.js | 19 --------------- .../account-card-description/index.js | 4 ---- .../account-details.js | 0 .../connected-google-combo-account-card.js | 18 ++++++++++----- .../connected-google-combo-account-card.scss | 11 --------- .../indicator.js | 0 ...-accounts.js => useAccountCreationText.js} | 23 ++++++++----------- 7 files changed, 22 insertions(+), 53 deletions(-) delete mode 100644 js/src/components/google-combo-account-card/account-card-description/account-card-description.js delete mode 100644 js/src/components/google-combo-account-card/account-card-description/index.js rename js/src/components/google-combo-account-card/{account-card-description => }/account-details.js (100%) rename js/src/components/google-combo-account-card/{account-card-description => }/indicator.js (100%) rename js/src/components/google-combo-account-card/{account-card-description/creating-accounts.js => useAccountCreationText.js} (74%) diff --git a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js b/js/src/components/google-combo-account-card/account-card-description/account-card-description.js deleted file mode 100644 index cd755a8520..0000000000 --- a/js/src/components/google-combo-account-card/account-card-description/account-card-description.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Internal dependencies - */ -import AccountDetails from './account-details'; -import CreatingAccounts from './creating-accounts'; - -/** - * AccountCardDescription component. - * @return {JSX.Element} AccountCardDescription component. - */ -const AccountCardDescription = ( { creatingAccounts } ) => { - if ( creatingAccounts ) { - return ; - } - - return ; -}; - -export default AccountCardDescription; diff --git a/js/src/components/google-combo-account-card/account-card-description/index.js b/js/src/components/google-combo-account-card/account-card-description/index.js deleted file mode 100644 index ab3c6c78ba..0000000000 --- a/js/src/components/google-combo-account-card/account-card-description/index.js +++ /dev/null @@ -1,4 +0,0 @@ -export { default } from './account-card-description'; -export { default as CreatingAccounts } from './creating-accounts.js'; -export { default as AccountDetails } from './account-details'; -export { default as Indicator } from './indicator.js'; diff --git a/js/src/components/google-combo-account-card/account-card-description/account-details.js b/js/src/components/google-combo-account-card/account-details.js similarity index 100% rename from js/src/components/google-combo-account-card/account-card-description/account-details.js rename to js/src/components/google-combo-account-card/account-details.js diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 39cf3f6eba..f548f4a744 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -7,8 +7,10 @@ import { useEffect, useRef } from '@wordpress/element'; * Internal dependencies */ import AccountCard, { APPEARANCE } from '../account-card'; -import AccountCardDescription, { Indicator } from './account-card-description'; +import AccountDetails from './account-details'; import AppSpinner from '../app-spinner'; +import Indicator from './indicator'; +import useAccountCreationText from './useAccountCreationText'; import useAutoCreateAdsMCAccounts from '.~/hooks/useAutoCreateAdsMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; @@ -19,6 +21,8 @@ import './connected-google-combo-account-card.scss'; * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. */ const ConnectedGoogleComboAccountCard = () => { + const wasCreatingAccounts = useRef( null ); + const { googleAdsAccount, hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, @@ -32,7 +36,10 @@ const ConnectedGoogleComboAccountCard = () => { const { accountsCreated, hasDetermined, creatingWhich } = useAutoCreateAdsMCAccounts(); - const wasCreatingAccounts = useRef( null ); + const { text, subText } = useAccountCreationText( + wasCreatingAccounts.current + ); + const accountDetailsResolved = hasFinishedResolutionForCurrentAdsAccount && hasFinishedResolutionForCurrentMCAccount; @@ -76,11 +83,10 @@ const ConnectedGoogleComboAccountCard = () => { appearance={ APPEARANCE.GOOGLE } alignIcon="top" className="gla-google-combo-account-card--connected" - helper={ - + description={ + !! wasCreatingAccounts.current ? text : } + helper={ subText } indicator={ } diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss index ecbad738bb..973e700ded 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss @@ -1,16 +1,5 @@ .gla-google-combo-account-card--connected { - .gla-account-card__helper { - font-style: normal; - font-size: $gla-font-base; - color: $black; - - em { - font-style: italic; - color: $gray-700; - } - } - .gla-account-card__account_details { display: flex; flex-direction: column; diff --git a/js/src/components/google-combo-account-card/account-card-description/indicator.js b/js/src/components/google-combo-account-card/indicator.js similarity index 100% rename from js/src/components/google-combo-account-card/account-card-description/indicator.js rename to js/src/components/google-combo-account-card/indicator.js diff --git a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js b/js/src/components/google-combo-account-card/useAccountCreationText.js similarity index 74% rename from js/src/components/google-combo-account-card/account-card-description/creating-accounts.js rename to js/src/components/google-combo-account-card/useAccountCreationText.js index d0e8d380bf..dec6dd1c19 100644 --- a/js/src/components/google-combo-account-card/account-card-description/creating-accounts.js +++ b/js/src/components/google-combo-account-card/useAccountCreationText.js @@ -10,19 +10,18 @@ import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, -} from '../constants'; +} from './constants'; /** * Account creation in progress description. - * @param {Object} props Component props. - * @param {string|null} props.creatingAccounts Whether the accounts are being created. Possible values are: 'both', 'ads', 'mc'. - * @return {JSX.Element|null} JSX markup. + * @param {string|null} creatingWhich Which account is being created. + * @return {Object} Text and subtext. */ -const CreatingAccounts = ( { creatingAccounts } ) => { +const useAccountCreationText = ( creatingWhich ) => { let text = null; let subText = null; - switch ( creatingAccounts ) { + switch ( creatingWhich ) { case CREATING_BOTH_ACCOUNTS: text = __( 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', @@ -57,12 +56,10 @@ const CreatingAccounts = ( { creatingAccounts } ) => { break; } - return ( - <> -

{ text }

- { subText } - - ); + return { + text, + subText, + }; }; -export default CreatingAccounts; +export default useAccountCreationText; From 98808af646a764c3449ccf95c0fb96ac4a591598 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 17:24:55 +0530 Subject: [PATCH 72/91] Optimize the useAutoCreateAdsMCAccounts hook and fix tests. --- .../account-details.js | 10 +- .../connected-google-combo-account-card.js | 63 +++++------ .../connected-google-combo-account-card.scss | 7 +- js/src/hooks/useAutoCreateAdsMCAccounts.js | 81 ++++++++------ .../hooks/useAutoCreateAdsMCAccounts.test.js | 100 ++++++++++++++---- .../getAccountCreationTexts.js} | 6 +- 6 files changed, 172 insertions(+), 95 deletions(-) rename js/src/{components/google-combo-account-card/useAccountCreationText.js => utils/getAccountCreationTexts.js} (90%) diff --git a/js/src/components/google-combo-account-card/account-details.js b/js/src/components/google-combo-account-card/account-details.js index 5c2c4b131b..4f10f34d75 100644 --- a/js/src/components/google-combo-account-card/account-details.js +++ b/js/src/components/google-combo-account-card/account-details.js @@ -21,21 +21,21 @@ const AccountDetails = () => { return (
- { google.email } - +

{ google.email }

+

{ sprintf( // Translators: %s is the Merchant Center ID __( 'Merchant Center ID: %s', 'google-listings-and-ads' ), googleMCAccount.id ) } - - +

+

{ sprintf( // Translators: %s is the Google Ads ID __( 'Google Ads ID: %s', 'google-listings-and-ads' ), googleAdsAccount.id ) } - +

); }; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index f548f4a744..0376a91e9d 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { useEffect, useRef } from '@wordpress/element'; +import { useEffect, useState } from '@wordpress/element'; /** * Internal dependencies @@ -10,7 +10,7 @@ import AccountCard, { APPEARANCE } from '../account-card'; import AccountDetails from './account-details'; import AppSpinner from '../app-spinner'; import Indicator from './indicator'; -import useAccountCreationText from './useAccountCreationText'; +import getAccountCreationTexts from '.~/utils/getAccountCreationTexts'; import useAutoCreateAdsMCAccounts from '.~/hooks/useAutoCreateAdsMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; @@ -21,7 +21,9 @@ import './connected-google-combo-account-card.scss'; * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. */ const ConnectedGoogleComboAccountCard = () => { - const wasCreatingAccounts = useRef( null ); + // Used to track whether the account creation ever happened. + const [ wasCreatingAccounts, setWasCreatingAccounts ] = + useState( undefined ); const { googleAdsAccount, @@ -33,44 +35,37 @@ const ConnectedGoogleComboAccountCard = () => { hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, } = useGoogleMCAccount(); - const { accountsCreated, hasDetermined, creatingWhich } = - useAutoCreateAdsMCAccounts(); - - const { text, subText } = useAccountCreationText( - wasCreatingAccounts.current - ); + const { hasDetermined, creatingWhich } = useAutoCreateAdsMCAccounts(); + const { text, subText } = getAccountCreationTexts( wasCreatingAccounts ); const accountDetailsResolved = + hasDetermined && hasFinishedResolutionForCurrentAdsAccount && hasFinishedResolutionForCurrentMCAccount; - useEffect( () => { - if ( creatingWhich ) { - wasCreatingAccounts.current = creatingWhich; - } + const accountsCreated = + wasCreatingAccounts !== undefined && ! creatingWhich; - if ( - wasCreatingAccounts.current && - accountsCreated && - accountDetailsResolved - ) { - const accountsReady = - !! googleAdsAccount?.id && !! googleMCAccount?.id; + const accountsReady = + accountDetailsResolved && + !! googleAdsAccount?.id && + !! googleMCAccount?.id; - if ( accountsReady ) { - wasCreatingAccounts.current = null; - } + const displayAccountDetails = + wasCreatingAccounts && + accountsCreated && + accountDetailsResolved && + accountsReady; + + useEffect( () => { + if ( creatingWhich ) { + setWasCreatingAccounts( creatingWhich ); } - }, [ - accountDetailsResolved, - accountsCreated, - creatingWhich, - googleAdsAccount, - googleMCAccount, - ] ); + }, [ creatingWhich ] ); if ( ! accountsCreated && + wasCreatingAccounts === undefined && ( ! hasDetermined || ! hasFinishedResolutionForCurrentAdsAccount || ! hasFinishedResolutionForCurrentMCAccount ) @@ -83,12 +78,10 @@ const ConnectedGoogleComboAccountCard = () => { appearance={ APPEARANCE.GOOGLE } alignIcon="top" className="gla-google-combo-account-card--connected" - description={ - !! wasCreatingAccounts.current ? text : - } - helper={ subText } + description={ ! displayAccountDetails ? text : } + helper={ ! displayAccountDetails ? subText : null } indicator={ - + } /> ); diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss index 973e700ded..e3e6949c9d 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss @@ -1,8 +1,9 @@ .gla-google-combo-account-card--connected { .gla-account-card__account_details { - display: flex; - flex-direction: column; - gap: $grid-unit; + + p { + margin: 0.5em 0; + } } } diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 71e69a2e3d..6bccf39a1b 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -6,16 +6,56 @@ import { useEffect, useState, useRef } from '@wordpress/element'; /** * Internal dependencies */ +import useGoogleAdsAccount from './useGoogleAdsAccount'; +import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; +import useGoogleMCAccount from './useGoogleMCAccount'; +import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; import useCreateMCAccount from './useCreateMCAccount'; import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount'; -import useShouldCreateAdsAccount from './useShouldCreateAdsAccount'; -import useShouldCreateMCAccount from './useShouldCreateMCAccount'; import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, } from '.~/components/google-combo-account-card/constants'; +const useShouldCreateAdsAccount = () => { + const { + hasFinishedResolution: hasResolvedAccount, + hasGoogleAdsConnection: hasConnection, + } = useGoogleAdsAccount(); + + const { + hasFinishedResolution: hasResolvedExistingAccounts, + existingAccounts: accounts, + } = useExistingGoogleAdsAccounts(); + + // Return null if the account hasn't been resolved or the existing accounts haven't been resolved + if ( ! hasResolvedAccount || ! hasResolvedExistingAccounts ) { + return null; + } + + return ! hasConnection && accounts?.length === 0; +}; + +const useShouldCreateMCAccount = () => { + const { + hasFinishedResolution: hasResolvedAccount, + hasGoogleMCConnection: hasConnection, + } = useGoogleMCAccount(); + + const { + hasFinishedResolution: hasResolvedExistingAccounts, + data: accounts, + } = useExistingGoogleMCAccounts(); + + // Return null if the account hasn't been resolved or the existing accounts haven't been resolved + if ( ! hasResolvedAccount || ! hasResolvedExistingAccounts ) { + return null; + } + + return ! hasConnection && accounts?.length === 0; +}; + /** * @typedef {Object} AutoCreateAdsMCAccountsData * @property {boolean} accountsCreated - Whether the accounts have been successfully created. @@ -32,44 +72,26 @@ import { const useAutoCreateAdsMCAccounts = () => { const lockedRef = useRef( false ); // Create separate states. - const [ accountsCreated, setAccountsCreated ] = useState( false ); const [ creatingWhich, setCreatingWhich ] = useState( null ); const [ hasDetermined, setDetermined ] = useState( false ); const shouldCreateAds = useShouldCreateAdsAccount(); const shouldCreateMC = useShouldCreateMCAccount(); - const [ handleCreateAccount, { response } ] = useCreateMCAccount(); - const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount(); + const [ handleCreateAccount ] = useCreateMCAccount(); + const [ upsertAdsAccount ] = useUpsertAdsAccount(); useEffect( () => { if ( + // Wait for all determinations to be ready shouldCreateMC === null || shouldCreateAds === null || - accountsCreated + // Avoid repeated calls + lockedRef.current ) { return; } - if ( lockedRef.current && !! creatingWhich ) { - const mcAccountCreated = !! response?.status; - - const resetState = - ( creatingWhich === CREATING_ADS_ACCOUNT && ! loading ) || - ( creatingWhich === CREATING_MC_ACCOUNT && mcAccountCreated ) || - ( creatingWhich === CREATING_BOTH_ACCOUNTS && - mcAccountCreated && - ! loading ); - - if ( resetState ) { - lockedRef.current = false; - setAccountsCreated( true ); - setCreatingWhich( null ); - } - - return; - } - let which = null; lockedRef.current = true; @@ -90,29 +112,26 @@ const useAutoCreateAdsMCAccounts = () => { if ( which === CREATING_BOTH_ACCOUNTS ) { await handleCreateAccount(); await upsertAdsAccount(); + setCreatingWhich( null ); } else if ( which === CREATING_MC_ACCOUNT ) { await handleCreateAccount(); + setCreatingWhich( null ); } else if ( which === CREATING_ADS_ACCOUNT ) { await upsertAdsAccount(); + setCreatingWhich( null ); } }; handleCreateAccountCallback(); - setCreatingWhich( which ); } }, [ - accountsCreated, - creatingWhich, handleCreateAccount, - loading, - response?.status, shouldCreateAds, shouldCreateMC, upsertAdsAccount, ] ); return { - accountsCreated, hasDetermined, creatingWhich, }; diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index 7c44710362..bad8d3a858 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -1,21 +1,25 @@ /** * External dependencies */ -import { renderHook } from '@testing-library/react'; +import { act, renderHook } from '@testing-library/react'; /** * Internal dependencies */ import useAutoCreateAdsMCAccounts from './useAutoCreateAdsMCAccounts'; +import useGoogleAdsAccount from './useGoogleAdsAccount'; +import useExistingGoogleAdsAccounts from './useExistingGoogleAdsAccounts'; +import useGoogleMCAccount from './useGoogleMCAccount'; +import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; import useCreateMCAccount from './useCreateMCAccount'; import useUpsertAdsAccount from './useUpsertAdsAccount'; -import useShouldCreateAdsAccount from './useShouldCreateAdsAccount'; -import useShouldCreateMCAccount from './useShouldCreateMCAccount'; jest.mock( './useCreateMCAccount' ); jest.mock( './useUpsertAdsAccount' ); -jest.mock( './useShouldCreateAdsAccount' ); -jest.mock( './useShouldCreateMCAccount' ); +jest.mock( './useGoogleAdsAccount' ); +jest.mock( './useExistingGoogleAdsAccounts' ); +jest.mock( './useGoogleMCAccount' ); +jest.mock( './useExistingGoogleMCAccounts' ); describe( 'useAutoCreateAdsMCAccounts hook', () => { let handleCreateAccount; @@ -25,8 +29,25 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { handleCreateAccount = jest.fn( () => Promise.resolve() ); upsertAdsAccount = jest.fn( () => Promise.resolve() ); - useShouldCreateAdsAccount.mockReturnValue( true ); - useShouldCreateMCAccount.mockReturnValue( true ); + useGoogleAdsAccount.mockReturnValue( { + hasFinishedResolution: true, + hasGoogleAdsConnection: false, + } ); + + useExistingGoogleAdsAccounts.mockReturnValue( { + hasFinishedResolution: true, + existingAccounts: [], + } ); + + useGoogleMCAccount.mockReturnValue( { + hasFinishedResolution: true, + hasGoogleMCConnection: false, + } ); + + useExistingGoogleMCAccounts.mockReturnValue( { + hasFinishedResolution: true, + data: [], + } ); } ); describe( 'Automatic account creation', () => { @@ -41,32 +62,75 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { ] ); } ); - it( 'should create both accounts', () => { + it( 'should create both accounts', async () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - // It should create both accounts. - expect( result.current.creatingWhich ).toBe( 'both' ); + await act( async () => { + // It should create both accounts. + expect( result.current.creatingWhich ).toBe( 'both' ); + } ); } ); - it( 'should create only the Merchant Center account', () => { - useShouldCreateAdsAccount.mockReturnValue( false ); + it( 'should create only the Merchant Center account', async () => { + useExistingGoogleAdsAccounts.mockReturnValue( { + hasFinishedResolution: true, + existingAccounts: [ + { + id: '1234', + name: 'Test Account', + }, + ], + } ); + const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should create only the Merchant Center account. - expect( result.current.creatingWhich ).toBe( 'mc' ); + await act( async () => { + // It should create both accounts. + expect( result.current.creatingWhich ).toBe( 'mc' ); + } ); } ); - it( 'should create only the Google Ads account', () => { - useShouldCreateMCAccount.mockReturnValue( false ); + it( 'should create only the Google Ads account', async () => { + useExistingGoogleMCAccounts.mockReturnValue( { + hasFinishedResolution: true, + data: [ + { + id: '12345', + name: 'Test Account', + }, + ], + } ); + const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); // It should create only the Google Ads account. - expect( result.current.creatingWhich ).toBe( 'ads' ); + await act( async () => { + expect( result.current.creatingWhich ).toBe( 'ads' ); + } ); } ); } ); describe( 'Existing accounts', () => { beforeEach( () => { - useShouldCreateAdsAccount.mockReturnValue( false ); - useShouldCreateMCAccount.mockReturnValue( false ); + // Existing Ads and MC accounts. + useExistingGoogleAdsAccounts.mockReturnValue( { + hasFinishedResolution: true, + existingAccounts: [ + { + id: '1234', + name: 'Test Account', + }, + ], + } ); + + useExistingGoogleMCAccounts.mockReturnValue( { + hasFinishedResolution: true, + data: [ + { + id: '12345', + name: 'Test Account', + }, + ], + } ); } ); it( 'should not create accounts if they already exist', () => { diff --git a/js/src/components/google-combo-account-card/useAccountCreationText.js b/js/src/utils/getAccountCreationTexts.js similarity index 90% rename from js/src/components/google-combo-account-card/useAccountCreationText.js rename to js/src/utils/getAccountCreationTexts.js index dec6dd1c19..1873aad120 100644 --- a/js/src/components/google-combo-account-card/useAccountCreationText.js +++ b/js/src/utils/getAccountCreationTexts.js @@ -10,14 +10,14 @@ import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, -} from './constants'; +} from '../components/google-combo-account-card/constants'; /** * Account creation in progress description. * @param {string|null} creatingWhich Which account is being created. * @return {Object} Text and subtext. */ -const useAccountCreationText = ( creatingWhich ) => { +const getAccountCreationTexts = ( creatingWhich ) => { let text = null; let subText = null; @@ -62,4 +62,4 @@ const useAccountCreationText = ( creatingWhich ) => { }; }; -export default useAccountCreationText; +export default getAccountCreationTexts; From e74b5e3bf5c3113f408f16ca722f74e65c044a28 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 17:54:36 +0530 Subject: [PATCH 73/91] Style changes. --- .../google-combo-account-card/account-details.js | 4 ++-- .../connected-google-combo-account-card.js | 10 ++-------- .../connected-google-combo-account-card.scss | 7 ++----- .../components/google-combo-account-card/indicator.js | 6 +++--- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/js/src/components/google-combo-account-card/account-details.js b/js/src/components/google-combo-account-card/account-details.js index 4f10f34d75..32a8b2d500 100644 --- a/js/src/components/google-combo-account-card/account-details.js +++ b/js/src/components/google-combo-account-card/account-details.js @@ -20,7 +20,7 @@ const AccountDetails = () => { const { googleMCAccount } = useGoogleMCAccount(); return ( -
+ <>

{ google.email }

{ sprintf( @@ -36,7 +36,7 @@ const AccountDetails = () => { googleAdsAccount.id ) }

-
+ ); }; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 0376a91e9d..bd12ae303d 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -51,11 +51,7 @@ const ConnectedGoogleComboAccountCard = () => { !! googleAdsAccount?.id && !! googleMCAccount?.id; - const displayAccountDetails = - wasCreatingAccounts && - accountsCreated && - accountDetailsResolved && - accountsReady; + const displayAccountDetails = accountDetailsResolved && accountsReady; useEffect( () => { if ( creatingWhich ) { @@ -80,9 +76,7 @@ const ConnectedGoogleComboAccountCard = () => { className="gla-google-combo-account-card--connected" description={ ! displayAccountDetails ? text : } helper={ ! displayAccountDetails ? subText : null } - indicator={ - - } + indicator={ } /> ); }; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss index e3e6949c9d..7d9cd284c1 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss @@ -1,9 +1,6 @@ .gla-google-combo-account-card--connected { - .gla-account-card__account_details { - - p { - margin: 0.5em 0; - } + .gla-account-card__description { + gap: 0.6em; } } diff --git a/js/src/components/google-combo-account-card/indicator.js b/js/src/components/google-combo-account-card/indicator.js index 35e089b96c..8775bc0c22 100644 --- a/js/src/components/google-combo-account-card/indicator.js +++ b/js/src/components/google-combo-account-card/indicator.js @@ -15,10 +15,10 @@ import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; * Account creation indicator. * Displays a loading indicator when accounts are being created or a connected icon when accounts are connected. * @param {Object} props Component props. - * @param {boolean} props.creatingAccounts Whether the accounts are being created. + * @param {boolean} props.showSpinner Whether to display a spinner. * @return {JSX.Element|null} Indicator component. */ -const Indicator = ( { creatingAccounts } ) => { +const Indicator = ( { showSpinner } ) => { const { googleMCAccount, isPreconditionReady } = useGoogleMCAccount(); const isGoogleAdsConnected = useGoogleAdsAccountReady(); @@ -28,7 +28,7 @@ const Indicator = ( { creatingAccounts } ) => { ( googleMCAccount?.status === 'incomplete' && googleMCAccount?.step === 'link_ads' ) ); - if ( creatingAccounts ) { + if ( showSpinner ) { return ( Date: Wed, 23 Oct 2024 17:57:44 +0530 Subject: [PATCH 74/91] Remove unnecessary files. --- js/src/hooks/useShouldCreateAdsAccount.js | 32 ----------------------- js/src/hooks/useShouldCreateMCAccount.js | 32 ----------------------- 2 files changed, 64 deletions(-) delete mode 100644 js/src/hooks/useShouldCreateAdsAccount.js delete mode 100644 js/src/hooks/useShouldCreateMCAccount.js diff --git a/js/src/hooks/useShouldCreateAdsAccount.js b/js/src/hooks/useShouldCreateAdsAccount.js deleted file mode 100644 index 6b390d9f23..0000000000 --- a/js/src/hooks/useShouldCreateAdsAccount.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Internal dependencies - */ -import useGoogleAdsAccount from './useGoogleMCAccount'; -import useExistingGoogleAdsAccounts from './useExistingGoogleMCAccounts'; - -/** - * Hook to determine if a Google Ads account should be created. - * This is based on whether the user has any existing Google Ads accounts and if they have a connection to Google Ads. - * If the user has no existing accounts and no connection, a new ads account should be created. - * @return {boolean} Whether a new Google Ads account should be created. - */ -const useShouldCreateAdsAccount = () => { - const { - hasFinishedResolution: hasResolvedAccount, - hasGoogleAdsConnection: hasConnection, - } = useGoogleAdsAccount(); - - const { - hasFinishedResolution: hasResolvedExistingAccounts, - data: accounts, - } = useExistingGoogleAdsAccounts(); - - // Return null if the account hasn't been resolved or the existing accounts haven't been resolved - if ( ! hasResolvedAccount || ! hasResolvedExistingAccounts ) { - return null; - } - - return ! hasConnection && accounts?.length === 0; -}; - -export default useShouldCreateAdsAccount; diff --git a/js/src/hooks/useShouldCreateMCAccount.js b/js/src/hooks/useShouldCreateMCAccount.js deleted file mode 100644 index 9c0673eaea..0000000000 --- a/js/src/hooks/useShouldCreateMCAccount.js +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Internal dependencies - */ -import useGoogleMCAccount from './useGoogleMCAccount'; -import useExistingGoogleMCAccounts from './useExistingGoogleMCAccounts'; - -/** - * Hook to determine if a Merchant Center account should be created. - * This is based on whether the user has any existing Merchant Center accounts and if they have a connection to Merchant Center. - * If the user has no existing accounts and no connection, a new account should be created. - * @return {boolean} Whether a new Merchant Center account should be created. - */ -const useShouldCreateMCAccount = () => { - const { - hasFinishedResolution: hasResolvedAccount, - hasGoogleMCConnection: hasConnection, - } = useGoogleMCAccount(); - - const { - hasFinishedResolution: hasResolvedExistingAccounts, - data: accounts, - } = useExistingGoogleMCAccounts(); - - // Return null if the account hasn't been resolved or the existing accounts haven't been resolved - if ( ! hasResolvedAccount || ! hasResolvedExistingAccounts ) { - return null; - } - - return ! hasConnection && accounts?.length === 0; -}; - -export default useShouldCreateMCAccount; From 18256f34148a2a8a65af749023529efcd1eacac1 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 20:48:28 +0530 Subject: [PATCH 75/91] Update display account details logic. --- .../connected-google-combo-account-card.js | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index bd12ae303d..5d04642099 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -25,15 +25,11 @@ const ConnectedGoogleComboAccountCard = () => { const [ wasCreatingAccounts, setWasCreatingAccounts ] = useState( undefined ); - const { - googleAdsAccount, - hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount, - } = useGoogleAdsAccount(); + const { hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount } = + useGoogleAdsAccount(); - const { - googleMCAccount, - hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount, - } = useGoogleMCAccount(); + const { hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount } = + useGoogleMCAccount(); const { hasDetermined, creatingWhich } = useAutoCreateAdsMCAccounts(); const { text, subText } = getAccountCreationTexts( wasCreatingAccounts ); @@ -43,24 +39,16 @@ const ConnectedGoogleComboAccountCard = () => { hasFinishedResolutionForCurrentAdsAccount && hasFinishedResolutionForCurrentMCAccount; - const accountsCreated = - wasCreatingAccounts !== undefined && ! creatingWhich; - - const accountsReady = - accountDetailsResolved && - !! googleAdsAccount?.id && - !! googleMCAccount?.id; - - const displayAccountDetails = accountDetailsResolved && accountsReady; + const displayAccountDetails = + accountDetailsResolved && wasCreatingAccounts === null; useEffect( () => { - if ( creatingWhich ) { + if ( hasDetermined ) { setWasCreatingAccounts( creatingWhich ); } - }, [ creatingWhich ] ); + }, [ creatingWhich, hasDetermined ] ); if ( - ! accountsCreated && wasCreatingAccounts === undefined && ( ! hasDetermined || ! hasFinishedResolutionForCurrentAdsAccount || From 7a9854b05d58405a66b53bb8f3d5ada96b92f787 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 23:40:02 +0530 Subject: [PATCH 76/91] Add useGoogleMCAccountReady hook. --- js/src/hooks/useGoogleMCAccountReady.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 js/src/hooks/useGoogleMCAccountReady.js diff --git a/js/src/hooks/useGoogleMCAccountReady.js b/js/src/hooks/useGoogleMCAccountReady.js new file mode 100644 index 0000000000..a19128a1b0 --- /dev/null +++ b/js/src/hooks/useGoogleMCAccountReady.js @@ -0,0 +1,17 @@ +/** + * Internal dependencies + */ +import useGoogleMCAccount from './useGoogleMCAccount'; +import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; + +const useGoogleMCAccountReady = () => { + const { googleMCAccount } = useGoogleMCAccount(); + + return ( + googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || + ( googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && + googleMCAccount?.step === 'link_ads' ) + ); +}; + +export default useGoogleMCAccountReady; From 2859cf56aeae23067101b4675703310ce711d19d Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Wed, 23 Oct 2024 23:40:21 +0530 Subject: [PATCH 77/91] Update account details rendering logic. --- .../account-details.js | 25 +++++++++++-------- .../connected-google-combo-account-card.js | 2 +- .../connected-google-combo-account-card.scss | 2 +- .../getAccountCreationTexts.js | 2 +- .../google-combo-account-card/indicator.js | 10 ++------ .../setup-stepper/setup-accounts/index.js | 14 ++++------- 6 files changed, 25 insertions(+), 30 deletions(-) rename js/src/{utils => components/google-combo-account-card}/getAccountCreationTexts.js (96%) diff --git a/js/src/components/google-combo-account-card/account-details.js b/js/src/components/google-combo-account-card/account-details.js index 32a8b2d500..40f81bcf74 100644 --- a/js/src/components/google-combo-account-card/account-details.js +++ b/js/src/components/google-combo-account-card/account-details.js @@ -23,18 +23,23 @@ const AccountDetails = () => { <>

{ google.email }

- { sprintf( - // Translators: %s is the Merchant Center ID - __( 'Merchant Center ID: %s', 'google-listings-and-ads' ), - googleMCAccount.id - ) } + { googleMCAccount.id > 0 && + sprintf( + // Translators: %s is the Merchant Center ID + __( + 'Merchant Center ID: %s', + 'google-listings-and-ads' + ), + googleMCAccount.id + ) }

- { sprintf( - // Translators: %s is the Google Ads ID - __( 'Google Ads ID: %s', 'google-listings-and-ads' ), - googleAdsAccount.id - ) } + { googleAdsAccount.id > 0 && + sprintf( + // Translators: %s is the Google Ads ID + __( 'Google Ads ID: %s', 'google-listings-and-ads' ), + googleAdsAccount.id + ) }

); diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 5d04642099..a7f0b68a5f 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -10,7 +10,7 @@ import AccountCard, { APPEARANCE } from '../account-card'; import AccountDetails from './account-details'; import AppSpinner from '../app-spinner'; import Indicator from './indicator'; -import getAccountCreationTexts from '.~/utils/getAccountCreationTexts'; +import getAccountCreationTexts from './getAccountCreationTexts'; import useAutoCreateAdsMCAccounts from '.~/hooks/useAutoCreateAdsMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss index 7d9cd284c1..9c65e53adf 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.scss @@ -1,6 +1,6 @@ .gla-google-combo-account-card--connected { .gla-account-card__description { - gap: 0.6em; + gap: 0; } } diff --git a/js/src/utils/getAccountCreationTexts.js b/js/src/components/google-combo-account-card/getAccountCreationTexts.js similarity index 96% rename from js/src/utils/getAccountCreationTexts.js rename to js/src/components/google-combo-account-card/getAccountCreationTexts.js index 1873aad120..accf7da2bb 100644 --- a/js/src/utils/getAccountCreationTexts.js +++ b/js/src/components/google-combo-account-card/getAccountCreationTexts.js @@ -10,7 +10,7 @@ import { CREATING_ADS_ACCOUNT, CREATING_BOTH_ACCOUNTS, CREATING_MC_ACCOUNT, -} from '../components/google-combo-account-card/constants'; +} from './constants'; /** * Account creation in progress description. diff --git a/js/src/components/google-combo-account-card/indicator.js b/js/src/components/google-combo-account-card/indicator.js index 8775bc0c22..dcbb293509 100644 --- a/js/src/components/google-combo-account-card/indicator.js +++ b/js/src/components/google-combo-account-card/indicator.js @@ -8,8 +8,8 @@ import { __ } from '@wordpress/i18n'; */ import ConnectedIconLabel from '.~/components/connected-icon-label'; import LoadingLabel from '.~/components/loading-label/loading-label'; -import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; +import useGoogleMCAccountReady from '.~/hooks/useGoogleMCAccountReady'; /** * Account creation indicator. @@ -19,14 +19,8 @@ import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; * @return {JSX.Element|null} Indicator component. */ const Indicator = ( { showSpinner } ) => { - const { googleMCAccount, isPreconditionReady } = useGoogleMCAccount(); const isGoogleAdsConnected = useGoogleAdsAccountReady(); - - const isGoogleMCConnected = - isPreconditionReady && - ( googleMCAccount?.status === 'connected' || - ( googleMCAccount?.status === 'incomplete' && - googleMCAccount?.step === 'link_ads' ) ); + const isGoogleMCConnected = useGoogleMCAccountReady(); if ( showSpinner ) { return ( diff --git a/js/src/setup-mc/setup-stepper/setup-accounts/index.js b/js/src/setup-mc/setup-stepper/setup-accounts/index.js index 534b4de7f5..58d8658884 100644 --- a/js/src/setup-mc/setup-stepper/setup-accounts/index.js +++ b/js/src/setup-mc/setup-stepper/setup-accounts/index.js @@ -25,6 +25,7 @@ import Faqs from './faqs'; import './index.scss'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; +import useGoogleMCAccountReady from '.~/hooks/useGoogleMCAccountReady'; /** * Renders the disclaimer of Comparison Shopping Service (CSS). @@ -87,6 +88,10 @@ const SetupAccounts = ( props ) => { useGoogleMCAccount(); const { hasFinishedResolution } = useGoogleAdsAccount(); const isGoogleAdsReady = useGoogleAdsAccountReady(); + // MC is ready when we have a connection and preconditions are met. + // The `link_ads` step will be resolved when the Ads account is connected + // since these can be connected in any order. + const isGoogleMCReady = useGoogleMCAccountReady(); /** * When jetpack is loading, or when google account is loading, @@ -109,15 +114,6 @@ const SetupAccounts = ( props ) => { return ; } - // MC is ready when we have a connection and preconditions are met. - // The `link_ads` step will be resolved when the Ads account is connected - // since these can be connected in any order. - const isGoogleMCReady = - isGMCPreconditionReady && - ( googleMCAccount?.status === 'connected' || - ( googleMCAccount?.status === 'incomplete' && - googleMCAccount?.step === 'link_ads' ) ); - const isContinueButtonDisabled = ! ( hasFinishedResolution && isGoogleAdsReady && From 7a24be5528f90b7048d27f878fc1a3a04429a66b Mon Sep 17 00:00:00 2001 From: Joe McGill <801097+joemcgill@users.noreply.github.com> Date: Wed, 23 Oct 2024 14:34:16 -0500 Subject: [PATCH 78/91] Tweak useGoogleMCAccountReady hook --- js/src/hooks/useGoogleMCAccountReady.js | 10 ++++++---- js/src/setup-mc/setup-stepper/setup-accounts/index.js | 3 --- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/js/src/hooks/useGoogleMCAccountReady.js b/js/src/hooks/useGoogleMCAccountReady.js index a19128a1b0..0b04fa6fd2 100644 --- a/js/src/hooks/useGoogleMCAccountReady.js +++ b/js/src/hooks/useGoogleMCAccountReady.js @@ -5,12 +5,14 @@ import useGoogleMCAccount from './useGoogleMCAccount'; import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; const useGoogleMCAccountReady = () => { - const { googleMCAccount } = useGoogleMCAccount(); + const { hasGoogleMCConnection, googleMCAccount } = useGoogleMCAccount(); + // MC is ready when we have a connection and preconditions are met. + // The `link_ads` step will be resolved when the Ads account is connected + // since these can be connected in any order. return ( - googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || - ( googleMCAccount?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && - googleMCAccount?.step === 'link_ads' ) + hasGoogleMCConnection && + [ '', 'link_merchant' ].includes( googleMCAccount?.step ) ); }; diff --git a/js/src/setup-mc/setup-stepper/setup-accounts/index.js b/js/src/setup-mc/setup-stepper/setup-accounts/index.js index 58d8658884..69cbb4588c 100644 --- a/js/src/setup-mc/setup-stepper/setup-accounts/index.js +++ b/js/src/setup-mc/setup-stepper/setup-accounts/index.js @@ -88,9 +88,6 @@ const SetupAccounts = ( props ) => { useGoogleMCAccount(); const { hasFinishedResolution } = useGoogleAdsAccount(); const isGoogleAdsReady = useGoogleAdsAccountReady(); - // MC is ready when we have a connection and preconditions are met. - // The `link_ads` step will be resolved when the Ads account is connected - // since these can be connected in any order. const isGoogleMCReady = useGoogleMCAccountReady(); /** From e62562f5d5cff90ea3c06e13702fc444bbc37654 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Wed, 23 Oct 2024 14:37:09 -0500 Subject: [PATCH 79/91] Remove unused constant --- js/src/hooks/useGoogleMCAccountReady.js | 1 - 1 file changed, 1 deletion(-) diff --git a/js/src/hooks/useGoogleMCAccountReady.js b/js/src/hooks/useGoogleMCAccountReady.js index 0b04fa6fd2..a2189b62e3 100644 --- a/js/src/hooks/useGoogleMCAccountReady.js +++ b/js/src/hooks/useGoogleMCAccountReady.js @@ -2,7 +2,6 @@ * Internal dependencies */ import useGoogleMCAccount from './useGoogleMCAccount'; -import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; const useGoogleMCAccountReady = () => { const { hasGoogleMCConnection, googleMCAccount } = useGoogleMCAccount(); From bd1f3e3e77b4f9828179841d9e8fd769074b0522 Mon Sep 17 00:00:00 2001 From: Joe McGill Date: Wed, 23 Oct 2024 14:46:23 -0500 Subject: [PATCH 80/91] Clean up E2E tests for account creation This removes the unnecessary `SetupAdsAccountPage` from the E2E tests, since they were only being used for mocking and both `SetupAdsAccountPage` and `SetUpAccountsPage` extend the same mocking library. --- .../specs/setup-mc/step-1-accounts.test.js | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 9ea9a0b866..0d41293cc0 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -2,7 +2,6 @@ * Internal dependencies */ import SetUpAccountsPage from '../../utils/pages/setup-mc/step-1-set-up-accounts'; -import SetupAdsAccountPage from '../../utils/pages/setup-ads/setup-ads-accounts'; import { LOAD_STATE } from '../../utils/constants'; import { getFAQPanelTitle, @@ -24,11 +23,6 @@ test.describe.configure( { mode: 'serial' } ); */ let setUpAccountsPage = null; -/** - * @type {import('../../utils/pages/setup-ads/setup-ads-accounts.js').default} setupAdsAccountPage - */ -let setupAdsAccountPage = null; - /** * @type {import('@playwright/test').Page} page */ @@ -38,7 +32,6 @@ test.describe( 'Set up accounts', () => { test.beforeAll( async ( { browser } ) => { page = await browser.newPage(); setUpAccountsPage = new SetUpAccountsPage( page ); - setupAdsAccountPage = new SetupAdsAccountPage( page ); } ); test.afterAll( async () => { @@ -222,10 +215,10 @@ test.describe( 'Set up accounts', () => { test( 'should create merchant center and ads account if does not exist for the user', async () => { await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); - await setupAdsAccountPage.mockAdsAccountDisconnected(); + await setUpAccountsPage.mockAdsAccountDisconnected(); await setUpAccountsPage.mockMCNotConnected(); - await setupAdsAccountPage.fulfillAdsAccounts( + await setUpAccountsPage.fulfillAdsAccounts( [ [], [ @@ -240,7 +233,7 @@ test.describe( 'Set up accounts', () => { true ); - await setupAdsAccountPage.fulfillMCAccounts( + await setUpAccountsPage.fulfillMCAccounts( [ [], [ @@ -319,7 +312,7 @@ test.describe( 'Set up accounts', () => { await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); await setUpAccountsPage.mockMCConnected(); - await setupAdsAccountPage.mockAdsAccountConnected(); + await setUpAccountsPage.mockAdsAccountConnected(); await setUpAccountsPage.goto(); } ); @@ -371,7 +364,7 @@ test.describe( 'Set up accounts', () => { test.describe( 'When only Ads is connected', async () => { test.beforeAll( async () => { - await setupAdsAccountPage.mockAdsAccountConnected(); + await setUpAccountsPage.mockAdsAccountConnected(); await setUpAccountsPage.mockMCNotConnected(); await setUpAccountsPage.goto(); @@ -386,7 +379,7 @@ test.describe( 'Set up accounts', () => { test.describe( 'When only MC is connected', async () => { test.beforeAll( async () => { - await setupAdsAccountPage.mockAdsAccountDisconnected(); + await setUpAccountsPage.mockAdsAccountDisconnected(); await setUpAccountsPage.mockMCConnected(); await setUpAccountsPage.goto(); @@ -401,10 +394,10 @@ test.describe( 'Set up accounts', () => { test.describe( 'When all accounts are connected', async () => { test.beforeAll( async () => { - await setupAdsAccountPage.mockJetpackConnected(); + await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); - await setupAdsAccountPage.mockAdsAccountConnected(); - await setupAdsAccountPage.mockAdsStatusClaimed(); + await setUpAccountsPage.mockAdsAccountConnected(); + await setUpAccountsPage.mockAdsStatusClaimed(); await setUpAccountsPage.mockMCConnected(); await setUpAccountsPage.goto(); From 56a2e155988f048da0032fc70997b0244c93c27c Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 24 Oct 2024 12:02:37 +0530 Subject: [PATCH 81/91] Fix: E2E test. --- tests/e2e/specs/setup-mc/step-1-accounts.test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 0d41293cc0..d4018a9d87 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -337,6 +337,10 @@ test.describe( 'Set up accounts', () => { const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); + const cardBody = googleAccountCard.locator( + '.gla-google-combo-account-card--connected' + ); + await setUpAccountsPage.fulfillAdsAccountStatus( { has_access: true, invite_link: '', @@ -344,7 +348,7 @@ test.describe( 'Set up accounts', () => { } ); await expect( - googleAccountCard.getByText( 'Connected', { exact: true } ) + cardBody.getByText( 'Connected', { exact: true } ) ).toBeVisible(); } ); } ); From 599c2d209707ce06f382fd82e0c181bd04543e46 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 24 Oct 2024 14:07:18 +0530 Subject: [PATCH 82/91] E2E tests changs for new hook. --- js/src/hooks/useGoogleMCAccountReady.js | 2 +- .../specs/setup-mc/step-1-accounts.test.js | 24 ++++++++++++------- tests/e2e/utils/mock-requests.js | 2 ++ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/js/src/hooks/useGoogleMCAccountReady.js b/js/src/hooks/useGoogleMCAccountReady.js index a2189b62e3..1a2505620d 100644 --- a/js/src/hooks/useGoogleMCAccountReady.js +++ b/js/src/hooks/useGoogleMCAccountReady.js @@ -11,7 +11,7 @@ const useGoogleMCAccountReady = () => { // since these can be connected in any order. return ( hasGoogleMCConnection && - [ '', 'link_merchant' ].includes( googleMCAccount?.step ) + [ '', 'link_ads' ].includes( googleMCAccount?.step ) ); }; diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index d4018a9d87..899c905228 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -337,18 +337,23 @@ test.describe( 'Set up accounts', () => { const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); - const cardBody = googleAccountCard.locator( - '.gla-google-combo-account-card--connected' - ); - await setUpAccountsPage.fulfillAdsAccountStatus( { has_access: true, invite_link: '', step: 'link_merchant', } ); + await setUpAccountsPage.fulfillMCConnection( { + id: 1234, + name: 'Test Merchant Center', + subaccount: null, + domain: 'example.com', + status: 'connected', + step: '', + } ); + await expect( - cardBody.getByText( 'Connected', { exact: true } ) + googleAccountCard.getByText( 'Connected', { exact: true } ) ).toBeVisible(); } ); } ); @@ -398,12 +403,15 @@ test.describe( 'Set up accounts', () => { test.describe( 'When all accounts are connected', async () => { test.beforeAll( async () => { - await setUpAccountsPage.mockJetpackConnected(); - await setUpAccountsPage.mockGoogleConnected(); await setUpAccountsPage.mockAdsAccountConnected(); - await setUpAccountsPage.mockAdsStatusClaimed(); await setUpAccountsPage.mockMCConnected(); + await setUpAccountsPage.fulfillAdsAccountStatus( { + has_access: true, + invite_link: '', + step: 'link_merchant', + } ); + await setUpAccountsPage.goto(); } ); diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index bf1f2e5dfb..2b857f09ab 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -601,6 +601,7 @@ export default class MockRequests { currency: 'TWD', symbol: 'NT$', status: 'connected', + step: '', } ); } @@ -638,6 +639,7 @@ export default class MockRequests { status: 'connected', notification_service_enabled: notificationServiceEnabled, wpcom_rest_api_status: wpcomRestApiStatus, + step: '', } ); } From f3f63fe1afc8e6f683e973770dca250701b0bedf Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 24 Oct 2024 20:14:50 +0530 Subject: [PATCH 83/91] CR feedback. --- .../connected-google-combo-account-card.js | 4 ++-- .../google-combo-account-card/indicator.js | 4 ++-- js/src/hooks/useAutoCreateAdsMCAccounts.js | 6 +----- .../hooks/useAutoCreateAdsMCAccounts.test.js | 17 +++++++++-------- js/src/hooks/useGoogleAdsAccountReady.js | 16 ++++++++++------ js/src/hooks/useGoogleMCAccount.js | 11 +++++++++++ js/src/hooks/useGoogleMCAccountReady.js | 18 ------------------ .../setup-stepper/setup-accounts/index.js | 9 +++++---- 8 files changed, 40 insertions(+), 45 deletions(-) delete mode 100644 js/src/hooks/useGoogleMCAccountReady.js diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index a7f0b68a5f..bbc96c8f94 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -8,9 +8,9 @@ import { useEffect, useState } from '@wordpress/element'; */ import AccountCard, { APPEARANCE } from '../account-card'; import AccountDetails from './account-details'; -import AppSpinner from '../app-spinner'; import Indicator from './indicator'; import getAccountCreationTexts from './getAccountCreationTexts'; +import SpinnerCard from '.~/components/spinner-card'; import useAutoCreateAdsMCAccounts from '.~/hooks/useAutoCreateAdsMCAccounts'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; @@ -54,7 +54,7 @@ const ConnectedGoogleComboAccountCard = () => { ! hasFinishedResolutionForCurrentAdsAccount || ! hasFinishedResolutionForCurrentMCAccount ) ) { - return } />; + return ; } return ( diff --git a/js/src/components/google-combo-account-card/indicator.js b/js/src/components/google-combo-account-card/indicator.js index dcbb293509..5a65c0b6b7 100644 --- a/js/src/components/google-combo-account-card/indicator.js +++ b/js/src/components/google-combo-account-card/indicator.js @@ -9,7 +9,7 @@ import { __ } from '@wordpress/i18n'; import ConnectedIconLabel from '.~/components/connected-icon-label'; import LoadingLabel from '.~/components/loading-label/loading-label'; import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; -import useGoogleMCAccountReady from '.~/hooks/useGoogleMCAccountReady'; +import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; /** * Account creation indicator. @@ -20,7 +20,7 @@ import useGoogleMCAccountReady from '.~/hooks/useGoogleMCAccountReady'; */ const Indicator = ( { showSpinner } ) => { const isGoogleAdsConnected = useGoogleAdsAccountReady(); - const isGoogleMCConnected = useGoogleMCAccountReady(); + const { isReady: isGoogleMCConnected } = useGoogleMCAccount(); if ( showSpinner ) { return ( diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.js b/js/src/hooks/useAutoCreateAdsMCAccounts.js index 6bccf39a1b..e295f263bb 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.js @@ -58,7 +58,6 @@ const useShouldCreateMCAccount = () => { /** * @typedef {Object} AutoCreateAdsMCAccountsData - * @property {boolean} accountsCreated - Whether the accounts have been successfully created. * @property {boolean} hasDetermined - Whether the checks to determine if accounts should be created are finished. * @property {('ads'|'mc'|'both'|null)} creatingWhich - Which accounts are being created ('ads', 'mc', 'both'), or `null` if none. */ @@ -71,7 +70,6 @@ const useShouldCreateMCAccount = () => { */ const useAutoCreateAdsMCAccounts = () => { const lockedRef = useRef( false ); - // Create separate states. const [ creatingWhich, setCreatingWhich ] = useState( null ); const [ hasDetermined, setDetermined ] = useState( false ); @@ -112,14 +110,12 @@ const useAutoCreateAdsMCAccounts = () => { if ( which === CREATING_BOTH_ACCOUNTS ) { await handleCreateAccount(); await upsertAdsAccount(); - setCreatingWhich( null ); } else if ( which === CREATING_MC_ACCOUNT ) { await handleCreateAccount(); - setCreatingWhich( null ); } else if ( which === CREATING_ADS_ACCOUNT ) { await upsertAdsAccount(); - setCreatingWhich( null ); } + setCreatingWhich( null ); }; handleCreateAccountCallback(); diff --git a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js index bad8d3a858..84c3ce5da5 100644 --- a/js/src/hooks/useAutoCreateAdsMCAccounts.test.js +++ b/js/src/hooks/useAutoCreateAdsMCAccounts.test.js @@ -66,9 +66,11 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); await act( async () => { - // It should create both accounts. expect( result.current.creatingWhich ).toBe( 'both' ); } ); + + expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); + expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); } ); it( 'should create only the Merchant Center account', async () => { @@ -83,11 +85,12 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - // It should create only the Merchant Center account. await act( async () => { - // It should create both accounts. expect( result.current.creatingWhich ).toBe( 'mc' ); } ); + + expect( handleCreateAccount ).toHaveBeenCalledTimes( 1 ); + expect( upsertAdsAccount ).toHaveBeenCalledTimes( 0 ); } ); it( 'should create only the Google Ads account', async () => { @@ -102,16 +105,17 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { } ); const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - // It should create only the Google Ads account. await act( async () => { expect( result.current.creatingWhich ).toBe( 'ads' ); } ); + + expect( handleCreateAccount ).toHaveBeenCalledTimes( 0 ); + expect( upsertAdsAccount ).toHaveBeenCalledTimes( 1 ); } ); } ); describe( 'Existing accounts', () => { beforeEach( () => { - // Existing Ads and MC accounts. useExistingGoogleAdsAccounts.mockReturnValue( { hasFinishedResolution: true, existingAccounts: [ @@ -136,10 +140,7 @@ describe( 'useAutoCreateAdsMCAccounts hook', () => { it( 'should not create accounts if they already exist', () => { const { result } = renderHook( () => useAutoCreateAdsMCAccounts() ); - // It should not create any accounts. expect( result.current.creatingWhich ).toBe( null ); - - // make sure functions are not called. expect( handleCreateAccount ).not.toHaveBeenCalled(); expect( upsertAdsAccount ).not.toHaveBeenCalled(); } ); diff --git a/js/src/hooks/useGoogleAdsAccountReady.js b/js/src/hooks/useGoogleAdsAccountReady.js index 0b6de9cd4a..cb95e06145 100644 --- a/js/src/hooks/useGoogleAdsAccountReady.js +++ b/js/src/hooks/useGoogleAdsAccountReady.js @@ -4,18 +4,22 @@ import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; +/** + * Hook to check if the Google Ads account is ready. + * This is used to determine if the user can proceed to the next step. + * + * @return {boolean|null} Whether the Google Ads account is ready. `null` if the state is not yet determined. + */ const useGoogleAdsAccountReady = () => { const { hasGoogleAdsConnection } = useGoogleAdsAccount(); const { hasAccess, step } = useGoogleAdsAccountStatus(); - // Ads is ready when we have a connection and verified and verified access. - // Billing is not required, and the 'link_merchant' step will be resolved - // when the MC the account is connected. - return ( + const isReady = hasGoogleAdsConnection && hasAccess && - [ '', 'billing', 'link_merchant' ].includes( step ) - ); + [ '', 'billing', 'link_merchant' ].includes( step ); + + return isReady !== null ? isReady : null; }; export default useGoogleAdsAccountReady; diff --git a/js/src/hooks/useGoogleMCAccount.js b/js/src/hooks/useGoogleMCAccount.js index 255943f1a3..8dbf3a0fff 100644 --- a/js/src/hooks/useGoogleMCAccount.js +++ b/js/src/hooks/useGoogleMCAccount.js @@ -18,6 +18,8 @@ import { GOOGLE_MC_ACCOUNT_STATUS } from '.~/constants'; * @property {boolean} isResolving Whether resolution is in progress. * @property {boolean} hasFinishedResolution Whether resolution has completed. * @property {boolean} isPreconditionReady Whether the precondition of continued connection processing is fulfilled. + * @property {boolean} hasGoogleMCConnection Whether the user has a Google Merchant Center account connection established. + * @property {boolean} isReady Whether the user has a Google Merchant Center account is in connected state. */ const googleMCAccountSelector = 'getGoogleMCAccount'; @@ -46,6 +48,8 @@ const useGoogleMCAccount = () => { // has not been granted necessary access permissions for Google Merchant Center, then // the precondition doesn't meet. isPreconditionReady: false, + hasGoogleMCConnection: false, + isReady: false, }; } @@ -60,6 +64,12 @@ const useGoogleMCAccount = () => { GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE, ].includes( acc?.status ); + const isReady = + hasGoogleMCConnection && + ( acc.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || + ( acc.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && + acc?.step === 'link_ads' ) ); + return { googleMCAccount: acc, isResolving: isResolvingGoogleMCAccount, @@ -68,6 +78,7 @@ const useGoogleMCAccount = () => { ), isPreconditionReady: true, hasGoogleMCConnection, + isReady, }; }, [ diff --git a/js/src/hooks/useGoogleMCAccountReady.js b/js/src/hooks/useGoogleMCAccountReady.js deleted file mode 100644 index 1a2505620d..0000000000 --- a/js/src/hooks/useGoogleMCAccountReady.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Internal dependencies - */ -import useGoogleMCAccount from './useGoogleMCAccount'; - -const useGoogleMCAccountReady = () => { - const { hasGoogleMCConnection, googleMCAccount } = useGoogleMCAccount(); - - // MC is ready when we have a connection and preconditions are met. - // The `link_ads` step will be resolved when the Ads account is connected - // since these can be connected in any order. - return ( - hasGoogleMCConnection && - [ '', 'link_ads' ].includes( googleMCAccount?.step ) - ); -}; - -export default useGoogleMCAccountReady; diff --git a/js/src/setup-mc/setup-stepper/setup-accounts/index.js b/js/src/setup-mc/setup-stepper/setup-accounts/index.js index 69cbb4588c..cf200ed4df 100644 --- a/js/src/setup-mc/setup-stepper/setup-accounts/index.js +++ b/js/src/setup-mc/setup-stepper/setup-accounts/index.js @@ -25,7 +25,6 @@ import Faqs from './faqs'; import './index.scss'; import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady'; -import useGoogleMCAccountReady from '.~/hooks/useGoogleMCAccountReady'; /** * Renders the disclaimer of Comparison Shopping Service (CSS). @@ -84,11 +83,13 @@ const SetupAccounts = ( props ) => { const { onContinue = () => {} } = props; const { jetpack } = useJetpackAccount(); const { google, scope } = useGoogleAccount(); - const { googleMCAccount, isPreconditionReady: isGMCPreconditionReady } = - useGoogleMCAccount(); + const { + googleMCAccount, + isPreconditionReady: isGMCPreconditionReady, + isReady: isGoogleMCReady, + } = useGoogleMCAccount(); const { hasFinishedResolution } = useGoogleAdsAccount(); const isGoogleAdsReady = useGoogleAdsAccountReady(); - const isGoogleMCReady = useGoogleMCAccountReady(); /** * When jetpack is loading, or when google account is loading, From 72434e2553fce9d3f7518a6120307cde8d5d7d63 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 24 Oct 2024 21:04:29 +0530 Subject: [PATCH 84/91] Remove redundant code. --- .../connected-google-combo-account-card.js | 41 +++---------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index bbc96c8f94..55a46826c5 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -12,8 +12,6 @@ import Indicator from './indicator'; import getAccountCreationTexts from './getAccountCreationTexts'; import SpinnerCard from '.~/components/spinner-card'; import useAutoCreateAdsMCAccounts from '.~/hooks/useAutoCreateAdsMCAccounts'; -import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount'; -import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount'; import './connected-google-combo-account-card.scss'; /** @@ -21,39 +19,10 @@ import './connected-google-combo-account-card.scss'; * It will also kickoff Ads and Merchant Center account creation if the user does not have accounts. */ const ConnectedGoogleComboAccountCard = () => { - // Used to track whether the account creation ever happened. - const [ wasCreatingAccounts, setWasCreatingAccounts ] = - useState( undefined ); - - const { hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount } = - useGoogleAdsAccount(); - - const { hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount } = - useGoogleMCAccount(); - const { hasDetermined, creatingWhich } = useAutoCreateAdsMCAccounts(); - const { text, subText } = getAccountCreationTexts( wasCreatingAccounts ); - - const accountDetailsResolved = - hasDetermined && - hasFinishedResolutionForCurrentAdsAccount && - hasFinishedResolutionForCurrentMCAccount; - - const displayAccountDetails = - accountDetailsResolved && wasCreatingAccounts === null; - - useEffect( () => { - if ( hasDetermined ) { - setWasCreatingAccounts( creatingWhich ); - } - }, [ creatingWhich, hasDetermined ] ); + const { text, subText } = getAccountCreationTexts( creatingWhich ); - if ( - wasCreatingAccounts === undefined && - ( ! hasDetermined || - ! hasFinishedResolutionForCurrentAdsAccount || - ! hasFinishedResolutionForCurrentMCAccount ) - ) { + if ( ! hasDetermined ) { return ; } @@ -62,9 +31,9 @@ const ConnectedGoogleComboAccountCard = () => { appearance={ APPEARANCE.GOOGLE } alignIcon="top" className="gla-google-combo-account-card--connected" - description={ ! displayAccountDetails ? text : } - helper={ ! displayAccountDetails ? subText : null } - indicator={ } + description={ text || } + helper={ subText } + indicator={ } /> ); }; From e00c6e30d2e0ef8195fe478dc725f2ee21db4f7e Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Thu, 24 Oct 2024 21:09:15 +0530 Subject: [PATCH 85/91] Fix: JS lint. --- .../connected-google-combo-account-card.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js index 55a46826c5..5d981edf80 100644 --- a/js/src/components/google-combo-account-card/connected-google-combo-account-card.js +++ b/js/src/components/google-combo-account-card/connected-google-combo-account-card.js @@ -1,8 +1,3 @@ -/** - * External dependencies - */ -import { useEffect, useState } from '@wordpress/element'; - /** * Internal dependencies */ From 7f20af762939b5a603d60815bc4b614ae8ac656c Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 25 Oct 2024 02:01:46 +0530 Subject: [PATCH 86/91] Fix: condition in hook. --- js/src/hooks/useGoogleAdsAccountReady.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/hooks/useGoogleAdsAccountReady.js b/js/src/hooks/useGoogleAdsAccountReady.js index cb95e06145..3ea2f55bfe 100644 --- a/js/src/hooks/useGoogleAdsAccountReady.js +++ b/js/src/hooks/useGoogleAdsAccountReady.js @@ -19,7 +19,7 @@ const useGoogleAdsAccountReady = () => { hasAccess && [ '', 'billing', 'link_merchant' ].includes( step ); - return isReady !== null ? isReady : null; + return isReady === null ? null : !! isReady; }; export default useGoogleAdsAccountReady; From d363edc9b134c9db8879250151257a7add668ce9 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 25 Oct 2024 19:10:49 +0530 Subject: [PATCH 87/91] E2E improvements. --- js/src/hooks/useGoogleAdsAccountReady.js | 22 ++- js/src/hooks/useGoogleMCAccount.js | 7 +- .../specs/setup-mc/step-1-accounts.test.js | 116 +++------------ tests/e2e/utils/mock-requests.js | 140 +++++------------- 4 files changed, 77 insertions(+), 208 deletions(-) diff --git a/js/src/hooks/useGoogleAdsAccountReady.js b/js/src/hooks/useGoogleAdsAccountReady.js index 3ea2f55bfe..b593e44e2d 100644 --- a/js/src/hooks/useGoogleAdsAccountReady.js +++ b/js/src/hooks/useGoogleAdsAccountReady.js @@ -11,15 +11,25 @@ import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus'; * @return {boolean|null} Whether the Google Ads account is ready. `null` if the state is not yet determined. */ const useGoogleAdsAccountReady = () => { - const { hasGoogleAdsConnection } = useGoogleAdsAccount(); - const { hasAccess, step } = useGoogleAdsAccountStatus(); + const { + hasGoogleAdsConnection, + hasFinishedResolution: adsAccountResolved, + } = useGoogleAdsAccount(); + const { + hasAccess, + step, + hasFinishedResolution: adsAccountStatusResolved, + } = useGoogleAdsAccountStatus(); - const isReady = + if ( ! adsAccountResolved || ! adsAccountStatusResolved ) { + return null; + } + + return ( hasGoogleAdsConnection && hasAccess && - [ '', 'billing', 'link_merchant' ].includes( step ); - - return isReady === null ? null : !! isReady; + [ '', 'billing', 'link_merchant' ].includes( step ) + ); }; export default useGoogleAdsAccountReady; diff --git a/js/src/hooks/useGoogleMCAccount.js b/js/src/hooks/useGoogleMCAccount.js index 8dbf3a0fff..22a4ecbc24 100644 --- a/js/src/hooks/useGoogleMCAccount.js +++ b/js/src/hooks/useGoogleMCAccount.js @@ -65,10 +65,9 @@ const useGoogleMCAccount = () => { ].includes( acc?.status ); const isReady = - hasGoogleMCConnection && - ( acc.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || - ( acc.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && - acc?.step === 'link_ads' ) ); + acc?.status === GOOGLE_MC_ACCOUNT_STATUS.CONNECTED || + ( acc?.status === GOOGLE_MC_ACCOUNT_STATUS.INCOMPLETE && + acc?.step === 'link_ads' ); return { googleMCAccount: acc, diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 899c905228..9a91ce4fad 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -215,91 +215,25 @@ test.describe( 'Set up accounts', () => { test( 'should create merchant center and ads account if does not exist for the user', async () => { await setUpAccountsPage.mockJetpackConnected(); await setUpAccountsPage.mockGoogleConnected(); - await setUpAccountsPage.mockAdsAccountDisconnected(); - await setUpAccountsPage.mockMCNotConnected(); - - await setUpAccountsPage.fulfillAdsAccounts( - [ - [], - [ - { - id: 78787878, - name: 'gla', - }, - ], - ], - 200, - [ 'GET' ], - true - ); - await setUpAccountsPage.fulfillMCAccounts( - [ - [], - [ - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - }, - ], - ], - 200, - 'GET', - true - ); + await setUpAccountsPage.fulfillAdsAccounts( [ { id: 1 } ] ); + await setUpAccountsPage.mockMCHasAccounts(); + await setUpAccountsPage.mockAdsAccountIncomplete(); + await setUpAccountsPage.mockMCConnected(); - await setUpAccountsPage.fulfillAdsConnection( - [ - { - id: 0, - currency: 'USD', - status: 'disconnected', - symbol: '$', - }, - { - id: 78787878, - currency: 'USD', - status: 'incomplete', - step: 'account_access', - sub_account: true, - symbol: '$', - }, - ], - 200, - 'GET', - true - ); + const once = setUpAccountsPage.fulfillTimes( 1 ); - await setUpAccountsPage.fulfillMCConnection( - [ - { - id: 0, - name: null, - subaccount: null, - domain: null, - }, - { - id: 5432178, - name: null, - subaccount: null, - domain: null, - status: 'incomplete', - step: 'claim', - }, - ], - 200, - 'GET', - true - ); + await once.mockAdsHasNoAccounts(); + await once.mockMCHasNoAccounts(); + await once.mockAdsAccountDisconnected(); + await once.mockMCNotConnected(); await setUpAccountsPage.goto(); const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); await expect( googleAccountCard.getByText( - /You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you./, + 'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.', { exact: true, } @@ -318,6 +252,16 @@ test.describe( 'Set up accounts', () => { } ); test( 'should see the merchant center id and ads account id if connected', async () => { + await setUpAccountsPage.fulfillAdsAccounts( [ { id: 12345 } ] ); + await setUpAccountsPage.mockAdsAccountConnected(); + await setUpAccountsPage.mockMCConnected(); + await setUpAccountsPage.mockMCHasAccounts(); + await setUpAccountsPage.fulfillAdsAccountStatus( { + has_access: true, + invite_link: '', + step: 'link_merchant', + } ); + const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); await expect( @@ -331,26 +275,6 @@ test.describe( 'Set up accounts', () => { exact: true, } ) ).toBeVisible(); - } ); - - test( 'should see the connected label', async () => { - const googleAccountCard = - setUpAccountsPage.getGoogleAccountCard(); - - await setUpAccountsPage.fulfillAdsAccountStatus( { - has_access: true, - invite_link: '', - step: 'link_merchant', - } ); - - await setUpAccountsPage.fulfillMCConnection( { - id: 1234, - name: 'Test Merchant Center', - subaccount: null, - domain: 'example.com', - status: 'connected', - step: '', - } ); await expect( googleAccountCard.getByText( 'Connected', { exact: true } ) diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index 2b857f09ab..9dc2e1192e 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -11,6 +11,23 @@ export default class MockRequests { this.page = page; } + fulfillTimes( times ) { + return new Proxy( this, { + get( target, property ) { + const value = Reflect.get( ...arguments ); + + if ( property === 'fulfillRequest' ) { + return function ( url, payload, status, methods ) { + const args = [ url, payload, status, methods, times ]; + return value.apply( target, args ); + }; + } + + return value; + }, + } ); + } + /** * Fulfill a request with a payload. * @@ -18,54 +35,26 @@ export default class MockRequests { * @param {Object} payload The payload to send. * @param {number} status The HTTP status in the response. * @param {Array} methods The HTTP methods in the request to be fulfill. - * @param {boolean} multiRequestMock Whether to mock multiple requests. + * @param {number} times The number of times to fulfill the request. * @return {Promise} */ - async fulfillRequest( - url, - payload, - status = 200, - methods = [], - multiRequestMock = false - ) { - let callCount = 0; - - await this.page.route( url, ( route ) => { - const requestMethod = route.request().method(); - - if ( methods.length === 0 || methods.includes( requestMethod ) ) { - let currentPayload; - - if ( multiRequestMock ) { - // Handle multiple requests scenario - if ( - Array.isArray( payload ) && - callCount < payload.length - ) { - currentPayload = payload[ callCount ]; - callCount += 1; - } else if ( ! Array.isArray( payload ) ) { - currentPayload = payload; - } else { - // Fallback if all payloads are fulfilled - route.fallback(); - return; - } - } else { - // Handle single response scenario - currentPayload = payload; - } - - route.fulfill( { + async fulfillRequest( url, payload, status = 200, methods = [], times ) { + const handler = async ( route ) => { + if ( + methods.length === 0 || + methods.includes( route.request().method() ) + ) { + return route.fulfill( { status, contentType: 'application/json', headers: { 'Access-Control-Allow-Origin': '*' }, - body: JSON.stringify( currentPayload ), + body: JSON.stringify( payload ), } ); - } else { - route.fallback(); } - } ); + return route.fallback(); + }; + + await this.page.route( url, handler, { times } ); } /** @@ -129,21 +118,14 @@ export default class MockRequests { * @param {Object} payload * @param {number} status * @param {string[]} [methods] - * @param {boolean} multiRequestMock * @return {Promise} */ - async fulfillMCAccounts( - payload, - status = 200, - methods, - multiRequestMock = false - ) { + async fulfillMCAccounts( payload, status = 200, methods ) { await this.fulfillRequest( /\/wc\/gla\/mc\/accounts\b/, payload, status, - methods, - multiRequestMock + methods ); } @@ -166,24 +148,9 @@ export default class MockRequests { * Fulfill the MC connection request. * * @param {Object} payload - * @param {number} status - * @param {Array} methods - * @param {boolean} multiRequestMock - * @return {Promise} */ - async fulfillMCConnection( - payload, - status = 200, - methods = [], - multiRequestMock = false - ) { - await this.fulfillRequest( - /\/wc\/gla\/mc\/connection\b/, - payload, - status, - methods, - multiRequestMock - ); + async fulfillMCConnection( payload ) { + await this.fulfillRequest( /\/wc\/gla\/mc\/connection\b/, payload ); } /** @@ -240,24 +207,9 @@ export default class MockRequests { * Fulfill the Ads Connection request. * * @param {Object} payload - * @param {number} status - * @param {Array} methods - * @param {boolean} multiRequestMock - * @return {Promise} */ - async fulfillAdsConnection( - payload, - status = 200, - methods = [], - multiRequestMock = false - ) { - await this.fulfillRequest( - /\/wc\/gla\/ads\/connection\b/, - payload, - status, - methods, - multiRequestMock - ); + async fulfillAdsConnection( payload ) { + await this.fulfillRequest( /\/wc\/gla\/ads\/connection\b/, payload ); } /** @@ -281,24 +233,10 @@ export default class MockRequests { * Fulfill the Ads Account request. * * @param {Object} payload - * @param {number} status - * @param {Array} methods - * @param {boolean} multiRequestMock * @return {Promise} */ - async fulfillAdsAccounts( - payload, - status = 200, - methods = [], - multiRequestMock = false - ) { - await this.fulfillRequest( - /\/wc\/gla\/ads\/accounts\b/, - payload, - status, - methods, - multiRequestMock - ); + async fulfillAdsAccounts( payload ) { + await this.fulfillRequest( /\/wc\/gla\/ads\/accounts\b/, payload ); } /** @@ -601,7 +539,6 @@ export default class MockRequests { currency: 'TWD', symbol: 'NT$', status: 'connected', - step: '', } ); } @@ -639,7 +576,6 @@ export default class MockRequests { status: 'connected', notification_service_enabled: notificationServiceEnabled, wpcom_rest_api_status: wpcomRestApiStatus, - step: '', } ); } From 4b8badb2e398020149a87b6ad6e6fee649b7561e Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 25 Oct 2024 19:16:57 +0530 Subject: [PATCH 88/91] Use E2E mockAdsStatusClaimed function --- tests/e2e/specs/setup-mc/step-1-accounts.test.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index 9a91ce4fad..bb19a607ca 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -256,11 +256,7 @@ test.describe( 'Set up accounts', () => { await setUpAccountsPage.mockAdsAccountConnected(); await setUpAccountsPage.mockMCConnected(); await setUpAccountsPage.mockMCHasAccounts(); - await setUpAccountsPage.fulfillAdsAccountStatus( { - has_access: true, - invite_link: '', - step: 'link_merchant', - } ); + await setUpAccountsPage.mockAdsStatusClaimed(); const googleAccountCard = setUpAccountsPage.getGoogleAccountCard(); From 9137ef6b60a80e210080689ae679946ea1078126 Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 25 Oct 2024 20:30:33 +0530 Subject: [PATCH 89/91] Use mockAdsAccountConnected utility. --- tests/e2e/specs/setup-mc/step-1-accounts.test.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index bb19a607ca..f9d7fbeab4 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -325,12 +325,7 @@ test.describe( 'Set up accounts', () => { test.beforeAll( async () => { await setUpAccountsPage.mockAdsAccountConnected(); await setUpAccountsPage.mockMCConnected(); - - await setUpAccountsPage.fulfillAdsAccountStatus( { - has_access: true, - invite_link: '', - step: 'link_merchant', - } ); + await setUpAccountsPage.mockAdsAccountConnected(); await setUpAccountsPage.goto(); } ); From 8d381c4349571f54b6c05676dd540dc601e8325a Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Fri, 25 Oct 2024 21:00:59 +0530 Subject: [PATCH 90/91] Update docblocks. --- tests/e2e/utils/mock-requests.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index 9dc2e1192e..b58da25a60 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -11,6 +11,12 @@ export default class MockRequests { this.page = page; } + /** + * Fulfill a request multiple times. + * + * @param {number} times The number of times to fulfill the request. + * @return {Proxy} A proxy object to modify the behavior of the `fulfillRequest` method. + */ fulfillTimes( times ) { return new Proxy( this, { get( target, property ) { @@ -148,6 +154,7 @@ export default class MockRequests { * Fulfill the MC connection request. * * @param {Object} payload + * @return {Promise} */ async fulfillMCConnection( payload ) { await this.fulfillRequest( /\/wc\/gla\/mc\/connection\b/, payload ); @@ -207,6 +214,7 @@ export default class MockRequests { * Fulfill the Ads Connection request. * * @param {Object} payload + * @return {Promise} */ async fulfillAdsConnection( payload ) { await this.fulfillRequest( /\/wc\/gla\/ads\/connection\b/, payload ); From 8ab1be088fb38dcbf1c50be4ba18f5f8985c836a Mon Sep 17 00:00:00 2001 From: Ankit Gade Date: Mon, 28 Oct 2024 11:29:09 +0530 Subject: [PATCH 91/91] Update JSDoc. --- tests/e2e/specs/setup-mc/step-1-accounts.test.js | 4 ---- tests/e2e/utils/mock-requests.js | 4 ++-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/e2e/specs/setup-mc/step-1-accounts.test.js b/tests/e2e/specs/setup-mc/step-1-accounts.test.js index f9d7fbeab4..04b3f1cc1a 100644 --- a/tests/e2e/specs/setup-mc/step-1-accounts.test.js +++ b/tests/e2e/specs/setup-mc/step-1-accounts.test.js @@ -252,10 +252,6 @@ test.describe( 'Set up accounts', () => { } ); test( 'should see the merchant center id and ads account id if connected', async () => { - await setUpAccountsPage.fulfillAdsAccounts( [ { id: 12345 } ] ); - await setUpAccountsPage.mockAdsAccountConnected(); - await setUpAccountsPage.mockMCConnected(); - await setUpAccountsPage.mockMCHasAccounts(); await setUpAccountsPage.mockAdsStatusClaimed(); const googleAccountCard = diff --git a/tests/e2e/utils/mock-requests.js b/tests/e2e/utils/mock-requests.js index b58da25a60..29306ad059 100644 --- a/tests/e2e/utils/mock-requests.js +++ b/tests/e2e/utils/mock-requests.js @@ -15,7 +15,7 @@ export default class MockRequests { * Fulfill a request multiple times. * * @param {number} times The number of times to fulfill the request. - * @return {Proxy} A proxy object to modify the behavior of the `fulfillRequest` method. + * @return {this} A proxied instance intercepts the subsequent fulfillRequest calls to attach the `times` option. */ fulfillTimes( times ) { return new Proxy( this, { @@ -41,7 +41,7 @@ export default class MockRequests { * @param {Object} payload The payload to send. * @param {number} status The HTTP status in the response. * @param {Array} methods The HTTP methods in the request to be fulfill. - * @param {number} times The number of times to fulfill the request. + * @param {number} [times] The number of times to fulfill the request. Optional. * @return {Promise} */ async fulfillRequest( url, payload, status = 200, methods = [], times ) {