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

KMW / 7577 Visits Per Visitor KMW Tile #7628

Merged
merged 19 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
fd2a85a
Merge branch 'develop' of github.com:google/site-kit-wp into develop.
10upsimon Sep 7, 2023
d9b5572
Merge branch 'develop' of github.com:google/site-kit-wp into develop.
10upsimon Sep 12, 2023
126f3aa
Merge branch 'develop' of github.com:google/site-kit-wp into develop.
10upsimon Sep 20, 2023
33d4682
Merge branch 'develop' of github.com:google/site-kit-wp into develop.
10upsimon Sep 22, 2023
553bddd
Work in progress add VisitsPerVisitorWidget KMW component.
10upsimon Sep 25, 2023
f81c32b
Define KM_ANALYTICS_VISITS_PER_VISITOR widget, title and description …
10upsimon Sep 25, 2023
a30ac31
Define KM_ANALYTICS_VISITS_PER_VISITOR in keyMetricsGA4Widgets array.
10upsimon Sep 25, 2023
521b372
Export default VisitsPerVisitorWidget component.
10upsimon Sep 25, 2023
5db714e
Register KM_ANALYTICS_VISITS_PER_VISITOR KM widget.
10upsimon Sep 25, 2023
8fdb884
Add sessionsPerUser as allowable shared metric in GA4 report request.
10upsimon Sep 26, 2023
840ba76
Amend totalUsers metric to instead by activeUsers metric to align wit…
10upsimon Sep 26, 2023
ab7c4d3
Add VisitsPerVisitorWidget stories.
10upsimon Sep 27, 2023
f5c6f24
Merge branch 'develop' of github.com:google/site-kit-wp into develop.
10upsimon Sep 27, 2023
467361b
Merge branch 'develop' into kmw/7577-visits-per-visitor-kmw-tile.
10upsimon Sep 27, 2023
5c35224
Add sessionsPerUser to ANALYTICS_4_METRIC_TYPES.
10upsimon Sep 27, 2023
538a4f3
Move registration of KM_ANALYTICS_VISITS_PER_VISITOR widget behind ne…
10upsimon Sep 27, 2023
afb1654
Merge branch 'develop' of github.com:google/site-kit-wp into develop.
10upsimon Sep 28, 2023
6f7adc2
Merge develop into kmw/7577-visits-per-visitor-kmw-tile.
10upsimon Sep 28, 2023
81ab140
Add and update VRT reference files.
10upsimon Sep 28, 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
8 changes: 8 additions & 0 deletions assets/js/components/KeyMetrics/key-metrics-widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
KM_ANALYTICS_TOP_CONVERTING_TRAFFIC_SOURCE,
KM_ANALYTICS_TOP_RETURNING_VISITOR_PAGES,
KM_SEARCH_CONSOLE_POPULAR_KEYWORDS,
KM_ANALYTICS_VISITS_PER_VISITOR,
CORE_USER,
} from '../../googlesitekit/datastore/user/constants';
import { CORE_SITE } from '../../googlesitekit/datastore/site/constants';
Expand Down Expand Up @@ -116,6 +117,13 @@ const KEY_METRICS_WIDGETS = {
'google-site-kit'
),
},
[ KM_ANALYTICS_VISITS_PER_VISITOR ]: {
title: __( 'Visits per visitor', 'google-site-kit' ),
description: __(
'Average number of sessions per site visitor',
'google-site-kit'
),
},
};

if ( isFeatureEnabled( 'newsKeyMetrics' ) ) {
Expand Down
2 changes: 2 additions & 0 deletions assets/js/googlesitekit/datastore/user/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const KM_ANALYTICS_TOP_RETURNING_VISITOR_PAGES =
'kmAnalyticsTopReturningVisitorPages';
export const KM_SEARCH_CONSOLE_POPULAR_KEYWORDS =
'kmSearchConsolePopularKeywords';
export const KM_ANALYTICS_VISITS_PER_VISITOR = 'kmAnalyticsVisitsPerVisitor';

export const keyMetricsGA4Widgets = [
KM_ANALYTICS_ADSENSE_TOP_EARNING_CONTENT,
Expand All @@ -73,6 +74,7 @@ export const keyMetricsGA4Widgets = [
KM_ANALYTICS_TOP_COUNTRIES,
KM_ANALYTICS_TOP_TRAFFIC_SOURCE,
KM_ANALYTICS_TOP_RETURNING_VISITOR_PAGES,
KM_ANALYTICS_VISITS_PER_VISITOR,
];

export const allKeyMetricsTileWidgets = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* VisitsPerVisitorWidget 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.
*/

/**
* External dependencies
*/
import PropTypes from 'prop-types';
import { get } from 'lodash';

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

/**
* Internal dependencies
*/
import Data from 'googlesitekit-data';
import { CORE_USER } from '../../../../googlesitekit/datastore/user/constants';
import {
DATE_RANGE_OFFSET,
MODULES_ANALYTICS_4,
} from '../../datastore/constants';
import { MetricTileNumeric } from '../../../../components/KeyMetrics';
import whenActive from '../../../../util/when-active';
import ConnectGA4CTATileWidget from './ConnectGA4CTATileWidget';
import { numFmt } from '../../../../util';

const { useSelect, useInViewSelect } = Data;

function VisitsPerVisitorWidget( { Widget } ) {
const dates = useSelect( ( select ) =>
select( CORE_USER ).getDateRangeDates( {
offsetDays: DATE_RANGE_OFFSET,
compare: true,
} )
);

const reportOptions = {
...dates,
metrics: [ { name: 'sessionsPerUser' }, { name: 'activeUsers' } ],
};

const report = useInViewSelect( ( select ) =>
select( MODULES_ANALYTICS_4 ).getReport( reportOptions )
);

const error = useSelect( ( select ) =>
select( MODULES_ANALYTICS_4 ).getErrorForSelector( 'getReport', [
reportOptions,
] )
);

const loading = useSelect(
( select ) =>
! select( MODULES_ANALYTICS_4 ).hasFinishedResolution(
'getReport',
[ reportOptions ]
)
);

const { rows = [], totals = [] } = report || {};

const makeFind = ( dateRange ) => ( row ) =>
get( row, 'dimensionValues.0.value' ) === dateRange;

const currentVisitsPerVisitor =
rows.find( makeFind( 'date_range_0' ) )?.metricValues?.[ 0 ]?.value ||
0;

const previousVisitsPerVisitor =
rows.find( makeFind( 'date_range_1' ) )?.metricValues?.[ 0 ]?.value ||
0;

const currentTotalVisitors =
Number( totals[ 0 ]?.metricValues?.[ 1 ]?.value ) || 0;

return (
<MetricTileNumeric
Widget={ Widget }
title={ __( 'Visits per visitor', 'google-site-kit' ) }
metricValue={ currentVisitsPerVisitor }
subText={ sprintf(
/* translators: %d: Number of total readers visiting the site. */
__( '%s total visitors', 'google-site-kit' ),
numFmt( currentTotalVisitors, { style: 'decimal' } )
) }
previousValue={ Number( previousVisitsPerVisitor ) }
currentValue={ Number( currentVisitsPerVisitor ) }
loading={ loading }
error={ error }
moduleSlug="analytics-4"
infoTooltip={ __(
'Average number of sessions per site visitor',
'google-site-kit'
) }
/>
);
}

VisitsPerVisitorWidget.propTypes = {
Widget: PropTypes.elementType.isRequired,
};

export default whenActive( {
moduleName: 'analytics-4',
FallbackComponent: ConnectGA4CTATileWidget,
} )( VisitsPerVisitorWidget );
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/**
* VisitsPerVisitor 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 {
provideKeyMetrics,
provideModuleRegistrations,
provideModules,
} from '../../../../../../tests/js/utils';
import { withWidgetComponentProps } from '../../../../googlesitekit/widgets/util';
import WithRegistrySetup from '../../../../../../tests/js/WithRegistrySetup';
import VisitsPerVisitorWidget from './VisitsPerVisitorWidget';
import { MODULES_ANALYTICS_4 } from '../../datastore/constants';
import {
getAnalytics4MockResponse,
provideAnalytics4MockReport,
} from '../../utils/data-mock';
import { replaceValuesInAnalytics4ReportWithZeroData } from '../../../../../../.storybook/utils/zeroReports';
import { CORE_USER } from '../../../../googlesitekit/datastore/user/constants';
import { ERROR_REASON_INSUFFICIENT_PERMISSIONS } from '../../../../util/errors';
import { MODULES_ANALYTICS } from '../../../analytics/datastore/constants';

const reportOptions = {
compareStartDate: '2020-07-14',
compareEndDate: '2020-08-10',
startDate: '2020-08-11',
endDate: '2020-09-07',
metrics: [
{
name: 'sessionsPerUser',
},
{
name: 'activeUsers',
},
],
};

const WidgetWithComponentProps = withWidgetComponentProps(
'kmAnalyticsVisitsPerVisitor'
)( VisitsPerVisitorWidget );

const Template = ( { setupRegistry, ...args } ) => (
<WithRegistrySetup func={ setupRegistry }>
<WidgetWithComponentProps { ...args } />
</WithRegistrySetup>
);

export const Ready = Template.bind( {} );
Ready.storyName = 'Ready';
Ready.args = {
setupRegistry: ( registry ) => {
provideAnalytics4MockReport( registry, reportOptions );
},
};
Ready.scenario = {
label: 'KeyMetrics/VisitsPerVisitor/Ready',
delay: 250,
};

export const Loading = Template.bind( {} );
Loading.storyName = 'Loading';
Loading.args = {
setupRegistry: ( { dispatch } ) => {
dispatch( MODULES_ANALYTICS_4 ).startResolution( 'getReport', [
reportOptions,
] );
},
};

export const ZeroData = Template.bind( {} );
ZeroData.storyName = 'Zero Data';
ZeroData.args = {
setupRegistry: ( { dispatch } ) => {
const report = getAnalytics4MockResponse( reportOptions );
const zeroReport =
replaceValuesInAnalytics4ReportWithZeroData( report );

dispatch( MODULES_ANALYTICS_4 ).receiveGetReport( zeroReport, {
options: reportOptions,
} );
},
};
ZeroData.scenario = {
label: 'KeyMetrics/VisitsPerVisitor/ZeroData',
delay: 250,
};

export const Error = Template.bind( {} );
Error.storyName = 'Error';
Error.args = {
setupRegistry: ( { dispatch } ) => {
const errorObject = {
code: 400,
message: 'Test error message. ',
data: {
status: 400,
reason: 'badRequest',
},
selectorData: {
storeName: 'modules/analytics-4',
name: 'getReport',
args: [ reportOptions ],
},
};

dispatch( MODULES_ANALYTICS_4 ).receiveError(
errorObject,
'getReport',
[ reportOptions ]
);

dispatch( MODULES_ANALYTICS_4 ).finishResolution( 'getReport', [
reportOptions,
] );
},
};
Error.scenario = {
label: 'KeyMetrics/VisitsPerVisitor/Error',
delay: 250,
};

export const InsufficientPermissions = Template.bind( {} );
InsufficientPermissions.storyName = 'Insufficient Permissions';
InsufficientPermissions.args = {
setupRegistry: ( { dispatch } ) => {
const errorObject = {
code: 403,
message: 'Test error message. ',
data: {
status: 403,
reason: ERROR_REASON_INSUFFICIENT_PERMISSIONS,
},
selectorData: {
storeName: 'modules/analytics-4',
name: 'getReport',
args: [ reportOptions ],
},
};

dispatch( MODULES_ANALYTICS_4 ).receiveError(
errorObject,
'getReport',
[ reportOptions ]
);

dispatch( MODULES_ANALYTICS_4 ).finishResolution( 'getReport', [
reportOptions,
] );
},
};

InsufficientPermissions.scenario = {
label: 'KeyMetrics/VisitsPerVisitor/InsufficientPermissions',
delay: 250,
};

export default {
title: 'Key Metrics/VisitsPerVisitor',
decorators: [
( Story, { args } ) => {
const setupRegistry = ( registry ) => {
provideModules( registry, [
{
slug: 'analytics-4',
active: true,
connected: true,
},
] );

provideModuleRegistrations( registry );

const [ accountID, propertyID, webDataStreamID ] = [
'12345',
'34567',
'56789',
];

registry
.dispatch( MODULES_ANALYTICS )
.setAccountID( accountID );
registry
.dispatch( MODULES_ANALYTICS_4 )
.setPropertyID( propertyID );
registry
.dispatch( MODULES_ANALYTICS_4 )
.setWebDataStreamID( webDataStreamID );

registry.dispatch( CORE_USER ).setReferenceDate( '2020-09-08' );

provideKeyMetrics( registry );

// Call story-specific setup.
args.setupRegistry( registry );
};

return (
<WithRegistrySetup func={ setupRegistry }>
<Story />
</WithRegistrySetup>
);
},
],
};
1 change: 1 addition & 0 deletions assets/js/modules/analytics-4/components/widgets/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export { default as TopCountriesWidget } from './TopCountriesWidget';
export { default as TopTrafficSourceWidget } from './TopTrafficSourceWidget';
export { default as TopConvertingTrafficSourceWidget } from './TopConvertingTrafficSourceWidget';
export { default as TopReturningVisitorPages } from './TopReturningVisitorPages';
export { default as VisitsPerVisitorWidget } from './VisitsPerVisitorWidget';
Loading
Loading