Skip to content

Commit

Permalink
Merge pull request #2644 from woocommerce/update/2582-claim-ads-account
Browse files Browse the repository at this point in the history
Onboarding: Claim New Ads Accounts in the Google Combo Accounts Card
  • Loading branch information
joemcgill authored Nov 13, 2024
2 parents 900d45d + 6c93d64 commit 768ce3c
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ const ClaimAccountButton = ( { onClick = noop, ...restProps } ) => {
onClick( event );
};

// If there is no invite link, we don't render the button.
if ( ! inviteLink ) {
return null;

Check warning on line 47 in js/src/components/google-ads-account-card/claim-account-button.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/google-ads-account-card/claim-account-button.js#L47

Added line #L47 was not covered by tests
}

return (
<AppButton
{ ...restProps }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe( 'ClaimAccountButton', () => {

useGoogleAdsAccountStatus.mockReturnValue( {
inviteLink: 'https://example.com',
hasFinishedResolution: true,
} );
} );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import NonConnected from './non-connected';
import AuthorizeAds from './authorize-ads';
import DisabledCard from './disabled-card';
import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus';
import showAdsConversionNotice from '.~/utils/showAdsConversionNotice';

export default function GoogleAdsAccountCard() {
const {
Expand Down Expand Up @@ -60,9 +61,7 @@ export default function GoogleAdsAccountCard() {
return <NonConnected />;
}

const showSuccessNotice =
googleAdsAccount.status === GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED ||
googleAdsAccount.step === 'link_merchant';
const showSuccessNotice = showAdsConversionNotice( googleAdsAccount );

Check warning on line 64 in js/src/components/google-ads-account-card/google-ads-account-card.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/google-ads-account-card/google-ads-account-card.js#L64

Added line #L64 was not covered by tests

return (
<ConnectedGoogleAdsAccountCard googleAdsAccount={ googleAdsAccount }>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import ClaimAccountButton from '.~/components/google-ads-account-card/claim-account-button';
import { useAppDispatch } from '.~/data';
import useWindowFocusCallbackIntervalEffect from '.~/hooks/useWindowFocusCallbackIntervalEffect';
import './claim-ads-account.scss';

/**
* ClaimAdsAccount component.
*
* @return {JSX.Element} ClaimAdsAccount component.
*/
const ClaimAdsAccount = () => {
const { fetchGoogleAdsAccountStatus } = useAppDispatch();
useWindowFocusCallbackIntervalEffect( fetchGoogleAdsAccountStatus, 30 );

return (
<div className="gla-claim-ads-account-box">
<h4>
{ __(
'Claim your Google Ads account',
'google-listings-and-ads'
) }
</h4>
<p>
{ __(
'You need to accept the invitation to the Google Ads account we created for you. This gives you access to Google Ads and sets up conversion measurement. You must claim your account in the next 20 days.',
'google-listings-and-ads'
) }
</p>
<p className="gla-ads-post-claim-instructions">
{ __(
'After accepting the invitation, you’ll be prompted to set up billing. We highly recommend doing this to avoid having to do it later on.',
'google-listings-and-ads'
) }
</p>
<ClaimAccountButton
text={ __(
'Claim account in Google Ads',
'google-listings-and-ads'
) }
isPrimary
/>
</div>
);
};

export default ClaimAdsAccount;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.gla-claim-ads-account-box {
border: 1px solid $gray-300;
display: flex;
flex-direction: column;
gap: $grid-unit-10;
padding: $grid-unit-30;

h4 {
font-size: $gla-font-small;
margin: 0;
}

p {
margin: 0;
}

.gla-ads-post-claim-instructions {
color: $gray-700;
font-style: italic;
}

.app-button {
align-self: flex-end;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './claim-ads-account';
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Notice } from '@wordpress/components';

/**
* Internal dependencies
*/
import ClaimAdsAccount from './claim-ads-account';
import './connected-ads-account-detail.scss';

/**
* Renders details related to a connected Google Ads account, including the option to claim the account and a notice indicating whether conversion measurement has been set up.
* @param {Object} props Component props.
* @param {boolean} props.claimGoogleAdsAccount Whether the user should claim the Google Ads account.
* @param {boolean} props.showConversionMeasurementNotice Whether to show the conversion measurement notice.
*/
const ConnectedAdsAccountDetail = ( {
claimGoogleAdsAccount,
showConversionMeasurementNotice,
} ) => {
if ( ! claimGoogleAdsAccount && ! showConversionMeasurementNotice ) {
return null;
}

return (
<div className="gla-connected-ads-account-detail">
{ claimGoogleAdsAccount && <ClaimAdsAccount /> }

{ showConversionMeasurementNotice && (
<Notice status="success" isDismissible={ false }>
{ __(
'Google Ads conversion measurement has been set up for your store.',
'google-listings-and-ads'
) }
</Notice>
) }
</div>
);
};

export default ConnectedAdsAccountDetail;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.gla-connected-ads-account-detail {

.components-notice.is-success {
margin: 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
/**
* External dependencies
*/
import { useEffect } from '@wordpress/element';

/**
* Internal dependencies
*/
import { useAppDispatch } from '.~/data';
import AccountCard, { APPEARANCE } from '../account-card';
import ConnectAds from './connect-ads';
import AccountDetails from './account-details';
import ConnectedAdsAccountDetail from './connected-ads-account-detail';
import Indicator from './indicator';
import getAccountCreationTexts from './getAccountCreationTexts';
import SpinnerCard from '.~/components/spinner-card';
Expand All @@ -14,6 +21,10 @@ import useCreateMCAccount from '.~/hooks/useCreateMCAccount';
import ConnectMC from '.~/components/google-mc-account-card/connect-mc';
import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady';
import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts';
import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus';
import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';
import useUpsertAdsAccount from '.~/hooks/useUpsertAdsAccount';
import showAdsConversionNotice from '.~/utils/showAdsConversionNotice';
import './connected-google-combo-account-card.scss';

/**
Expand All @@ -34,13 +45,37 @@ const ConnectedGoogleComboAccountCard = () => {
const { existingAccounts: existingGoogleAdsAccounts } =
useExistingGoogleAdsAccounts();
const isConnected = useGoogleAdsAccountReady();
const { invalidateResolution } = useAppDispatch();
const { googleAdsAccount } = useGoogleAdsAccount();
const { hasAccess, step } = useGoogleAdsAccountStatus();
const [ upsertAdsAccount, { loading } ] = useUpsertAdsAccount();

const finalizeAdsAccountCreation =
hasAccess === true && step === 'conversion_action';

// Ideally updating the account should be done in ConnectMC component but the latter is not always rendered,
// (for e.g when the user is creating the first account).
useEffect( () => {
const upsertAccount = async () => {
if ( finalizeAdsAccountCreation ) {
await upsertAdsAccount();
invalidateResolution( 'getExistingGoogleAdsAccounts', [] );
}
};

upsertAccount();
}, [ finalizeAdsAccountCreation, upsertAdsAccount, invalidateResolution ] );

if ( ! hasDetermined ) {
return <SpinnerCard />;
}

// @TODO: edit mode implementation in 2605
const editMode = true;
const editMode = false;
const shouldClaimGoogleAdsAccount = Boolean(
! loading && googleAdsAccount?.id && hasAccess === false
);

const hasExistingGoogleMCAccounts = existingGoogleMCAccounts?.length > 0;
const showConnectMC =
( editMode && hasExistingGoogleMCAccounts ) ||
Expand All @@ -51,6 +86,16 @@ const ConnectedGoogleComboAccountCard = () => {
( editMode && hasExistingGoogleAdsAccounts ) ||
( ! isConnected && hasExistingGoogleAdsAccounts );

// Show the spinner if there's an account creation in progress and account should not be claimed.
// If we are not showing the ConnectMC screen, for e.g when we are creating the first account,
// then show the spinner in the Google combo card while the Ads account is being claimed.
const showSpinner =
( Boolean( creatingWhich ) && ! shouldClaimGoogleAdsAccount ) ||
( ! showConnectAds && finalizeAdsAccountCreation );

const showConversionMeasurementNotice =
showAdsConversionNotice( googleAdsAccount );

return (
<div>
<AccountCard
Expand All @@ -59,9 +104,16 @@ const ConnectedGoogleComboAccountCard = () => {
className="gla-google-combo-account-card gla-google-combo-account-card--connected gla-google-combo-service-account-card--google"
description={ text || <AccountDetails /> }
helper={ subText }
indicator={
<Indicator showSpinner={ Boolean( creatingWhich ) } />
indicator={ <Indicator showSpinner={ showSpinner } /> }
detail={
<ConnectedAdsAccountDetail
showConversionMeasurementNotice={
showConversionMeasurementNotice
}
claimGoogleAdsAccount={ shouldClaimGoogleAdsAccount }
/>
}
expandedDetail
/>

{ showConnectAds && <ConnectAds /> }
Expand Down
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 @@ -18,11 +18,11 @@ export default function GoogleComboAccountCard( { disabled = false } ) {

const isConnected = google?.active === 'yes';

if ( isConnected && scope.glaRequired ) {
if ( isConnected && scope.gmcRequired && scope.adsRequired ) {
return <ConnectedGoogleComboAccountCard />;
}

if ( isConnected && ! scope.glaRequired ) {
if ( isConnected && ( ! scope.gmcRequired || ! scope.adsRequired ) ) {
return (
<RequestFullAccessGoogleAccountCard
additionalScopeEmail={ google.email }
Expand Down
18 changes: 18 additions & 0 deletions js/src/utils/showAdsConversionNotice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Internal dependencies
*/
import { GOOGLE_ADS_ACCOUNT_STATUS } from '.~/constants';

/**
* Helper for determining whether to show the ads conversion notice based on the
* Google Ads account status and step.
*
* @param {Object} googleAdsAccount A Google Ads account object.
* @return {boolean} Whether to show the ads conversion notice.
*/
export default function showAdsConversionNotice( googleAdsAccount ) {
return (
googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED ||
[ 'link_merchant', 'billing' ].includes( googleAdsAccount?.step )

Check warning on line 16 in js/src/utils/showAdsConversionNotice.js

View check run for this annotation

Codecov / codecov/patch

js/src/utils/showAdsConversionNotice.js#L13-L16

Added lines #L13 - L16 were not covered by tests
);
}
Loading

0 comments on commit 768ce3c

Please sign in to comment.