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

Enhance/#8138 - Add the Audiences Widget Area happy path view #8672

Merged
merged 38 commits into from
May 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c911e4b
Rename AudienceTiles to AudienceTilesWidget.
hussain-t May 7, 2024
02a92fe
Rename AudienceTilesWidget stories file.
hussain-t May 7, 2024
6c3d968
Export AudienceTilesWidget with whenActive hoc.
hussain-t May 7, 2024
844af8e
Add InfoNoticeWidget component.
hussain-t May 7, 2024
d34816e
Add AudienceAreaFooter component.
hussain-t May 7, 2024
b7fb602
Export default.
hussain-t May 7, 2024
fe04f5c
Add settings.Footer and make settings.title optional.
hussain-t May 7, 2024
af18b5d
Add AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION const.
hussain-t May 7, 2024
539e153
Register AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION widget area.
hussain-t May 7, 2024
040302e
Render widget area Footer.
hussain-t May 7, 2024
792ac1e
Register AudienceTilesWidget and InfoNoticeWidget widgets.
hussain-t May 7, 2024
f0178e5
Merge branch 'develop' into enhance/#8138-audience-widget-area.
hussain-t May 9, 2024
fbf99f1
Rendr PreviewBlock for loading.
hussain-t May 13, 2024
260e2f5
Add isActive to analyticsAudienceTiles widget.
hussain-t May 13, 2024
015438b
Add logic in AudienceAreaFooter.
hussain-t May 13, 2024
5dffe4b
Set noPadding for InfoNoticeWidget widget.
hussain-t May 13, 2024
a5fffea
Check if all the reports are loaded.
hussain-t May 13, 2024
80ff619
Conditionally set the dimension values.
hussain-t May 13, 2024
1f66065
Conditionall set the dimension values in AudienceTilePagesMetric.
hussain-t May 13, 2024
c63c42b
Apply source link styles.
hussain-t May 13, 2024
a363353
Add loaded prop to the stories.
hussain-t May 13, 2024
d8ee1da
Fix AudienceTilesWidget by mocking modules.
hussain-t May 13, 2024
e1c7d8d
Update registerWidgetArea tests.
hussain-t May 13, 2024
63c1180
Merge branch 'develop' into enhance/#8138-audience-widget-area.
hussain-t May 13, 2024
30e5dfc
Update AudienceTilesWidget VRT images.
hussain-t May 13, 2024
299f22f
Merge branch 'develop' into enhance/#8138-audience-widget-area.
hussain-t May 23, 2024
89d3d82
Fix dimension values being undefined in AudienceTileCitiesMetric.
hussain-t May 23, 2024
dd9c6d7
Fix dimension values being undefined in AudienceTilePagesMetric.
hussain-t May 23, 2024
5d52fd2
Merge branch 'develop' into enhance/#8138-audience-widget-area.
hussain-t May 23, 2024
8e9c6a7
Merge branch 'develop' into enhance/#8138-audience-widget-area.
hussain-t May 27, 2024
7edafa6
Update component name in the header.
hussain-t May 27, 2024
7fb7fb9
Rearrage imports.
hussain-t May 27, 2024
5ef18f5
Use Array.filter instead of some.
hussain-t May 27, 2024
0866b0e
Remove provideModuleRegistrations.
hussain-t May 27, 2024
6c9831d
Remove log used for debugging.
hussain-t May 27, 2024
d63e277
Remove unused VRT images.
hussain-t May 27, 2024
de47de3
Fix prevent NaN value by handling zero totalPageviews.
hussain-t May 27, 2024
aab48f8
Cast `totalPageviews` to be a number.
nfmohit May 27, 2024
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
12 changes: 11 additions & 1 deletion assets/js/googlesitekit/widgets/components/WidgetAreaRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
</WidgetCellWrapper>
) );

const { Icon, title, style, subtitle, CTA } = widgetArea;
const { Icon, title, style, subtitle, CTA, Footer } = widgetArea;

return (
<InViewProvider value={ inViewState }>
Expand Down Expand Up @@ -232,6 +232,16 @@ export default function WidgetAreaRenderer( { slug, contextID } ) {
) }
</Row>
</div>
{ Footer && (
<Row>
<Cell
className="googlesitekit-widget-area-footer"
size={ 12 }
>
<Footer />
</Cell>
</Row>
) }
</Grid>
) }
{
Expand Down
9 changes: 6 additions & 3 deletions assets/js/googlesitekit/widgets/datastore/areas.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,17 @@ export const actions = {
* @since 1.9.0
* @since 1.107.0 Extended to support an optional CTA component.
* @since 1.110.0 Extended to support an optional filterActiveWidgets function.
* @since n.e.x.t Extended to make title optional and support an optional Footer component.
*
* @param {string} slug Widget Area's slug.
* @param {Object} settings Widget Area's settings.
* @param {string} settings.title Title for this widget area.
* @param {string} [settings.title] Optional. Title for this widget area.
* @param {string} [settings.subtitle] Optional. Subtitle for this widget area.
* @param {WPComponent} [settings.Icon] Optional. React component to render icon for this widget area.
* @param {string} [settings.style] Optional. Widget area style (one of "boxes", "composite"). Default: "boxes".
* @param {number} [settings.priority] Optional. Priority for this widget area. Default: 10.
* @param {WPComponent} [settings.CTA] React component used as CTA appearing beside the subtitle.
* @param {WPComponent} [settings.CTA] Optional. React component used as CTA appearing beside the subtitle.
* @param {WPComponent} [settings.Footer] Optional. React component used as footer for the widget area.
* @param {Function} [settings.filterActiveWidgets] Optional. Function used to filter active widgets.
* @return {Object} Redux-style action.
*/
Expand All @@ -103,11 +105,11 @@ export const actions = {
subtitle,
Icon,
CTA,
Footer,
filterActiveWidgets,
} = {}
) {
invariant( slug, 'slug is required.' );
invariant( title, 'settings.title is required.' );
invariant(
Object.values( WIDGET_AREA_STYLES ).includes( style ),
`settings.style must be one of: ${ WidgetAreaStyleKeys }.`
Expand All @@ -123,6 +125,7 @@ export const actions = {
subtitle,
Icon,
CTA,
Footer,
filterActiveWidgets,
},
},
Expand Down
25 changes: 4 additions & 21 deletions assets/js/googlesitekit/widgets/datastore/areas.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,32 +135,17 @@ describe( 'core/widgets Widget areas', () => {
} ).toThrow( 'slug is required.' );
} );

it( 'requires settings', () => {
// (It will throw for the first missing param, because the settings argument is
// always defined .)
it( 'allows settings without a title', () => {
expect( () => {
registry
.dispatch( CORE_WIDGETS )
.registerWidgetArea( 'my-cool-slug' );
} ).toThrow( 'settings.title is required.' );
} );

it( 'requires a title in settings', () => {
expect( () => {
registry
.dispatch( CORE_WIDGETS )
.registerWidgetArea( 'header', {} );
} ).toThrow( 'settings.title is required.' );

expect( () => {
registry
.dispatch( CORE_WIDGETS )
.registerWidgetArea( 'header', {
title: 'Analytics Header',
.registerWidgetArea( 'my-cool-slug', {
subtitle: 'Analytics tell you about visitors',
} );
} ).not.toThrow();
} );

it( 'correctly handles settings with a title', () => {
expect( () => {
registry
.dispatch( CORE_WIDGETS )
Expand All @@ -170,8 +155,6 @@ describe( 'core/widgets Widget areas', () => {
style: 'composite',
} );
} ).not.toThrow();

expect( console ).toHaveWarned();
} );

it( 'should register multiple widget areas', () => {
Expand Down
2 changes: 2 additions & 0 deletions assets/js/googlesitekit/widgets/default-areas.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY =
'mainDashboardKeyMetricsPrimary';
export const AREA_MAIN_DASHBOARD_TRAFFIC_PRIMARY =
'mainDashboardTrafficPrimary';
export const AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION =
'mainDashboardTrafficAudienceSegmentation';
export const AREA_MAIN_DASHBOARD_CONTENT_PRIMARY =
'mainDashboardContentPrimary';
export const AREA_MAIN_DASHBOARD_SPEED_PRIMARY = 'mainDashboardSpeedPrimary';
Expand Down
21 changes: 20 additions & 1 deletion assets/js/googlesitekit/widgets/register-defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ import {
ChangeMetricsLink,
} from '../../components/KeyMetrics';
import AddMetricCTATile from '../../components/KeyMetrics/AddMetricCTATile';
import ConnectGA4CTAWidget from '../../modules/analytics-4/components/widgets/ConnectGA4CTAWidget';
import KeyMetricsNewBadge from '../../components/KeyMetrics/KeyMetricsNewBadge';
import ConnectGA4CTAWidget from '../../modules/analytics-4/components/widgets/ConnectGA4CTAWidget';
import { AudienceAreaFooter } from '../../modules/analytics-4/components/audience-segmentation/dashboard';
import { isFeatureEnabled } from '../../features';

const { ...ADDITIONAL_WIDGET_CONTEXTS } = WIDGET_CONTEXTS;

Expand Down Expand Up @@ -74,6 +76,7 @@ export function registerDefaults( widgetsAPI ) {
// Main dashboard
AREA_MAIN_DASHBOARD_KEY_METRICS_PRIMARY,
AREA_MAIN_DASHBOARD_TRAFFIC_PRIMARY,
AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION,
AREA_MAIN_DASHBOARD_CONTENT_PRIMARY,
AREA_MAIN_DASHBOARD_SPEED_PRIMARY,
AREA_MAIN_DASHBOARD_MONETIZATION_PRIMARY,
Expand Down Expand Up @@ -138,6 +141,22 @@ export function registerDefaults( widgetsAPI ) {
CONTEXT_MAIN_DASHBOARD_TRAFFIC
);

if ( isFeatureEnabled( 'audienceSegmentation' ) ) {
widgetsAPI.registerWidgetArea(
AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION,
{
subtitle: __(
'Understand how different visitor groups interact with your site',
'google-site-kit'
),
style: WIDGET_AREA_STYLES.BOXES,
priority: 2,
Footer: AudienceAreaFooter,
},
CONTEXT_MAIN_DASHBOARD_TRAFFIC
);
}

widgetsAPI.registerWidgetArea(
AREA_MAIN_DASHBOARD_CONTENT_PRIMARY,
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/**
* AudienceAreaFooter component.
*
* Site Kit by Google, Copyright 2024 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 { _x } 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 { CORE_MODULES } from '../../../../../googlesitekit/modules/datastore/constants';
import SourceLink from '../../../../../components/SourceLink';
import useViewOnly from '../../../../../hooks/useViewOnly';
const { useSelect } = Data;

export default function AudienceAreaFooter() {
const viewOnlyDashboard = useViewOnly();

const dates = useSelect( ( select ) =>
select( CORE_USER ).getDateRangeDates( {
offsetDays: DATE_RANGE_OFFSET,
} )
);

const sourceLinkURL = useSelect( ( select ) => {
if ( viewOnlyDashboard ) {
return null;
}

return select( MODULES_ANALYTICS_4 ).getServiceReportURL( 'audiences', {
dates,
} );
} );

const isAnalyticsConnected = useSelect( ( select ) =>
select( CORE_MODULES ).isModuleConnected( 'analytics-4' )
);

if ( ! isAnalyticsConnected ) {
return null;
}

return (
<SourceLink
className="googlesitekit-audience-widget__source"
name={ _x( 'Analytics', 'Service name', 'google-site-kit' ) }
href={ sourceLinkURL }
external
/>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ export default function AudienceTileCitiesMetric( {
title,
topCities,
} ) {
const validDimensionValues =
topCities?.dimensionValues?.filter( Boolean ) || [];
const hasDimensionValues = !! validDimensionValues.length;

return (
<div className="googlesitekit-audience-segmentation-tile-metric googlesitekit-audience-segmentation-tile-metric--cities">
<div className="googlesitekit-audience-segmentation-tile-metric__icon">
Expand All @@ -42,26 +46,27 @@ export default function AudienceTileCitiesMetric( {
{ title }
</div>
<div className="googlesitekit-audience-segmentation-tile-metric__content">
{ topCities === null && <AudienceTileNoData /> }
{ topCities?.dimensionValues.map( ( city, index ) => (
<div
key={ city.value }
className="googlesitekit-audience-segmentation-tile-metric__cities-metric"
>
<div className="googlesitekit-audience-segmentation-tile-metric__cities-metric-name">
{ city.value }
</div>
<div className="googlesitekit-audience-segmentation-tile-metric__cities-metric-value">
{ numFmt(
topCities.metricValues[ index ].value,
{
style: 'percent',
maximumFractionDigits: 1,
}
) }
{ ! hasDimensionValues && <AudienceTileNoData /> }
{ hasDimensionValues &&
validDimensionValues.map( ( city, index ) => (
<div
key={ city?.value }
className="googlesitekit-audience-segmentation-tile-metric__cities-metric"
>
<div className="googlesitekit-audience-segmentation-tile-metric__cities-metric-name">
{ city?.value }
</div>
<div className="googlesitekit-audience-segmentation-tile-metric__cities-metric-value">
{ numFmt(
topCities?.metricValues[ index ]?.value,
{
style: 'percent',
maximumFractionDigits: 1,
}
) }
</div>
</div>
</div>
) ) }
) ) }
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,13 @@ export default function AudienceTilePagesMetric( {
} )
);

const validDimensionValues =
topContent?.dimensionValues?.filter( Boolean ) || [];
const hasDimensionValues = !! validDimensionValues.length;

function ContentLinkComponent( { content } ) {
const pageTitle = topContentTitles[ content.value ];
const url = content.value;
const pageTitle = topContentTitles[ content?.value ];
const url = content?.value;

const serviceURL = useSelect( ( select ) => {
return ! viewOnlyDashboard
Expand Down Expand Up @@ -124,22 +128,24 @@ export default function AudienceTilePagesMetric( {
) }
</div>
<div className="googlesitekit-audience-segmentation-tile-metric__content">
{ topContent === null && <AudienceTileNoData /> }
{ topContent?.dimensionValues.map( ( content, index ) => {
return (
<div
key={ content.value }
className="googlesitekit-audience-segmentation-tile-metric__page-metric-container"
>
<ContentLinkComponent content={ content } />
<div className="googlesitekit-audience-segmentation-tile-metric__page-metric-value">
{ numFmt(
topContent.metricValues[ index ].value
) }
{ ! hasDimensionValues && <AudienceTileNoData /> }
{ hasDimensionValues &&
validDimensionValues.map( ( content, index ) => {
return (
<div
key={ content?.value }
className="googlesitekit-audience-segmentation-tile-metric__page-metric-container"
>
<ContentLinkComponent content={ content } />
<div className="googlesitekit-audience-segmentation-tile-metric__page-metric-value">
{ numFmt(
topContent?.metricValues[ index ]
?.value
) }
</div>
</div>
</div>
);
} ) }
);
} ) }
{ isMobileBreakpoint && isTopContentPartialData && (
<PartialDataNotice
content={ __(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,19 @@ import AudienceMetricIconTopContent from '../../../../../../../svg/icons/audienc
import AudienceTileMetric from './AudienceTileMetric';
import AudienceTileCitiesMetric from './AudienceTileCitiesMetric';
import AudienceTilePagesMetric from './AudienceTilePagesMetric';
import PreviewBlock from '../../../../../../components/PreviewBlock';
import ChangeBadge from '../../../../../../components/ChangeBadge';
import InfoTooltip from '../../../../../../components/InfoTooltip';
import PartialDataBadge from '../PartialDataBadge';
import PartialDataNotice from '../PartialDataNotice';
import { numFmt } from '../../../../../../util';

const { useSelect } = Data;

// TODO: as part of #8484 the report props should be updated to expect
// the full report rows for the current tile to reduce data manipulation
// in AudienceTiles.
export default function AudienceTile( {
loaded,
title,
infoTooltip,
visitors,
Expand Down Expand Up @@ -101,6 +102,11 @@ export default function AudienceTile( {
breakpoint
);

// TODO: Loading states will be implemented as part of https://github.com/google/site-kit-wp/issues/8145.
if ( ! loaded ) {
return <PreviewBlock width="100%" height="500px" />;
}

return (
<Widget noPadding>
<div
Expand Down Expand Up @@ -223,6 +229,7 @@ export default function AudienceTile( {
}

AudienceTile.propTypes = {
loaded: PropTypes.bool,
title: PropTypes.string.isRequired,
infoTooltip: PropTypes.oneOfType( [ PropTypes.string, PropTypes.element ] ),
visitors: PropTypes.object,
Expand Down
Loading
Loading