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

Connect MC Account within combo card #2639

Open
wants to merge 85 commits into
base: feature/2509-consolidate-google-account-cards
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 78 commits
Commits
Show all changes
85 commits
Select commit Hold shift + click to select a range
874ef00
Save WIP.
asvinb Oct 3, 2024
1ead7f9
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 3, 2024
4428639
Extract DisconnectAccount button.
asvinb Oct 3, 2024
bebfaed
Add ConnectAccountCard component.
asvinb Oct 4, 2024
872787e
Add ConnectMCBody and ConnectMCFooter component.
asvinb Oct 4, 2024
9475ec2
Save WIP.
asvinb Oct 7, 2024
3965234
Check for non connected state.
asvinb Oct 7, 2024
8a4ba4c
Add preConditionReady check.
asvinb Oct 7, 2024
8b850fd
Revert dev temp changes.
asvinb Oct 7, 2024
176a4a8
Save E2E tests,
asvinb Oct 7, 2024
b4b4347
Merge branch 'feature/2509-consolidate-google-account-cards' into upd…
asvinb Oct 7, 2024
e9626f0
Save WIP.
asvinb Oct 8, 2024
57c4693
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 8, 2024
e86de9b
Review class names.
asvinb Oct 8, 2024
9ad469a
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 8, 2024
75723e2
Fix e2e tests.
asvinb Oct 8, 2024
9923f70
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 8, 2024
406f028
Use mock functions available.
asvinb Oct 8, 2024
26ec13a
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 9, 2024
acedda6
Address CR feedback.
asvinb Oct 9, 2024
13d8d2b
Cast googleMCAccount?.id to a boolean.
asvinb Oct 9, 2024
9e8649b
Add description when connecting extra account.
asvinb Oct 9, 2024
2981067
Fix card when reclaiming URL.
asvinb Oct 9, 2024
e03f3c3
Fix E2E tests.
asvinb Oct 9, 2024
3b096ff
Add isConnected property to useGoogleMCAccount hook.
asvinb Oct 10, 2024
deaa836
Removed unused constant.
asvinb Oct 10, 2024
66d6eb9
Wrap all cards together.
asvinb Oct 10, 2024
fa5b3ea
Add more properties to useAutoCreateAdsMCAccounts.js hook.
asvinb Oct 10, 2024
8707fea
Use useState.
asvinb Oct 10, 2024
14a08e8
Add isConnected check.
asvinb Oct 10, 2024
d3c2a36
Use single hook.
asvinb Oct 10, 2024
02a607a
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 16, 2024
25d2ff3
Save WIP.
asvinb Oct 16, 2024
a8d5db1
Save WIP
asvinb Oct 16, 2024
87a2046
Changes to how we manage the state.
asvinb Oct 16, 2024
06960d9
Fix select rendering.
asvinb Oct 16, 2024
8b06ef7
Revert changes
asvinb Oct 16, 2024
96c11a2
Update JSDocs.
asvinb Oct 17, 2024
3b1fe26
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 22, 2024
cd62e71
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 23, 2024
b582447
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 23, 2024
4eb41ac
Do not use template literals.
asvinb Oct 23, 2024
eb0bfc1
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 23, 2024
6696ee6
Update hooks.
asvinb Oct 23, 2024
d2e4b57
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 23, 2024
67b8d3b
Revert change.
asvinb Oct 23, 2024
ba5c054
Revert change.
asvinb Oct 23, 2024
6fd6dc4
Remove unused file.
asvinb Oct 23, 2024
c13c524
Review changes.
asvinb Oct 23, 2024
e845ece
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 24, 2024
b64bba7
Show ID only when connected.
asvinb Oct 24, 2024
841bb90
Make app select control non interactive.
asvinb Oct 24, 2024
dc6ea40
Fix failing test.
asvinb Oct 24, 2024
881ee8c
Fix linting error.
asvinb Oct 24, 2024
b9809e1
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 24, 2024
f41df99
Fix E2E tests.
asvinb Oct 24, 2024
2cadd89
Invalidate resolution for existing accounts when reclaiming url.
asvinb Oct 24, 2024
604c5c8
Invalidate existing accounts.
asvinb Oct 24, 2024
5f4435a
Add hasAccountConnectionIssue utility function.
asvinb Oct 25, 2024
8875a28
Connected select control.
asvinb Oct 25, 2024
49f51ca
Add MerchantCenterSelect component.
asvinb Oct 25, 2024
4d41762
No need to wait for data.
asvinb Oct 25, 2024
c117be7
Merge branch 'feature/2567-kickoff-mc-ads-account-creation' into upda…
asvinb Oct 25, 2024
fa72d4e
Merge branch 'feature/2509-consolidate-google-account-cards' into upd…
asvinb Oct 28, 2024
7a4e40d
Add JS Docs.
asvinb Oct 28, 2024
53c80c5
Update AccountCard component
joemcgill Oct 30, 2024
a9ea1b1
Incorporate new AccountCard into ConnectMC
joemcgill Oct 30, 2024
cb667fd
Update docblocks to AccountCard
joemcgill Oct 30, 2024
14c653c
JSLint fix
joemcgill Oct 30, 2024
a9c8839
Delete ConnectAccountCard
joemcgill Oct 30, 2024
a8b4f8c
Remove todo
joemcgill Oct 30, 2024
9c55a39
Add missing styles.
asvinb Oct 31, 2024
c40800b
Use correct button variant.
asvinb Oct 31, 2024
7a757a2
Merge pull request #2657 from woocommerce/update/2597-connect-mc-refa…
asvinb Oct 31, 2024
cc3e804
Sync changes.
asvinb Oct 31, 2024
8c4cd7a
Merge branch 'feature/2509-consolidate-google-account-cards' into upd…
asvinb Oct 31, 2024
a3040fe
Update JSDocs.
asvinb Oct 31, 2024
e75a930
Fix E2E tests.
asvinb Oct 31, 2024
8fba3e4
Remove unused functions.
asvinb Oct 31, 2024
17e7c84
Address CR feedback.
asvinb Nov 1, 2024
0e15813
Add MerchantCenterAccountInfoCard component.
asvinb Nov 4, 2024
4e201c1
Fix linting errors.
asvinb Nov 4, 2024
65e6854
Remove unused component.
asvinb Nov 4, 2024
4b777bc
Reorder imports.
asvinb Nov 4, 2024
9a368f1
Use correcct prop name.
asvinb Nov 4, 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
Expand Up @@ -17,13 +17,13 @@ import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount';
const AccountDetails = () => {
const { google } = useGoogleAccount();
const { googleAdsAccount } = useGoogleAdsAccount();
const { googleMCAccount } = useGoogleMCAccount();
const { googleMCAccount, isReady: isGoogleMCReady } = useGoogleMCAccount();

return (
<>
<p>{ google.email }</p>
<p>
{ googleMCAccount?.id > 0 &&
{ isGoogleMCReady &&
sprintf(
// Translators: %s is the Merchant Center ID
__(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import useApiFetchCallback from '.~/hooks/useApiFetchCallback';
import useDispatchCoreNotices from '.~/hooks/useDispatchCoreNotices';
import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';
import { useAppDispatch } from '.~/data';
import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts';
import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady';
import AccountCard from '.~/components/account-card';
import AdsAccountSelectControl from '.~/components/ads-account-select-control';
Expand All @@ -32,14 +31,7 @@ const ConnectAds = () => {
const { createNotice } = useDispatchCoreNotices();
const { fetchGoogleAdsAccountStatus } = useAppDispatch();
const isConnected = useGoogleAdsAccountReady();
const {
existingAccounts: accounts,
hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount,
} = useExistingGoogleAdsAccounts();
const {
googleAdsAccount,
hasFinishedResolution: hasFinishedResolutionForCurrentAccount,
} = useGoogleAdsAccount();
const { googleAdsAccount, hasFinishedResolution } = useGoogleAdsAccount();
const [ connectGoogleAdsAccount ] = useApiFetchCallback( {
path: '/wc/gla/ads/accounts',
method: 'POST',
Expand Down Expand Up @@ -75,16 +67,11 @@ const ConnectAds = () => {
}
};

// If the accounts are still being fetched, we don't want to show the card.
if (
! hasFinishedResolutionForExistingAdsAccount ||
! hasFinishedResolutionForCurrentAccount ||
! accounts?.length
) {
return null;
}

const getIndicator = () => {
if ( ! hasFinishedResolution ) {
return <LoadingLabel />;
}

if ( isLoading ) {
return (
<LoadingLabel
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import CreateAccountButton from '.~/components/google-mc-account-card/create-account-button';
import DisconnectAccountButton from '.~/components/google-mc-account-card/disconnect-account-button';

/**
* ConnectMCFooter component.
*
* This component renders the footer for the Merchant Center connection section.
* It conditionally renders either a button to disconnect the account if already
* connected, or a button to create a new Merchant Center account.
*
* @param {Object} props
* @param {boolean} props.isConnected Whether the Merchant Center account is connected.
* @param {Object} props.resultConnectMC The result of the connection request, used to handle loading state.
* @param {Object} props.resultCreateAccount The result of the create account request.
* @param {Function} props.handleCreateAccount Callback function for creating a new Merchant Center account.
*/
const ConnectMCFooter = ( {
isConnected,
resultConnectMC,
resultCreateAccount,
handleCreateAccount,
} ) => {
if ( isConnected ) {
const handleDisconnect = () => {
resultConnectMC.reset();
resultCreateAccount.reset();
};

return (
<DisconnectAccountButton
onDisconnect={ handleDisconnect }
isTertiary
/>
);
}

return (
<CreateAccountButton
isTertiary
disabled={ resultConnectMC.loading }
onCreateAccount={ handleCreateAccount }
>
{ __(
'Or, create a new Merchant Center account',
'google-listings-and-ads'
) }
</CreateAccountButton>
);
};

export default ConnectMCFooter;
137 changes: 137 additions & 0 deletions js/src/components/google-combo-account-card/connect-mc/connect-mc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { useEffect, useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount';
import AccountCard from '.~/components/account-card';
import AppButton from '.~/components/app-button';
import ConnectedIconLabel from '.~/components/connected-icon-label';
import ConnectMCFooter from './connect-mc-footer';
import LoadingLabel from '.~/components/loading-label';
import AccountConnectionStatus from '.~/components/google-mc-account-card/connect-mc/account-connection-status';
import MerchantCenterSelect from './merchant-center-select';
import useConnectMCAccount from '.~/hooks/useConnectMCAccount';
import { hasAccountConnectionIssue } from '.~/components/google-mc-account-card/connect-mc/utils';

/**
* Clicking on the "Switch account" button to select a different Google Merchant Center account to connect.
*
* @event gla_mc_account_switch_account_button_click
* @property {string} context (`switch-url`|`reclaim-url`) - indicate the button is clicked from which step.
*/

/**
* Clicking on the button to connect an existing Google Merchant Center account.
*
* @event gla_mc_account_connect_button_click
* @property {number} id The account ID to be connected.
*/

/**
* ConnectMC component.
*
* This component renders Merchant Center connection section.
* It is using createMCAccount and resultCreateMCAccount from the parent component.
* @fires gla_mc_account_connect_button_click
* @param {Object} props
* @param {Function} props.createMCAccount Callback function for creating a new Merchant Center account.
* @param {Object} props.resultCreateMCAccount The result of the create account request.
*/
const ConnectMC = ( { createMCAccount, resultCreateMCAccount } ) => {
joemcgill marked this conversation as resolved.
Show resolved Hide resolved
const {
googleMCAccount,
hasFinishedResolution,
isReady: isGoogleMCReady,
} = useGoogleMCAccount();
const [ accountID, setAccountID ] = useState();
const [ handleConnectMC, resultConnectMC ] =
useConnectMCAccount( accountID );

useEffect( () => {
if ( isGoogleMCReady ) {
setAccountID( googleMCAccount.id );
}
}, [ googleMCAccount, isGoogleMCReady ] );
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand why we need to save the MC account separately as component state here rather than using googleMcaccount.id directly?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joemcgill We need to save the value set from the select in case the user needs to connect to a different acccount.


const accountConnectionIssue = hasAccountConnectionIssue(
resultConnectMC,
resultCreateMCAccount
);

if ( ! isGoogleMCReady && accountConnectionIssue ) {
return (
<AccountConnectionStatus
resultConnectMC={ resultConnectMC }
resultCreateAccount={ resultCreateMCAccount }
onRetry={ createMCAccount }
/>
);
}

const getIndicator = () => {
if ( ! hasFinishedResolution ) {
return <LoadingLabel />;
}

if ( isGoogleMCReady ) {
return <ConnectedIconLabel />;
}

if ( resultConnectMC.loading ) {
return (
<LoadingLabel
text={ __( 'Connecting…', 'google-listings-and-ads' ) }
/>
);
}

return (
<AppButton
isSecondary
eventName="gla_mc_account_connect_button_click"
eventProps={ { id: Number( accountID ) } }
onClick={ handleConnectMC }
>
{ __( 'Connect', 'google-listings-and-ads' ) }
</AppButton>
);
};

return (
<AccountCard
className="gla-google-combo-account-card gla-google-combo-service-account-card--mc"
title={ __(
'Connect to existing Merchant Center account',
'google-listings-and-ads'
) }
helper={ __(
'Required to sync products so they show on Google.',
'google-listings-and-ads'
) }
alignIndicator="toDetail"
indicator={ getIndicator() }
detail={
<MerchantCenterSelect
isConnected={ isGoogleMCReady }
value={ accountID }
onChange={ setAccountID }
/>
}
actions={
<ConnectMCFooter
isConnected={ isGoogleMCReady }
resultConnectMC={ resultConnectMC }
resultCreateAccount={ resultCreateMCAccount }
handleCreateAccount={ createMCAccount }
/>
}
/>
);
};

export default ConnectMC;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './connect-mc';
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { getSetting } from '@woocommerce/settings'; // eslint-disable-line import/no-unresolved

/**
* Internal dependencies
*/
import MerchantCenterSelectControl from '.~/components/merchant-center-select-control';
import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts';
import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount';
import AppSelectControl from '.~/components/app-select-control';

/**
* Renders the connected Merchant Center details, leveraging existing functionality
* and styles from AppSelectControl.
*
* Ideally, using MerchantCenterSelectControl only to display the list of MC accounts would be fine. However, during testing,
* we found that when a URL is reclaimed for Merchant Center (MC), the Google API does not
* return the newly reclaimed account immediately in the list provided by the useExistingGoogleMCAccounts hook,
* even though the data in the store is invalidated. In that case, thus we end up having an account ID
* which is not in the list of existing accounts. We then fake the connected select by manually providing
* the connected ID.
*
* @param {Object} props
* @param {boolean} props.isConnected Whether the Merchant Center account is connected.
*/
const MerchantCenterSelect = ( { isConnected, ...rest } ) => {
const { data: existingAccounts } = useExistingGoogleMCAccounts();
const { googleMCAccount } = useGoogleMCAccount();
const domain = new URL( getSetting( 'homeUrl' ) ).host;
eason9487 marked this conversation as resolved.
Show resolved Hide resolved

const accountIdExists = existingAccounts?.some(
( existingAccount ) => existingAccount.id === googleMCAccount.id
);

// If the account ID is not in the list of existing accounts, fake the select options by displaying the connected account ID only.
if ( ! accountIdExists && isConnected ) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a clever workaround. I assume this is for a newly created account that has not yet shown up in the API response for existing accounts? If so, adding that context to the inline doc would be helpful.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return (
<AppSelectControl
autoSelectFirstOption
nonInteractive
value={ googleMCAccount.id }
options={ [
{
value: googleMCAccount.id,
label: sprintf(
// translators: 1: account domain, 2: account ID.
__( '%1$s (%2$s)', 'google-listings-and-ads' ),
domain,
googleMCAccount.id
),
},
] }
/>
);
}

return (
<MerchantCenterSelectControl
nonInteractive={ isConnected }
{ ...rest }
/>
);
};

export default MerchantCenterSelect;
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import Indicator from './indicator';
import getAccountCreationTexts from './getAccountCreationTexts';
import SpinnerCard from '.~/components/spinner-card';
import useAutoCreateAdsMCAccounts from '.~/hooks/useAutoCreateAdsMCAccounts';
import useGoogleMCAccount from '.~/hooks/useGoogleMCAccount';
import useExistingGoogleMCAccounts from '.~/hooks/useExistingGoogleMCAccounts';
import useCreateMCAccount from '.~/hooks/useCreateMCAccount';
import ConnectMC from './connect-mc';
import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady';
import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts';
import './connected-google-combo-account-card.scss';
Expand All @@ -17,7 +21,15 @@ 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 { hasDetermined, creatingWhich } = useAutoCreateAdsMCAccounts();
// We use a single instance of the hook to create a MC (Merchant Center) account,
// ensuring consistent results across both the main component (ConnectedGoogleComboAccountCard) and its child component (ConnectMC).
// This approach is especially useful when an MC account is automatically created, and the URL needs to be reclaimed.
// The URL reclaim component is rendered within the ConnectMC component.
const [ createMCAccount, resultCreateMCAccount ] = useCreateMCAccount();
const { data: existingGoogleMCAccounts } = useExistingGoogleMCAccounts();
const { isReady: isGoogleMCReady } = useGoogleMCAccount();
const { hasDetermined, creatingWhich } =
useAutoCreateAdsMCAccounts( createMCAccount );
const { text, subText } = getAccountCreationTexts( creatingWhich );
const { existingAccounts: existingGoogleAdsAccounts } =
useExistingGoogleAdsAccounts();
Expand All @@ -29,6 +41,11 @@ const ConnectedGoogleComboAccountCard = () => {

// @TODO: edit mode implementation in 2605
const editMode = false;
const hasExistingGoogleMCAccounts = existingGoogleMCAccounts?.length > 0;
const showConnectMC =
( editMode && hasExistingGoogleMCAccounts ) ||
( ! isGoogleMCReady && hasExistingGoogleMCAccounts );

const hasExistingGoogleAdsAccounts = existingGoogleAdsAccounts?.length > 0;
const showConnectAds =
( editMode && hasExistingGoogleAdsAccounts ) ||
Expand All @@ -39,7 +56,7 @@ const ConnectedGoogleComboAccountCard = () => {
<AccountCard
appearance={ APPEARANCE.GOOGLE }
alignIcon="top"
className="gla-google-combo-account-card--connected"
className="gla-google-combo-account-card gla-google-combo-account-card--connected"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding the gla-google-combo-account-card to be consistent with the other cards.

description={ text || <AccountDetails /> }
helper={ subText }
indicator={
Expand All @@ -48,6 +65,13 @@ const ConnectedGoogleComboAccountCard = () => {
/>

{ showConnectAds && <ConnectAds /> }

{ showConnectMC && (
<ConnectMC
createMCAccount={ createMCAccount }
resultCreateMCAccount={ resultCreateMCAccount }
/>
) }
</div>
);
};
Expand Down
Loading