Skip to content

Commit

Permalink
Merge pull request #8954 from google/enhancement/#8178-audience-setti…
Browse files Browse the repository at this point in the history
…ngs-setup-cta

Implement audience settings setup CTA
  • Loading branch information
techanvil committed Jul 19, 2024
2 parents 9c5bdd5 + 18c7281 commit 9aca65a
Show file tree
Hide file tree
Showing 19 changed files with 1,077 additions and 105 deletions.
25 changes: 23 additions & 2 deletions assets/js/components/DashboardMainApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ import { CORE_FORMS } from '../googlesitekit/datastore/forms/constants';
import OfflineNotification from './notifications/OfflineNotification';
import OverlayNotificationsRenderer from './OverlayNotification/OverlayNotificationsRenderer';
import ModuleDashboardEffects from './ModuleDashboardEffects';
import { useMonitorInternetConnection } from '../hooks/useMonitorInternetConnection';
import { useBreakpoint } from '../hooks/useBreakpoint';
import { useFeature } from '../hooks/useFeature';
import { useMonitorInternetConnection } from '../hooks/useMonitorInternetConnection';
import useQueryArg from '../hooks/useQueryArg';
import { getContextScrollTop } from '../util/scroll';

export default function DashboardMainApp() {
const audienceSegmentationEnabled = useFeature( 'audienceSegmentation' );
Expand All @@ -82,6 +85,10 @@ export default function DashboardMainApp() {

const viewOnlyDashboard = useViewOnly();

const breakpoint = useBreakpoint();

const [ widgetArea, setWidgetArea ] = useQueryArg( 'widgetArea' );

const { setValues } = useDispatch( CORE_FORMS );

const grantedScopes = useSelect( ( select ) =>
Expand All @@ -100,10 +107,24 @@ export default function DashboardMainApp() {
);

useMount( () => {
// Render the current survey portal in 5 seconds after the initial rendering.
if ( ! viewOnlyDashboard ) {
// Render the current survey portal in 5 seconds after the initial rendering.
setTimeout( () => setShowSurveyPortal( true ), 5000 );
}

// Scroll to a widget area if specified in the URL.
if ( widgetArea ) {
const widgetClass = `.googlesitekit-widget-area--${ widgetArea }`;

setTimeout( () => {
global.scrollTo( {
top: getContextScrollTop( widgetClass, breakpoint ),
behavior: 'smooth',
} );

setWidgetArea( undefined );
}, 100 );
}
} );

useEffect( () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,8 @@ import PropTypes from 'prop-types';
* WordPress dependencies
*/
import { compose } from '@wordpress/compose';
import { addQueryArgs } from '@wordpress/url';
import { __ } from '@wordpress/i18n';
import { Fragment, useCallback, useState, useEffect } from '@wordpress/element';
import { Fragment, useCallback, useState } from '@wordpress/element';

/**
* Internal dependencies
Expand All @@ -42,37 +41,35 @@ import { CORE_USER } from '../../../../../googlesitekit/datastore/user/constants
import { CORE_SITE } from '../../../../../googlesitekit/datastore/site/constants';
import {
MODULES_ANALYTICS_4,
EDIT_SCOPE,
AUDIENCE_SEGMENTATION_SETUP_FORM,
} from '../../../datastore/constants';
import { SETTINGS_VISITOR_GROUPS_SETUP_SUCCESS_NOTIFICATION } from '../settings/SettingsCardVisitorGroups/SetupSuccess';
import { Button, SpinnerButton } from 'googlesitekit-components';
import { Cell, Grid, Row } from '../../../../../material-components';
import {
BREAKPOINT_SMALL,
BREAKPOINT_TABLET,
useBreakpoint,
} from '../../../../../hooks/useBreakpoint';
import { ERROR_CODE_MISSING_REQUIRED_SCOPE } from '../../../../../util/errors';
import {
AdminMenuTooltip,
useShowTooltip,
useTooltipState,
} from '../../../../../components/AdminMenuTooltip';
import { withWidgetComponentProps } from '../../../../../googlesitekit/widgets/util';
import { WEEK_IN_SECONDS } from '../../../../../util';
import useEnableAudienceGroup from '../../../hooks/useEnableAudienceGroup';
import AudienceErrorModal from './AudienceErrorModal';

export const AUDIENCE_SEGMENTATION_SETUP_CTA_NOTIFICATION =
'audience_segmentation_setup_cta-notification';

function AudienceSegmentationSetupCTAWidget( { Widget, WidgetNull } ) {
const [ isSaving, setIsSaving ] = useState( false );
const breakpoint = useBreakpoint();
const isMobileBreakpoint = breakpoint === BREAKPOINT_SMALL;
const isTabletBreakpoint = breakpoint === BREAKPOINT_TABLET;

const { setValues } = useDispatch( CORE_FORMS );
const { setPermissionScopeError } = useDispatch( CORE_USER );
const showTooltip = useShowTooltip(
AUDIENCE_SEGMENTATION_SETUP_CTA_NOTIFICATION
);
Expand All @@ -91,97 +88,34 @@ function AudienceSegmentationSetupCTAWidget( { Widget, WidgetNull } ) {
)
);

const { enableAudienceGroup } = useDispatch( MODULES_ANALYTICS_4 );

const configuredAudiences = useSelect( ( select ) =>
select( MODULES_ANALYTICS_4 ).getConfiguredAudiences()
);

const hasAnalytics4EditScope = useSelect( ( select ) =>
select( CORE_USER ).hasScope( EDIT_SCOPE )
);

const autoSubmit = useSelect( ( select ) =>
select( CORE_FORMS ).getValue(
AUDIENCE_SEGMENTATION_SETUP_FORM,
'autoSubmit'
)
);

const redirectURL = addQueryArgs( global.location.href, {
notification: 'audience_segmentation',
} );

const [ apiErrors, setApiErrors ] = useState( [] );
const [ failedAudiences, setFailedAudiences ] = useState( [] );
const [ showErrorModal, setShowErrorModal ] = useState( false );

const onEnableGroups = useCallback( async () => {
setIsSaving( true );

// If scope not granted, trigger scope error right away. These are
// typically handled automatically based on API responses, but
// this particular case has some special handling to improve UX.
if ( ! hasAnalytics4EditScope ) {
setValues( AUDIENCE_SEGMENTATION_SETUP_FORM, {
autoSubmit: true,
} );

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,
},
} );

return;
}

setValues( AUDIENCE_SEGMENTATION_SETUP_FORM, {
autoSubmit: false,
const { dismissItem, dismissPrompt } = useDispatch( CORE_USER );

const { apiErrors, failedAudiences, isSaving, onEnableGroups } =
useEnableAudienceGroup( {
onSuccess: () => {
// Dismiss success notification in settings.
dismissItem(
SETTINGS_VISITOR_GROUPS_SETUP_SUCCESS_NOTIFICATION
);
},
onError: () => {
setShowErrorModal( true );
},
} );

const { error, failedSiteKitAudienceSlugs } =
( await enableAudienceGroup( failedAudiences ) ) || {};

if ( error ) {
setApiErrors( [ error ] );
setFailedAudiences( [] );
} else if ( Array.isArray( failedSiteKitAudienceSlugs ) ) {
setFailedAudiences( failedSiteKitAudienceSlugs );
setApiErrors( [] );
} else {
setApiErrors( [] );
setFailedAudiences( [] );
}

setShowErrorModal( !! error || !! failedSiteKitAudienceSlugs );
setIsSaving( false );
}, [
hasAnalytics4EditScope,
setValues,
enableAudienceGroup,
failedAudiences,
setPermissionScopeError,
redirectURL,
] );

// If the user ends up back on this component with the required scope granted,
// and already submitted the form, trigger the submit again.
useEffect( () => {
if ( hasAnalytics4EditScope && autoSubmit ) {
onEnableGroups();
}
}, [ hasAnalytics4EditScope, autoSubmit, onEnableGroups ] );

const analyticsIsDataAvailableOnLoad = useSelect( ( select ) => {
// We should call isGatheringData() within this component for completeness
// as we do not want to rely on it being called in other components.
Expand All @@ -192,7 +126,6 @@ function AudienceSegmentationSetupCTAWidget( { Widget, WidgetNull } ) {
return select( MODULES_ANALYTICS_4 ).isDataAvailableOnLoad();
} );

const { dismissPrompt } = useDispatch( CORE_USER );
const handleDismissClick = async () => {
showTooltip();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/**
* SettingsCardVisitorGroups SetupCTA 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 { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { AUDIENCE_SEGMENTATION_SETUP_CTA_NOTIFICATION } from '../../dashboard/AudienceSegmentationSetupCTAWidget';
import { AUDIENCE_SEGMENTATION_SETUP_SUCCESS_NOTIFICATION } from '../../dashboard/AudienceSegmentationSetupSuccessSubtleNotification';
import { CORE_USER } from '../../../../../../googlesitekit/datastore/user/constants';
import { useDispatch, useSelect } from 'googlesitekit-data';
import useEnableAudienceGroup from '../../../../hooks/useEnableAudienceGroup';
import { ProgressBar } from 'googlesitekit-components';
import Link from '../../../../../../components/Link';

export default function SetupCTA() {
const { dismissItem } = useDispatch( CORE_USER );

const { isSaving, onEnableGroups } = useEnableAudienceGroup( {
redirectURL: global.location.href,
onSuccess: () => {
// Dismiss success notification in dashboard.
dismissItem( AUDIENCE_SEGMENTATION_SETUP_SUCCESS_NOTIFICATION );
},
} );

const isDismissed = useSelect( ( select ) =>
select( CORE_USER ).isPromptDismissed(
AUDIENCE_SEGMENTATION_SETUP_CTA_NOTIFICATION
)
);

if ( isDismissed === undefined || isDismissed ) {
return null;
}

return (
<div className="googlesitekit-settings-visitor-groups__setup">
<p>
{ __(
'To set up new visitor groups for your site, Site Kit needs to update your Google Analytics property.',
'google-site-kit'
) }
</p>
{ isSaving && (
<div className="googlesitekit-settings-visitor-groups__setup-progress">
<p>{ __( 'Enabling groups', 'google-site-kit' ) }</p>
<ProgressBar compress />
</div>
) }
{ ! isSaving && (
<Link onClick={ onEnableGroups }>
{ __( 'Enable groups', 'google-site-kit' ) }
</Link>
) }
</div>
);
}
Loading

0 comments on commit 9aca65a

Please sign in to comment.