Skip to content

Commit

Permalink
Merge pull request #6752 from google/enhance/6544-switch-to-ga4-banner
Browse files Browse the repository at this point in the history
Add `shouldPromptGA4DashboardView` selector and `SwitchGA4DashboardViewNotification` component.
  • Loading branch information
techanvil authored Mar 23, 2023
2 parents d25505a + 9e520a2 commit 39198ce
Show file tree
Hide file tree
Showing 10 changed files with 390 additions and 20 deletions.
9 changes: 9 additions & 0 deletions assets/js/components/notifications/BannerNotifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import useViewOnly from '../../hooks/useViewOnly';
import ZeroDataStateNotifications from './ZeroDataStateNotifications';
import EnableAutoUpdateBannerNotification from './EnableAutoUpdateBannerNotification';
import GoogleTagIDMismatchNotification from './GoogleTagIDMismatchNotification';
import SwitchGA4DashboardViewNotification from './SwitchGA4DashboardViewNotification';

const { useSelect } = Data;

Expand All @@ -47,6 +48,7 @@ export default function BannerNotifications() {
const userInputEnabled = useFeature( 'userInput' );
const ga4ActivationBannerEnabled = useFeature( 'ga4ActivationBanner' );
const gteSupportEnabled = useFeature( 'gteSupport' );
const ga4ReportingEnabled = useFeature( 'ga4Reporting' );

const viewOnly = useViewOnly();

Expand All @@ -57,6 +59,10 @@ export default function BannerNotifications() {
select( CORE_MODULES ).isModuleActive( 'adsense' )
);

const analyticsModuleConnected = useSelect( ( select ) =>
select( CORE_MODULES ).isModuleConnected( 'analytics' )
);

const [ notification ] = useQueryArg( 'notification' );

return (
Expand All @@ -81,6 +87,9 @@ export default function BannerNotifications() {
) }
{ adSenseModuleActive && <AdSenseAlerts /> }
{ gteSupportEnabled && <GoogleTagIDMismatchNotification /> }
{ ga4ReportingEnabled && analyticsModuleConnected && (
<SwitchGA4DashboardViewNotification />
) }
</Fragment>
) }
</Fragment>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* SwitchGA4DashboardViewNotification component.
*
* Site Kit by Google, Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import Data from 'googlesitekit-data';
import BannerNotification from './BannerNotification';
import { CORE_SITE } from '../../googlesitekit/datastore/site/constants';
import {
DASHBOARD_VIEW_GA4,
MODULES_ANALYTICS,
} from '../../modules/analytics/datastore/constants';
import GA4SuccessGreenSVG from '../../../svg/graphics/ga4-success-green.svg';

const { useDispatch, useSelect } = Data;

export default function SwitchGA4DashboardViewNotification() {
const shouldPromptGA4DashboardView = useSelect( ( select ) =>
select( MODULES_ANALYTICS ).shouldPromptGA4DashboardView()
);

const ga4DocumentationURL = useSelect( ( select ) =>
select( CORE_SITE ).getDocumentationLinkURL( 'ga4' )
);

const { setDashboardView, saveSettings } = useDispatch( MODULES_ANALYTICS );

const handleCTAClick = async () => {
await setDashboardView( DASHBOARD_VIEW_GA4 );
await saveSettings();
};

if ( ! shouldPromptGA4DashboardView ) {
return null;
}

return (
<BannerNotification
id="switch-ga4-dashboard-view"
title={ __(
'Display data from Google Analytics 4 on your dashboard',
'google-site-kit'
) }
description={ __(
'Update your dashboard to show data from the new version of Analytics (Google Analytics 4) instead of the old version (Universal Analytics).',
'google-site-kit'
) }
ctaLink="#"
ctaLabel={ __( 'Update dashboard', 'google-site-kit' ) }
onCTAClick={ handleCTAClick }
dismiss={ __( 'Maybe later', 'google-site-kit' ) }
WinImageSVG={ GA4SuccessGreenSVG }
learnMoreLabel={ __( 'Learn what’s new', 'google-site-kit' ) }
learnMoreURL={ ga4DocumentationURL }
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* SwitchGA4DashboardViewNotification Component stories.
*
* Site Kit by Google, Copyright 2023 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/**
* Internal dependencies
*/
import {
DASHBOARD_VIEW_UA,
MODULES_ANALYTICS,
} from '../../modules/analytics/datastore/constants';
import { MODULES_ANALYTICS_4 } from '../../modules/analytics-4/datastore/constants';
import SwitchGA4DashboardViewNotification from './SwitchGA4DashboardViewNotification';
import {
createTestRegistry,
provideModules,
provideSiteInfo,
WithTestRegistry,
} from '../../../../tests/js/utils';
import { enabledFeatures } from '../../features';

function Template( { ...args } ) {
return <SwitchGA4DashboardViewNotification { ...args } />;
}

export const SwitchGA4DashboardViewNotificationDefault = Template.bind( {} );
SwitchGA4DashboardViewNotificationDefault.storyName = 'Default';

export default {
title: 'Components/SwitchGA4DashboardViewNotification',
component: SwitchGA4DashboardViewNotification,
decorators: [
( Story ) => {
enabledFeatures.add( 'ga4Reporting' );
const registry = createTestRegistry();
provideSiteInfo( registry );
provideModules( registry, [
{
slug: 'analytics-4',
active: true,
connected: true,
},
] );

registry.dispatch( MODULES_ANALYTICS ).setSettings( {
dashboardView: DASHBOARD_VIEW_UA,
} );

registry
.dispatch( MODULES_ANALYTICS_4 )
.receiveIsGatheringData( false );
return (
<WithTestRegistry registry={ registry }>
<Story />
</WithTestRegistry>
);
},
],
};
4 changes: 2 additions & 2 deletions assets/js/modules/analytics-4/datastore/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@ const gatheringDataStore = createGatheringDataStore( 'analytics-4', {

const createTime = new Date( property.createTime ).getTime();

// If the property was created within the last two days and has no data, assume it's still gathering data.
if ( createTime > Date.now() - DAY_IN_SECONDS * 2 * 1000 ) {
// If the property was created within the last three days and has no data, assume it's still gathering data.
if ( createTime > Date.now() - DAY_IN_SECONDS * 3 * 1000 ) {
return false;
}

Expand Down
12 changes: 6 additions & 6 deletions assets/js/modules/analytics-4/datastore/report.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,10 @@ describe( 'modules/analytics-4 report', () => {
await waitForDefaultTimeouts();
} );

it( 'should return TRUE if the connnected GA4 property is under two days old', async () => {
// Create a timestamp that is one and a half days ago.
it( 'should return TRUE if the connnected GA4 property is under three days old', async () => {
// Create a timestamp that is two and a half days ago.
const createTime = new Date(
Date.now() - DAY_IN_SECONDS * 1.5 * 1000
Date.now() - DAY_IN_SECONDS * 2.5 * 1000
).toISOString();

const property = {
Expand Down Expand Up @@ -383,16 +383,16 @@ describe( 'modules/analytics-4 report', () => {
expect( isGatheringData() ).toBe( true );
} );

it( 'should return FALSE if the connnected GA4 property is older than two days', async () => {
it( 'should return FALSE if the connnected GA4 property is older than three days', async () => {
muteFetch(
new RegExp(
'^/google-site-kit/v1/modules/analytics-4/data/data-available'
)
);

// Create a timestamp that is two days ago.
// Create a timestamp that is three days ago.
const createTime = new Date(
Date.now() - DAY_IN_SECONDS * 2 * 1000
Date.now() - DAY_IN_SECONDS * 3 * 1000
).toISOString();

const property = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ EntityDashboardZeroData.args = {
// Set the property creation timestamp to two days ago, so that
// the property is not considered to be in the gathering data state.
const createTime = new Date(
Date.now() - DAY_IN_SECONDS * 2 * 1000
Date.now() - DAY_IN_SECONDS * 3 * 1000
).toISOString();

const property = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ MainDashboardZeroData.args = {
// Set the property creation timestamp to two days ago, so that
// the property is not considered to be in the gathering data state.
const createTime = new Date(
Date.now() - DAY_IN_SECONDS * 2 * 1000
Date.now() - DAY_IN_SECONDS * 3 * 1000
).toISOString();

const property = {
Expand Down
3 changes: 3 additions & 0 deletions assets/js/modules/analytics/datastore/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
getCanUseSnippet,
isGA4DashboardView,
rollbackChanges,
shouldPromptGA4DashboardView,
submitChanges,
validateCanSubmitChanges,
} from './settings';
Expand Down Expand Up @@ -57,5 +58,7 @@ const baseModuleStore = Modules.createModuleStore( 'analytics', {

baseModuleStore.selectors.getCanUseSnippet = getCanUseSnippet;
baseModuleStore.selectors.isGA4DashboardView = isGA4DashboardView;
baseModuleStore.selectors.shouldPromptGA4DashboardView =
shouldPromptGA4DashboardView;

export default baseModuleStore;
59 changes: 57 additions & 2 deletions assets/js/modules/analytics/datastore/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,9 @@ export const getCanUseSnippet = createRegistrySelector( ( select ) => () => {
* @return {boolean|undefined} True if the dashboard view is GA4, false if it is UA, or undefined if not loaded.
*/
export const isGA4DashboardView = createRegistrySelector( ( select ) => () => {
const isGA4Enabled = isFeatureEnabled( 'ga4Reporting' );
if ( ! isGA4Enabled ) {
const ga4ReportingEnabled = isFeatureEnabled( 'ga4Reporting' );

if ( ! ga4ReportingEnabled ) {
return false;
}

Expand All @@ -301,3 +302,57 @@ export const isGA4DashboardView = createRegistrySelector( ( select ) => () => {

return dashboardView === DASHBOARD_VIEW_GA4;
} );

/**
* Determines whether the user should be prompted to switch to GA4 Dashboard View.
*
* @since n.e.x.t
*
* @return {boolean} True if the user should be prompted to switch to the GA4 Dashboard View, false otherwise, or undefined if not loaded.
*/
export const shouldPromptGA4DashboardView = createRegistrySelector(
( select ) => () => {
const ga4ReportingEnabled = isFeatureEnabled( 'ga4Reporting' );

if ( ! ga4ReportingEnabled ) {
return false;
}

const ga4ModuleConnected =
select( CORE_MODULES ).isModuleConnected( 'analytics-4' );

if ( ga4ModuleConnected === undefined ) {
return undefined;
}

if ( ! ga4ModuleConnected ) {
return false;
}

const ga4DashboardView =
select( MODULES_ANALYTICS ).isGA4DashboardView();

if ( ga4DashboardView === undefined ) {
return undefined;
}

// Don't prompt if the user is already on the GA4 Dashboard.
if ( ga4DashboardView ) {
return false;
}

const ga4GatheringData =
select( MODULES_ANALYTICS_4 ).isGatheringData();

if ( ga4GatheringData === undefined ) {
return undefined;
}

// Don't prompt if GA4 is still gathering data.
if ( ga4GatheringData ) {
return false;
}

return true;
}
);
Loading

0 comments on commit 39198ce

Please sign in to comment.