-
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: Connect to existing Google Ads account via the combo card #2640
Changes from 12 commits
63b182b
f73c4b2
96e3ef2
7e73f98
ba5ca7b
df93a29
6fce3e6
4173593
2466f7e
a4d0eb4
f4fb5c2
4ef6d25
32864c3
2e6bcfe
2b7c811
aa6a670
fbb199f
c20fbea
7c9c848
57023bc
9617a63
9475fa2
8a562d1
693efd2
63c4fba
a83c242
73350ef
d58278e
5c3c5c3
47a0c3d
713afc0
5dd622e
87c0686
1299ad1
efe843a
da1a10e
690067d
fe1b2ec
6f85011
60a101a
098b886
0046434
b449092
31c35a8
f12e5e3
5632913
2724b0f
e5edd82
4901758
0b23082
c7e0e70
4c9bb4b
79a66ff
b77f799
e3bbd83
84811bd
4cba145
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import classNames from 'classnames'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import Section from '.~/wcdl/section'; | ||
import AccountCard from '.~/components/account-card'; | ||
import './connect-account-card.scss'; | ||
|
||
/** | ||
* ConnectAccountCard component renders an account card with a title, helper text, body, and footer sections. | ||
* | ||
* @param {Object} props Props. | ||
* @param {string} props.title The title of the account card. | ||
* @param {string} props.helperText The helper text for the account card. | ||
* @param {JSX.Element} props.body The content for the body of the account card. | ||
* @param {JSX.Element} props.footer The content for the footer of the account card. | ||
* @param {string} props.className Additional class names for the account card. | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @return {JSX.Element} ConnectAccountCard component. | ||
*/ | ||
const ConnectAccountCard = ( { | ||
title, | ||
helperText, | ||
body, | ||
footer, | ||
className = '', | ||
} ) => { | ||
return ( | ||
<AccountCard | ||
className={ classNames( | ||
'gla-google-combo-service-account-card', | ||
className | ||
) } | ||
title={ title } | ||
helper={ helperText } | ||
> | ||
<Section.Card.Body className="gla-google-combo-service-account-card__body"> | ||
{ body } | ||
</Section.Card.Body> | ||
<Section.Card.Footer className="gla-google-combo-service-account-card__footer"> | ||
{ footer } | ||
</Section.Card.Footer> | ||
</AccountCard> | ||
); | ||
}; | ||
|
||
export default ConnectAccountCard; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
.gla-google-combo-service-account-card { | ||
padding: var(--large-gap); | ||
|
||
> div { | ||
display: flex; | ||
flex-direction: column; | ||
gap: calc(var(--main-gap) / 2); | ||
} | ||
|
||
.wcdl-section-card-body, | ||
.gla-google-combo-service-account-card__body { | ||
padding: 0; | ||
|
||
.app-select-control { | ||
flex-grow: 1; | ||
} | ||
} | ||
|
||
.gla-google-combo-service-account-card__footer { | ||
border: 0; | ||
padding: 0; | ||
} | ||
|
||
.gla-connected-icon-label { | ||
flex-basis: content; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { useEffect, useRef } from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import AdsAccountSelectControl from '.~/components/ads-account-select-control'; | ||
import AppButton from '.~/components/app-button'; | ||
import ContentButtonLayout from '.~/components/content-button-layout'; | ||
import ConnectedIconLabel from '.~/components/connected-icon-label'; | ||
import LoadingLabel from '.~/components/loading-label/loading-label'; | ||
import useEventPropertiesFilter from '.~/hooks/useEventPropertiesFilter'; | ||
import { FILTER_ONBOARDING } from '.~/utils/tracks'; | ||
|
||
/** | ||
* | ||
* @param {Object} props Props. | ||
* @param {Array} props.accounts Accounts. | ||
* @param {Object} props.googleAdsAccount Google Ads account object. | ||
* @param {boolean} props.isConnected Whether the account is connected. | ||
* @param {Function} props.handleConnectClick Callback to handle the connect click. | ||
* @param {boolean} props.isLoading Whether the card is in a loading state. | ||
* @param {Function} props.setValue Callback to set the value. | ||
* @param {string} props.value Ads account ID. | ||
* @return {JSX.Element} Body component. | ||
*/ | ||
const ConnectAdsBody = ( { | ||
accounts, | ||
googleAdsAccount, | ||
isConnected, | ||
handleConnectClick, | ||
eason9487 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
isLoading, | ||
setValue, | ||
eason9487 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
value, | ||
} ) => { | ||
const initialValueRef = useRef( googleAdsAccount.id ); | ||
const getEventProps = useEventPropertiesFilter( FILTER_ONBOARDING ); | ||
|
||
useEffect( () => { | ||
setValue( initialValueRef.current ); | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}, [ initialValueRef, setValue ] ); | ||
|
||
const ConnectCTA = () => { | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if ( isConnected && initialValueRef.current === Number( value ) ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ankitrox I feel There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @asvinb It checks whether:
In this case, we show There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ankitrox Not sure if am following here. When in connected state, the select is disabled, meaning the only way to change the Ads ID is by disconnecting the Ads account. So if we just check for |
||
return <ConnectedIconLabel />; | ||
} | ||
|
||
return ( | ||
<AppButton | ||
isSecondary | ||
disabled={ ! value } | ||
eventName="gla_ads_account_connect_button_click" | ||
eventProps={ getEventProps( { | ||
id: Number( value ), | ||
} ) } | ||
onClick={ handleConnectClick } | ||
> | ||
{ __( 'Connect', 'google-listings-and-ads' ) } | ||
</AppButton> | ||
); | ||
}; | ||
|
||
return ( | ||
<ContentButtonLayout> | ||
<AdsAccountSelectControl | ||
accounts={ accounts } | ||
value={ value } | ||
onChange={ setValue } | ||
/> | ||
{ isLoading ? ( | ||
<LoadingLabel | ||
text={ __( 'Connecting…', 'google-listings-and-ads' ) } | ||
/> | ||
) : ( | ||
<ConnectCTA /> | ||
) } | ||
</ContentButtonLayout> | ||
); | ||
}; | ||
|
||
export default ConnectAdsBody; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import AppButton from '.~/components/app-button'; | ||
|
||
/** | ||
* | ||
* @param {Object} props Props. | ||
* @param {boolean} props.isLoading Whether the footer is in a loading state. | ||
* @param {Function} props.onCreateNew Callback to handle the new ads account creation. | ||
* @return {JSX.Element} Footer component. | ||
*/ | ||
const ConnectAdsFooter = ( { isLoading, onCreateNew = () => {} } ) => ( | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
<AppButton isTertiary disabled={ isLoading } onClick={ onCreateNew }> | ||
{ __( | ||
'Or, create a new Google Ads account', | ||
'google-listings-and-ads' | ||
) } | ||
</AppButton> | ||
); | ||
|
||
export default ConnectAdsFooter; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { useState } from '@wordpress/element'; | ||
import { __ } from '@wordpress/i18n'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import AccountCard from '.~/components/account-card'; | ||
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 ConnectAccountCard from '../connect-account-card'; | ||
import ConnectAdsFooter from './connect-ads-footer'; | ||
import ConnectAdsBody from './connect-ads-body'; | ||
|
||
/** | ||
* Clicking on the button to connect an existing Google Ads account. | ||
* | ||
* @event gla_ads_account_connect_button_click | ||
* @property {number} id The account ID to be connected. | ||
* @property {string} [context] Indicates the place where the button is located. | ||
* @property {string} [step] Indicates the step in the onboarding process. | ||
*/ | ||
|
||
/** | ||
* ConnectAds component renders an account card to connect to an existing Google Ads account. | ||
* | ||
* @fires gla_ads_account_connect_button_click when "Connect" button is clicked. | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @fires gla_documentation_link_click with `{ context: 'setup-ads-connect-account', link_id: 'connect-sub-account', href: 'https://support.google.com/google-ads/answer/6139186' }` | ||
eason9487 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @return {JSX.Element} {@link AccountCard} filled with content. | ||
*/ | ||
const ConnectAds = () => { | ||
eason9487 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const { | ||
existingAccounts: accounts, | ||
hasFinishedResolution: hasFinishedResolutionForExistingAdsAccount, | ||
} = useExistingGoogleAdsAccounts(); | ||
|
||
const { | ||
googleAdsAccount, | ||
hasFinishedResolution: hasFinishedResolutionForCurrentAccount, | ||
} = useGoogleAdsAccount(); | ||
|
||
const isConnected = | ||
googleAdsAccount?.status === 'connected' || | ||
( googleAdsAccount?.status === 'incomplete' && | ||
googleAdsAccount?.step === 'link_merchant' ); | ||
eason9487 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const [ value, setValue ] = useState(); | ||
const [ isLoading, setLoading ] = useState( false ); | ||
const [ fetchConnectAdsAccount ] = useApiFetchCallback( { | ||
eason9487 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
path: `/wc/gla/ads/accounts`, | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
method: 'POST', | ||
data: { id: value }, | ||
} ); | ||
const { refetchGoogleAdsAccount } = useGoogleAdsAccount(); | ||
const { createNotice } = useDispatchCoreNotices(); | ||
const { fetchGoogleAdsAccountStatus } = useAppDispatch(); | ||
|
||
const handleConnectClick = async () => { | ||
if ( ! value ) { | ||
return; | ||
} | ||
|
||
setLoading( true ); | ||
try { | ||
await fetchConnectAdsAccount(); | ||
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' | ||
) | ||
); | ||
} | ||
}; | ||
|
||
// If the accounts are still being fetched, we don't want to show the card. | ||
if ( | ||
! hasFinishedResolutionForExistingAdsAccount || | ||
! hasFinishedResolutionForCurrentAccount || | ||
accounts.length === 0 | ||
) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<ConnectAccountCard | ||
className="gla-google-combo-service-account-card--ads" | ||
title={ __( | ||
'Connect to existing Google Ads account', | ||
'google-listings-and-ads' | ||
) } | ||
helperText={ __( | ||
'Required to set up conversion measurement for your store.', | ||
'google-listings-and-ads' | ||
) } | ||
body={ | ||
<ConnectAdsBody | ||
{ ...{ | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
accounts, | ||
googleAdsAccount, | ||
isConnected, | ||
handleConnectClick, | ||
isLoading, | ||
setValue, | ||
value, | ||
} } | ||
/> | ||
} | ||
footer={ <ConnectAdsFooter /> } | ||
/> | ||
); | ||
}; | ||
|
||
export default ConnectAds; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
/** | ||
asvinb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* Internal dependencies | ||
*/ | ||
|
||
export { default as ConnectAds } from './connect-ads'; |
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.
Just FYI, this will updated in https://github.com/woocommerce/google-listings-and-ads/pull/2639/files#diff-8c885f578f99827b77511ccb568a741365e07f9fd3eecea8bc62ac67253ac3a3R126