Skip to content

Commit

Permalink
Merge pull request #10164 from google/enhancement/#10066-rrm-cta-plac…
Browse files Browse the repository at this point in the history
…ement-settings

Add RRM CTA placement settings
  • Loading branch information
hussain-t authored Feb 8, 2025
2 parents aaa172c + 79a025d commit 24f1c20
Show file tree
Hide file tree
Showing 33 changed files with 708 additions and 44 deletions.
13 changes: 11 additions & 2 deletions assets/js/googlesitekit/components-gm2/Chip.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default function Chip( {
selected,
className,
CheckMark = ChipCheckmark,
disabled,
...props
} ) {
return (
Expand All @@ -38,9 +39,17 @@ export default function Chip( {
data-chip-id={ id }
id={ id }
label={ label }
onClick={ onClick }
onClick={ ( event ) => {
if ( disabled ) {
return;
}

onClick?.( event );
} }
selected={ selected }
className={ classnames( 'googlesitekit-chip', className ) }
className={ classnames( 'googlesitekit-chip', className, {
'googlesitekit-chip--disabled': disabled,
} ) }
{ ...props }
/>
);
Expand Down
8 changes: 8 additions & 0 deletions assets/js/googlesitekit/components-gm2/Chip.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ SelectedChip.args = {
selected: true,
};

export const DisabledChip = Template.bind( {} );
DisabledChip.storyName = 'Disabled Chip';
DisabledChip.args = {
id: 'disabled',
label: 'Disabled Chip',
disabled: true,
};

export default {
title: 'Components/Chip',
component: Chip,
Expand Down
16 changes: 13 additions & 3 deletions assets/js/googlesitekit/components-gm2/Select.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,28 @@
/**
* External dependencies
*/
import MaterialSelect from '@material/react-select';
import MaterialSelect, { SelectHelperText } from '@material/react-select';

/**
* WordPress dependencies
*/
import { useInstanceId } from '@wordpress/compose';

export default function Select( { id, ...props } ) {
export default function Select( { id, helperText, ...props } ) {
// For accessibility, provide a generated id fallback if an id
// is not supplied. Adding an id is mandatory because otherwise the label
// is not able to associate with the select.
const idFallback = useInstanceId( Select, 'googlesitekit-select' );

return <MaterialSelect id={ id || idFallback } { ...props } />;
return (
<MaterialSelect
id={ id || idFallback }
helperText={
!! helperText ? (
<SelectHelperText>{ helperText }</SelectHelperText>
) : undefined
}
{ ...props }
/>
);
}
16 changes: 15 additions & 1 deletion assets/js/googlesitekit/components-gm2/Select.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ BasicSelect.args = {
outlined: true,
};

export const WithHelperText = Template.bind( {} );
WithHelperText.args = {
name: 'select',
label: __( 'With helper text', 'google-site-kit' ),
options: [ 'Demo Option 1', 'Demo Option 2', 'Demo Option 3' ],
value: 'Demo Option 1',
outlined: true,
helperText: 'This is a helper text',
};

export function VRTStory() {
return (
<div>
Expand All @@ -117,14 +127,18 @@ export function VRTStory() {
<div style={ { marginBottom: '50px' } }>
<OpenSelect { ...OpenSelect.args } />
</div>
<div style={ { marginBottom: '250px' } }>
<div style={ { marginBottom: '50px' } }>
<BasicSelect { ...BasicSelect.args } />
</div>
<div style={ { marginBottom: '250px' } }>
<WithHelperText { ...WithHelperText.args } />
</div>
</div>
);
}
VRTStory.storyName = 'All Selects VRT';
VRTStory.scenario = {
// eslint-disable-next-line sitekit/no-storybook-scenario-label
label: 'Global/Selects',
delay: 3000, // Sometimes the click doesn't work, waiting for everything to load.
clickSelector: '.googlesitekit-story-select-click',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Post Types Select 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.
*/

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

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

/**
* Internal dependencies
*/
import { useSelect, useDispatch } from 'googlesitekit-data';
import { CORE_SITE } from '../../../../googlesitekit/datastore/site/constants';
import { MODULES_READER_REVENUE_MANAGER } from '../../datastore/constants';
import {
ChipMultiSelect,
ChipMultiSelectItem,
} from '../../../../components/ChipMultiSelect';

export default function PostTypesSelect( props ) {
const { isDisabled, hasModuleAccess, onChange = () => {} } = props;

const allPostTypes = useSelect( ( select ) =>
select( CORE_SITE ).getPostTypes()
);

const postTypes = useSelect( ( select ) =>
select( MODULES_READER_REVENUE_MANAGER ).getPostTypes()
);

const { setPostTypes } = useDispatch( MODULES_READER_REVENUE_MANAGER );

const onPostTypesChange = useCallback(
( slug ) => {
const newPostTypes = postTypes.includes( slug )
? postTypes.filter( ( id ) => id !== slug )
: [ ...postTypes, slug ];

setPostTypes( newPostTypes );

onChange( newPostTypes );
},
[ onChange, postTypes, setPostTypes ]
);

return (
<ChipMultiSelect onToggleChip={ onPostTypesChange }>
{ allPostTypes.map( ( { slug, label } ) => (
<ChipMultiSelectItem
key={ slug }
id={ slug }
selected={ postTypes.includes( slug ) }
disabled={ isDisabled || ! hasModuleAccess }
>
{ label }
</ChipMultiSelectItem>
) ) }
</ChipMultiSelect>
);
}

PostTypesSelect.propTypes = {
isDisabled: PropTypes.bool,
hasModuleAccess: PropTypes.bool,
onChange: PropTypes.func,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/**
* Post Types Select component tests.
*
* 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.
*/

/**
* Internal dependencies
*/
import PostTypesSelect from './PostTypesSelect';
import { CORE_SITE } from '../../../../googlesitekit/datastore/site/constants';
import { MODULES_READER_REVENUE_MANAGER } from '../../datastore/constants';
import {
createTestRegistry,
provideSiteInfo,
render,
} from '../../../../../../tests/js/test-utils';

describe( 'PostTypesSelect', () => {
let registry;

beforeEach( () => {
registry = createTestRegistry();

provideSiteInfo( registry, {
postTypes: [
{ slug: 'post', label: 'Posts' },
{ slug: 'page', label: 'Pages' },
{ slug: 'products', label: 'Products' },
],
} );

registry
.dispatch( MODULES_READER_REVENUE_MANAGER )
.receiveGetSettings( {
postTypes: [ '' ],
} );
} );

it( 'should render a chip multi-select field', async () => {
const { container, waitForRegistry } = render( <PostTypesSelect />, {
registry,
} );

await waitForRegistry();

expect(
container.querySelector( '.googlesitekit-chip-multi-select' )
).toBeInTheDocument();
} );

it( 'should render an option for each post type', async () => {
const { container, waitForRegistry } = render( <PostTypesSelect />, {
registry,
} );

await waitForRegistry();

const listItems = container.querySelectorAll(
'.googlesitekit-chip-multi-select__item'
);

const allPostTypes = registry.select( CORE_SITE ).getPostTypes();

expect( listItems ).toHaveLength( allPostTypes.length );

listItems.forEach( ( listItem, index ) => {
// Assert that data-chip-id of listItem is equal to the post type slug.
// eslint-disable-next-line sitekit/acronym-case
expect( listItem.dataset.chipId ).toBe(
allPostTypes[ index ].slug
);

expect(
listItem.querySelector( '.mdc-chip__text' ).textContent
).toEqual( allPostTypes[ index ].label );
} );
} );

it( 'should disable the post types select if the user does not have module access', async () => {
const { container, waitForRegistry } = render(
<PostTypesSelect hasModuleAccess={ false } />,
{
registry,
}
);

await waitForRegistry();

const listItems = container.querySelectorAll(
'.googlesitekit-chip-multi-select__item'
);

listItems.forEach( ( listItem ) => {
expect( listItem ).toHaveClass( 'googlesitekit-chip--disabled' );
} );
} );
} );
Loading

0 comments on commit 24f1c20

Please sign in to comment.