Skip to content

Commit

Permalink
Merge pull request #2660 from woocommerce/update/2605-edit-accounts
Browse files Browse the repository at this point in the history
Consolidate accounts onboarding: Add edit mode to the combo card to enable it to disconnect accounts
  • Loading branch information
eason9487 authored Nov 21, 2024
2 parents 64085a0 + 68fa52b commit 4998d88
Show file tree
Hide file tree
Showing 19 changed files with 564 additions and 90 deletions.
36 changes: 36 additions & 0 deletions js/src/components/ads-account-select-control/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,51 @@
/**
* External dependencies
*/
import { __, sprintf } from '@wordpress/i18n';
import { getSetting } from '@woocommerce/settings'; // eslint-disable-line import/no-unresolved

/**
* Internal dependencies
*/
import AppSelectControl from '.~/components/app-select-control';
import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts';
import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';

/**
* @param {Object} props The component props
* @return {JSX.Element} An enhanced AppSelectControl component.
*/
const AdsAccountSelectControl = ( props ) => {
const { existingAccounts } = useExistingGoogleAdsAccounts();
const { googleAdsAccount, hasGoogleAdsConnection } = useGoogleAdsAccount();

const accountIdExists = existingAccounts?.some(
( existingAccount ) => existingAccount.id === googleAdsAccount?.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 && hasGoogleAdsConnection ) {
const domain = new URL( getSetting( 'homeUrl' ) ).host;

Check warning on line 28 in js/src/components/ads-account-select-control/index.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/ads-account-select-control/index.js#L28

Added line #L28 was not covered by tests

return (

Check warning on line 30 in js/src/components/ads-account-select-control/index.js

View check run for this annotation

Codecov / codecov/patch

js/src/components/ads-account-select-control/index.js#L30

Added line #L30 was not covered by tests
<AppSelectControl
autoSelectFirstOption
nonInteractive
value={ googleAdsAccount.id }
options={ [
{
value: googleAdsAccount.id,
label: sprintf(
// translators: 1: account domain, 2: account ID.
__( '%1$s (%2$s)', 'google-listings-and-ads' ),
domain,
googleAdsAccount.id
),
},
] }
/>
);
}

const options = existingAccounts?.map( ( acc ) => ( {
value: acc.id,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,10 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import AccountCard, { APPEARANCE } from '.~/components/account-card';
import AppButton from '.~/components/app-button';
import ConnectedIconLabel from '.~/components/connected-icon-label';
import Section from '.~/wcdl/section';
import useSwitchGoogleAccount from './useSwitchGoogleAccount';

/**
* Clicking on the "connect to a different Google account" button.
*
* @event gla_google_account_connect_different_account_button_click
*/
import SwitchAccountButton from './switch-account-button';

/**
* Renders a Google account card UI with connected account information.
Expand All @@ -26,16 +14,12 @@ import useSwitchGoogleAccount from './useSwitchGoogleAccount';
* @param {{ email: string }} props.googleAccount A data payload object containing the user's Google account email.
* @param {JSX.Element} [props.helper] Helper content below the Google account email.
* @param {boolean} [props.hideAccountSwitch=false] Indicate whether hide the account switch block at the card footer.
*
* @fires gla_google_account_connect_different_account_button_click
*/
const ConnectedGoogleAccountCard = ( {
googleAccount,
helper,
hideAccountSwitch = false,
} ) => {
const [ handleSwitch, { loading } ] = useSwitchGoogleAccount();

return (
<AccountCard
appearance={ APPEARANCE.GOOGLE }
Expand All @@ -45,16 +29,7 @@ const ConnectedGoogleAccountCard = ( {
>
{ ! hideAccountSwitch && (
<Section.Card.Footer>
<AppButton
isLink
disabled={ loading }
text={ __(
'Or, connect to a different Google account',
'google-listings-and-ads'
) }
eventName="gla_google_account_connect_different_account_button_click"
onClick={ handleSwitch }
/>
<SwitchAccountButton />
</Section.Card.Footer>
) }
</AccountCard>
Expand Down
46 changes: 46 additions & 0 deletions js/src/components/google-account-card/switch-account-button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import AppButton from '.~/components/app-button';
import useSwitchGoogleAccount from './useSwitchGoogleAccount';

/**
* Clicking on the "connect to a different Google account" button.
*
* @event gla_google_account_connect_different_account_button_click
*/

/**
* Renders a switch button that lets user connect with another Google account.
*
* @fires gla_google_account_connect_different_account_button_click
* @param {Object} props React props
* @param {string} [props.text="Or, connect to a different Google account"] Text to display on the button
*/
const SwitchAccountButton = ( {
text = __(
'Or, connect to a different Google account',
'google-listings-and-ads'
),
...restProps
} ) => {
const [ handleSwitch, { loading } ] = useSwitchGoogleAccount();

return (
<AppButton
isLink
disabled={ loading }
text={ text }
eventName="gla_google_account_connect_different_account_button_click"
onClick={ handleSwitch }
{ ...restProps }
/>
);
};

export default SwitchAccountButton;
10 changes: 10 additions & 0 deletions js/src/components/google-account-card/useSwitchGoogleAccount.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ const useSwitchGoogleAccount = () => {
method: 'DELETE',
} );

const [
fetchGoogleAdsDisconnect,
{ loading: loadingGoogleAdsDisconnect },
] = useApiFetchCallback( {
path: `${ API_NAMESPACE }/ads/connection`,
method: 'DELETE',
} );

/**
* Note: we are manually calling `DELETE /google/connect` instead of using
* `disconnectGoogleAccount` action from wp-data store
Expand Down Expand Up @@ -66,6 +74,7 @@ const useSwitchGoogleAccount = () => {

try {
await fetchGoogleMCDisconnect();
await fetchGoogleAdsDisconnect();
await fetchGoogleDisconnect();
const { url } = await fetchGoogleConnect();
window.location.href = url;
Expand All @@ -83,6 +92,7 @@ const useSwitchGoogleAccount = () => {

const loading =
loadingGoogleMCDisconnect ||
loadingGoogleAdsDisconnect ||
loadingGoogleDisconnect ||
loadingGoogleConnect ||
dataGoogleConnect;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Icon } from '@wordpress/components';
import { external as externalIcon } from '@wordpress/icons';

/**
* Internal dependencies
Expand Down Expand Up @@ -40,13 +42,13 @@ const ClaimAdsAccount = () => {
'google-listings-and-ads'
) }
</p>
<ClaimAccountButton
text={ __(
<ClaimAccountButton isPrimary>
{ __(
'Claim account in Google Ads',
'google-listings-and-ads'
) }
isPrimary
/>
<Icon icon={ externalIcon } size={ 20 } />
</ClaimAccountButton>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,47 @@ import { __ } from '@wordpress/i18n';
*/
import AppButton from '.~/components/app-button';
import DisconnectAccount from '.~/components/google-ads-account-card/disconnect-account';
import useExistingGoogleAdsAccounts from '.~/hooks/useExistingGoogleAdsAccounts';
import useGoogleAdsAccountStatus from '.~/hooks/useGoogleAdsAccountStatus';
import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';

/**
* Footer component.
*
* @param {Object} props Props.
* @param {boolean} props.isConnected Whether the account is connected.
* @param {Function} props.onCreateNewClick Callback when clicking on the button to create a new account.
* @param {boolean} props.disabled Whether to disable the create account button.
* @param {Object} props.restProps Rest props. Passed to AppButton.
* @return {JSX.Element} Footer component.
*/
const ConnectAdsFooter = ( {
isConnected,
onCreateNewClick,
disabled,
...restProps
} ) => {
if ( isConnected ) {
const { existingAccounts } = useExistingGoogleAdsAccounts();
const { googleAdsAccount } = useGoogleAdsAccount();
const { hasAccess } = useGoogleAdsAccountStatus();
const shouldClaimGoogleAdsAccount = Boolean(
googleAdsAccount?.id && hasAccess === false
);

if ( isConnected && existingAccounts.length > 0 ) {
return <DisconnectAccount />;
}

const disabledButton =
disabled ||
( shouldClaimGoogleAdsAccount && ! existingAccounts.length );
return (
<AppButton isTertiary onClick={ onCreateNewClick } { ...restProps }>
<AppButton
isTertiary
onClick={ onCreateNewClick }
disabled={ disabledButton }
{ ...restProps }
>
{ __(
'Or, create a new Google Ads account',
'google-listings-and-ads'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,23 @@ const ConnectExistingAccount = ( { onCreateClick } ) => {
const { createNotice } = useDispatchCoreNotices();
const { fetchGoogleAdsAccountStatus } = useAppDispatch();
const isConnected = useGoogleAdsAccountReady();
const { googleAdsAccount, hasFinishedResolution, refetchGoogleAdsAccount } =
useGoogleAdsAccount();
const {
googleAdsAccount,
hasFinishedResolution,
hasGoogleAdsConnection,
refetchGoogleAdsAccount,
} = useGoogleAdsAccount();
const [ connectGoogleAdsAccount ] = useApiFetchCallback( {
path: '/wc/gla/ads/accounts',
method: 'POST',
data: { id: value },
} );

useEffect( () => {
if ( isConnected ) {
if ( hasGoogleAdsConnection ) {
setValue( googleAdsAccount.id );
}
}, [ googleAdsAccount, isConnected ] );
}, [ googleAdsAccount, hasGoogleAdsConnection ] );

const handleConnectClick = async () => {
if ( ! value ) {
Expand Down Expand Up @@ -86,7 +90,11 @@ const ConnectExistingAccount = ( { onCreateClick } ) => {
}

return (
<ConnectButton accountID={ value } onClick={ handleConnectClick } />
<ConnectButton
disabled={ hasGoogleAdsConnection }
accountID={ value }
onClick={ handleConnectClick }
/>
);
};

Expand All @@ -108,13 +116,13 @@ const ConnectExistingAccount = ( { onCreateClick } ) => {
value={ value }
onChange={ setValue }
autoSelectFirstOption
nonInteractive={ isConnected }
nonInteractive={ hasGoogleAdsConnection }
/>
}
actions={
<ConnectAdsFooter
disabled={ isLoading }
isConnected={ isConnected }
isConnected={ hasGoogleAdsConnection }
onCreateNewClick={ onCreateClick }
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const UpsertingAccount = ( { upsertingAction } ) => {
className="gla-google-combo-service-account-card--ads"
title={ title }
helper={ __(
'This may take a few minutes, please wait a moment…',
'This may take a few moments, please wait…',
'google-listings-and-ads'
) }
indicator={ <LoadingLabel text={ indicatorLabel } /> }
Expand Down
Loading

0 comments on commit 4998d88

Please sign in to comment.