diff --git a/assets/js/components/DashboardMainApp.js b/assets/js/components/DashboardMainApp.js
index ce4aa3a1757..007a28fe437 100644
--- a/assets/js/components/DashboardMainApp.js
+++ b/assets/js/components/DashboardMainApp.js
@@ -46,7 +46,6 @@ import {
AudienceSegmentationSetupCTAWidget,
AudienceSelectionPanel,
} from '../modules/analytics-4/components/audience-segmentation/dashboard';
-import ReaderRevenueManagerSetupCTABanner from '../modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner';
import EntitySearchInput from './EntitySearchInput';
import DateRangeSelector from './DateRangeSelector';
import HelpMenu from './help/HelpMenu';
@@ -88,7 +87,6 @@ import {
export default function DashboardMainApp() {
const audienceSegmentationEnabled = useFeature( 'audienceSegmentation' );
- const readerRevenueManagerEnabled = useFeature( 'rrmModule' );
const [ showSurveyPortal, setShowSurveyPortal ] = useState( false );
@@ -276,14 +274,6 @@ export default function DashboardMainApp() {
) }
- { ! viewOnlyDashboard && (
-
- { readerRevenueManagerEnabled && (
-
- ) }
-
- ) }
-
{
- if ( breakpoint === BREAKPOINT_SMALL ) {
- return FPMSetupCTASVGMobile;
- }
-
- if ( breakpoint === BREAKPOINT_TABLET ) {
- return FPMSetupCTASVGTablet;
- }
-
- return FPMSetupCTASVGDesktop;
+ const breakpointSVGMap = {
+ [ BREAKPOINT_SMALL ]: FPMSetupCTASVGMobile,
+ [ BREAKPOINT_TABLET ]: FPMSetupCTASVGTablet,
};
return (
@@ -201,7 +194,7 @@ export default function FirstPartyModeSetupBanner( { id, Notification } ) {
} }
/>
}
- SVG={ getBannerSVG() }
+ SVG={ breakpointSVGMap[ breakpoint ] || FPMSetupCTASVGDesktop }
/>
);
diff --git a/assets/js/googlesitekit/notifications/datastore/notifications.js b/assets/js/googlesitekit/notifications/datastore/notifications.js
index 3176e087fc4..53a7a3d7ea5 100644
--- a/assets/js/googlesitekit/notifications/datastore/notifications.js
+++ b/assets/js/googlesitekit/notifications/datastore/notifications.js
@@ -64,10 +64,11 @@ export const actions = {
* @param {WPComponent} [settings.Component] React component used to display the contents of this notification.
* @param {number} [settings.priority] Notification's priority for ordering (lower number is higher priority, like WordPress hooks). Ideally in increments of 10. Default 10.
* @param {string} [settings.areaSlug] The slug of the area where the notification should be rendered, e.g. notification-area-banners-above-nav.
- * @param {string} [settings.groupID] The ID of the group of notifications that should be rendered in their own individual queue.
+ * @param {string} [settings.groupID] Optional. The ID of the group of notifications that should be rendered in their own individual queue. Default 'default'.
* @param {Array.} [settings.viewContexts] Array of Site Kit contexts, e.g. VIEW_CONTEXT_MAIN_DASHBOARD.
* @param {Function} [settings.checkRequirements] Optional. Callback function to determine if the notification should be queued.
- * @param {boolean} [settings.isDismissible] Flag to check if the notification should be queued and is not dismissed.
+ * @param {boolean} [settings.isDismissible] Optional. Flag to check if the notification should be queued and is not dismissed.
+ * @param {number} [settings.dismissRetries] Optional. An integer number denoting how many times a notification should be shown again on dismissal. Default 0.
* @return {Object} Redux-style action.
*/
registerNotification(
@@ -80,6 +81,7 @@ export const actions = {
viewContexts,
checkRequirements,
isDismissible,
+ dismissRetries = 0,
}
) {
invariant(
@@ -117,6 +119,7 @@ export const actions = {
viewContexts,
checkRequirements,
isDismissible,
+ dismissRetries,
},
},
type: REGISTER_NOTIFICATION,
@@ -226,6 +229,25 @@ export const actions = {
return;
}
+ // Use prompts if a notification should be shown again until it
+ // is dismissed for a certain number of retries.
+ if ( notification.dismissRetries > 0 ) {
+ const dismissCount = registry
+ .select( CORE_USER )
+ .getPromptDismissCount( id );
+
+ const expirationInSeconds =
+ dismissCount < notification.dismissRetries
+ ? expiresInSeconds
+ : 0;
+
+ return yield commonActions.await(
+ registry.dispatch( CORE_USER ).dismissPrompt( id, {
+ expiresInSeconds: expirationInSeconds,
+ } )
+ );
+ }
+
return yield commonActions.await(
registry
.dispatch( CORE_USER )
@@ -407,8 +429,8 @@ export const selectors = {
/**
* Determines whether a notification is dismissed or not.
*
- * Currently, this selector simply forwards the call to the dismissed items API.
- * We can potentially add more notification-specific logic here in the future.
+ * If the notification should appear again for a certain number of times after dismissal,
+ * then we store them as prompts. So we check for dismissed prompts instead of dismissed items.
*
* @since 1.132.0
*
@@ -418,9 +440,59 @@ export const selectors = {
*/
isNotificationDismissed: createRegistrySelector(
( select ) => ( state, id ) => {
+ const notification =
+ select( CORE_NOTIFICATIONS ).getNotification( id );
+
+ if ( notification === undefined ) {
+ return undefined;
+ }
+
+ if ( notification.dismissRetries > 0 ) {
+ return select( CORE_USER ).isPromptDismissed( id );
+ }
+
return select( CORE_USER ).isItemDismissed( id );
}
),
+ /**
+ * Determines whether a notification that can reappear again for a fixed number of times
+ * on dismissal is at its final appearance.
+ *
+ * @since n.e.x.t
+ *
+ * @param {Object} state Data store's state.
+ * @param {string} id Notification id.
+ * @return {(boolean|undefined)} TRUE if notification is on its final retry, otherwise FALSE, `undefined` if not resolved yet.
+ */
+ isNotificationDismissalFinal: createRegistrySelector(
+ ( select ) => ( state, id ) => {
+ const notification =
+ select( CORE_NOTIFICATIONS ).getNotification( id );
+
+ if ( notification === undefined ) {
+ return undefined;
+ }
+
+ invariant(
+ notification.isDismissible,
+ 'Notification should be dismissible to check if a notification is on its final dismissal.'
+ );
+
+ // If a notification does not have retries, it always will be on its final render.
+ if ( notification.dismissRetries === 0 ) {
+ return true;
+ }
+
+ const dismissCount =
+ select( CORE_USER ).getPromptDismissCount( id );
+
+ if ( dismissCount >= notification.dismissRetries ) {
+ return true;
+ }
+
+ return false;
+ }
+ ),
};
export default {
diff --git a/assets/js/googlesitekit/notifications/datastore/notifications.test.js b/assets/js/googlesitekit/notifications/datastore/notifications.test.js
index 5834c641977..15ea9c54590 100644
--- a/assets/js/googlesitekit/notifications/datastore/notifications.test.js
+++ b/assets/js/googlesitekit/notifications/datastore/notifications.test.js
@@ -21,6 +21,7 @@
*/
import {
createTestRegistry,
+ provideNotifications,
untilResolved,
} from '../../../../../tests/js/utils';
import { render } from '../../../../../tests/js/test-utils';
@@ -42,6 +43,9 @@ describe( 'core/notifications Notifications', () => {
const fetchDismissItem = new RegExp(
'^/google-site-kit/v1/core/user/data/dismiss-item'
);
+ const fetchGetDismissedPrompts = new RegExp(
+ '^/google-site-kit/v1/core/user/data/dismissed-prompts'
+ );
let registry;
let store;
@@ -576,30 +580,215 @@ describe( 'core/notifications Notifications', () => {
} );
describe( 'isNotificationDismissed', () => {
- let isNotificationDismissed;
+ describe( 'when using dismissed items', () => {
+ let isNotificationDismissed;
+ beforeEach( () => {
+ // Register the Gathering Data Notification as a test
+ provideNotifications( registry );
+
+ ( { isNotificationDismissed } =
+ registry.select( CORE_NOTIFICATIONS ) );
+ } );
+
+ it( 'should return undefined if getDismissedItems selector is not resolved yet', async () => {
+ fetchMock.getOnce( fetchGetDismissedItems, { body: [] } );
+ expect(
+ isNotificationDismissed( 'gathering-data-notification' )
+ ).toBeUndefined();
+ await untilResolved(
+ registry,
+ CORE_USER
+ ).getDismissedItems();
+ } );
+
+ it( 'should return TRUE if the notification is dismissed', () => {
+ registry
+ .dispatch( CORE_USER )
+ .receiveGetDismissedItems( [
+ 'gathering-data-notification',
+ 'some-other-notification',
+ ] );
+ expect(
+ isNotificationDismissed( 'gathering-data-notification' )
+ ).toBe( true );
+ } );
+
+ it( 'should return FALSE if the notification is not dismissed', () => {
+ registry
+ .dispatch( CORE_USER )
+ .receiveGetDismissedItems( [ 'foo', 'bar' ] );
+ expect(
+ isNotificationDismissed( 'gathering-data-notification' )
+ ).toBe( false );
+ } );
+ } );
+ describe( 'when using dismissed prompts', () => {
+ let isNotificationDismissed;
+ beforeEach( () => {
+ provideNotifications( registry, {
+ 'test-notification-using-prompts': {
+ Component: () => {},
+ areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV,
+ viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ],
+ priority: 11,
+ checkRequirements: () => true,
+ isDismissible: false,
+ dismissRetries: 1,
+ },
+ } );
+
+ ( { isNotificationDismissed } =
+ registry.select( CORE_NOTIFICATIONS ) );
+ } );
+
+ it( 'should return undefined if getDismissedPrompts selector is not resolved yet', async () => {
+ fetchMock.getOnce( fetchGetDismissedPrompts, { body: [] } );
+ expect(
+ isNotificationDismissed(
+ 'test-notification-using-prompts'
+ )
+ ).toBeUndefined();
+ await untilResolved(
+ registry,
+ CORE_USER
+ ).getDismissedPrompts();
+ } );
+
+ it( 'should return TRUE if the notification is dismissed', () => {
+ registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {
+ 'test-notification-using-prompts': {
+ expires: 0,
+ count: 1,
+ },
+ 'some-other-notification': { expires: 0, count: 2 },
+ } );
+ expect(
+ isNotificationDismissed(
+ 'test-notification-using-prompts'
+ )
+ ).toBe( true );
+ } );
+
+ it( 'should return FALSE if the notification is not dismissed', () => {
+ registry
+ .dispatch( CORE_USER )
+ .receiveGetDismissedPrompts( [ 'foo', 'bar' ] );
+ expect(
+ isNotificationDismissed(
+ 'test-notification-using-prompts'
+ )
+ ).toBe( false );
+ } );
+ } );
+ } );
+
+ describe( 'isNotificationDismissalFinal', () => {
+ let isNotificationDismissalFinal;
beforeEach( () => {
- ( { isNotificationDismissed } =
+ ( { isNotificationDismissalFinal } =
registry.select( CORE_NOTIFICATIONS ) );
} );
- it( 'should return undefined if getDismissedItems selector is not resolved yet', async () => {
- fetchMock.getOnce( fetchGetDismissedItems, { body: [] } );
- expect( isNotificationDismissed( 'foo' ) ).toBeUndefined();
- await untilResolved( registry, CORE_USER ).getDismissedItems();
+ it( 'should return undefined if notification is undefined', () => {
+ expect(
+ isNotificationDismissalFinal( 'test-notification' )
+ ).toBeUndefined();
} );
- it( 'should return TRUE if the notification is dismissed', () => {
- registry
- .dispatch( CORE_USER )
- .receiveGetDismissedItems( [ 'foo', 'bar' ] );
- expect( isNotificationDismissed( 'foo' ) ).toBe( true );
+ it( 'requires notification to be dismissible', () => {
+ provideNotifications( registry, {
+ 'test-notification': {
+ Component: () => {},
+ areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV,
+ viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ],
+ dismissRetries: 1,
+ },
+ } );
+
+ expect( () =>
+ isNotificationDismissalFinal( 'test-notification' )
+ ).toThrow(
+ 'Notification should be dismissible to check if a notification is on its final dismissal.'
+ );
} );
- it( 'should return FALSE if the notification is not dismissed', () => {
- registry
- .dispatch( CORE_USER )
- .receiveGetDismissedItems( [ 'foo', 'bar' ] );
- expect( isNotificationDismissed( 'baz' ) ).toBe( false );
+ it( 'returns true if notification does not have retries', () => {
+ provideNotifications( registry, {
+ 'test-notification': {
+ Component: () => {},
+ areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV,
+ viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ],
+ isDismissible: true,
+ },
+ } );
+
+ expect(
+ isNotificationDismissalFinal( 'test-notification' )
+ ).toBe( true );
+ } );
+
+ it( 'returns true if notification is on the final retry', () => {
+ provideNotifications( registry, {
+ 'test-notification': {
+ Component: () => {},
+ areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV,
+ viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ],
+ isDismissible: true,
+ dismissRetries: 2,
+ },
+ } );
+
+ registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {
+ 'test-notification': {
+ expires: 0,
+ count: 2,
+ },
+ 'some-other-notification': { expires: 0, count: 2 },
+ } );
+
+ expect(
+ isNotificationDismissalFinal( 'test-notification' )
+ ).toBe( true );
+ } );
+
+ it( 'returns false if notification has never been dismissed', () => {
+ provideNotifications( registry, {
+ 'test-notification': {
+ Component: () => {},
+ areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV,
+ viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ],
+ isDismissible: true,
+ dismissRetries: 1,
+ },
+ } );
+
+ expect(
+ isNotificationDismissalFinal( 'test-notification' )
+ ).toBe( false );
+ } );
+
+ it( 'returns false if notification is not on the final retry', () => {
+ provideNotifications( registry, {
+ 'test-notification': {
+ Component: () => {},
+ areaSlug: NOTIFICATION_AREAS.BANNERS_ABOVE_NAV,
+ viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ],
+ isDismissible: true,
+ dismissRetries: 2,
+ },
+ } );
+
+ registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {
+ 'test-notification': {
+ expires: 0,
+ count: 1,
+ },
+ 'some-other-notification': { expires: 0, count: 2 },
+ } );
+
+ expect(
+ isNotificationDismissalFinal( 'test-notification' )
+ ).toBe( false );
} );
} );
} );
diff --git a/assets/js/modules/ads/datastore/settings.test.js b/assets/js/modules/ads/datastore/settings.test.js
index 38e4fc6e2d9..19902b08d1a 100644
--- a/assets/js/modules/ads/datastore/settings.test.js
+++ b/assets/js/modules/ads/datastore/settings.test.js
@@ -118,6 +118,17 @@ describe( 'modules/ads settings', () => {
FPM_SETUP_CTA_BANNER_NOTIFICATION,
] );
+ provideNotifications(
+ registry,
+ {
+ [ FPM_SETUP_CTA_BANNER_NOTIFICATION ]:
+ DEFAULT_NOTIFICATIONS[
+ FPM_SETUP_CTA_BANNER_NOTIFICATION
+ ],
+ },
+ { overwrite: true }
+ );
+
fetchMock.postOnce( settingsEndpoint, ( url, opts ) => ( {
body: JSON.parse( opts.body )?.data,
status: 200,
diff --git a/assets/js/modules/analytics-4/datastore/settings.test.js b/assets/js/modules/analytics-4/datastore/settings.test.js
index 74a61ad82de..20ed39fe53f 100644
--- a/assets/js/modules/analytics-4/datastore/settings.test.js
+++ b/assets/js/modules/analytics-4/datastore/settings.test.js
@@ -528,6 +528,17 @@ describe( 'modules/analytics-4 settings', () => {
FPM_SETUP_CTA_BANNER_NOTIFICATION,
] );
+ provideNotifications(
+ registry,
+ {
+ [ FPM_SETUP_CTA_BANNER_NOTIFICATION ]:
+ DEFAULT_NOTIFICATIONS[
+ FPM_SETUP_CTA_BANNER_NOTIFICATION
+ ],
+ },
+ { overwrite: true }
+ );
+
const validSettings = {
accountID: fixtures.createProperty._accountID,
propertyID: fixtures.createProperty._id,
diff --git a/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.js b/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.js
index 0630964bd0b..24f0fec2b64 100644
--- a/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.js
+++ b/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.js
@@ -24,11 +24,9 @@ import PropTypes from 'prop-types';
/**
* WordPress dependencies
*/
-import { compose } from '@wordpress/compose';
import {
createInterpolateElement,
Fragment,
- useCallback,
useEffect,
} from '@wordpress/element';
import { __ } from '@wordpress/i18n';
@@ -37,130 +35,65 @@ 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 useActivateModuleCallback from '../../../../hooks/useActivateModuleCallback';
-import whenInactive from '../../../../util/when-inactive';
-import { withWidgetComponentProps } from '../../../../googlesitekit/widgets/util';
-import { CORE_MODULES } from '../../../../googlesitekit/modules/datastore/constants';
import { CORE_USER } from '../../../../googlesitekit/datastore/user/constants';
-import {
- READER_REVENUE_MANAGER_MODULE_SLUG,
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY,
-} from '../../datastore/constants';
-import { Cell, Grid, Row } from '../../../../material-components';
+import { READER_REVENUE_MANAGER_MODULE_SLUG } from '../../datastore/constants';
import SetupSVG from '../../../../../svg/graphics/reader-revenue-manager-setup.svg';
import SetupTabletSVG from '../../../../../svg/graphics/reader-revenue-manager-setup-tablet.svg';
import SetupMobileSVG from '../../../../../svg/graphics/reader-revenue-manager-setup-mobile.svg';
-import Link from '../../../../components/Link';
-import { trackEvent, WEEK_IN_SECONDS } from '../../../../util';
import {
AdminMenuTooltip,
useShowTooltip,
useTooltipState,
} from '../../../../components/AdminMenuTooltip';
-import useViewContext from '../../../../hooks/useViewContext';
-
-function ReaderRevenueManagerSetupCTABanner( { Widget, WidgetNull } ) {
- const viewContext = useViewContext();
+import { CORE_NOTIFICATIONS } from '../../../../googlesitekit/notifications/datastore/constants';
+import NotificationWithSVG from '../../../../googlesitekit/notifications/components/layout/NotificationWithSVG';
+import LearnMoreLink from '../../../../googlesitekit/notifications/components/common/LearnMoreLink';
+import ActionsCTALinkDismiss from '../../../../googlesitekit/notifications/components/common/ActionsCTALinkDismiss';
+import { WEEK_IN_SECONDS } from '../../../../util';
+
+export default function ReaderRevenueManagerSetupCTABanner( {
+ id,
+ Notification,
+} ) {
const breakpoint = useBreakpoint();
- const isMobileBreakpoint = breakpoint === BREAKPOINT_SMALL;
- const isTabletBreakpoint = breakpoint === BREAKPOINT_TABLET;
const onSetupActivate = useActivateModuleCallback(
READER_REVENUE_MANAGER_MODULE_SLUG
);
- const onSetupCallback = useCallback( () => {
- trackEvent(
- `${ viewContext }_rrm-setup-notification`,
- 'confirm_notification'
- ).finally( () => {
- onSetupActivate();
- } );
- }, [ onSetupActivate, viewContext ] );
-
- const showTooltip = useShowTooltip(
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY
- );
- const { isTooltipVisible } = useTooltipState(
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY
- );
+ const showTooltip = useShowTooltip( id );
+ const { isTooltipVisible } = useTooltipState( id );
- const isDismissed = useSelect( ( select ) =>
- select( CORE_USER ).isPromptDismissed(
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY
- )
- );
+ const { triggerSurvey } = useDispatch( CORE_USER );
- const isDismissingPrompt = useSelect( ( select ) =>
- select( CORE_USER ).isDismissingPrompt(
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY
- )
+ const isDismissalFinal = useSelect( ( select ) =>
+ select( CORE_NOTIFICATIONS ).isNotificationDismissalFinal( id )
);
- const dismissCount = useSelect( ( select ) =>
- select( CORE_USER ).getPromptDismissCount(
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY
- )
+ // See TODO note below.
+ const isCTADismissed = useSelect( ( select ) =>
+ select( CORE_NOTIFICATIONS ).isNotificationDismissed( id )
);
-
const dismissedPromptsLoaded = useSelect( ( select ) =>
select( CORE_USER ).hasFinishedResolution( 'getDismissedPrompts', [] )
);
-
- const { dismissPrompt, triggerSurvey } = useDispatch( CORE_USER );
-
- const onDismiss = useCallback( () => {
- trackEvent(
- `${ viewContext }_rrm-setup-notification`,
- 'dismiss_notification'
- ).finally( () => {
- const expirationInSeconds =
- dismissCount < 1 ? 2 * WEEK_IN_SECONDS : 0;
-
- showTooltip();
-
- dismissPrompt( READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY, {
- expiresInSeconds: expirationInSeconds,
- } );
- } );
- }, [ dismissCount, dismissPrompt, showTooltip, viewContext ] );
-
- const readerRevenueManagerDocumentationURL =
- 'https://readerrevenue.withgoogle.com';
-
- const canActivateRRMModule = useSelect( ( select ) =>
- select( CORE_MODULES ).canActivateModule(
- READER_REVENUE_MANAGER_MODULE_SLUG
- )
- );
-
- const showBanner =
- isDismissed === false &&
- ! isDismissingPrompt &&
- canActivateRRMModule &&
- dismissedPromptsLoaded === true;
+ const hideCTABanner = isCTADismissed || ! dismissedPromptsLoaded;
useEffect( () => {
- if ( showBanner ) {
- trackEvent(
- `${ viewContext }_rrm-setup-notification`,
- 'view_notification'
- );
-
+ if ( ! hideCTABanner ) {
triggerSurvey( 'view_reader_revenue_manager_cta' );
}
- }, [ showBanner, triggerSurvey, viewContext ] );
+ }, [ hideCTABanner, triggerSurvey ] );
if ( isTooltipVisible ) {
return (
-
);
}
- if ( ! showBanner ) {
- return ;
+ // TODO Remove this hack
+ // 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;
}
+ const breakpointSVGMap = {
+ [ BREAKPOINT_SMALL ]: SetupMobileSVG,
+ [ BREAKPOINT_TABLET ]: SetupTabletSVG,
+ };
+
return (
-
-
-
-
-
-
-
-
-
- { __(
- 'Grow your revenue and deepen reader engagement',
+
+
+
+ { createInterpolateElement(
+ __(
+ 'Turn casual visitors into loyal readers and earn more from your content with voluntary contributions, surveys, newsletter sign-ups and reader insight tools. Learn more',
+ 'google-site-kit'
+ ),
+ {
+ a: (
+
-
-
- { createInterpolateElement(
- __(
- 'Turn casual visitors into loyal readers and earn more from your content with voluntary contributions, surveys, newsletter sign-ups and reader insight tools. Learn more',
- 'google-site-kit'
- ),
- {
- a: (
-
- ),
- }
- ) }
-
-
- { __(
- '* Support for subscriptions coming soon',
- 'google-site-kit'
- ) }
-
-
-
-
-
-
-
- |
- { ! isMobileBreakpoint &&
- ! isTabletBreakpoint && (
-
-
- |
- ) }
- { isTabletBreakpoint && (
-
-
- |
- ) }
- { isMobileBreakpoint && (
-
-
- |
- ) }
-
-
-
- |
-
-
-
+ url="https://readerrevenue.withgoogle.com"
+ />
+ ),
+ }
+ ) }
+
+
+ { __(
+ '* Support for subscriptions coming soon',
+ 'google-site-kit'
+ ) }
+
+
+ }
+ actions={
+
+ }
+ SVG={ breakpointSVGMap[ breakpoint ] || SetupSVG }
+ />
+
);
}
ReaderRevenueManagerSetupCTABanner.propTypes = {
- Widget: PropTypes.elementType.isRequired,
- WidgetNull: PropTypes.elementType.isRequired,
+ id: PropTypes.string,
+ Notification: PropTypes.elementType,
};
-
-export default compose(
- whenInactive( {
- moduleName: READER_REVENUE_MANAGER_MODULE_SLUG,
- } ),
- withWidgetComponentProps( 'readerRevenueManagerSetupCTABanner' )
-)( ReaderRevenueManagerSetupCTABanner );
diff --git a/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.stories.js b/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.stories.js
index e7762125eba..b6ebf1c5ebd 100644
--- a/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.stories.js
+++ b/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.stories.js
@@ -25,22 +25,19 @@ import fetchMock from 'fetch-mock';
* Internal dependencies
*/
import { provideModules } from '../../../../../../tests/js/utils';
-import { withWidgetComponentProps } from '../../../../googlesitekit/widgets/util';
+import { withNotificationComponentProps } from '../../../../googlesitekit/notifications/util/component-props';
import WithRegistrySetup from '../../../../../../tests/js/WithRegistrySetup';
import ReaderRevenueManagerSetupCTABanner from './ReaderRevenueManagerSetupCTABanner';
-import {
- READER_REVENUE_MANAGER_MODULE_SLUG,
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY,
-} from '../../datastore/constants';
+import { READER_REVENUE_MANAGER_MODULE_SLUG } from '../../datastore/constants';
import { CORE_USER } from '../../../../googlesitekit/datastore/user/constants';
import { WEEK_IN_SECONDS } from '../../../../util';
-const WidgetWithComponentProps = withWidgetComponentProps(
- 'readerRevenueManagerSetupCTABanner'
+const NotificationWithComponentProps = withNotificationComponentProps(
+ 'rrm-setup-notification'
)( ReaderRevenueManagerSetupCTABanner );
function Template() {
- return ;
+ return ;
}
export const Default = Template.bind( {} );
@@ -60,6 +57,10 @@ export default {
] );
registry.dispatch( CORE_USER ).receiveGetDismissedItems( [] );
+ registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( [] );
+ registry
+ .dispatch( CORE_USER )
+ .finishResolution( 'getDismissedPrompts', [] );
fetchMock.postOnce(
new RegExp(
@@ -67,12 +68,10 @@ export default {
),
{
body: {
- [ READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY ]:
- {
- expires:
- Date.now() / 1000 + WEEK_IN_SECONDS,
- count: 1,
- },
+ 'rrm-setup-notification': {
+ expires: Date.now() / 1000 + WEEK_IN_SECONDS,
+ count: 1,
+ },
},
status: 200,
}
diff --git a/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.test.js b/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.test.js
index 4c99a134442..d5d38cdec47 100644
--- a/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.test.js
+++ b/assets/js/modules/reader-revenue-manager/components/dashboard/ReaderRevenueManagerSetupCTABanner.test.js
@@ -34,25 +34,23 @@ import {
waitFor,
provideUserAuthentication,
} from '../../../../../../tests/js/test-utils';
-import { getWidgetComponentProps } from '../../../../googlesitekit/widgets/util';
+import { withNotificationComponentProps } from '../../../../googlesitekit/notifications/util/component-props';
import { CORE_USER } from '../../../../googlesitekit/datastore/user/constants';
import { CORE_MODULES } from '../../../../googlesitekit/modules/datastore/constants';
import {
ERROR_CODE_NON_HTTPS_SITE,
READER_REVENUE_MANAGER_MODULE_SLUG,
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY,
+ LEGACY_RRM_SETUP_BANNER_DISMISSED_KEY,
} from '../../datastore/constants';
import { VIEW_CONTEXT_MAIN_DASHBOARD } from '../../../../googlesitekit/constants';
-import * as tracking from '../../../../util/tracking';
import useActivateModuleCallback from '../../../../hooks/useActivateModuleCallback';
import { WEEK_IN_SECONDS } from '../../../../util';
import {
mockSurveyEndpoints,
surveyTriggerEndpoint,
} from '../../../../../../tests/js/mock-survey-endpoints';
-
-const mockTrackEvent = jest.spyOn( tracking, 'trackEvent' );
-mockTrackEvent.mockImplementation( () => Promise.resolve() );
+import { CORE_NOTIFICATIONS } from '../../../../googlesitekit/notifications/datastore/constants';
+import { NOTIFICATIONS } from '../..';
jest.mock( '../../../../hooks/useActivateModuleCallback' );
@@ -60,12 +58,14 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
let registry;
let activateModuleMock;
- const { Widget, WidgetNull } = getWidgetComponentProps(
- 'readerRevenueManagerSetupCTABanner'
- );
+ const ReaderRevenueManagerSetupCTABannerComponent =
+ withNotificationComponentProps( 'rrm-setup-notification' )(
+ ReaderRevenueManagerSetupCTABanner
+ );
+
+ const notification = NOTIFICATIONS[ 'rrm-setup-notification' ];
beforeEach( () => {
- mockTrackEvent.mockClear();
registry = createTestRegistry();
activateModuleMock = jest.fn( () => jest.fn() );
@@ -84,62 +84,41 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
},
] );
+ registry
+ .dispatch( CORE_NOTIFICATIONS )
+ .registerNotification( 'rrm-setup-notification', notification );
+
useActivateModuleCallback.mockImplementation( activateModuleMock );
} );
- it( 'should render the Reader Revenue Manager setup CTA banner when not dismissed', async () => {
+ it( 'should render the Reader Revenue Manager setup CTA banner', async () => {
mockSurveyEndpoints();
const { getByText, waitForRegistry } = render(
- ,
+ ,
{
registry,
- viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
}
);
await waitForRegistry();
- expect( mockTrackEvent ).toHaveBeenCalledWith(
- `${ VIEW_CONTEXT_MAIN_DASHBOARD }_rrm-setup-notification`,
- 'view_notification'
- );
-
expect(
getByText( /Grow your revenue and deepen reader engagement/ )
).toBeInTheDocument();
} );
- it( 'should not render the Reader Revenue Manager setup CTA banner when dismissed', async () => {
- registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {
- [ READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY ]: {
- expires: Date.now() / 1000 + WEEK_IN_SECONDS,
- count: 1,
- },
- } );
- const { container, waitForRegistry } = render(
- ,
+ it( 'should call the "useActivateModuleCallback" hook when the setup CTA is clicked', async () => {
+ mockSurveyEndpoints();
+
+ fetchMock.postOnce(
+ RegExp( '^/google-site-kit/v1/core/user/data/dismiss-prompt' ),
{
- registry,
- viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
+ body: JSON.stringify( [ 'rrm-setup-notification' ] ),
+ status: 200,
}
);
- await waitForRegistry();
-
- expect( container ).toBeEmptyDOMElement();
- expect( mockTrackEvent ).not.toHaveBeenCalled();
- } );
-
- it( 'should call the "useActivateModuleCallback" hook when the setup CTA is clicked', async () => {
- mockSurveyEndpoints();
-
registry
.dispatch( CORE_MODULES )
.receiveCheckRequirementsSuccess(
@@ -147,13 +126,9 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
);
const { container, getByRole, waitForRegistry } = render(
- ,
+ ,
{
registry,
- viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
}
);
@@ -161,25 +136,16 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
expect( container ).not.toBeEmptyDOMElement();
- fireEvent.click(
- getByRole( 'button', {
- name: /Set up Reader Revenue Manager/i,
- } )
- );
+ // eslint-disable-next-line require-await
+ await act( async () => {
+ fireEvent.click(
+ getByRole( 'button', {
+ name: /Set up Reader Revenue Manager/i,
+ } )
+ );
+ } );
expect( activateModuleMock ).toHaveBeenCalledTimes( 1 );
-
- expect( mockTrackEvent ).toHaveBeenNthCalledWith(
- 1,
- `${ VIEW_CONTEXT_MAIN_DASHBOARD }_rrm-setup-notification`,
- 'view_notification'
- );
-
- expect( mockTrackEvent ).toHaveBeenNthCalledWith(
- 2,
- `${ VIEW_CONTEXT_MAIN_DASHBOARD }_rrm-setup-notification`,
- 'confirm_notification'
- );
} );
it( 'should call the dismiss item endpoint when the banner is dismissed', async () => {
@@ -188,12 +154,7 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
fetchMock.postOnce(
RegExp( '^/google-site-kit/v1/core/user/data/dismiss-prompt' ),
{
- body: {
- [ READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY ]: {
- expires: Date.now() / 1000 + WEEK_IN_SECONDS,
- count: 1,
- },
- },
+ body: JSON.stringify( [ 'rrm-setup-notification' ] ),
status: 200,
}
);
@@ -205,14 +166,10 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
Settings
-
+ ,
,
{
registry,
- viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
}
);
@@ -225,64 +182,39 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
// 3 fetches: 1 for the survey trigger, 1 for the survey timeout, 1 for the dismiss prompt.
expect( fetchMock ).toHaveFetchedTimes( 3 );
-
- expect( mockTrackEvent ).toHaveBeenNthCalledWith(
- 1,
- `${ VIEW_CONTEXT_MAIN_DASHBOARD }_rrm-setup-notification`,
- 'view_notification'
- );
-
- expect( mockTrackEvent ).toHaveBeenNthCalledWith(
- 2,
- `${ VIEW_CONTEXT_MAIN_DASHBOARD }_rrm-setup-notification`,
- 'dismiss_notification'
- );
} );
- it( 'should not render the Reader Revenue Manager setup CTA banner when the module requirements do not meet', async () => {
- // Throw error from checkRequirements to simulate non-HTTPS site error.
- provideModules( registry, [
- {
- slug: READER_REVENUE_MANAGER_MODULE_SLUG,
- active: false,
- checkRequirements: () => {
- throw {
- code: ERROR_CODE_NON_HTTPS_SITE,
- message:
- 'The site should use HTTPS to set up Reader Revenue Manager',
- data: null,
- };
- },
- },
- ] );
+ it( 'should trigger a survey when the banner is displayed', async () => {
+ mockSurveyEndpoints();
- const { container, waitForRegistry } = render(
- ,
+ const { waitForRegistry } = render(
+ ,
{
registry,
- viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
}
);
await waitForRegistry();
- expect( container ).toBeEmptyDOMElement();
- expect( mockTrackEvent ).not.toHaveBeenCalled();
+ // The survey trigger endpoint should be called with the correct trigger ID.
+ await waitFor( () =>
+ expect( fetchMock ).toHaveFetched( surveyTriggerEndpoint, {
+ body: {
+ data: { triggerID: 'view_reader_revenue_manager_cta' },
+ },
+ } )
+ );
} );
- it( 'should not render the banner when the dismissed prompts selector is not resolved', async () => {
- registry
- .dispatch( CORE_USER )
- .startResolution( 'getDismissedPrompts', [] );
-
+ it( 'should not render the Reader Revenue Manager setup CTA banner when dismissed', async () => {
+ registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {
+ 'rrm-setup-notification': {
+ expires: Date.now() / 1000 + WEEK_IN_SECONDS,
+ count: 1,
+ },
+ } );
const { container, waitForRegistry } = render(
- ,
+ ,
{
registry,
}
@@ -293,24 +225,15 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
expect( container ).toBeEmptyDOMElement();
} );
- it( 'should not render the banner when it is being dismissed', async () => {
- registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( [] );
-
+ it( 'should not render the banner when the dismissed prompts selector is not resolved', async () => {
registry
.dispatch( CORE_USER )
- .setIsPromptDimissing(
- READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY,
- true
- );
+ .startResolution( 'getDismissedPrompts', [] );
const { container, waitForRegistry } = render(
- ,
+ ,
{
registry,
- viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
}
);
@@ -326,8 +249,8 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
RegExp( '^/google-site-kit/v1/core/user/data/dismiss-prompt' ),
{
body: {
- [ READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY ]: {
- expires: Date.now() / 1000 + 2 * WEEK_IN_SECONDS,
+ 'rrm-setup-notification': {
+ expires: 2 * WEEK_IN_SECONDS,
count: 1,
},
},
@@ -342,10 +265,7 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
Settings
-
+ ,
,
{
registry,
@@ -366,7 +286,7 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
expect( fetchMock ).toHaveFetched( dismissPromptEndpoint, {
body: {
data: {
- slug: READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY,
+ slug: 'rrm-setup-notification',
expiration: WEEK_IN_SECONDS * 2,
},
},
@@ -388,7 +308,7 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
RegExp( '^/google-site-kit/v1/core/user/data/dismiss-prompt' ),
{
body: {
- [ READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY ]: {
+ 'rrm-setup-notification': {
expires: 0, // Expiry of 0 permanently dismisses the prompt.
count: 2,
},
@@ -398,7 +318,7 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
);
registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {
- [ READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY ]: {
+ 'rrm-setup-notification': {
expires: Date.now() / 1000 - 2 * WEEK_IN_SECONDS + 1,
count: 1,
},
@@ -411,10 +331,7 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
Settings
-
+ ,
,
{
registry,
@@ -435,7 +352,7 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
expect( fetchMock ).toHaveFetched( dismissPromptEndpoint, {
body: {
data: {
- slug: READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY,
+ slug: 'rrm-setup-notification',
expiration: 0,
},
},
@@ -444,29 +361,55 @@ describe( 'ReaderRevenueManagerSetupCTABanner', () => {
} );
} );
- it( 'should trigger a survey when the banner is displayed', async () => {
- mockSurveyEndpoints();
+ describe( 'checkRequirements', () => {
+ it( 'is active when all required conditions are met', async () => {
+ const isActive = await notification.checkRequirements(
+ registry,
+ VIEW_CONTEXT_MAIN_DASHBOARD
+ );
- const { waitForRegistry } = render(
- ,
- {
+ expect( isActive ).toBe( true );
+ } );
+
+ it( 'is not active when the banner was dismissed with the legacy dismissal key', async () => {
+ registry.dispatch( CORE_USER ).receiveGetDismissedPrompts( {
+ [ LEGACY_RRM_SETUP_BANNER_DISMISSED_KEY ]: {
+ expires: Date.now() / 1000 + WEEK_IN_SECONDS,
+ count: 1,
+ },
+ } );
+
+ const isActive = await notification.checkRequirements(
registry,
- viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
- }
- );
+ VIEW_CONTEXT_MAIN_DASHBOARD
+ );
- await waitForRegistry();
+ expect( isActive ).toBe( false );
+ } );
- // The survey trigger endpoint should be called with the correct trigger ID.
- await waitFor( () =>
- expect( fetchMock ).toHaveFetched( surveyTriggerEndpoint, {
- body: {
- data: { triggerID: 'view_reader_revenue_manager_cta' },
+ it( 'is not active when the module requirements do not meet', async () => {
+ // Throw error from checkRequirements to simulate non-HTTPS site error.
+ provideModules( registry, [
+ {
+ slug: READER_REVENUE_MANAGER_MODULE_SLUG,
+ active: false,
+ checkRequirements: () => {
+ throw {
+ code: ERROR_CODE_NON_HTTPS_SITE,
+ message:
+ 'The site should use HTTPS to set up Reader Revenue Manager',
+ data: null,
+ };
+ },
},
- } )
- );
+ ] );
+
+ const isActive = await notification.checkRequirements(
+ registry,
+ VIEW_CONTEXT_MAIN_DASHBOARD
+ );
+
+ expect( isActive ).toBe( false );
+ } );
} );
} );
diff --git a/assets/js/modules/reader-revenue-manager/datastore/constants.js b/assets/js/modules/reader-revenue-manager/datastore/constants.js
index c4a26d18919..c8a034972ec 100644
--- a/assets/js/modules/reader-revenue-manager/datastore/constants.js
+++ b/assets/js/modules/reader-revenue-manager/datastore/constants.js
@@ -32,7 +32,7 @@ export const PUBLICATION_ONBOARDING_STATES = {
export const UI_KEY_READER_REVENUE_MANAGER_SHOW_PUBLICATION_APPROVED_NOTIFICATION =
'READER_REVENUE_MANAGER_SHOW_PUBLICATION_APPROVED_NOTIFICATION';
-export const READER_REVENUE_MANAGER_SETUP_BANNER_DISMISSED_KEY =
+export const LEGACY_RRM_SETUP_BANNER_DISMISSED_KEY =
'rrm_module_setup_banner_dismissed_key';
export const READER_REVENUE_MANAGER_SETUP_FORM =
diff --git a/assets/js/modules/reader-revenue-manager/index.js b/assets/js/modules/reader-revenue-manager/index.js
index 9367ad5d4f7..993f97a02f6 100644
--- a/assets/js/modules/reader-revenue-manager/index.js
+++ b/assets/js/modules/reader-revenue-manager/index.js
@@ -30,15 +30,24 @@ import {
MODULES_READER_REVENUE_MANAGER,
ERROR_CODE_NON_HTTPS_SITE,
READER_REVENUE_MANAGER_MODULE_SLUG,
+ LEGACY_RRM_SETUP_BANNER_DISMISSED_KEY,
} from './datastore/constants';
import { SetupMain } from './components/setup';
import { SettingsEdit, SettingsView } from './components/settings';
import ReaderRevenueManagerIcon from '../../../svg/graphics/reader-revenue-manager.svg';
import { isURLUsingHTTPS } from './utils/validation';
-import { RRMSetupSuccessSubtleNotification } from './components/dashboard';
-import { NOTIFICATION_AREAS } from '../../googlesitekit/notifications/datastore/constants';
+import {
+ ReaderRevenueManagerSetupCTABanner,
+ RRMSetupSuccessSubtleNotification,
+} from './components/dashboard';
+import {
+ NOTIFICATION_AREAS,
+ NOTIFICATION_GROUPS,
+} from '../../googlesitekit/notifications/datastore/constants';
import { VIEW_CONTEXT_MAIN_DASHBOARD } from '../../googlesitekit/constants';
import { CORE_MODULES } from '../../googlesitekit/modules/datastore/constants';
+import { isFeatureEnabled } from '../../features';
+import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
export { registerStore } from './datastore';
@@ -76,8 +85,33 @@ export const registerModule = ( modules ) => {
} );
};
-export const registerNotifications = ( notifications ) => {
- notifications.registerNotification( 'setup-success-notification-rrm', {
+export const NOTIFICATIONS = {
+ 'rrm-setup-notification': {
+ Component: ReaderRevenueManagerSetupCTABanner,
+ priority: 50,
+ areaSlug: NOTIFICATION_AREAS.BANNERS_BELOW_NAV,
+ groupID: NOTIFICATION_GROUPS.SETUP_CTAS,
+ viewContexts: [ VIEW_CONTEXT_MAIN_DASHBOARD ],
+ checkRequirements: async ( { select, resolveSelect } ) => {
+ // Check if the prompt with the legacy key used before the banner was refactored
+ // to use the `notification ID` as the dismissal key, is dismissed.
+ await resolveSelect( CORE_USER ).getDismissedPrompts();
+ const isLegacyDismissed = select( CORE_USER ).isPromptDismissed(
+ LEGACY_RRM_SETUP_BANNER_DISMISSED_KEY
+ );
+
+ if ( isLegacyDismissed ) {
+ return false;
+ }
+
+ return await resolveSelect( CORE_MODULES ).canActivateModule(
+ READER_REVENUE_MANAGER_MODULE_SLUG
+ );
+ },
+ isDismissible: true,
+ dismissRetries: 1,
+ },
+ 'setup-success-notification-rrm': {
Component: RRMSetupSuccessSubtleNotification,
priority: 10,
areaSlug: NOTIFICATION_AREAS.BANNERS_BELOW_NAV,
@@ -110,5 +144,16 @@ export const registerNotifications = ( notifications ) => {
return false;
},
isDismissible: false,
- } );
+ },
+};
+
+export const registerNotifications = ( notificationsAPI ) => {
+ if ( isFeatureEnabled( 'rrmModule' ) ) {
+ for ( const notificationID in NOTIFICATIONS ) {
+ notificationsAPI.registerNotification(
+ notificationID,
+ NOTIFICATIONS[ notificationID ]
+ );
+ }
+ }
};
diff --git a/assets/sass/components/reader-revenue-manager/_googlesitekit-rrm-setup-cta-banner.scss b/assets/sass/components/reader-revenue-manager/_googlesitekit-rrm-setup-cta-banner.scss
index 31c02e91ec0..0ae15e30c8c 100644
--- a/assets/sass/components/reader-revenue-manager/_googlesitekit-rrm-setup-cta-banner.scss
+++ b/assets/sass/components/reader-revenue-manager/_googlesitekit-rrm-setup-cta-banner.scss
@@ -17,7 +17,7 @@
*/
.googlesitekit-plugin {
- .googlesitekit-reader-revenue-manager-setup-cta-widget {
+ .googlesitekit-setup-cta-banner--rrm-setup-notification {
.googlesitekit-setup-cta-banner__primary-cell {
padding: $grid-gap-desktop - 4 $grid-gap-phone 0;
@@ -27,10 +27,6 @@
}
.googlesitekit-setup-cta-banner__title {
- @media (min-width: $width-tablet + 1 + px) {
- font-weight: $fw-medium;
- }
-
@media (min-width: $bp-nonMobile) {
font-size: $fs-headline-sm;
line-height: $lh-headline-sm;
@@ -66,7 +62,13 @@
}
}
- .googlesitekit-setup-cta-banner__svg-wrapper {
+ .googlesitekit-setup-cta-banner__svg-wrapper--rrm-setup-notification {
+ align-items: center;
+ display: flex;
+ height: 100%;
+ justify-content: center;
+ overflow: hidden;
+ position: relative;
svg {
flex: 1;
@@ -75,12 +77,16 @@
// Increase the SVG size via scale in order to achieve the desired clipping effect
// in conjunction with the parent's overflow: hidden.
scale: 1;
+ transform-origin: center 2px;
@media (min-width: $bp-nonTablet) {
+ height: 100%;
max-height: 272px;
+ position: absolute;
right: 70px;
scale: 1.6;
top: 10px;
+ transform-origin: initial;
width: 65%;
}
diff --git a/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_1_medium.png b/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_1_medium.png
index d39805a31ff..e87f595c887 100644
Binary files a/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_1_medium.png and b/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_1_medium.png differ
diff --git a/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_2_large.png b/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_2_large.png
index a8eefcd2530..985a1ba2e98 100644
Binary files a/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_2_large.png and b/tests/backstop/reference/google-site-kit_Modules_ReaderRevenueManager_Components_Dashboard_ReaderRevenueManagerSetupCTABanner_Default_0_document_2_large.png differ