-
Notifications
You must be signed in to change notification settings - Fork 21
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
Consolidate accounts onboarding: Claim Google Ads account via the combo card #2644
Consolidate accounts onboarding: Claim Google Ads account via the combo card #2644
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## feature/2509-consolidate-google-account-cards #2644 +/- ##
===============================================================================
- Coverage 62.7% 62.7% -0.0%
===============================================================================
Files 325 326 +1
Lines 5161 5166 +5
Branches 1265 1266 +1
===============================================================================
+ Hits 3238 3239 +1
- Misses 1746 1751 +5
+ Partials 177 176 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
|
* @param {boolean} [props.loading] Whether the button is in a loading state. | ||
* @param {Object} props.restProps Props to be forwarded to AppButton. | ||
*/ | ||
const ClaimAdsAccountButton = ( { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox Any idea why we cannot use the ClaimAccountButton
from js/src/components/google-ads-account-card/claim-account-button.js
?
onClick( event ); | ||
}; | ||
|
||
if ( loading ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox I think we should be able to do the same thing by passing the loading
prop to AppButton
along with the text
prop.
*/ | ||
const ClaimAdsAccount = () => { | ||
const [ , forceUpdate ] = useState( 0 ); | ||
const isWindowFocused = useWindowFocus(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox Can we use the same logic in js/src/components/google-ads-account-card/claim-account/index.js
const { fetchGoogleAdsAccountStatus } = useAppDispatch();
useWindowFocusCallbackIntervalEffect( fetchGoogleAdsAccountStatus, 30 );
|
||
useEffect( () => { | ||
if ( isWindowFocused && claimButtonClickedRef.current ) { | ||
invalidateResolution( 'getGoogleAdsAccountStatus' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox There won't be the need to invalidate the data when we'll use the suggested approach above, i.e using useWindowFocusCallbackIntervalEffect
step === 'conversion_action' && | ||
! claimInProgressRef.current | ||
) { | ||
claimInProgressRef.current = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox I don't think we should check whether there's a claim in progress to upsert an Ads account. I think hasAccess
and step === 'conversion_action'
should be enough:
useEffect( () => {
if ( hasAccess === true && step === 'conversion_action' ) {
upsertAdsAccount();
}
}, [ hasAccess, upsertAdsAccount, step ] );
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been changed to
useEffect( () => {
if ( hasAccess === true && step === 'conversion_action' ) {
upsertAdsAccount();
}
}, [ hasAccess, step, upsertAdsAccount ] );
* 1. The user has access to the Google Ads account. | ||
* 2. The resolution has not finished and the claim button has not been clicked. | ||
*/ | ||
if ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox I think the condition to render ClaimAdsAccount
should be in ConnectedGoogleComboAccountCard
and we can check as follows:
const shouldClaimGoogleAdsAccount = Boolean(
googleAdsAccount.id && hasAccess === false
);
Thus we won't need to track for any button click. Side note, we don't need to check for ! hasFinishedResolution
since hasAccess
will be falsy if that's not the case.
<ClaimAdsAccountButton | ||
inviteLink={ inviteLink } | ||
loading={ isLoading } | ||
onClick={ () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox The only thing we need from onClick
is to have an internal state for the loading
feature. We don't need to track whether it was clicked or not.
@@ -93,19 +97,31 @@ const ConnectedGoogleComboAccountCard = () => { | |||
return null; | |||
}; | |||
|
|||
const getCardDescription = () => { | |||
return ( | |||
<> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox Unnecessary fragment.
<> |
isCreatingWhichAccount={ isCreatingWhichAccount } | ||
/> | ||
} | ||
description={ getCardDescription() } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox Can we not render AccountCreationDescription
directly? Why a function? 🤔
<AccountCreationDescription
isCreatingWhichAccount={ isCreatingWhichAccount }
/>
/> | ||
> | ||
{ showSuccessNotice && <ConversionMeasurementNotice /> } | ||
<ClaimAdsAccount /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ankitrox Check my previous comments. Let's add the condition to display ClaimAdsAccount
const checkUpdatedAdsAccountStatus = useCallback( async () => { | ||
setUpdating( true ); | ||
await fetchGoogleAdsAccountStatus(); | ||
setUpdating( false ); | ||
}, [ fetchGoogleAdsAccountStatus ] ); | ||
|
||
useWindowFocusCallbackIntervalEffect( checkUpdatedAdsAccountStatus, 30 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks very close. One thing that I think we can do to improve this is to do something similar to what the useAutoCheckBillingStatusEffect()
hook does here and return early from this callback once we no longer need to check on the claim status of the account.
Here's a quick example:
diff --git a/js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js b/js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
index 547ef9927..fb22d1f02 100644
--- a/js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
+++ b/js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
@@ -29,11 +29,19 @@ const ClaimAdsAccount = () => {
const { hasAccess, step } = useGoogleAdsAccountStatus();
const [ upsertAdsAccount ] = useUpsertAdsAccount();
+ const shouldClaimGoogleAdsAccount = Boolean(
+ googleAdsAccount.id && hasAccess === false
+ );
+
const checkUpdatedAdsAccountStatus = useCallback( async () => {
+ if ( ! shouldClaimGoogleAdsAccount ) {
+ return;
+ }
+
setUpdating( true );
await fetchGoogleAdsAccountStatus();
setUpdating( false );
- }, [ fetchGoogleAdsAccountStatus ] );
+ }, [ fetchGoogleAdsAccountStatus, hasAccess ] );
useWindowFocusCallbackIntervalEffect( checkUpdatedAdsAccountStatus, 30 );
@@ -43,9 +51,7 @@ const ClaimAdsAccount = () => {
}
}, [ hasAccess, step, upsertAdsAccount ] );
- const shouldClaimGoogleAdsAccount = Boolean(
- googleAdsAccount.id && hasAccess === false
- );
+
if ( ! shouldClaimGoogleAdsAccount ) {
return null;
} | ||
> | ||
<ConversionMeasurementNotice /> | ||
<ClaimAdsAccount /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative way we could avoid needing to poll the ads/account-status
API is to move the shouldClaimGoogleAdsAccount
logic to this component, and only render this component if shouldClaimGoogleAdsAccount
is true
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed it as per this comment
Thanks for reviewing it @joemcgill. I have added Also, this component will hold the business logic like whether or not to show the other components like claim ads account or conversion measurement notice so that the other components like Over to you for another review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The latest updates here are looking good to me.
I tried looking for a better way handle the Claim Ads E2E test so that the successful claim could be checked without a page refresh, but waiting for the useWindowFocusCallbackIntervalEffect
to run makes that test take too long, so I modified it again to just confirm that the AccountCard shows the 'Connected' message in 3e2d8ee with additional cleanup in 0f38c5e.
I also cherry-picked the changes from 80764f0 that fixes some flakiness with the account creation tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Found an issue that was not introduced by this PR but must be raised.
If a merchant doesn't authorize all required scopes when connecting Google account, the automatically created process may get stuck and can not continue. Refreshing webpage also remains in the same stuck state.
The following video demos the issue when the Google Ads scope ('https://www.googleapis.com/auth/adwords'
) is not selected.
Kapture.2024-11-07.at.15.42.10.mp4
The original scope.glaRequired
checking logic is no longer applicable to the current implementation. The conditions below must check both scope.gmcRequired
and scope.adsRequired
.
google-listings-and-ads/js/src/components/google-combo-account-card/index.js
Lines 21 to 25 in 0f38c5e
if ( isConnected && scope.glaRequired ) { | |
return <ConnectedGoogleComboAccountCard />; | |
} | |
if ( isConnected && ! scope.glaRequired ) { |
js/src/components/google-combo-account-card/connected-google-combo-account-card.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/connected-google-combo-account-card.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/connected-google-combo-account-card.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/connected-ads-account-actions.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/connected-google-combo-account-card.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.scss
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.scss
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.scss
Outdated
Show resolved
Hide resolved
js/src/components/google-ads-account-card/claim-account-button.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
Outdated
Show resolved
Hide resolved
@eason9487 I've left some feedback about one of the questions you raised, but I think it's ready otherwise. |
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.scss
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/connected-ads-account-detail.scss
Outdated
Show resolved
Hide resolved
js/src/components/google-ads-account-card/claim-account-button.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/connected-google-combo-account-card.js
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy to remove the logic to conditionally show the conversion notice, but I don't think the changes are quite right yet. Left two suggestions inline.
const showConversionMeasurementNotice = | ||
( googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED || | ||
googleAdsAccount?.step === 'billing' ) && | ||
! shouldClaimGoogleAdsAccount; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Happy for us to remove the useEffect
logic that only shows this when the conversion action has first been set up, but if we're using similar logic to the GoogleAdsAccountCard
we should make it consistent, i.e.
const showConversionMeasurementNotice = | |
( googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED || | |
googleAdsAccount?.step === 'billing' ) && | |
! shouldClaimGoogleAdsAccount; | |
const showConversionMeasurementNotice = | |
( googleAdsAccount?.status === GOOGLE_ADS_ACCOUNT_STATUS.CONNECTED || | |
googleAdsAccount?.step === 'link_merchant' ) && | |
! shouldClaimGoogleAdsAccount; |
Also, thought it doesn't hurt things, I don't think the ! shouldClaimGoogleAdsAccount
is necessary, because in neither condition above would shouldClaimGoogleAdsAccount
resolve to true
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've handled this in ac3eef9 and moved this logic to a utility function to avoid inconsistent logic.
return ( | ||
<AppButton | ||
{ ...restProps } | ||
loading={ loading || ! inviteLink } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the inviteLink
value as part of the loading value is problematic, because it is possible for the inviteLink
to be an empty string, (ie. inviteLink: ""
). The case of the inviteLink
being empty seems to be related to a strange race condition.
When no account is connected, the initial state for account-status will be:
{
"has_access": false,
"step": "",
"invite_link": ""
}
To create a new account, we call upsertAdsAccount()
, which internally makes a direct POST request (bypassing actions altogether), followed by refetching the Ads account and the new Ads account status.
This is where a race condition can happen because the store will still have the initial account-status with an invite_link: ""
and has_access: false
but the Ads account will be resolved, causing this logic to be true:
const shouldClaimGoogleAdsAccount = Boolean(
googleAdsAccount?.id && hasAccess === false
);
I think the safest thing to do is to either invalidate the account-status data whenever we're creating a new account, or add a condition to shouldClaimGoogleAdsAccount
that waits for the upsertAdsAccount()
loading
value to be false
. Here's an example:
diff --git a/js/src/components/google-ads-account-card/claim-account-button.js b/js/src/components/google-ads-account-card/claim-account-button.js
index e9afa0a78..b53ded9c9 100644
--- a/js/src/components/google-ads-account-card/claim-account-button.js
+++ b/js/src/components/google-ads-account-card/claim-account-button.js
@@ -45,7 +45,7 @@ const ClaimAccountButton = ( { onClick = noop, loading, ...restProps } ) => {
return (
<AppButton
{ ...restProps }
- loading={ loading || ! inviteLink }
+ loading={ loading }
eventName="gla_open_ads_account_claim_invitation_button_click"
eventProps={ getEventProps() }
onClick={ handleClaimAccountClick }
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 ab2a4eab8..536db2912 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
@@ -48,7 +48,7 @@ const ConnectedGoogleComboAccountCard = () => {
const { invalidateResolution } = useAppDispatch();
const { googleAdsAccount } = useGoogleAdsAccount();
const { hasAccess, step } = useGoogleAdsAccountStatus();
- const [ upsertAdsAccount, { action } ] = useUpsertAdsAccount();
+ const [ upsertAdsAccount, { action, loading } ] = useUpsertAdsAccount();
const finalizeAdsAccountCreation =
hasAccess === true && step === 'conversion_action';
@@ -73,7 +73,7 @@ const ConnectedGoogleComboAccountCard = () => {
// @TODO: edit mode implementation in 2605
const editMode = false;
const shouldClaimGoogleAdsAccount = Boolean(
- googleAdsAccount?.id && hasAccess === false
+ ! loading && googleAdsAccount?.id && hasAccess === false
);
const hasExistingGoogleMCAccounts = existingGoogleMCAccounts?.length > 0;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@eason9487 this is ready for another review, though it may be easier to test everything if we go ahead and merge #2651 into this PR, since testing that the A summary of the latest updates:
Let me know your thoughts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The retry mechanism is less than ideal, but if showing a waiting indicator is necessary, then the current implementation can be kept for now.
The naming of useRef
variable and redundant loading
forwards still need to be resolved.
js/src/components/google-ads-account-card/claim-account-button.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
Outdated
Show resolved
Hide resolved
js/src/components/google-combo-account-card/claim-ads-account/claim-ads-account.js
Outdated
Show resolved
Hide resolved
768ce3c
into
feature/2509-consolidate-google-account-cards
Changes proposed in this Pull Request:
Closes #2582
Replace this with a good description of your changes & reasoning.
Screenshots:
Detailed test instructions:
Claim your Google Ads account
button, it will open the pop-up window to accept the invitation.Updating...
spinner in place ofClaim your Google Ads account
button and eventually claim card will go away and in place of that green colored notice will be shown as shown in screenshot.Additional details:
Changelog entry