Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kickoff MC and Ads account creation #2618

Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
1535369
Initial structure.
ankitrox Sep 18, 2024
0d7965c
Use hooks to determine existing accounts.
ankitrox Sep 19, 2024
9e9b662
Fix lint.
ankitrox Sep 19, 2024
c5023b6
Fix: CreateAccounts component.
ankitrox Sep 20, 2024
d41d825
Remove redundant props.
ankitrox Sep 20, 2024
41e6d04
Remove redundant code.
ankitrox Sep 23, 2024
6917337
Introduce hook.
ankitrox Sep 23, 2024
d1b4c77
Fix: Flicker in component due to resolution state.
ankitrox Sep 23, 2024
b997713
Update account creation checks.
ankitrox Sep 24, 2024
d293f15
Update name for resolved checks property.
ankitrox Sep 25, 2024
9ef6c13
E2E tests.
ankitrox Sep 25, 2024
767a906
Move hook to hooks directory.
ankitrox Sep 25, 2024
2de300a
Add JS tests for useCreateAccounts hook.
ankitrox Sep 25, 2024
8239b47
Add indicator style.
ankitrox Sep 25, 2024
2e16bf4
Fix css lint error.
ankitrox Sep 25, 2024
32b47d5
Refactor hook to handle either of the account creation.
ankitrox Sep 27, 2024
f55fd1d
CR feedback - round 2.
ankitrox Sep 30, 2024
95fe0cb
Add CR feedback changes.
ankitrox Oct 1, 2024
1a24f0d
Remove unwanted props.
ankitrox Oct 3, 2024
2325d7a
Use refs to remove no-deps eslint rule.
ankitrox Oct 3, 2024
a0dcb9a
Fix: e2e tests.
ankitrox Oct 3, 2024
ea3a30f
Fix: hook tests.
ankitrox Oct 3, 2024
58738f8
Lint fix.
ankitrox Oct 3, 2024
a2b5f19
Remove unnecessary act in tests.
ankitrox Oct 3, 2024
c4f0d2b
Move hooks to relevant component.
ankitrox Oct 3, 2024
0d5130f
Fix js linting.
ankitrox Oct 3, 2024
896c681
Load correct scss file in appropriate component.
asvinb Oct 3, 2024
1252ac9
Add connected icon label.
ankitrox Oct 8, 2024
6d46a02
Fix: E2E tests.
ankitrox Oct 8, 2024
948acf0
Merge branch 'feature/2509-consolidate-google-account-cards' into fea…
asvinb Oct 8, 2024
2466e3c
Fix: Creating account message showing up constantly.
ankitrox Oct 8, 2024
e0d7ea1
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' of https:…
ankitrox Oct 8, 2024
11eba1b
Update filfilrequest utility.
ankitrox Oct 8, 2024
0df9699
Fix: unit test errors.
ankitrox Oct 8, 2024
ab0d80d
Add E2E test case for connected label.
ankitrox Oct 8, 2024
f2b3c21
Remove ambiguous request mocking.
ankitrox Oct 8, 2024
b1023b6
Remove use of useCallback and redundant code.
ankitrox Oct 14, 2024
7d343cd
Update conditions for rendering.
ankitrox Oct 14, 2024
37859b3
Formatting updates.
ankitrox Oct 14, 2024
298c0f4
Remove unused component.
ankitrox Oct 15, 2024
5ac6cf1
Update property names and description.
ankitrox Oct 15, 2024
d3f4f6f
Add status for MC account mock.
ankitrox Oct 15, 2024
60eff85
Rename constants.
ankitrox Oct 17, 2024
bd98116
Simplify the auto creation hook.
ankitrox Oct 17, 2024
cb382e8
Fix: js lint.
ankitrox Oct 17, 2024
747097d
Update existing MC accounts check.
ankitrox Oct 17, 2024
79eddb9
Add tests for existing accounts.
ankitrox Oct 17, 2024
e03d479
Remove unnecessary refs.
ankitrox Oct 17, 2024
3230a8b
Consolidate useEffect hook into one.
ankitrox Oct 17, 2024
b5e23ff
Optimize hook to use limited refs.
ankitrox Oct 17, 2024
40bd01c
Remove unused constants.
ankitrox Oct 17, 2024
4e65cd7
Fix: E2E tests.
ankitrox Oct 17, 2024
63c2f7f
Add hasGoogleMCConnection property in useGoogleMCAccount hook.
ankitrox Oct 17, 2024
2da86e6
Update doc block.
ankitrox Oct 18, 2024
1180ca8
Refactor to account creation description components.
ankitrox Oct 22, 2024
8393630
Add account creation data hook.
ankitrox Oct 22, 2024
971497a
Improve code readability.
ankitrox Oct 22, 2024
5d1048c
Fix: hook tests.
ankitrox Oct 22, 2024
1b4cae2
Replace isCreatingWhichAccount with creatingWhichAccount.
ankitrox Oct 22, 2024
e74287c
Use separate state variables.
ankitrox Oct 22, 2024
0cc906e
Add doc blocks.
ankitrox Oct 22, 2024
19a3a34
Add hooks for account creation determination.
ankitrox Oct 22, 2024
d3e380e
Refactor useAutoCreateAdsMCAccounts hook.
ankitrox Oct 22, 2024
3561c05
Rename useAccountCreationData hook to useAccountsData.
ankitrox Oct 22, 2024
8813820
Fix: tests.
ankitrox Oct 22, 2024
c9b9f2f
Remove redundant code.
ankitrox Oct 22, 2024
85cc699
Fix: TypeError.
ankitrox Oct 22, 2024
b62199d
Update doc blocks.
ankitrox Oct 22, 2024
3c93840
Fix: E2E tests.
ankitrox Oct 22, 2024
47af5ad
Fix: E2E.
ankitrox Oct 22, 2024
7937784
Add useGoogleAdsAccountReady hook.
ankitrox Oct 23, 2024
1d86086
Remove use of context.
ankitrox Oct 23, 2024
0be881e
Remove unwanted components.
ankitrox Oct 23, 2024
98808af
Optimize the useAutoCreateAdsMCAccounts hook and fix tests.
ankitrox Oct 23, 2024
e74b5e3
Style changes.
ankitrox Oct 23, 2024
38137a3
Remove unnecessary files.
ankitrox Oct 23, 2024
18256f3
Update display account details logic.
ankitrox Oct 23, 2024
7a9854b
Add useGoogleMCAccountReady hook.
ankitrox Oct 23, 2024
2859cf5
Update account details rendering logic.
ankitrox Oct 23, 2024
7a24be5
Tweak useGoogleMCAccountReady hook
joemcgill Oct 23, 2024
e62562f
Remove unused constant
joemcgill Oct 23, 2024
bd1f3e3
Clean up E2E tests for account creation
joemcgill Oct 23, 2024
56a2e15
Fix: E2E test.
ankitrox Oct 24, 2024
599c2d2
E2E tests changs for new hook.
ankitrox Oct 24, 2024
f3f63fe
CR feedback.
ankitrox Oct 24, 2024
72434e2
Remove redundant code.
ankitrox Oct 24, 2024
e00c6e3
Fix: JS lint.
ankitrox Oct 24, 2024
7f20af7
Fix: condition in hook.
ankitrox Oct 24, 2024
d363edc
E2E improvements.
ankitrox Oct 25, 2024
4b8badb
Use E2E mockAdsStatusClaimed function
ankitrox Oct 25, 2024
9137ef6
Use mockAdsAccountConnected utility.
ankitrox Oct 25, 2024
8d381c4
Update docblocks.
ankitrox Oct 25, 2024
8ab1be0
Update JSDoc.
ankitrox Oct 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import useGoogleAccount from '.~/hooks/useGoogleAccount';

/**
* Renders the description for the account creation card.
*
* @param {*} param0 Props.
asvinb marked this conversation as resolved.
Show resolved Hide resolved
* @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 = ( {
asvinb marked this conversation as resolved.
Show resolved Hide resolved
isCreatingAccounts,
asvinb marked this conversation as resolved.
Show resolved Hide resolved
asvinb marked this conversation as resolved.
Show resolved Hide resolved
isCreatingMCAccount,
isCreatingAdsAccount,
googleMCAccount = {},
asvinb marked this conversation as resolved.
Show resolved Hide resolved
googleAdsAccount = {},
} ) => {
const { google } = useGoogleAccount();

const getDescription = () => {
asvinb marked this conversation as resolved.
Show resolved Hide resolved
let description;
asvinb marked this conversation as resolved.
Show resolved Hide resolved

if ( isCreatingAccounts ) {
asvinb marked this conversation as resolved.
Show resolved Hide resolved
if ( isCreatingMCAccount && isCreatingAdsAccount ) {
description = (
<p>
{ __(
'You don’t have Merchant Center nor Google Ads accounts, so we’re creating them for you.',
'google-listings-and-ads'
) }
</p>
);
} else if ( isCreatingAdsAccount ) {
description = (
<>
<p>
{ __(
'You don’t have Google Ads account, so we’re creating one for you.',
'google-listings-and-ads'
) }
</p>
<em>
{ __(
'Required to set up conversion measurement for your store.',
'google-listings-and-ads'
) }
</em>
</>
);
} else if ( isCreatingMCAccount ) {
description = (
<>
<p>
{ __(
'You don’t have Merchant Center account, so we’re creating one for you.',
'google-listings-and-ads'
) }
</p>
<em>
{ __(
'Required to sync products so they show on Google.',
'google-listings-and-ads'
) }
</em>
</>
);
}
} else {
description = (
<>
<p>{ google?.email }</p>
{ googleMCAccount?.id && (
<p>
{ sprintf(
// Translators: %s is the Merchant Center ID
__(
'Merchant Center ID: %s',
'google-listings-and-ads'
),
googleMCAccount.id
) }
</p>
) }
{ googleAdsAccount?.id && (
<p>
{ sprintf(
// Translators: %s is the Google Ads ID
__(
'Google Ads ID: %s',
'google-listings-and-ads'
),
googleAdsAccount.id
) }
</p>
) }
</>
);
}

return description;
};

return (
<div className="gla-connected-google-combo-account-card__description">
asvinb marked this conversation as resolved.
Show resolved Hide resolved
{ getDescription() }
</div>
);
};

export default AccountCreationDescription;
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
.gla-connect-google-combo-account-card {
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
.gla-google-combo-account-card--connected {

.gla-account-card__helper {
font-size: $gla-font-base;
.gla-account-card__icon {
align-self: flex-start;
}

.gla-account-card__description p {
margin: 0;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* External dependencies
*/
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';
import AccountCreationDescription from './account-creation-description';

/**
* 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 {{ googleAccount: object }} props.googleAccount The Google account.
*
* @fires gla_google_account_connect_different_account_button_click
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
*/
const ConnectedGoogleComboAccountCard = ( { googleAccount } ) => {
asvinb marked this conversation as resolved.
Show resolved Hide resolved
const {
googleMCAccount,
hasFinishedResolution: hasFinishedResolutionForCurrentMCAccount,
} = useGoogleMCAccount();

const {
googleAdsAccount,
hasFinishedResolution: hasFinishedResolutionForCurrentAdsAccount,
} = useGoogleAdsAccount();

const {
accountsCreated,
accountCreationChecksResolved,
asvinb marked this conversation as resolved.
Show resolved Hide resolved
isCreatingAdsAccount,
isCreatingMCAccount,
} = useAutoCreateAdsMCAccounts();

const isCreatingAccounts = isCreatingAdsAccount || isCreatingMCAccount;

if (
! accountsCreated &&
( ! hasFinishedResolutionForCurrentAdsAccount ||
asvinb marked this conversation as resolved.
Show resolved Hide resolved
! hasFinishedResolutionForCurrentMCAccount ||
! accountCreationChecksResolved )
) {
return <AccountCard description={ <AppSpinner /> } />;
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
}

const creatingAccounts =
isCreatingAccounts ||
( accountsCreated &&
( ! hasFinishedResolutionForCurrentMCAccount ||
! hasFinishedResolutionForCurrentAdsAccount ) );

const getHelper = () =>
isCreatingAdsAccount &&
isCreatingMCAccount && (
<p>
{ __(
'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>
);
joemcgill marked this conversation as resolved.
Show resolved Hide resolved

const getIndicator = () => {
if ( creatingAccounts ) {
return (
<LoadingLabel
text={ __( 'Creating…', 'google-listings-and-ads' ) }
/>
);
}

return null;
};

return (
<AccountCard
appearance={ APPEARANCE.GOOGLE }
className="gla-google-combo-account-card--connected"
description={
<AccountCreationDescription
isCreatingAccounts={ creatingAccounts }
isCreatingAdsAccount={ isCreatingAdsAccount }
isCreatingMCAccount={ isCreatingMCAccount }
googleAccount={ googleAccount }
asvinb marked this conversation as resolved.
Show resolved Hide resolved
googleMCAccount={ googleMCAccount }
googleAdsAccount={ googleAdsAccount }
/>
}
helper={ getHelper() }
indicator={ getIndicator() }
/>
);
};

export default ConnectedGoogleComboAccountCard;
4 changes: 2 additions & 2 deletions js/src/components/google-combo-account-card/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ 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';

export default function GoogleComboAccountCard( { disabled = false } ) {
const { google, scope, hasFinishedResolution } = useGoogleAccount();
Expand All @@ -18,7 +18,7 @@ export default function GoogleComboAccountCard( { disabled = false } ) {
const isConnected = google?.active === 'yes';

if ( isConnected && scope.glaRequired ) {
return <ConnectedGoogleAccountCard googleAccount={ google } />;
return <ConnectedGoogleComboAccountCard googleAccount={ google } />;
}

if ( isConnected && ! scope.glaRequired ) {
Expand Down
115 changes: 115 additions & 0 deletions js/src/hooks/useAutoCreateAdsMCAccounts.js
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/**
* External dependencies
*/
import { useEffect, useRef } from '@wordpress/element';

/**
* Internal dependencies
*/
import useCreateMCAccount from '../components/google-mc-account-card/useCreateMCAccount';
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount';
import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts';
import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts';

/**
* Custom hook to handle the creation of Google Merchant Center (MC) and Google Ads accounts.
*
* @typedef {Object} AutoCreateAccountsStatus
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
* @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 = () => {
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
/**
* 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.
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
* accountsCreatedRef - Indicates if the accounts have been created.
*/
const accountCreationChecksResolvedRef = useRef( false );
const isCreatingAccountsRef = useRef( false );
const isCreatingAdsAccountsRef = useRef( false );
const isCreatingMCAccountsRef = useRef( false );
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
const accountsCreatedRef = useRef( false );

const {
data: existingMCAccounts,
hasFinishedResolution: hasFinishedResolutionForExistingMCAccounts,
} = useExistingGoogleMCAccounts();

const {
existingAccounts: existingAdsAccount,
eason9487 marked this conversation as resolved.
Show resolved Hide resolved
isResolving: isResolvingExistingAdsAccount,
asvinb marked this conversation as resolved.
Show resolved Hide resolved
} = useExistingGoogleAdsAccounts();

const [ handleCreateAccount, { response } ] = useCreateMCAccount();
const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount();

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 (
asvinb marked this conversation as resolved.
Show resolved Hide resolved
isCreatingAccountsRef.current === true &&
response?.status === 200 &&
! loading
) {
isCreatingMCAccountsRef.current = false;
isCreatingAdsAccountsRef.current = false;
isCreatingAccountsRef.current = false;
accountsCreatedRef.current = true;
}
}, [ response, loading ] );

useEffect( () => {
const existingAccountsResolved =
! isResolvingExistingAdsAccount &&
hasFinishedResolutionForExistingMCAccounts;

accountCreationChecksResolvedRef.current = existingAccountsResolved;

if (
existingAccountsResolved &&
isCreatingAccountsRef.current === false
) {
const hasExistingMCAccount = existingMCAccounts?.length > 0;
const hasExistingAdsAccount = existingAdsAccount?.length > 0;

if ( ! hasExistingMCAccount || ! hasExistingAdsAccount ) {
createAccounts();
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
asvinb marked this conversation as resolved.
Show resolved Hide resolved
}, [
isResolvingExistingAdsAccount,
hasFinishedResolutionForExistingMCAccounts,
] );

return {
accountsCreated: accountsCreatedRef.current,
accountCreationChecksResolved: accountCreationChecksResolvedRef.current,
isCreatingAdsAccount: isCreatingAdsAccountsRef.current,
isCreatingMCAccount: isCreatingMCAccountsRef.current,
};
};

export default useAutoCreateAdsMCAccounts;
Loading