Skip to content

Commit 4c7f1ff

Browse files
authored
Merge pull request #10732 from google/enhancement/#10364-refactor-SearchFunnelWidgetGA4-Overview
Enhancement/#10364 - Fix eslint cyclomatic complexity issues in `SearchFunnelWidgetGA4/Overview`
2 parents aadb161 + 35cb6db commit 4c7f1ff

4 files changed

Lines changed: 377 additions & 238 deletions

File tree

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
/**
2+
* DataBlocks component for SearchFunnelWidgetGA4/Overview.
3+
*
4+
* Site Kit by Google, Copyright 2025 Google LLC
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* https://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
/**
20+
* External dependencies
21+
*/
22+
import PropTypes from 'prop-types';
23+
import { isPlainObject } from 'lodash';
24+
25+
/**
26+
* WordPress dependencies
27+
*/
28+
import { __ } from '@wordpress/i18n';
29+
30+
/**
31+
* Internal dependencies
32+
*/
33+
import { useSelect, useInViewSelect } from 'googlesitekit-data';
34+
import { Cell } from '../../../../../../material-components';
35+
import { extractSearchConsoleDashboardData } from '../../../../util';
36+
import DataBlock from '../../../../../../components/DataBlock';
37+
import DataBlockGroup from '../../../../../../components/DataBlockGroup';
38+
import NewBadge from '../../../../../../components/NewBadge';
39+
import { CORE_MODULES } from '../../../../../../googlesitekit/modules/datastore/constants';
40+
import { MODULES_ANALYTICS_4 } from '../../../../../analytics-4/datastore/constants';
41+
import { MODULES_SEARCH_CONSOLE } from '../../../../datastore/constants';
42+
import {
43+
DASHBOARD_TYPE_ENTITY,
44+
DASHBOARD_TYPE_MAIN,
45+
} from '../../../../../../hooks/useDashboardType';
46+
import { getCellProps, getDatapointAndChange } from './utils';
47+
48+
export default function DataBlocks( {
49+
ga4Data,
50+
ga4VisitorsData,
51+
searchConsoleData,
52+
selectedStats,
53+
handleStatsSelection,
54+
dateRangeLength,
55+
showGA4,
56+
dashboardType,
57+
showConversionsCTA,
58+
engagementRateLearnMoreURL,
59+
onGA4NewBadgeLearnMoreClick,
60+
} ) {
61+
const ga4ModuleActive = useSelect( ( select ) =>
62+
select( CORE_MODULES ).isModuleActive( 'analytics-4' )
63+
);
64+
const ga4ModuleConnected = useSelect( ( select ) =>
65+
select( CORE_MODULES ).isModuleConnected( 'analytics-4' )
66+
);
67+
const isGA4GatheringData = useInViewSelect(
68+
( select ) =>
69+
ga4ModuleConnected
70+
? select( MODULES_ANALYTICS_4 ).isGatheringData()
71+
: false,
72+
[ ga4ModuleConnected ]
73+
);
74+
const isSearchConsoleGatheringData = useInViewSelect( ( select ) =>
75+
select( MODULES_SEARCH_CONSOLE ).isGatheringData()
76+
);
77+
78+
const {
79+
totalClicks,
80+
totalImpressions,
81+
totalClicksChange,
82+
totalImpressionsChange,
83+
} = extractSearchConsoleDashboardData( searchConsoleData, dateRangeLength );
84+
85+
let ga4ConversionsChange = null;
86+
let ga4ConversionsDatapoint = null;
87+
let ga4EngagementRateDatapoint = null;
88+
let ga4EngagementRateChange = null;
89+
let ga4VisitorsDatapoint = null;
90+
let ga4VisitorsChange = null;
91+
92+
if (
93+
ga4ModuleActive &&
94+
isPlainObject( ga4Data ) &&
95+
isPlainObject( ga4VisitorsData )
96+
) {
97+
( { change: ga4ConversionsChange } = getDatapointAndChange(
98+
ga4Data,
99+
0,
100+
100
101+
) );
102+
ga4ConversionsDatapoint =
103+
ga4Data?.totals?.[ 0 ]?.metricValues?.[ 0 ]?.value;
104+
105+
( {
106+
datapoint: ga4EngagementRateDatapoint,
107+
change: ga4EngagementRateChange,
108+
} = getDatapointAndChange( ga4Data, 1 ) );
109+
110+
ga4VisitorsDatapoint =
111+
ga4VisitorsData?.totals?.[ 0 ]?.metricValues?.[ 0 ]?.value;
112+
( { change: ga4VisitorsChange } = getDatapointAndChange(
113+
ga4VisitorsData,
114+
0,
115+
100
116+
) );
117+
}
118+
119+
const {
120+
quarterCellProps,
121+
halfCellProps,
122+
oneThirdCellProps,
123+
threeQuartersCellProps,
124+
fullCellProps,
125+
} = getCellProps( showConversionsCTA );
126+
127+
// Collection of all the data blocks to be displayed.
128+
const dataBlocks = [
129+
{
130+
id: 'impressions',
131+
stat: 0,
132+
title: __( 'Total Impressions', 'google-site-kit' ),
133+
datapoint: totalImpressions,
134+
change: totalImpressionsChange,
135+
isGatheringData: isSearchConsoleGatheringData,
136+
},
137+
{
138+
id: 'clicks',
139+
stat: 1,
140+
title: __( 'Total Clicks', 'google-site-kit' ),
141+
datapoint: totalClicks,
142+
change: totalClicksChange,
143+
isGatheringData: isSearchConsoleGatheringData,
144+
},
145+
...( showGA4
146+
? [
147+
{
148+
id: 'visitors',
149+
stat: 2,
150+
title: __(
151+
'Unique Visitors from Search',
152+
'google-site-kit'
153+
),
154+
datapoint: ga4VisitorsDatapoint,
155+
change: ga4VisitorsChange,
156+
isGatheringData: isGA4GatheringData,
157+
},
158+
]
159+
: [] ),
160+
...( showGA4 &&
161+
dashboardType === DASHBOARD_TYPE_MAIN &&
162+
! showConversionsCTA
163+
? [
164+
{
165+
id: 'conversions',
166+
stat: 3,
167+
title: __( 'Conversions', 'google-site-kit' ),
168+
datapoint: ga4ConversionsDatapoint,
169+
change: ga4ConversionsChange,
170+
isGatheringData: isGA4GatheringData,
171+
},
172+
]
173+
: [] ),
174+
...( showGA4 && dashboardType === DASHBOARD_TYPE_ENTITY
175+
? [
176+
{
177+
id: 'engagement-rate',
178+
stat: 4,
179+
title: __( 'Engagement Rate', 'google-site-kit' ),
180+
datapoint: ga4EngagementRateDatapoint,
181+
datapointUnit: '%',
182+
change: ga4EngagementRateChange,
183+
isGatheringData: isGA4GatheringData,
184+
badge: (
185+
<NewBadge
186+
tooltipTitle={ __(
187+
'Sessions which lasted 10 seconds or longer, had 1 or more conversion events, or 2 or more page views.',
188+
'google-site-kit'
189+
) }
190+
learnMoreLink={ engagementRateLearnMoreURL }
191+
onLearnMoreClick={ onGA4NewBadgeLearnMoreClick }
192+
/>
193+
),
194+
},
195+
]
196+
: [] ),
197+
];
198+
199+
const dataBlockWrapperCellProps = {
200+
2: halfCellProps,
201+
3: threeQuartersCellProps,
202+
4: fullCellProps,
203+
};
204+
205+
const dataBlockCellProps = {
206+
2: {
207+
...halfCellProps,
208+
smSize: 2,
209+
},
210+
3: oneThirdCellProps,
211+
4: quarterCellProps,
212+
};
213+
214+
return (
215+
<Cell { ...dataBlockWrapperCellProps[ dataBlocks.length ] }>
216+
<DataBlockGroup className="mdc-layout-grid__inner">
217+
{ dataBlocks.map( ( dataBlock, index ) => (
218+
<Cell
219+
key={ dataBlock.id }
220+
{ ...dataBlockCellProps[ dataBlocks.length ] }
221+
>
222+
<DataBlock
223+
stat={ dataBlock.stat }
224+
className={ `googlesitekit-data-block--${
225+
dataBlock.id
226+
} googlesitekit-data-block--button-${ index + 1 }` }
227+
title={ dataBlock.title }
228+
datapoint={ dataBlock.datapoint }
229+
datapointUnit={
230+
dataBlock.datapointUnit
231+
? dataBlock.datapointUnit
232+
: undefined
233+
}
234+
change={ dataBlock.change }
235+
changeDataUnit="%"
236+
context="button"
237+
selected={ selectedStats === dataBlock.stat }
238+
handleStatSelection={ handleStatsSelection }
239+
gatheringData={ dataBlock.isGatheringData }
240+
/>
241+
</Cell>
242+
) ) }
243+
</DataBlockGroup>
244+
</Cell>
245+
);
246+
}
247+
248+
DataBlocks.propTypes = {
249+
ga4Data: PropTypes.object,
250+
ga4VisitorsData: PropTypes.object,
251+
searchConsoleData: PropTypes.arrayOf( PropTypes.object ),
252+
selectedStats: PropTypes.number.isRequired,
253+
handleStatsSelection: PropTypes.func.isRequired,
254+
dateRangeLength: PropTypes.number.isRequired,
255+
showGA4: PropTypes.bool,
256+
dashboardType: PropTypes.string,
257+
showConversionsCTA: PropTypes.bool,
258+
isGA4GatheringData: PropTypes.bool,
259+
isSearchConsoleGatheringData: PropTypes.bool,
260+
engagementRateLearnMoreURL: PropTypes.string,
261+
onGA4NewBadgeLearnMoreClick: PropTypes.func.isRequired,
262+
};

assets/js/modules/search-console/components/dashboard/SearchFunnelWidgetGA4/Overview/OptionalCells.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,11 @@ import {
4040
BREAKPOINT_SMALL,
4141
useBreakpoint,
4242
} from '../../../../../../hooks/useBreakpoint';
43+
import { getCellProps } from './utils';
4344

4445
export default function OptionalCells( {
4546
canViewSharedAnalytics4,
4647
error,
47-
halfCellProps,
48-
quarterCellProps,
4948
showGA4,
5049
showConversionsCTA,
5150
showRecoverableGA4,
@@ -62,6 +61,9 @@ export default function OptionalCells( {
6261
const analyticsModuleActiveAndConnected =
6362
ga4ModuleActive && ga4ModuleConnected;
6463

64+
const { quarterCellProps, halfCellProps } =
65+
getCellProps( showConversionsCTA );
66+
6567
return (
6668
<Fragment>
6769
{ canViewSharedAnalytics4 &&
@@ -110,8 +112,6 @@ export default function OptionalCells( {
110112
OptionalCells.propTypes = {
111113
canViewSharedAnalytics4: PropTypes.bool.isRequired,
112114
error: PropTypes.object,
113-
halfCellProps: PropTypes.object.isRequired,
114-
quarterCellProps: PropTypes.object.isRequired,
115115
showGA4: PropTypes.bool.isRequired,
116116
showConversionsCTA: PropTypes.bool.isRequired,
117117
showRecoverableGA4: PropTypes.bool,

0 commit comments

Comments
 (0)