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

Enhancement/10175 setup banner #10208

Open
wants to merge 53 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
9ab84a7
Refactor basic structure.
zutigrm Feb 11, 2025
a96b1dc
Add ADS_SETUP_CTA_BANNER_NOTIFICATION constant.
zutigrm Feb 11, 2025
e93a7a0
Remove the constant.
zutigrm Feb 11, 2025
3e2d619
Add basic notification registration.
zutigrm Feb 11, 2025
5579318
Add dismissable props to the registration of notification.
zutigrm Feb 11, 2025
ef52421
Implement isDismissalFinal check to render label.
zutigrm Feb 11, 2025
77c60e7
Add logic to skip hiding banner on dismiss.
zutigrm Feb 11, 2025
5920e42
Include tooltip.
zutigrm Feb 11, 2025
af5a08c
Add check for module being active.
zutigrm Feb 12, 2025
cf4f6bd
Adapt the styling.
zutigrm Feb 12, 2025
c8a2f7a
Adapt screen.
zutigrm Feb 12, 2025
caab7b4
Add AdditionalComponent prop to the Description component.
zutigrm Feb 12, 2025
a39011e
Include AdBlcker.
zutigrm Feb 12, 2025
c6e53c4
Change isActive to check isConnected and include canActivate check.
zutigrm Feb 12, 2025
23258be
Return the SVG based on the screen size.
zutigrm Feb 12, 2025
b8ad0df
Move breakpointSVGMap array declaration outside the function.
zutigrm Feb 18, 2025
22ae366
Adjust responsive styles.
zutigrm Feb 18, 2025
5267a5d
Resolve conflict.
zutigrm Feb 24, 2025
47855e1
Merge remote-tracking branch 'origin/enhancement/10172-add-WooCommerc…
zutigrm Feb 24, 2025
a75f758
Complete checkRequirements logic and change priority.
zutigrm Feb 24, 2025
ff9205b
Include modal.
zutigrm Feb 24, 2025
884e5ea
Quick re-order of the resolve selects.
zutigrm Feb 24, 2025
d97e33a
Add tests.
zutigrm Feb 24, 2025
6947055
Merge remote-tracking branch 'origin/develop' into enhancement/10175-…
zutigrm Feb 24, 2025
6464299
Add more tests.
zutigrm Feb 24, 2025
268cc35
Source plugin data from MODULES_ADS.
zutigrm Feb 24, 2025
feceedf
Remove plugin status constants from core site datastore.
zutigrm Feb 24, 2025
31ce027
Add plugin status constants to the MODULES_ADS datastore.
zutigrm Feb 24, 2025
0831bde
Remove plugin status from core site datastore.
zutigrm Feb 24, 2025
2ce5c5f
Remove plugins from inline state.
zutigrm Feb 24, 2025
9c4f5ea
Update plugin status selectors to source data from ads datastore in W…
zutigrm Feb 24, 2025
3221969
Move selectors to the module-data store partial.
zutigrm Feb 24, 2025
172ebb3
Source data in checkRequirements from ads datastore.
zutigrm Feb 24, 2025
f66d913
Update AccountLinkedViaGoogleForWooCommerceSubtleNotification checkRe…
zutigrm Feb 24, 2025
046ddd5
Remove plugin-status from core data store.
zutigrm Feb 24, 2025
9997652
Include plugins in the initial state of the module data partial.
zutigrm Feb 24, 2025
e474b21
Move plugin status tests to the module data partial tests file.
zutigrm Feb 24, 2025
c28f063
Remove plugin-status.tests file.
zutigrm Feb 24, 2025
b26c310
Fix property names for plugins.
zutigrm Feb 24, 2025
0cdc41c
Remove getPluginsData from info tests.
zutigrm Feb 24, 2025
9decaa3
Use stricter conditional checks in checkRequirements.
zutigrm Feb 24, 2025
94e1a47
Rename plugin name.
zutigrm Feb 24, 2025
0ea6a39
Cleanup tests.
zutigrm Feb 24, 2025
31d05a4
Use module data instead of site info in WooCommerceRedirectModal tests.
zutigrm Feb 24, 2025
c188380
Fix remaining core site usage in checkRequirements.
zutigrm Feb 24, 2025
b7ff88a
Fix AccountLinkedViaGoogleForWooCommerceSubtleNotification tests.
zutigrm Feb 24, 2025
e6f2cfc
Improve checkRequirements.
zutigrm Feb 24, 2025
3c2b5d5
Fix stories.
zutigrm Feb 24, 2025
444a1e5
Update messaging.
zutigrm Feb 24, 2025
b65aa1e
Improve padding for ad blocker notice.
zutigrm Feb 24, 2025
cee9813
Update VRT.
zutigrm Feb 24, 2025
1b7bef6
Fix test.
zutigrm Feb 24, 2025
d9b3a1d
Include skipFromQueue.
zutigrm Feb 24, 2025
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
319 changes: 184 additions & 135 deletions assets/js/components/notifications/AdsModuleSetupCTAWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,170 +24,219 @@ import PropTypes from 'prop-types';
/**
* WordPress dependencies
*/
import { compose } from '@wordpress/compose';
import { useCallback } from '@wordpress/element';
import { Fragment, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { useDispatch, useSelect } from 'googlesitekit-data';
import { Button } from 'googlesitekit-components';
import {
BREAKPOINT_SMALL,
BREAKPOINT_TABLET,
useBreakpoint,
} from '../../hooks/useBreakpoint';
import { ADS_MODULE_SETUP_BANNER_PROMPT_DISMISSED_KEY } from '../../modules/ads/datastore/constants';
import { CORE_NOTIFICATIONS } from '../../googlesitekit/notifications/datastore/constants';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
import { WEEK_IN_SECONDS } from '../../util';
import { Cell, Grid, Row } from '../../material-components';
import whenInactive from '../../util/when-inactive';
import { withWidgetComponentProps } from '../../googlesitekit/widgets/util';
import useActivateModuleCallback from '../../hooks/useActivateModuleCallback';
import AdsSetupSVG from '../../../svg/graphics/ads-setup.svg';
import AdsSetupTabletSVG from '../../../svg/graphics/ads-setup-tablet.svg';
import AdsSetupMobileSVG from '../../../svg/graphics/ads-setup-mobile.svg';
import NotificationWithSVG from '../../googlesitekit/notifications/components/layout/NotificationWithSVG';
import Description from '../../googlesitekit/notifications/components/common/Description';
import LearnMoreLink from '../../googlesitekit/notifications/components/common/LearnMoreLink';
import ActionsCTALinkDismiss from '../../googlesitekit/notifications/components/common/ActionsCTALinkDismiss';
import useActivateModuleCallback from '../../hooks/useActivateModuleCallback';
import AdBlockerWarning from './AdBlockerWarning';
import {
AdminMenuTooltip,
useShowTooltip,
useTooltipState,
} from '../AdminMenuTooltip';
import {
BREAKPOINT_SMALL,
BREAKPOINT_TABLET,
useBreakpoint,
} from '../../hooks/useBreakpoint';
import { WooCommerceRedirectModal } from '../../modules/ads/components/common';
import { useCallback } from 'react';
import {
ADS_WOOCOMMERCE_REDIRECT_MODAL_DISMISS_KEY,
MODULES_ADS,
} from '../../modules/ads/datastore/constants';

const breakpointSVGMap = {
[ BREAKPOINT_SMALL ]: AdsSetupMobileSVG,
[ BREAKPOINT_TABLET ]: AdsSetupTabletSVG,
};

function AdsModuleSetupCTAWidget( { WidgetNull, Widget } ) {
export default function AdsModuleSetupCTAWidget( { id, Notification } ) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ok, we need to move this component to the Ads module because we register it there. Plus this is no longer a widget, thus we need to rename it accordingly.

const breakpoint = useBreakpoint();
const isMobileBreakpoint = breakpoint === BREAKPOINT_SMALL;
const isTabletBreakpoint = breakpoint === BREAKPOINT_TABLET;
const [ openDialog, setOpenDialog ] = useState( false );
const [ isSaving, setIsSaving ] = useState( false );

const onSetupCallback = useActivateModuleCallback( 'ads' );
const learnMoreURL = undefined;

const isDismissed = useSelect( ( select ) =>
select( CORE_USER ).isPromptDismissed(
ADS_MODULE_SETUP_BANNER_PROMPT_DISMISSED_KEY
)
const isAdBlockerActive = useSelect( ( select ) =>
select( CORE_USER ).isAdBlockerActive()
);

const isDismissalFinal = useSelect( ( select ) =>
select( CORE_NOTIFICATIONS ).isNotificationDismissalFinal( id )
);
const isCTADismissed = useSelect( ( select ) =>
select( CORE_NOTIFICATIONS ).isNotificationDismissed( id )
);
const dismissCount = useSelect( ( select ) =>
select( CORE_USER ).getPromptDismissCount(
ADS_MODULE_SETUP_BANNER_PROMPT_DISMISSED_KEY
const dismissedPromptsLoaded = useSelect( ( select ) =>
select( CORE_USER ).hasFinishedResolution( 'getDismissedPrompts', [] )
);
const hideCTABanner = isCTADismissed || ! dismissedPromptsLoaded;

const shouldShowWooCommerceRedirectModal = useSelect( ( select ) => {
const {
isWooCommerceActivated,
isGoogleForWooCommerceActivated,
hasGoogleForWooCommerceAdsAccount,
} = select( MODULES_ADS );

return (
( isWooCommerceActivated() &&
isGoogleForWooCommerceActivated() &&
! hasGoogleForWooCommerceAdsAccount() ) ||
( isWooCommerceActivated() && ! isGoogleForWooCommerceActivated() )
);
} );

const isWooCommerceRedirectModalDismissed = useSelect( ( select ) =>
select( CORE_USER ).isItemDismissed(
ADS_WOOCOMMERCE_REDIRECT_MODAL_DISMISS_KEY
)
);

const { dismissPrompt } = useDispatch( CORE_USER );
const { dismissNotification } = useDispatch( CORE_NOTIFICATIONS );

const onDismiss = useCallback( async () => {
if ( dismissCount < 1 ) {
const twoWeeksInSeconds = WEEK_IN_SECONDS * 2;
const markNotificationDismissed = useCallback( () => {
dismissNotification( id, {
skipHidingFromQueue: true,
expiresInSeconds: 2 * WEEK_IN_SECONDS,
} );
}, [ id, dismissNotification ] );

await dismissPrompt( ADS_MODULE_SETUP_BANNER_PROMPT_DISMISSED_KEY, {
expiresInSeconds: twoWeeksInSeconds,
} );
} else {
// For the second dismissal, dismiss permanently.
await dismissPrompt( ADS_MODULE_SETUP_BANNER_PROMPT_DISMISSED_KEY );
const activateModule = useActivateModuleCallback( 'ads' );

const onSetupCallback = useCallback( () => {
if (
! shouldShowWooCommerceRedirectModal ||
isWooCommerceRedirectModalDismissed
) {
markNotificationDismissed();
activateModule();
setIsSaving( true );
return;
}
}, [ dismissCount, dismissPrompt ] );

if ( dismissCount > 1 || isDismissed || isDismissed === undefined ) {
return <WidgetNull />;
setOpenDialog( true );
}, [
shouldShowWooCommerceRedirectModal,
activateModule,
markNotificationDismissed,
isWooCommerceRedirectModalDismissed,
] );

const onModalDismiss = useCallback( () => {
markNotificationDismissed();
setOpenDialog( false );
}, [ markNotificationDismissed, setOpenDialog ] );

const showTooltip = useShowTooltip( id );
const { isTooltipVisible } = useTooltipState( id );

if ( isTooltipVisible ) {
return (
<Fragment>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Fragment is not needed here.

<AdminMenuTooltip
title=""
content={ __(
'You can always enable Ads from Settings later',
'google-site-kit'
) }
dismissLabel={ __( 'Got it', 'google-site-kit' ) }
tooltipStateKey={ id }
/>
</Fragment>
);
}

// TODO: Don't use `skipHidingFromQueue` and remove the need to check
// if this component should output anything.
//
// We "incorrectly" pass true to the `skipHidingFromQueue` option when dismissing this banner.
// This is because we don't want the component removed from the DOM as we have to still render
// the `AdminMenuTooltip` in this component. This means that we have to rely on manually
// checking for the dismissal state here.
if ( hideCTABanner ) {
return null;
}

return (
<div className="googlesitekit-widget-context">
<Grid className="googlesitekit-widget-area">
<Row>
<Cell size={ 12 }>
<Widget
noPadding
className="googlesitekit-setup-cta-banner googlesitekit-ads-setup-cta-widget"
>
<Grid collapsed>
<Row>
<Cell
smSize={ 12 }
mdSize={ 8 }
lgSize={ 6 }
className="googlesitekit-setup-cta-banner__primary-cell"
>
<h3 className="googlesitekit-setup-cta-banner__title">
{ __(
'Get better quality leads and enhance conversions with Ads',
'google-site-kit'
) }
</h3>
<div className="googlesitekit-setup-cta-banner__description">
<p>
{ __(
'Help drive sales, leads, or site traffic by getting your business in front of people who are actively searching Google for products or services you offer.',
'google-site-kit'
) }
</p>
</div>

<div className="googlesitekit-setup-cta-banner__actions-wrapper">
<Button
className="googlesitekit-key-metrics-cta-button"
onClick={ onSetupCallback }
>
{ __(
'Set up Ads',
'google-site-kit'
) }
</Button>
<Button
tertiary
onClick={ onDismiss }
>
{ dismissCount < 1
? __(
'Maybe later',
'google-site-kit'
)
: __(
'Don’t show again',
'google-site-kit'
) }
</Button>
</div>
</Cell>
{ ! isMobileBreakpoint &&
! isTabletBreakpoint && (
<Cell
alignBottom
className="googlesitekit-setup-cta-banner__svg-wrapper"
mdSize={ 8 }
lgSize={ 6 }
>
<AdsSetupSVG />
</Cell>
) }
{ isTabletBreakpoint && (
<Cell
className="googlesitekit-setup-cta-banner__svg-wrapper"
mdSize={ 8 }
>
<AdsSetupTabletSVG />
</Cell>
<Fragment>
<Notification>
<NotificationWithSVG
id={ id }
title={ __(
'Get better quality leads and enhance conversions with Ads',
'google-site-kit'
) }
description={
<Description
text={ __(
'Help drive sales, leads, or site traffic by getting your business in front of people who are actively searching Google for products or services you offer.',
'google-site-kit'
) }
learnMoreLink={
<LearnMoreLink
id={ id }
label={ __(
'Learn more',
'google-site-kit'
) }
{ isMobileBreakpoint && (
<Cell
alignBottom
className="googlesitekit-setup-cta-banner__svg-wrapper"
smSize={ 12 }
>
<AdsSetupMobileSVG />
</Cell>
) }
</Row>
</Grid>
</Widget>
</Cell>
</Row>
</Grid>
</div>
url={ learnMoreURL }
/>
}
AdditionalComponent={
isAdBlockerActive && (
<AdBlockerWarning moduleSlug="ads" />
)
}
/>
}
actions={
<ActionsCTALinkDismiss
id={ id }
className="googlesitekit-setup-cta-banner__actions-wrapper"
ctaLabel={ __( 'Set up Ads', 'google-site-kit' ) }
onCTAClick={ onSetupCallback }
dismissOnCTAClick={ false }
isSaving={ isSaving }
dismissLabel={
isDismissalFinal
? __(
'Don’t show again',
'google-site-kit'
)
: __( 'Maybe later', 'google-site-kit' )
}
onDismiss={ showTooltip }
dismissExpires={ 2 * WEEK_IN_SECONDS }
/>
}
SVG={ breakpointSVGMap[ breakpoint ] || AdsSetupSVG }
/>
</Notification>
<WooCommerceRedirectModal
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's move this to the Notification component children and remove Fragment usage.

dialogActive={ openDialog }
onDismiss={ onModalDismiss }
/>
Comment on lines +234 to +237
Copy link
Collaborator

Choose a reason for hiding this comment

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

Perhaps instead of always rendering this component, we should render it conditionally?

{ openDialog && <WooCommerceRedirectModal onDismiss={ onModalDismiss } dialogActive /> }

</Fragment>
);
}

AdsModuleSetupCTAWidget.propTypes = {
Widget: PropTypes.elementType.isRequired,
WidgetNull: PropTypes.elementType.isRequired,
id: PropTypes.string,
Notification: PropTypes.elementType,
Comment on lines +243 to +244
Copy link
Collaborator

Choose a reason for hiding this comment

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

These props should be required.

};

export default compose(
whenInactive( { moduleName: 'ads' } ),
withWidgetComponentProps( 'ads-setup-cta' )
)( AdsModuleSetupCTAWidget );
Loading
Loading