Skip to content

Commit

Permalink
Merge pull request #2651 from woocommerce/update/2603-create-ads-account
Browse files Browse the repository at this point in the history
Onboarding: Create new ads account.
  • Loading branch information
joemcgill authored Nov 13, 2024
2 parents 768ce3c + f2aa1c9 commit 14c080e
Show file tree
Hide file tree
Showing 10 changed files with 401 additions and 117 deletions.
2 changes: 1 addition & 1 deletion js/src/components/account-card/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ const appearanceDict = {
// The `center` is the default alignment, and no need to append any additional class name.
const alignStyleName = {
center: false,
top: `gla-account-card__styled--align-top`,
top: 'gla-account-card__styled--align-top',
};

const indicatorAlignStyleName = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import AppModal from '.~/components/app-modal';
import AppButton from '.~/components/app-button';
import WarningIcon from '.~/components/warning-icon';
import './confirm-create-modal.scss';

/**
* Google Ads account creation confirmation modal.
* This modal is shown when the user tries to create a new Google Ads account.
*
* @param {Object} props Component props.
* @param {Function} props.onContinue Callback to continue with account creation.
* @param {Function} props.onRequestClose Callback to close the modal.
* @return {JSX.Element} Confirmation modal.
*/
const ConfirmCreateModal = ( { onContinue, onRequestClose } ) => {
return (
<AppModal
className="gla-ads-warning-modal"
title={ __(
'Create Google Ads Account',
'google-listings-and-ads'
) }
buttons={ [
<AppButton key="confirm" isSecondary onClick={ onContinue }>
{ __(
'Yes, I want a new account',
'google-listings-and-ads'
) }
</AppButton>,
<AppButton key="cancel" isPrimary onClick={ onRequestClose }>
{ __( 'Cancel', 'google-listings-and-ads' ) }
</AppButton>,
] }
onRequestClose={ onRequestClose }
>
<p className="gla-ads-warning-modal__warning-text">
<WarningIcon />
<span>
{ __(
'Are you sure you want to create a new Google Ads account?',
'google-listings-and-ads'
) }
</span>
</p>
<p>
{ __(
'You already have another Ads account associated with this Google account.',
'google-listings-and-ads'
) }
</p>
<p>
{ __(
'If you create a new Google Ads account, you will need to accept an invite to the account before it can be used.',
'google-listings-and-ads'
) }
</p>
</AppModal>
);
};

export default ConfirmCreateModal;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.gla-ads-warning-modal {

.gla-ads-warning-modal__warning-text {
display: flex;
align-items: center;
gap: calc(var(--main-gap) / 3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,21 @@ import DisconnectAccount from '.~/components/google-ads-account-card/disconnect-
*
* @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 {Object} props.restProps Rest props. Passed to AppButton.
* @return {JSX.Element} Footer component.
*/
const ConnectAdsFooter = ( { isConnected, ...restProps } ) => {
// If the account is connected, show the disconnect button.
const ConnectAdsFooter = ( {
isConnected,
onCreateNewClick,
...restProps
} ) => {
if ( isConnected ) {
return <DisconnectAccount />;
}

return (
<AppButton isTertiary { ...restProps }>
<AppButton isTertiary onClick={ onCreateNewClick } { ...restProps }>
{ __(
'Or, create a new Google Ads account',
'google-listings-and-ads'
Expand Down
124 changes: 28 additions & 96 deletions js/src/components/google-combo-account-card/connect-ads/connect-ads.js
Original file line number Diff line number Diff line change
@@ -1,122 +1,54 @@
/**
* External dependencies
*/
import { useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import useApiFetchCallback from '.~/hooks/useApiFetchCallback';
import useDispatchCoreNotices from '.~/hooks/useDispatchCoreNotices';
import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';
import { useAppDispatch } from '.~/data';
import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady';
import AccountCard from '.~/components/account-card';
import AdsAccountSelectControl from '.~/components/ads-account-select-control';
import ConnectedIconLabel from '.~/components/connected-icon-label';
import ConnectAdsFooter from './connect-ads-footer';
import LoadingLabel from '.~/components/loading-label';
import ConnectButton from '.~/components/google-ads-account-card/connect-ads/connect-button';
import ConfirmCreateModal from './confirm-create-modal';
import ConnectExistingAccount from './connect-existing-account';
import UpsertingAccount from './upserting-account';

/**
* ConnectAds component renders an account card to connect to an existing Google Ads account.
*
* @param {Object} props Component props.
* @param {Function} props.onRequestCreate A callback to fire when creating a new account.
* @param {string|null} props.upsertingAction The action the user is performing. Possible values are 'create', 'update', or null.
* @return {JSX.Element} {@link AccountCard} filled with content.
*/
const ConnectAds = () => {
const [ value, setValue ] = useState();
const [ isLoading, setLoading ] = useState( false );
const { refetchGoogleAdsAccount } = useGoogleAdsAccount();
const { createNotice } = useDispatchCoreNotices();
const { fetchGoogleAdsAccountStatus } = useAppDispatch();
const isConnected = useGoogleAdsAccountReady();
const { googleAdsAccount, hasFinishedResolution } = useGoogleAdsAccount();
const [ connectGoogleAdsAccount ] = useApiFetchCallback( {
path: '/wc/gla/ads/accounts',
method: 'POST',
data: { id: value },
} );
const ConnectAds = ( { onRequestCreate, upsertingAction } ) => {
const [ showCreateNewModal, setShowCreateNewModal ] = useState( false );

useEffect( () => {
if ( isConnected ) {
setValue( googleAdsAccount.id );
}
}, [ googleAdsAccount, isConnected ] );
if ( upsertingAction ) {
return <UpsertingAccount upsertingAction={ upsertingAction } />;
}

const handleConnectClick = async () => {
if ( ! value ) {
return;
}

setLoading( true );
try {
await connectGoogleAdsAccount();
await fetchGoogleAdsAccountStatus();
await refetchGoogleAdsAccount();
setLoading( false );
} catch ( error ) {
setLoading( false );
createNotice(
'error',
__(
'Unable to connect your Google Ads account. Please try again later.',
'google-listings-and-ads'
)
);
}
const handleCreateClick = () => {
setShowCreateNewModal( true );
};

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

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

if ( isConnected ) {
return <ConnectedIconLabel />;
}
const handleRequestClose = () => {
setShowCreateNewModal( false );
};

return (
<ConnectButton accountID={ value } onClick={ handleConnectClick } />
);
const handleContinue = () => {
onRequestCreate();
handleRequestClose();
};

return (
<AccountCard
className="gla-google-combo-account-card gla-google-combo-service-account-card--ads"
title={ __(
'Connect to existing Google Ads account',
'google-listings-and-ads'
) }
helper={ __(
'Required to set up conversion measurement for your store.',
'google-listings-and-ads'
) }
alignIndicator="toDetail"
indicator={ getIndicator() }
detail={
<AdsAccountSelectControl
value={ value }
onChange={ setValue }
autoSelectFirstOption
nonInteractive={ isConnected }
<>
<ConnectExistingAccount onCreateClick={ handleCreateClick } />
{ showCreateNewModal && (
<ConfirmCreateModal
onContinue={ handleContinue }
onRequestClose={ handleRequestClose }
/>
}
actions={
<ConnectAdsFooter
isConnected={ isConnected }
disabled={ isLoading }
/>
}
/>
) }
</>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/**
* External dependencies
*/
import { useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import AccountCard from '.~/components/account-card';
import ConnectAdsFooter from './connect-ads-footer';
import LoadingLabel from '.~/components/loading-label';
import useApiFetchCallback from '.~/hooks/useApiFetchCallback';
import useDispatchCoreNotices from '.~/hooks/useDispatchCoreNotices';
import useGoogleAdsAccount from '.~/hooks/useGoogleAdsAccount';
import { useAppDispatch } from '.~/data';
import useGoogleAdsAccountReady from '.~/hooks/useGoogleAdsAccountReady';
import AdsAccountSelectControl from '.~/components/ads-account-select-control';
import ConnectedIconLabel from '.~/components/connected-icon-label';
import ConnectButton from '.~/components/google-ads-account-card/connect-ads/connect-button';

/**
* Renders an account card to connect to an existing Google Ads account.
*
* @param {Object} props Component props.
* @param {Function} props.onCreateClick Callback when clicking on the button to create a new account
*/
const ConnectExistingAccount = ( { onCreateClick } ) => {
const [ value, setValue ] = useState();
const [ isLoading, setLoading ] = useState( false );
const { createNotice } = useDispatchCoreNotices();
const { fetchGoogleAdsAccountStatus } = useAppDispatch();
const isConnected = useGoogleAdsAccountReady();
const { googleAdsAccount, hasFinishedResolution, refetchGoogleAdsAccount } =
useGoogleAdsAccount();
const [ connectGoogleAdsAccount ] = useApiFetchCallback( {
path: '/wc/gla/ads/accounts',
method: 'POST',
data: { id: value },
} );

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

const handleConnectClick = async () => {
if ( ! value ) {
return;
}

setLoading( true );
try {
await connectGoogleAdsAccount();
await fetchGoogleAdsAccountStatus();
await refetchGoogleAdsAccount();
} catch ( error ) {
createNotice(
'error',
__(
'Unable to connect your Google Ads account. Please try again later.',
'google-listings-and-ads'
)
);
} finally {
setLoading( false );
}
};

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

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

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

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

return (
<AccountCard
className="gla-google-combo-account-card gla-google-combo-service-account-card--ads"
title={ __(
'Connect to existing Google Ads account',
'google-listings-and-ads'
) }
helper={ __(
'Required to set up conversion measurement for your store.',
'google-listings-and-ads'
) }
alignIndicator="toDetail"
indicator={ getIndicator() }
detail={
<AdsAccountSelectControl
value={ value }
onChange={ setValue }
autoSelectFirstOption
nonInteractive={ isConnected }
/>
}
actions={
<ConnectAdsFooter
disabled={ isLoading }
isConnected={ isConnected }
onCreateNewClick={ onCreateClick }
/>
}
/>
);
};

export default ConnectExistingAccount;
Loading

0 comments on commit 14c080e

Please sign in to comment.