diff --git a/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/AudienceTilePagesMetric.js b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/AudienceTilePagesMetric.js
index da0fe52fed4..88bc2c2564b 100644
--- a/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/AudienceTilePagesMetric.js
+++ b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/AudienceTilePagesMetric.js
@@ -24,42 +24,32 @@ import PropTypes from 'prop-types';
/**
* WordPress dependencies
*/
-import { useCallback } from '@wordpress/element';
-import { addQueryArgs } from '@wordpress/url';
+import { useEffect } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
-import { useSelect, useDispatch } from 'googlesitekit-data';
+import { useSelect } from 'googlesitekit-data';
import {
BREAKPOINT_SMALL,
BREAKPOINT_TABLET,
useBreakpoint,
} from '@/js/hooks/useBreakpoint';
-import { CORE_FORMS } from '@/js/googlesitekit/datastore/forms/constants';
import { CORE_SITE } from '@/js/googlesitekit/datastore/site/constants';
-import { CORE_USER } from '@/js/googlesitekit/datastore/user/constants';
import {
AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE,
CUSTOM_DIMENSION_DEFINITIONS,
- EDIT_SCOPE,
MODULES_ANALYTICS_4,
} from '@/js/modules/analytics-4/datastore/constants';
-import { ERROR_CODE_MISSING_REQUIRED_SCOPE } from '@/js/util/errors';
import BadgeWithTooltip from '@/js/components/BadgeWithTooltip';
import AudienceTilePagesMetricContent from './AudienceTilePagesMetricContent';
-import AudienceErrorModal from '@/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceErrorModal';
-import { AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION } from '@/js/googlesitekit/widgets/default-areas';
import useViewContext from '@/js/hooks/useViewContext';
import { trackEvent } from '@/js/util';
import useFormValue from '@/js/hooks/useFormValue';
+import useCreateCustomDimension from '@/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/hooks/useCreateCustomDimension';
export default function AudienceTilePagesMetric( {
- // TODO: The prop `audienceTileNumber` is part of a temporary workaround to ensure `AudienceErrorModal` is only rendered once
- // within `AudienceTilesWidget`. This should be removed once the `AudienceErrorModal` render is extracted
- // from `AudienceTilePagesMetric` and it's rendered once at a higher level instead. See https://github.com/google/site-kit-wp/issues/9543.
- audienceTileNumber,
audienceSlug,
TileIcon,
title,
@@ -80,48 +70,12 @@ export default function AudienceTilePagesMetric( {
)
);
- const hasAnalyticsEditScope = useSelect( ( select ) =>
- select( CORE_USER ).hasScope( EDIT_SCOPE )
- );
-
- const redirectURL = addQueryArgs( global.location.href, {
- notification: 'audience_segmentation',
- widgetArea: AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION,
- } );
- const errorRedirectURL = addQueryArgs( global.location.href, {
- widgetArea: AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION,
- } );
-
- const isAutoCreatingCustomDimensionsForAudience = useFormValue(
- AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE,
- 'isAutoCreatingCustomDimensionsForAudience'
- );
-
- const isCreatingCustomDimension = useSelect( ( select ) =>
- select( MODULES_ANALYTICS_4 ).isCreatingCustomDimension(
- postTypeDimension
- )
- );
-
- const isSyncingAvailableCustomDimensions = useSelect( ( select ) =>
- select( MODULES_ANALYTICS_4 ).isFetchingSyncAvailableCustomDimensions()
- );
-
const customDimensionError = useSelect( ( select ) =>
select( MODULES_ANALYTICS_4 ).getCreateCustomDimensionError(
postTypeDimension
)
);
- const propertyID = useSelect( ( select ) =>
- select( MODULES_ANALYTICS_4 ).getPropertyID()
- );
-
- const { clearError } = useDispatch( MODULES_ANALYTICS_4 );
- const { setValues } = useDispatch( CORE_FORMS );
- const { setPermissionScopeError, clearPermissionScopeError } =
- useDispatch( CORE_USER );
-
const isRetryingCustomDimensionCreate = useFormValue(
AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE,
'isRetrying'
@@ -135,71 +89,24 @@ export default function AudienceTilePagesMetric( {
const setupErrorCode = useSelect( ( select ) =>
select( CORE_SITE ).getSetupErrorCode()
);
- const { setSetupErrorCode } = useDispatch( CORE_SITE );
const hasOAuthError = autoSubmit && setupErrorCode === 'access_denied';
- const onCreateCustomDimension = useCallback(
- ( { isRetrying } = {} ) => {
- setValues( AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE, {
- autoSubmit: true,
- isRetrying,
- } );
-
- if ( ! hasAnalyticsEditScope ) {
- setPermissionScopeError( {
- code: ERROR_CODE_MISSING_REQUIRED_SCOPE,
- message: __(
- 'Additional permissions are required to create new audiences in Analytics.',
- 'google-site-kit'
- ),
- data: {
- status: 403,
- scopes: [ EDIT_SCOPE ],
- skipModal: true,
- skipDefaultErrorNotifications: true,
- redirectURL,
- errorRedirectURL,
- },
- } );
- }
- },
- [
- hasAnalyticsEditScope,
- redirectURL,
- errorRedirectURL,
- setPermissionScopeError,
- setValues,
- ]
- );
-
- const onCancel = useCallback( () => {
- setValues( AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE, {
- autoSubmit: false,
- isRetrying: false,
- } );
- setSetupErrorCode( null );
- clearPermissionScopeError();
- clearError( 'createCustomDimension', [
- propertyID,
- CUSTOM_DIMENSION_DEFINITIONS.googlesitekit_post_type,
- ] );
- }, [
- clearError,
- clearPermissionScopeError,
- propertyID,
- setSetupErrorCode,
- setValues,
- ] );
-
const isMobileBreakpoint = [ BREAKPOINT_SMALL, BREAKPOINT_TABLET ].includes(
breakpoint
);
- const isSaving =
- isAutoCreatingCustomDimensionsForAudience ||
- isCreatingCustomDimension ||
- isSyncingAvailableCustomDimensions;
+ const { onCreateCustomDimension, isSaving, setShowErrorModal } =
+ useCreateCustomDimension();
+
+ const shouldShowErrorModal =
+ ( customDimensionError && ! isSaving ) ||
+ isRetryingCustomDimensionCreate ||
+ hasOAuthError;
+
+ useEffect( () => {
+ setShowErrorModal( shouldShowErrorModal );
+ }, [ shouldShowErrorModal, setShowErrorModal ] );
return (
@@ -235,42 +142,12 @@ export default function AudienceTilePagesMetric( {
onCreateCustomDimension={ onCreateCustomDimension }
isSaving={ isSaving }
/>
- { /*
- TODO: The `audienceTileNumber` check is part of a temporary workaround to ensure `AudienceErrorModal` is only rendered once
- within `AudienceTilesWidget`. This should be removed, and the `AudienceErrorModal` render extracted
- from here to be rendered once at a higher level instead. See https://github.com/google/site-kit-wp/issues/9543.
- */ }
- { audienceTileNumber === 0 &&
- ( ( customDimensionError && ! isSaving ) ||
- ( isRetryingCustomDimensionCreate &&
- ! isAutoCreatingCustomDimensionsForAudience ) ||
- hasOAuthError ) && (
-
- onCreateCustomDimension( { isRetrying: true } )
- }
- onCancel={ onCancel }
- inProgress={ isSaving }
- hasOAuthError={ hasOAuthError }
- trackEventCategory={ `${ viewContext }_audiences-top-content-cta` }
- />
- ) }
);
}
AudienceTilePagesMetric.propTypes = {
- audienceTileNumber: PropTypes.number,
audienceSlug: PropTypes.string.isRequired,
TileIcon: PropTypes.elementType.isRequired,
title: PropTypes.string.isRequired,
diff --git a/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/index.js b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/index.js
index d78fe5e7497..5522e16fef1 100644
--- a/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/index.js
+++ b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/AudienceTile/index.js
@@ -55,10 +55,6 @@ import BadgeWithTooltip from '@/js/components/BadgeWithTooltip';
import useViewContext from '@/js/hooks/useViewContext';
import AudienceTileZeroData from './AudienceTileZeroData';
export default function AudienceTile( {
- // TODO: The prop `audienceTileNumber` is part of a temporary workaround to ensure `AudienceErrorModal` is only rendered once
- // within `AudienceTilesWidget`. This should be removed once the `AudienceErrorModal` render is extracted
- // from `AudienceTilePagesMetric` and it's rendered once at a higher level instead. See https://github.com/google/site-kit-wp/issues/9543.
- audienceTileNumber = 0,
audienceSlug,
title,
infoTooltip,
@@ -284,7 +280,6 @@ export default function AudienceTile( {
( postTypeDimensionExists &&
! hasInvalidCustomDimensionError ) ) && (
{ allTilesError && ! loading && (
@@ -362,7 +357,6 @@ export default function Body( {
return (
- { allTilesError === false &&
- ! loading &&
- isTabbedBreakpoint &&
- visibleAudiences.length > 0 && (
-
- ) }
-
-
+
+
+ { allTilesError === false &&
+ ! loading &&
+ isTabbedBreakpoint &&
+ visibleAudiences.length > 0 && (
+
+ ) }
+
+
+ { showErrorModal && }
+
);
}
diff --git a/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/hooks/useCreateCustomDimension.js b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/hooks/useCreateCustomDimension.js
new file mode 100644
index 00000000000..596ffda1b8b
--- /dev/null
+++ b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/hooks/useCreateCustomDimension.js
@@ -0,0 +1,126 @@
+/**
+ * Audience Segmentation useCreateCustomDimension hook.
+ *
+ * Site Kit by Google, Copyright 2025 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.
+ */
+
+import { useCallback } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { addQueryArgs } from '@wordpress/url';
+import { useDispatch, useSelect } from '@/js/googlesitekit-data';
+import {
+ AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE,
+ CUSTOM_DIMENSION_DEFINITIONS,
+ EDIT_SCOPE,
+ MODULES_ANALYTICS_4,
+} from '@/js/modules/analytics-4/datastore/constants';
+import { CORE_FORMS } from '@/js/googlesitekit/datastore/forms/constants';
+import { CORE_UI } from '@/js/googlesitekit/datastore/ui/constants';
+import { CORE_USER } from '@/js/googlesitekit/datastore/user/constants';
+import { ERROR_CODE_MISSING_REQUIRED_SCOPE } from '@/js/util/errors';
+import { AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION } from '@/js/googlesitekit/widgets/default-areas';
+import useFormValue from '@/js/hooks/useFormValue';
+
+const SHOW_ERROR_MODAL_KEY = 'audience-tiles-show-error-modal';
+
+export default function useCreateCustomDimension() {
+ const showErrorModal = useSelect(
+ ( select ) =>
+ select( CORE_UI ).getValue( SHOW_ERROR_MODAL_KEY ) || false
+ );
+ const { setValue } = useDispatch( CORE_UI );
+ const setShowErrorModal = useCallback(
+ ( value ) => setValue( SHOW_ERROR_MODAL_KEY, value ),
+ [ setValue ]
+ );
+
+ const { setValues } = useDispatch( CORE_FORMS );
+ const hasAnalyticsEditScope = useSelect( ( select ) =>
+ select( CORE_USER ).hasScope( EDIT_SCOPE )
+ );
+ const { setPermissionScopeError } = useDispatch( CORE_USER );
+
+ const redirectURL = addQueryArgs( global.location.href, {
+ notification: 'audience_segmentation',
+ widgetArea: AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION,
+ } );
+ const errorRedirectURL = addQueryArgs( global.location.href, {
+ widgetArea: AREA_MAIN_DASHBOARD_TRAFFIC_AUDIENCE_SEGMENTATION,
+ } );
+
+ const onCreateCustomDimension = useCallback(
+ ( { isRetrying } = {} ) => {
+ setValues( AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE, {
+ autoSubmit: true,
+ isRetrying,
+ } );
+
+ if ( ! hasAnalyticsEditScope ) {
+ setPermissionScopeError( {
+ code: ERROR_CODE_MISSING_REQUIRED_SCOPE,
+ message: __(
+ 'Additional permissions are required to create new audiences in Analytics.',
+ 'google-site-kit'
+ ),
+ data: {
+ status: 403,
+ scopes: [ EDIT_SCOPE ],
+ skipModal: true,
+ skipDefaultErrorNotifications: true,
+ redirectURL,
+ errorRedirectURL,
+ },
+ } );
+ }
+ },
+ [
+ hasAnalyticsEditScope,
+ redirectURL,
+ errorRedirectURL,
+ setPermissionScopeError,
+ setValues,
+ ]
+ );
+
+ const isAutoCreatingCustomDimensionsForAudience = useFormValue(
+ AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE,
+ 'isAutoCreatingCustomDimensionsForAudience'
+ );
+
+ const postTypeDimension =
+ CUSTOM_DIMENSION_DEFINITIONS.googlesitekit_post_type.parameterName;
+
+ const isCreatingCustomDimension = useSelect( ( select ) =>
+ select( MODULES_ANALYTICS_4 ).isCreatingCustomDimension(
+ postTypeDimension
+ )
+ );
+
+ const isSyncingAvailableCustomDimensions = useSelect( ( select ) =>
+ select( MODULES_ANALYTICS_4 ).isFetchingSyncAvailableCustomDimensions()
+ );
+
+ const isSaving =
+ isAutoCreatingCustomDimensionsForAudience ||
+ isCreatingCustomDimension ||
+ isSyncingAvailableCustomDimensions;
+
+ return {
+ onCreateCustomDimension,
+ isSaving,
+ showErrorModal,
+ setShowErrorModal,
+ };
+}
diff --git a/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/CustomDimensionErrorModal.js b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/CustomDimensionErrorModal.js
new file mode 100644
index 00000000000..f338b9d459f
--- /dev/null
+++ b/assets/js/modules/analytics-4/components/audience-segmentation/dashboard/CustomDimensionErrorModal.js
@@ -0,0 +1,105 @@
+/**
+ * Audience Segmentation CustomDimensionErrorModal component.
+ *
+ * Site Kit by Google, Copyright 2025 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.
+ */
+
+import { useCallback } from '@wordpress/element';
+import { __ } from '@wordpress/i18n';
+import { useDispatch, useSelect } from '@/js/googlesitekit-data';
+import AudienceErrorModal from './AudienceErrorModal';
+import {
+ AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE,
+ CUSTOM_DIMENSION_DEFINITIONS,
+ MODULES_ANALYTICS_4,
+} from '@/js/modules/analytics-4/datastore/constants';
+import { CORE_SITE } from '@/js/googlesitekit/datastore/site/constants';
+import { CORE_FORMS } from '@/js/googlesitekit/datastore/forms/constants';
+import { CORE_USER } from '@/js/googlesitekit/datastore/user/constants';
+import useFormValue from '@/js/hooks/useFormValue';
+import useViewContext from '@/js/hooks/useViewContext';
+import useCreateCustomDimension from '@/js/modules/analytics-4/components/audience-segmentation/dashboard/AudienceTilesWidget/hooks/useCreateCustomDimension';
+
+export default function CustomDimensionErrorModal( {} ) {
+ const viewContext = useViewContext();
+
+ const postTypeDimension =
+ CUSTOM_DIMENSION_DEFINITIONS.googlesitekit_post_type.parameterName;
+
+ const customDimensionError = useSelect( ( select ) =>
+ select( MODULES_ANALYTICS_4 ).getCreateCustomDimensionError(
+ postTypeDimension
+ )
+ );
+
+ const autoSubmit = useFormValue(
+ AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE,
+ 'autoSubmit'
+ );
+
+ const setupErrorCode = useSelect( ( select ) =>
+ select( CORE_SITE ).getSetupErrorCode()
+ );
+
+ const hasOAuthError = autoSubmit && setupErrorCode === 'access_denied';
+
+ const { setSetupErrorCode } = useDispatch( CORE_SITE );
+ const { clearPermissionScopeError } = useDispatch( CORE_USER );
+ const { clearError } = useDispatch( MODULES_ANALYTICS_4 );
+ const propertyID = useSelect( ( select ) =>
+ select( MODULES_ANALYTICS_4 ).getPropertyID()
+ );
+ const { setValues } = useDispatch( CORE_FORMS );
+
+ const { onCreateCustomDimension, isSaving, setShowErrorModal } =
+ useCreateCustomDimension();
+
+ const onCancel = useCallback( () => {
+ setValues( AUDIENCE_TILE_CUSTOM_DIMENSION_CREATE, {
+ autoSubmit: false,
+ isRetrying: false,
+ } );
+ setSetupErrorCode( null );
+ clearPermissionScopeError();
+ clearError( 'createCustomDimension', [
+ propertyID,
+ CUSTOM_DIMENSION_DEFINITIONS.googlesitekit_post_type,
+ ] );
+ setShowErrorModal( false );
+ }, [
+ clearError,
+ clearPermissionScopeError,
+ propertyID,
+ setSetupErrorCode,
+ setShowErrorModal,
+ setValues,
+ ] );
+
+ return (
+ onCreateCustomDimension( { isRetrying: true } ) }
+ onCancel={ onCancel }
+ inProgress={ isSaving }
+ hasOAuthError={ hasOAuthError }
+ trackEventCategory={ `${ viewContext }_audiences-top-content-cta` }
+ />
+ );
+}