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

Free Listings + Paid Ads: Update learn more links, FAQs, CSS disclaimer, submission success modal, and title of free listings settings #1679

Merged
merged 9 commits into from
Sep 21, 2022
3 changes: 2 additions & 1 deletion js/src/components/faqs-panel/index.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.gla-faqs-panel {
.components-panel__row {
display: block;
flex-direction: column;
gap: 1.5em;
}

.components-panel__body-title {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@ import './index.scss';

/**
* Hero element for free listing configuration.
*
* @param {Object} props React props.
* @param {JSX.Element} props.headerTitle Title in the header block.
*/
const Hero = () => {
const Hero = ( { headerTitle } ) => {
return (
<div className="gla-setup-free-listing-hero">
<StepContentHeader
className="hero-text"
title={ __(
'Configure your product listings',
'google-listings-and-ads'
) }
title={ headerTitle }
description={
<div>
<p className="hero-text__subtitle">
Expand Down
4 changes: 3 additions & 1 deletion js/src/components/free-listings/setup-free-listings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const getSettings = ( values ) => {
* @param {(newValue: Object) => void} [props.onShippingTimesChange] Callback called with new data once shipping times are changed. Forwarded from {@link Form.Props.onChange}.
* @param {() => void} [props.onContinue] Callback called once continue button is clicked. Could be async. While it's being resolved the form would turn into a saving state.
* @param {string} [props.submitLabel] Submit button label, to be forwarded to `FormContent`.
* @param {JSX.Element} props.headerTitle Title in the header block of this setup.
*/
const SetupFreeListings = ( {
targetAudience,
Expand All @@ -86,6 +87,7 @@ const SetupFreeListings = ( {
onShippingTimesChange = noop,
onContinue = noop,
submitLabel,
headerTitle,
} ) => {
const [ saving, setSaving ] = useState( false );
const formPropsDelegateeRef = useRef( [] );
Expand Down Expand Up @@ -137,7 +139,7 @@ const SetupFreeListings = ( {

return (
<div className="gla-setup-free-listings">
<Hero />
<Hero headerTitle={ headerTitle } />
<Form
initialValues={ {
// Fields for target audience.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,17 @@ import DisabledCard from './disabled-card';
import NonConnected from './non-connected';

const GoogleMCAccountCard = () => {
const { hasFinishedResolution, googleMCAccount } = useGoogleMCAccount();
const {
hasFinishedResolution,
isPreconditionReady,
googleMCAccount,
} = useGoogleMCAccount();

if ( ! hasFinishedResolution ) {
return <SpinnerCard />;
}

/**
* If there is no googleMCAccount, this means users have not connected their Google account,
* or have not granted necessary access permissions for Google Merchant Center,
* so we show a DisabledCard here.
*/
if ( ! googleMCAccount ) {
if ( ! isPreconditionReady ) {
return <DisabledCard />;
}

Expand Down
118 changes: 69 additions & 49 deletions js/src/components/paid-ads/faqs-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,74 +2,94 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Panel, PanelBody, PanelRow } from '@wordpress/components';
import { recordEvent } from '@woocommerce/tracks';

/**
* Internal dependencies
*/
import Section from '.~/wcdl/section';
import FaqsPanel from '.~/components/faqs-panel';

const faqItems = [
{
trackId: 'how-does-google-ads-work',
question: __( 'How does Google Ads work?', 'google-listings-and-ads' ),
answer: __(
'Google Ads works by displaying your ad when people search online for the products and services you offer. By leveraging smart technology, Google Ads helps get your ads in front of potential customers at just the moment they’re ready to take action.',
'google-listings-and-ads'
),
},
{
trackId: 'what-is-a-product-feed',
question: __( 'What is a product feed?', 'google-listings-and-ads' ),
answer: __(
'Your product feed is the central data source that contains a list of products you want to advertise through Merchant Center. By default, Google syncs all active products from your WooCommerce inventory. You can choose to exclude products later after this setup.',
'google-listings-and-ads'
),
},
{
trackId: 'how-much-does-google-ads-cost',
question: __(
'How much does Google Ads cost?',
'google-listings-and-ads'
),
answer: __(
'With Google Ads, you decide how much to spend. There’s no minimum spend, and no time commitment. Your costs may vary from day to day, but you won’t be charged more than your daily budget times the number of days in a month. You pay only for the actual clicks and calls that your ad receives.',
'google-listings-and-ads'
),
},
{
trackId: 'where-will-my-products-appear',
question: __(
'Where will my products appear?',
'google-listings-and-ads'
),
answer: (
<>
<div>
{ __(
'If you’re selling in the US, then eligible free listings can appear in search results across Google Search, Google Images, and the Google Shopping tab. If you’re selling outside the US, free listings will appear on the Shopping tab.',
'google-listings-and-ads'
) }
</div>
<div>
{ __(
'If you’re running a Performance Max Campaign, your approved products can appear on Google Search, Google Maps, the Shopping tab, Gmail, Youtube, the Google Display Network, and Discover feed.',
'google-listings-and-ads'
) }
</div>
</>
),
},
{
trackId: 'how-long-until-i-see-results-with-google-ads',
question: __(
'How long until I see results with Google Ads?',
'google-listings-and-ads'
),
answer: __(
'Google’s Performance Max campaigns are powered by machine learning models. These models train and adapt based on the data you provide in your campaign. This means performance optimization can take time. Typically, this learning process takes 1—2 weeks.',
'google-listings-and-ads'
),
},
];

/**
* Clicking on faq items to collapse or expand it in the Setup Ads page
* Clicking on faq items to collapse or expand it in the Onboarding Flow or creating/editing a campaign
*
* @event gla_setup_ads_faq
* @property {string} id FAQ identifier
* @property {string} action (`expand`|`collapse`)
*/

/**
* Renders a toggleable FAQs section about Google Ads.
*
* @fires gla_setup_ads_faq
*/
const FaqsSection = () => {
const getPanelToggleHandler = ( id ) => ( isOpened ) => {
recordEvent( 'gla_setup_ads_faq', {
id,
action: isOpened ? 'expand' : 'collapse',
} );
};

return (
<Section>
<Panel
header={ __(
'Frequently asked questions',
'google-listings-and-ads'
) }
>
<PanelBody
initialOpen={ false }
title={ __(
'What do I pay for?',
'google-listings-and-ads'
) }
onToggle={ getPanelToggleHandler( 'what-do-i-pay-for' ) }
>
<PanelRow>
{ __(
'You only pay when someone clicks on your product ads to your store.',
'google-listings-and-ads'
) }
</PanelRow>
</PanelBody>
<PanelBody
initialOpen={ false }
title={ __(
'What does daily average or monthly max mean?',
'google-listings-and-ads'
) }
onToggle={ getPanelToggleHandler(
'what-does-daily-average-monthly-max-mean'
) }
>
<PanelRow>
{ __(
'Some days you might spend less than your daily average, and on others you might spend up to 4 times as much. But over a month, your total spend across the month will be approximately as calculated above.',
'google-listings-and-ads'
) }
</PanelRow>
</PanelBody>
</Panel>
<FaqsPanel trackName="gla_setup_ads_faq" faqItems={ faqItems } />
</Section>
);
};
Expand Down
6 changes: 6 additions & 0 deletions js/src/data/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ export const getSettings = ( state ) => {
* @property {string|''} displayName Owner name. Available for jetpack owner.
*/

/**
* @typedef {Object} GoogleMCAccount
* @property {number} id Account ID. It's 0 if not yet connected.
* @property {string} status Connection status.
*/

/**
* Select jetpack connection state.
*
Expand Down
4 changes: 4 additions & 0 deletions js/src/edit-free-campaign/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,10 @@ const EditFreeCampaign = () => {
backHref={ dashboardURL }
/>
<SetupFreeListings
headerTitle={ __(
'Edit your listings',
'google-listings-and-ads'
) }
targetAudience={ targetAudience }
resolveFinalCountries={ getFinalCountries }
onTargetAudienceChange={ updateTargetAudience }
Expand Down
12 changes: 7 additions & 5 deletions js/src/external-components/wordpress/guide/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,13 @@ export default function Guide( {
<div className="components-guide__page">
{ pages[ currentPage ].image }

<PageControl
currentPage={ currentPage }
numberOfPages={ pages.length }
setCurrentPage={ setCurrentPage }
/>
{ pages.length > 1 && (
<PageControl
currentPage={ currentPage }
numberOfPages={ pages.length }
setCurrentPage={ setCurrentPage }
/>
) }

{ pages[ currentPage ].content }
</div>
Expand Down
20 changes: 20 additions & 0 deletions js/src/hooks/useGoogleMCAccount.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ import { useSelect } from '@wordpress/data';
import { STORE_KEY } from '.~/data/constants';
import useGoogleAccount from './useGoogleAccount';

/**
* @typedef {import('.~/data/selectors').GoogleMCAccount} GoogleMCAccount
*
* @typedef {Object} GoogleMCAccountPayload
* @property {GoogleMCAccount|undefined} googleMCAccount The connection data of Google Merchant Center account associated with GLA.
* @property {boolean} isResolving Whether resolution is in progress.
* @property {boolean} hasFinishedResolution Whether resolution has completed.
* @property {boolean} isPreconditionReady Whether the precondition of continued connection processing is fulfilled.
*/

/**
* A hook to load the connection data of Google Merchant Center account.
*
* @return {GoogleMCAccountPayload} The data and its state.
*/
const useGoogleMCAccount = () => {
const {
google,
Expand All @@ -24,6 +39,10 @@ const useGoogleMCAccount = () => {
googleMCAccount: undefined,
isResolving: isResolvingGoogle,
hasFinishedResolution: hasFinishedResolutionGoogle,
// If a user has not yet connected their Google account or the connected Google account
// has not been granted necessary access permissions for Google Merchant Center, then
// the precondition doesn't meet.
isPreconditionReady: false,
};
}

Expand All @@ -39,6 +58,7 @@ const useGoogleMCAccount = () => {
hasFinishedResolution: hasFinishedResolution(
'getGoogleMCAccount'
),
isPreconditionReady: true,
};
},
[
Expand Down
2 changes: 1 addition & 1 deletion js/src/product-feed/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jest.mock( '.~/utils/localStorage', () => {
jest.mock( '.~/utils/isWCTracksEnabled', () => jest.fn() );

const SUBMISSION_SUCCESS_GUIDE_TEXT =
'You have successfully set up Google Listings & Ads! 🎉';
'You’ve successfully set up Google Listings & Ads! 🎉';
const CES_PROMPT_TEXT = 'How easy was it to set up Google Listings & Ads?';

jest.mock( '.~/components/customer-effort-score-prompt', () => () => (
Expand Down
Loading