Skip to content

Commit

Permalink
Merge branch 'main' into develop.
Browse files Browse the repository at this point in the history
  • Loading branch information
tofumatt committed Sep 18, 2024
2 parents d203e70 + 5d53e38 commit 2ac8581
Show file tree
Hide file tree
Showing 7 changed files with 490 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,24 @@
/**
* WordPress dependencies
*/
import { useCallback, useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { useSelect } from 'googlesitekit-data';
import { useSelect, useDispatch } from 'googlesitekit-data';
import { CORE_FORMS } from '../../../../googlesitekit/datastore/forms/constants';
import {
MODULES_READER_REVENUE_MANAGER,
PUBLICATION_ONBOARDING_STATES,
READER_REVENUE_MANAGER_NOTICES_FORM,
SYNC_PUBLICATION,
} from '../../datastore/constants';
import SubtleNotification from '../../../../components/notifications/SubtleNotification';
import { trackEvent } from '../../../../util';
import useViewContext from '../../../../hooks/useViewContext';
import { useEffect } from 'react';
import { useRefocus } from '../../../../hooks/useRefocus';

const { PENDING_VERIFICATION, ONBOARDING_ACTION_REQUIRED } =
PUBLICATION_ONBOARDING_STATES;
Expand Down Expand Up @@ -61,10 +65,44 @@ export default function PublicationOnboardingStateNotice() {
} )
);

const shouldSyncPublication = useSelect(
( select ) =>
select( CORE_FORMS ).getValue(
READER_REVENUE_MANAGER_NOTICES_FORM,
SYNC_PUBLICATION
) && actionableOnboardingStates.includes( onboardingState )
);

const { setValues } = useDispatch( CORE_FORMS );
const { syncPublicationOnboardingState } = useDispatch(
MODULES_READER_REVENUE_MANAGER
);

const showNotice =
onboardingState &&
actionableOnboardingStates.includes( onboardingState );

const onCTAClick = useCallback( () => {
// Set publication data to be reset when user re-focuses window.
setValues( READER_REVENUE_MANAGER_NOTICES_FORM, {
[ SYNC_PUBLICATION ]: true,
} );

trackEvent(
`${ viewContext }_rrm-onboarding-state-notification`,
'confirm_notification',
onboardingState
);
}, [ onboardingState, setValues, viewContext ] );

const syncPublication = useCallback( () => {
if ( ! shouldSyncPublication ) {
return;
}

syncPublicationOnboardingState();
}, [ shouldSyncPublication, syncPublicationOnboardingState ] );

useEffect( () => {
if ( ! showNotice ) {
return;
Expand All @@ -77,6 +115,9 @@ export default function PublicationOnboardingStateNotice() {
);
}, [ onboardingState, showNotice, viewContext ] );

// Sync publication data when user re-focuses window.
useRefocus( syncPublication, 15000 );

if ( ! showNotice ) {
return null;
}
Expand Down Expand Up @@ -105,13 +146,7 @@ export default function PublicationOnboardingStateNotice() {
ctaLink={ serviceURL }
isCTALinkExternal
variant="warning"
onCTAClick={ () => {
trackEvent(
`${ viewContext }_rrm-onboarding-state-notification`,
'confirm_notification',
onboardingState
);
} }
onCTAClick={ onCTAClick }
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ import {
provideUserAuthentication,
provideUserInfo,
render,
waitFor,
} from '../../../../../../tests/js/test-utils';
import { VIEW_CONTEXT_MAIN_DASHBOARD } from '../../../../googlesitekit/constants';
import * as fixtures from '../../datastore/__fixtures__';
import * as tracking from '../../../../util/tracking';
import {
MODULES_READER_REVENUE_MANAGER,
Expand All @@ -41,6 +43,13 @@ mockTrackEvent.mockImplementation( () => Promise.resolve() );
describe( 'PublicationOnboardingStateNotice', () => {
let registry;

const publicationsEndpoint = new RegExp(
'^/google-site-kit/v1/modules/reader-revenue-manager/data/publications'
);
const settingsEndpoint = new RegExp(
'^/google-site-kit/v1/modules/reader-revenue-manager/data/settings'
);

const {
ONBOARDING_ACTION_REQUIRED,
ONBOARDING_COMPLETE,
Expand Down Expand Up @@ -144,4 +153,84 @@ describe( 'PublicationOnboardingStateNotice', () => {
);
}
);

it( 'should sync onboarding state when the window is refocused 15 seconds after clicking the CTA', async () => {
const originalDateNow = Date.now;

// Mock the date to be an arbitrary time.
const mockNow = new Date( '2020-01-01 12:30:00' ).getTime();
Date.now = jest.fn( () => mockNow );

jest.useFakeTimers();

registry
.dispatch( MODULES_READER_REVENUE_MANAGER )
.receiveGetSettings( {
publicationID: 'QRSTUVWX',
publicationOnboardingState: ONBOARDING_ACTION_REQUIRED,
publicationOnboardingStateLastSyncedAtMs: 0,
} );

fetchMock.getOnce( publicationsEndpoint, {
body: fixtures.publications,
status: 200,
} );

fetchMock.postOnce( settingsEndpoint, ( _url, opts ) => {
const { data } = JSON.parse( opts.body );

// Return the same settings passed to the API.
return { body: data, status: 200 };
} );

const { container, getByText } = render(
<PublicationOnboardingStateNotice />,
{
registry,
viewContext: VIEW_CONTEXT_MAIN_DASHBOARD,
}
);

act( () => {
fireEvent.click( getByText( 'Complete publication setup' ) );
} );

act( () => {
global.window.dispatchEvent( new Event( 'blur' ) );
} );

act( () => {
jest.advanceTimersByTime( 15000 );
} );

act( () => {
global.window.dispatchEvent( new Event( 'focus' ) );
} );

await waitFor( () => {
expect( fetchMock ).toHaveFetched( publicationsEndpoint );
expect( fetchMock ).toHaveFetched( settingsEndpoint, {
body: {
data: {
publicationID: 'QRSTUVWX',
publicationOnboardingState: ONBOARDING_COMPLETE,
publicationOnboardingStateLastSyncedAtMs: Date.now(),
},
},
} );
} );

// Verify that the onboarding state has been synced.
expect(
registry
.select( MODULES_READER_REVENUE_MANAGER )
.getPublicationOnboardingState()
).toBe( ONBOARDING_COMPLETE );

// Verify the the notice is removed.
expect( container ).toBeEmptyDOMElement();

// Restore Date.now method.
Date.now = originalDateNow;
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,27 @@
/**
* WordPress dependencies
*/
import { useEffect } from '@wordpress/element';
import { useCallback, useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { useSelect } from 'googlesitekit-data';
import { useSelect, useDispatch } from 'googlesitekit-data';
import { Cell, Grid, Row } from '../../../../material-components';
import SubtleNotification from '../../../../components/notifications/SubtleNotification';
import useQueryArg from '../../../../hooks/useQueryArg';
import whenActive from '../../../../util/when-active';
import { trackEvent } from '../../../../util';
import { useRefocus } from '../../../../hooks/useRefocus';
import useViewContext from '../../../../hooks/useViewContext';
import { CORE_FORMS } from '../../../../googlesitekit/datastore/forms/constants';
import {
MODULES_READER_REVENUE_MANAGER,
PUBLICATION_ONBOARDING_STATES,
READER_REVENUE_MANAGER_MODULE_SLUG,
READER_REVENUE_MANAGER_NOTICES_FORM,
SYNC_PUBLICATION,
} from '../../datastore/constants';

const {
Expand All @@ -44,12 +48,16 @@ const {
ONBOARDING_ACTION_REQUIRED,
} = PUBLICATION_ONBOARDING_STATES;

const targetOnboardingStates = [
ONBOARDING_COMPLETE,
const actionableOnboardingStates = [
PENDING_VERIFICATION,
ONBOARDING_ACTION_REQUIRED,
];

const targetOnboardingStates = [
...actionableOnboardingStates,
ONBOARDING_COMPLETE,
];

function RRMSetupSuccessSubtleNotification() {
const viewContext = useViewContext();
const [ notification, setNotification ] = useQueryArg( 'notification' );
Expand All @@ -72,6 +80,20 @@ function RRMSetupSuccessSubtleNotification() {
} )
);

const shouldSyncPublication = useSelect(
( select ) =>
select( CORE_FORMS ).getValue(
READER_REVENUE_MANAGER_NOTICES_FORM,
SYNC_PUBLICATION
) &&
actionableOnboardingStates.includes( publicationOnboardingState )
);

const { setValues } = useDispatch( CORE_FORMS );
const { syncPublicationOnboardingState } = useDispatch(
MODULES_READER_REVENUE_MANAGER
);

const showNotification =
notification === 'authentication_success' &&
slug === READER_REVENUE_MANAGER_MODULE_SLUG &&
Expand All @@ -85,7 +107,7 @@ function RRMSetupSuccessSubtleNotification() {
const handleDismiss = () => {
if ( targetOnboardingStates.includes( publicationOnboardingState ) ) {
trackEvent(
`${ viewContext }_rrm-setup-success-notification`,
`${ viewContext }_setup-success-notification-rrm`,
'dismiss_notification',
publicationOnboardingState
);
Expand All @@ -94,29 +116,53 @@ function RRMSetupSuccessSubtleNotification() {
dismissNotice();
};

const onCTAClick = () => {
const onCTAClick = ( event ) => {
event.preventDefault();

// Set publication data to be reset when user re-focuses window.
if (
actionableOnboardingStates.includes( publicationOnboardingState )
) {
setValues( READER_REVENUE_MANAGER_NOTICES_FORM, {
[ SYNC_PUBLICATION ]: true,
} );
}

if ( targetOnboardingStates.includes( publicationOnboardingState ) ) {
trackEvent(
`${ viewContext }_rrm-setup-success-notification`,
`${ viewContext }_setup-success-notification-rrm`,
'confirm_notification',
publicationOnboardingState
);
}

global.open( serviceURL, '_blank' );
};

const syncPublication = useCallback( () => {
if ( ! shouldSyncPublication ) {
return;
}

syncPublicationOnboardingState();
}, [ shouldSyncPublication, syncPublicationOnboardingState ] );

useEffect( () => {
if (
showNotification &&
targetOnboardingStates.includes( publicationOnboardingState )
) {
trackEvent(
`${ viewContext }_rrm-setup-success-notification`,
`${ viewContext }_setup-success-notification-rrm`,
'view_notification',
publicationOnboardingState
);
}
}, [ publicationOnboardingState, showNotification, viewContext ] );

// Sync publication data when user re-focuses window.
useRefocus( syncPublication, 15000 );

if ( ! showNotification ) {
return null;
}
Expand Down
Loading

0 comments on commit 2ac8581

Please sign in to comment.