Skip to content

Commit

Permalink
Merge pull request #8348 from google/feature/8346-ads-module-setup
Browse files Browse the repository at this point in the history
Create the Ads module setup flow.
  • Loading branch information
tofumatt authored Mar 20, 2024
2 parents 281f23a + 65f6c0d commit 12bb2a8
Show file tree
Hide file tree
Showing 27 changed files with 675 additions and 41 deletions.
4 changes: 3 additions & 1 deletion assets/js/components/notifications/BannerNotifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export default function BannerNotifications() {
} );

const [ notification ] = useQueryArg( 'notification' );
const [ slug ] = useQueryArg( 'slug' );

if ( viewOnly ) {
return <ZeroDataStateNotifications />;
Expand All @@ -98,7 +99,8 @@ export default function BannerNotifications() {
<Fragment>
{ adSenseModuleActive && <AdSenseAlerts /> }
<ModuleRecoveryAlert />
{ 'authentication_success' === notification && (
{ /* The Ads module uses the new, subtle notification rather than the old SetupSuccessBannerNotification */ }
{ 'authentication_success' === notification && slug !== 'ads' && (
<SetupSuccessBannerNotification />
) }
{ 'ad_blocking_recovery_setup_success' === notification && (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/**
* SetupSuccessSubtleNotification 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 CheckFill from '../../../svg/icons/check-fill.svg';
import { Button } from 'googlesitekit-components';
import { Grid, Cell, Row } from '../../material-components';
import useQueryArg from '../../hooks/useQueryArg';

export default function SetupSuccessSubtleNotification() {
const [ notification, setNotification ] = useQueryArg( 'notification' );
const [ slug, setSlug ] = useQueryArg( 'slug' );

const onDismiss = () => {
setNotification( undefined );
setSlug( undefined );
};

// The Ads module setup flow is the only module setup flow that uses this new style subtle
// notification, all others use the BannerNotification still.
if ( 'authentication_success' !== notification || slug !== 'ads' ) {
return null;
}

return (
<Grid>
<Row>
<Cell
alignMiddle
size={ 12 }
className="googlesitekit-subtle-notification"
>
<div className="googlesitekit-subtle-notification__icon">
<CheckFill width={ 24 } height={ 24 } />
</div>
<div className="googlesitekit-subtle-notification__content">
<p>
{ __(
'Success! Your Ads conversion ID was added to your site',
'google-site-kit'
) }
</p>
<p className="googlesitekit-subtle-notification__secondary_description">
{ __(
'You can now track conversions for your Ads campaigns.',
'google-site-kit'
) }
</p>
</div>
<Button tertiary onClick={ onDismiss }>
{ __( 'Got it', 'google-site-kit' ) }
</Button>
</Cell>
</Row>
</Grid>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* SetupSuccessSubtleNotification Component Stories.
*
* 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.
*/

/**
* External dependencies
*/
import { withQuery } from '@storybook/addon-queryparams';

/**
* Internal dependencies
*/
import SetupSuccessSubtleNotification from './SetupSuccessSubtleNotification';
import { WithTestRegistry } from '../../../../tests/js/utils';

function Template( { ...args } ) {
return <SetupSuccessSubtleNotification { ...args } />;
}

export const Ads = Template.bind( {} );
Ads.storyName = 'Setup Success - Ads';
Ads.parameters = {
query: {
notification: 'authentication_success',
slug: 'ads',
},
};
Ads.scenario = {
label: 'Global/SetupSuccessSubtleNotification/Ads',
};

export default {
title: 'Components/SetupSuccessSubtleNotification',
component: SetupSuccessSubtleNotification,
decorators: [
withQuery,
( Story, { parameters } ) => {
return (
<WithTestRegistry features={ parameters.features || [] }>
<Story />
</WithTestRegistry>
);
},
],
};
2 changes: 2 additions & 0 deletions assets/js/components/notifications/SubtleNotifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { Fragment } from '@wordpress/element';
* Internal dependencies
*/
import GA4AdSenseLinkedNotification from './GA4AdSenseLinkedNotification';
import SetupSuccessSubtleNotification from './SetupSuccessSubtleNotification';

export default function SubtleNotifications() {
// Each notification component rendered here has its own logic to determine
Expand All @@ -37,6 +38,7 @@ export default function SubtleNotifications() {
return (
<Fragment>
<GA4AdSenseLinkedNotification />
<SetupSuccessSubtleNotification />
</Fragment>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Ads Module Ads Conversion ID 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.
*/

/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import Data from 'googlesitekit-data';
import { TextField } from 'googlesitekit-components';
import { MODULES_ADS } from '../../datastore/constants';
import VisuallyHidden from '../../../../components/VisuallyHidden';
import { isValidAdsConversionID } from '../../utils/validation';
import WarningIcon from '../../../../../svg/icons/warning-v2.svg';
const { useSelect, useDispatch } = Data;

export default function AdsConversionIDTextField() {
const adsConversionID = useSelect( ( select ) =>
select( MODULES_ADS ).getAdsConversionID()
);

const { setAdsConversionID } = useDispatch( MODULES_ADS );
const onChange = useCallback(
( { currentTarget } ) => {
let newValue = currentTarget.value.trim().toUpperCase();
// Automatically add the AW- prefix if not provided.
if ( 'AW-'.length < newValue.length && ! /^AW-/.test( newValue ) ) {
newValue = `AW-${ newValue }`;
}

if ( newValue !== adsConversionID ) {
setAdsConversionID( newValue );
}
},
[ adsConversionID, setAdsConversionID ]
);

const isValidValue = Boolean( isValidAdsConversionID( adsConversionID ) );

return (
<div className="googlesitekit-settings-module__fields-group">
<h4 className="googlesitekit-settings-module__fields-group-title">
{ __( 'Conversion ID', 'google-site-kit' ) }
</h4>
<TextField
label={ __( 'Ads Conversion ID', 'google-site-kit' ) }
className={ classnames( {
'mdc-text-field--error': ! isValidValue,
} ) }
helperText={
! isValidValue &&
__(
'Tracking for your Ads campaigns won’t work until you insert a valid ID',
'google-site-kit'
)
}
trailingIcon={
! isValidValue && (
<span className="googlesitekit-text-field-icon--error">
<VisuallyHidden>
{ __( 'Error', 'google-site-kit' ) }
</VisuallyHidden>
<WarningIcon width={ 14 } height={ 12 } />
</span>
)
}
outlined
value={ adsConversionID }
onChange={ onChange }
/>
</div>
);
}
19 changes: 19 additions & 0 deletions assets/js/modules/ads/components/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Ads Common components.
*
* 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.
*/

export { default as AdsConversionIDTextField } from './AdsConversionIDTextField';
92 changes: 92 additions & 0 deletions assets/js/modules/ads/components/setup/SetupForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Ads Setup form.
*
* 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.
*/

/**
* External dependencies
*/
import PropTypes from 'prop-types';

/**
* WordPress dependencies
*/
import { useCallback } from '@wordpress/element';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import Data from 'googlesitekit-data';
import { SpinnerButton } from 'googlesitekit-components';
import { MODULES_ADS } from '../../datastore/constants';
import { CORE_LOCATION } from '../../../../googlesitekit/datastore/location/constants';
import StoreErrorNotices from '../../../../components/StoreErrorNotices';
import AdsConversionIDTextField from '../common/AdsConversionIDTextField';
const { useSelect, useDispatch } = Data;

export default function SetupForm( { finishSetup } ) {
const canSubmitChanges = useSelect( ( select ) =>
select( MODULES_ADS ).canSubmitChanges()
);
const isSaving = useSelect(
( select ) =>
select( MODULES_ADS ).isDoingSubmitChanges() ||
select( CORE_LOCATION ).isNavigating()
);

const { submitChanges } = useDispatch( MODULES_ADS );

const submitForm = useCallback(
async ( event ) => {
event.preventDefault();

const { error } = await submitChanges();

if ( ! error ) {
finishSetup();
}
},
[ finishSetup, submitChanges ]
);

return (
<form className="googlesitekit-ads-setup__form" onSubmit={ submitForm }>
<StoreErrorNotices moduleSlug="ads" storeName={ MODULES_ADS } />

<div className="googlesitekit-setup-module__inputs">
<AdsConversionIDTextField />
</div>

<div className="googlesitekit-setup-module__action">
<SpinnerButton
disabled={ ! canSubmitChanges || isSaving }
isSaving={ isSaving }
>
{ __( 'Complete setup', 'google-site-kit' ) }
</SpinnerButton>
</div>
</form>
);
}

SetupForm.propTypes = {
finishSetup: PropTypes.func,
};

SetupForm.defaultProps = {
finishSetup: () => {},
};
Loading

0 comments on commit 12bb2a8

Please sign in to comment.