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

Key Metrics “Connect GA” CTA #7255

Merged
merged 29 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
da2251a
Create CTA widget layout components.
nfmohit Jul 4, 2023
9ae0ba5
Use CTA widget layout components.
nfmohit Jul 4, 2023
422aeb8
Create `ConnectGA4CTAWidget`.
nfmohit Jul 4, 2023
df1186d
Add widget visibility conditions.
nfmohit Jul 4, 2023
0214cfa
Complete actions.
nfmohit Jul 4, 2023
7b5d9bc
Register widget.
nfmohit Jul 4, 2023
54772b5
Register widget only if feature flag is enabled.
nfmohit Jul 4, 2023
4b81db6
Handle GA4 connection.
nfmohit Jul 5, 2023
fa90fd9
Cleanup stories.
nfmohit Jul 5, 2023
05ef7a3
Add tests for `ConnectGA4CTAWidget`.
nfmohit Jul 5, 2023
3a3a2fa
Add VRT references.
nfmohit Jul 5, 2023
ea13972
Fix test case label.
nfmohit Jul 5, 2023
21d695c
Move checks to `isActive`.
nfmohit Jul 6, 2023
1c70894
Remove unnecessary data from story.
nfmohit Jul 6, 2023
669c01a
Merge branch 'develop' into enhancement/#6265-connect-ga4-cta.
nfmohit Jul 6, 2023
28e454f
Create and use `provideWidgetRegistrations`.
nfmohit Jul 6, 2023
c4127a1
Fix typography.
nfmohit Jul 6, 2023
a03b8bf
Minor enhancements.
nfmohit Jul 6, 2023
4ce1d73
Update VRT references.
nfmohit Jul 6, 2023
7a6fcfc
Fix link colour.
nfmohit Jul 6, 2023
295dd6c
Merge branch 'develop' into enhancement/#6265-connect-ga4-cta.
nfmohit Jul 6, 2023
5cee01e
Move widget inside module.
nfmohit Jul 6, 2023
e44ad83
Remove redundant check for GA4 connection inside widget.
nfmohit Jul 6, 2023
aa3fdd0
Remove `provideWidgetRegistrations`.
nfmohit Jul 6, 2023
84f2dab
Update VRT references.
nfmohit Jul 6, 2023
a67951f
Fix `receiveIsUserInputCompleted` behaviour.
nfmohit Jul 6, 2023
c3972db
Alphabetically order exports.
nfmohit Jul 7, 2023
88b514c
Isolate test-only utility.
nfmohit Jul 7, 2023
4952559
Remove unnecessary GA4 connection.
nfmohit Jul 7, 2023
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
208 changes: 208 additions & 0 deletions assets/js/components/KeyMetrics/ConnectGA4CTAWidget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
/**
* ConnectGA4CTA 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';
import { useCallback, useEffect, useState } from '@wordpress/element';

/**
* Internal dependencies
*/
import Data from 'googlesitekit-data';
import { SpinnerButton } from 'googlesitekit-components';
import KeyMetricsCTAContent from './KeyMetricsCTAContent';
import KeyMetricsCTAFooter from './KeyMetricsCTAFooter';
import { CORE_MODULES } from '../../googlesitekit/modules/datastore/constants';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
import { CORE_WIDGETS } from '../../googlesitekit/widgets/datastore/constants';
import { AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY } from '../../googlesitekit/widgets/default-areas';
import {
FORM_SETUP,
MODULES_ANALYTICS,
} from '../../modules/analytics/datastore/constants';
import { CORE_LOCATION } from '../../googlesitekit/datastore/location/constants';
import { CORE_FORMS } from '../../googlesitekit/datastore/forms/constants';
import { CORE_SITE } from '../../googlesitekit/datastore/site/constants';
import useActivateModuleCallback from '../../hooks/useActivateModuleCallback';
import useCompleteModuleActivationCallback from '../../hooks/useCompleteModuleActivationCallback';
import { useDebounce } from '../../hooks/useDebounce';
import { snapshotAllStores } from '../../googlesitekit/data/create-snapshot-store';
const { useSelect, useDispatch } = Data;

export default function ConnectGA4CTAWidget( { Widget, WidgetNull } ) {
const DISMISSED_ITEM_KEY = 'key-metrics-connect-ga4-cta-widget';

const isCTADismissed = useSelect( ( select ) =>
select( CORE_USER ).isItemDismissed( DISMISSED_ITEM_KEY )
);
const isUserInputCompleted = useSelect( ( select ) =>
select( CORE_USER ).isUserInputCompleted()
);
const isGA4Connected = useSelect( ( select ) =>
select( CORE_MODULES ).isModuleConnected( 'analytics-4' )
);
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved
const ga4DependantKeyMetrics = useSelect( ( select ) => {
const keyMetrics = select( CORE_USER ).getKeyMetrics();
const widgets = select( CORE_WIDGETS ).getWidgets(
AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY
);

if ( ! keyMetrics || ! widgets ) {
return [];
}

return widgets.filter(
( { slug, modules } ) =>
keyMetrics.includes( slug ) && modules.includes( 'analytics-4' )
);
} );
const isAnalyticsActive = useSelect( ( select ) =>
select( CORE_MODULES ).isModuleActive( 'analytics' )
);
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved
const isNavigatingToReauthURL = useSelect( ( select ) => {
const adminReauthURL = select( MODULES_ANALYTICS ).getAdminReauthURL();

if ( ! adminReauthURL ) {
return false;
}

return select( CORE_LOCATION ).isNavigatingTo( adminReauthURL );
} );
const isActivatingAnalytics = useSelect( ( select ) =>
select( CORE_MODULES ).isFetchingSetModuleActivation(
'analytics',
true
)
);
const settingsURL = useSelect( ( select ) =>
select( CORE_SITE ).getAdminURL( 'googlesitekit-settings' )
);
const isAnalyticsConnected = useSelect( ( select ) =>
select( CORE_MODULES ).isModuleConnected( 'analytics' )
);
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved
const connectGA4URL = `${ settingsURL }#connected-services/analytics/edit`;
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved
const isNavigatingToGA4URL = useSelect( ( select ) =>
select( CORE_LOCATION ).isNavigatingTo( connectGA4URL )
);

const { dismissItem } = useDispatch( CORE_USER );
const { setValues } = useDispatch( CORE_FORMS );
const { navigateTo } = useDispatch( CORE_LOCATION );

const activateAnalytics = useActivateModuleCallback( 'analytics' );
const completeAnalyticsActivation =
useCompleteModuleActivationCallback( 'analytics' );

const handleCTAClick = useCallback( async () => {
if ( ! isAnalyticsConnected ) {
if ( isAnalyticsActive ) {
completeAnalyticsActivation();
} else {
activateAnalytics();
}
} else if ( ! isGA4Connected ) {
setValues( FORM_SETUP, {
// Pre-enable GA4 controls.
enableGA4: true,
// Enable tooltip highlighting GA4 property select.
enableGA4PropertyTooltip: true,
} );

await snapshotAllStores();

navigateTo( `${ settingsURL }#connected-services/analytics/edit` );
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved
}
}, [
activateAnalytics,
completeAnalyticsActivation,
isAnalyticsActive,
isAnalyticsConnected,
isGA4Connected,
navigateTo,
setValues,
settingsURL,
] );

const [ inProgress, setInProgress ] = useState( false );

/*
* Using debounce here because the spinner has to render across two separate calls.
* Rather than risk it flickering on and off in between the activation call completing and
* the navigate call starting, we will just set a debounce to keep the spinner for 3 seconds.
*/
const debouncedSetInProgress = useDebounce( setInProgress, 3000 );

useEffect( () => {
if (
isActivatingAnalytics ||
isNavigatingToReauthURL ||
isNavigatingToGA4URL
) {
setInProgress( true );
} else {
debouncedSetInProgress( false );
}
}, [
isActivatingAnalytics,
isNavigatingToReauthURL,
debouncedSetInProgress,
isNavigatingToGA4URL,
] );

if (
isCTADismissed ||
! isUserInputCompleted ||
isGA4Connected ||
ga4DependantKeyMetrics.length < 3
) {
return <WidgetNull />;
}

return (
<Widget
noPadding
Footer={ () => (
<KeyMetricsCTAFooter
onActionClick={ () => dismissItem( DISMISSED_ITEM_KEY ) }
/>
) }
>
<KeyMetricsCTAContent
className="googlesitekit-km-connect-ga4-cta"
title={ __(
'Google Analytics is disconnected',
'google-site-kit'
) }
description={ __(
'Metrics cannot be displayed without Google Analytics',
'google-site-kit'
) }
actions={
<SpinnerButton
onClick={ handleCTAClick }
isSaving={ inProgress }
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved
>
{ __( 'Connect Google Analytics', 'google-site-kit' ) }
</SpinnerButton>
}
/>
</Widget>
);
}
113 changes: 113 additions & 0 deletions assets/js/components/KeyMetrics/ConnectGA4CTAWidget.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* ConnectGA4CTAWidget 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 {
CORE_USER,
KM_ANALYTICS_ENGAGED_TRAFFIC_SOURCE,
KM_ANALYTICS_LOYAL_VISITORS,
KM_ANALYTICS_NEW_VISITORS,
KM_ANALYTICS_TOP_TRAFFIC_SOURCE,
} from '../../googlesitekit/datastore/user/constants';
import { CORE_WIDGETS } from '../../googlesitekit/widgets/datastore/constants';
import { AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY } from '../../googlesitekit/widgets/default-areas';
import { CONTEXT_MAIN_DASHBOARD_KEY_METRICS } from '../../googlesitekit/widgets/default-contexts';
import { provideKeyMetrics, provideModules } from '../../../../tests/js/utils';
import { withWidgetComponentProps } from '../../googlesitekit/widgets/util';
import WithRegistrySetup from '../../../../tests/js/WithRegistrySetup';
import ConnectGA4CTAWidget from './ConnectGA4CTAWidget';

const WidgetWithComponentProps = withWidgetComponentProps(
'keyMetricsConnectGA4CTA'
)( ConnectGA4CTAWidget );

const Template = () => <WidgetWithComponentProps />;

export const Default = Template.bind( {} );
Default.storyName = 'ConnectGA4CTAWidget';
Default.scenario = {
label: 'KeyMetrics/ConnectGA4CTAWidget',
delay: 250,
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved
};

export default {
title: 'Key Metrics/ConnectGA4CTAWidget',
decorators: [
( Story ) => {
const setupRegistry = ( registry ) => {
registry.dispatch( CORE_USER ).receiveGetDismissedItems( [] );
global._googlesitekitUserData.isUserInputCompleted = true;
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved

provideModules( registry, [
{
slug: 'analytics-4',
active: false,
connected: false,
},
] );

const keyMetricWidgets = [
KM_ANALYTICS_LOYAL_VISITORS,
KM_ANALYTICS_NEW_VISITORS,
KM_ANALYTICS_TOP_TRAFFIC_SOURCE,
KM_ANALYTICS_ENGAGED_TRAFFIC_SOURCE,
];

provideKeyMetrics( registry, {
widgetSlugs: keyMetricWidgets,
} );

registry
.dispatch( CORE_WIDGETS )
.registerWidgetArea(
AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY,
{
title: 'Key metrics',
}
);
registry
.dispatch( CORE_WIDGETS )
.assignWidgetArea(
AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY,
CONTEXT_MAIN_DASHBOARD_KEY_METRICS
);

keyMetricWidgets.forEach( ( slug ) => {
registry.dispatch( CORE_WIDGETS ).registerWidget( slug, {
Component: () => <div>Hello test.</div>,
modules: [ 'analytics-4' ],
} );
registry
.dispatch( CORE_WIDGETS )
.assignWidget(
slug,
AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY
);
} );
};
aaemnnosttv marked this conversation as resolved.
Show resolved Hide resolved

return (
<WithRegistrySetup func={ setupRegistry }>
<Story />
</WithRegistrySetup>
);
},
],
};
Loading