Skip to content

Commit

Permalink
Merge pull request #9836 from google/issue/9797-add-suggested-group-t…
Browse files Browse the repository at this point in the history
…o-kmw-selection-panel

Issue / 9797 Add Suggested Group to KMW Selection Panel
  • Loading branch information
eugene-manuilov authored Dec 19, 2024
2 parents d1c9ec6 + 2f6d6f6 commit 345eea8
Show file tree
Hide file tree
Showing 14 changed files with 146 additions and 191 deletions.
22 changes: 18 additions & 4 deletions assets/js/components/KeyMetrics/ChipTabGroup/Chip.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,18 @@ import classnames from 'classnames';
* Internal dependencies
*/
import { Button } from 'googlesitekit-components';
import { KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG } from '../constants';
import {
KEY_METRICS_GROUP_CURRENT,
KEY_METRICS_GROUP_SUGGESTED,
} from '../constants';
import CheckMark from '../../../../svg/icons/check-2.svg';
import StarFill from '../../../../svg/icons/star-fill.svg';
import Null from '../../../components/Null';

const icons = {
[ KEY_METRICS_GROUP_CURRENT.SLUG ]: CheckMark,
[ KEY_METRICS_GROUP_SUGGESTED.SLUG ]: StarFill,
};

export default function Chip( {
slug,
Expand All @@ -37,15 +47,19 @@ export default function Chip( {
hasNewBadge = false,
selectedCount = 0,
} ) {
const Icon = icons[ slug ] || Null;

return (
<Button
className={ classnames( 'googlesitekit-chip-tab-group__chip-item', {
'googlesitekit-chip-tab-group__chip-item--active': isActive,
} ) }
icon={
slug === KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG ? (
<CheckMark width={ 12 } height={ 12 } />
) : null
<Icon
width={ 12 }
height={ 12 }
className={ `googlesitekit-chip-tab-group__chip-item-svg googlesitekit-chip-tab-group__chip-item-svg__${ slug }` }
/>
}
trailingIcon={
selectedCount > 0 ? (
Expand Down
104 changes: 69 additions & 35 deletions assets/js/components/KeyMetrics/ChipTabGroup/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import { useSelect, useDispatch } from 'googlesitekit-data';
import { Tab, TabBar } from 'googlesitekit-components';
import {
EFFECTIVE_SELECTION,
KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG,
KEY_METRICS_GROUP_CURRENT,
KEY_METRICS_GROUP_SUGGESTED,
KEY_METRICS_GROUP_CONTENT_PERFORMANCE,
KEY_METRICS_GROUP_DRIVING_TRAFFIC,
KEY_METRICS_GROUP_GENERATING_LEADS,
Expand All @@ -47,22 +48,24 @@ import MetricItem from '../MetricsSelectionPanel/MetricItem';
import NoSelectedItemsSVG from '../../../../svg/graphics/key-metrics-no-selected-items.svg';
import { BREAKPOINT_SMALL, useBreakpoint } from '../../../hooks/useBreakpoint';
import CheckMark from '../../../../svg/icons/check-2.svg';
import StarFill from '../../../../svg/icons/star-fill.svg';
import Null from '../../../components/Null';
import {
CONVERSION_REPORTING_LEAD_EVENTS,
MODULES_ANALYTICS_4,
} from '../../../modules/analytics-4/datastore/constants';
import { CORE_UI } from '../../../googlesitekit/datastore/ui/constants';
import { CORE_MODULES } from '../../../googlesitekit/modules/datastore/constants';
import { CORE_USER } from '../../../googlesitekit/datastore/user/constants';
import { CORE_MODULES } from '../../../googlesitekit/modules/datastore/constants';

const currentSelectionGroup = {
SLUG: KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG,
LABEL: __( 'Current selection', 'google-site-kit' ),
const icons = {
[ KEY_METRICS_GROUP_CURRENT.SLUG ]: CheckMark,
[ KEY_METRICS_GROUP_SUGGESTED.SLUG ]: StarFill,
};

export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
const [ isActive, setIsActive ] = useState(
KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG
KEY_METRICS_GROUP_CURRENT.SLUG
);
// Used for mobile chip tabs, which leverages the TabBar component for seemless horizontal scroll
// but it accepts a numerical index for the active tab.
Expand Down Expand Up @@ -92,6 +95,12 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
UNSTAGED_SELECTION
) || []
);
const isUserInputCompleted = useSelect( ( select ) =>
select( CORE_USER ).isUserInputCompleted()
);
const answerBasedMetrics = useSelect( ( select ) =>
select( CORE_USER ).getAnswerBasedMetrics()
);

const currentlyActiveEvents = useSelect( ( select ) => {
const userPickedMetrics = select( CORE_USER ).getUserPickedMetrics();
Expand All @@ -117,6 +126,7 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
const userInputSettings = select( CORE_USER ).getUserInputSettings();
return userInputSettings?.includeConversionEvents?.values;
} );

const isGA4Connected = useSelect( ( select ) =>
select( CORE_MODULES ).isModuleConnected( 'analytics-4' )
);
Expand All @@ -142,8 +152,8 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
currentlyActiveEvents?.includes( item )
);

const keyMetricsGroups = useMemo(
() => [
const keyMetricsGroups = useMemo( () => {
return [
KEY_METRICS_GROUP_VISITORS,
KEY_METRICS_GROUP_DRIVING_TRAFFIC,
...( hasGeneratingLeadsGroup?.length
Expand All @@ -153,13 +163,20 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
? [ KEY_METRICS_GROUP_SELLING_PRODUCTS ]
: [] ),
KEY_METRICS_GROUP_CONTENT_PERFORMANCE,
],
[ hasGeneratingLeadsGroup, hasSellingProductsGroup ]
);
];
}, [ hasGeneratingLeadsGroup, hasSellingProductsGroup ] );

const dynamicGroups = useMemo( () => {
if ( isUserInputCompleted ) {
return [ KEY_METRICS_GROUP_CURRENT, KEY_METRICS_GROUP_SUGGESTED ];
}

return [ KEY_METRICS_GROUP_CURRENT ];
}, [ isUserInputCompleted ] );

const allGroups = useMemo(
() => [ currentSelectionGroup, ...keyMetricsGroups ],
[ keyMetricsGroups ]
() => [ ...dynamicGroups, ...keyMetricsGroups ],
[ dynamicGroups, keyMetricsGroups ]
);

const newBadgeEvents = useSelect( ( select ) => {
Expand Down Expand Up @@ -200,21 +217,31 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {

// Currently selected group does not include total selected number, so it will
// always be 0.
const selectedCounts = { [ KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG ]: 0 };
const selectedCounts = { [ KEY_METRICS_GROUP_CURRENT.SLUG ]: 0 };
const activeMetricItems = {};
const newlyDetectedMetrics = {};

for ( const metricItemSlug in allMetricItems ) {
const metricGroup = allMetricItems[ metricItemSlug ].group;
if (
metricGroup === isActive ||
( isActive === currentSelectionGroup.SLUG &&
( isActive === KEY_METRICS_GROUP_CURRENT.SLUG &&
effectiveSelection.includes( metricItemSlug ) )
) {
activeMetricItems[ metricItemSlug ] =
allMetricItems[ metricItemSlug ];
}

if (
isActive === KEY_METRICS_GROUP_SUGGESTED.SLUG &&
answerBasedMetrics.includes( metricItemSlug )
) {
if ( answerBasedMetrics.includes( metricItemSlug ) ) {
activeMetricItems[ metricItemSlug ] =
allMetricItems[ metricItemSlug ];
}
}

if ( ! selectedCounts[ metricGroup ] ) {
const selectedCount = Object.keys( allMetricItems ).filter(
( slug ) => {
Expand Down Expand Up @@ -291,6 +318,8 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
useEffect( () => {
// Ensure that current selection group is always active when selection panel re-opens.
if ( ! isSelectionPanelOpenPrevious && isSelectionPanelOpen ) {
setIsActive( KEY_METRICS_GROUP_CURRENT.SLUG );
setActiveGroupIndex( 0 );
if ( newlyDetectedMetricsKeys.length && isMobileBreakpoint ) {
const firstNewlyDetectedGroup = allGroups.find(
( group ) => group.SLUG === newlyDetectedMetricsKeys[ 0 ]
Expand All @@ -302,7 +331,7 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
setIsActive( firstNewlyDetectedGroup.SLUG );
} else {
setActiveGroupIndex( 0 );
setIsActive( KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG );
setIsActive( KEY_METRICS_GROUP_CURRENT.SLUG );
}
}

Expand All @@ -321,7 +350,7 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
] );

const chipItemRows = [
[ currentSelectionGroup, ...keyMetricsGroups.slice( 0, 2 ) ],
[ ...dynamicGroups, ...keyMetricsGroups.slice( 0, 2 ) ],
[ ...keyMetricsGroups.slice( 2 ) ],
];

Expand Down Expand Up @@ -360,24 +389,29 @@ export default function ChipTabGroup( { allMetricItems, savedItemSlugs } ) {
onChipChange( null, index )
}
>
{ allGroups.map( ( group, index ) => (
<Tab key={ index } aria-label={ group.LABEL }>
{ index === 0 && (
<span className="googlesitekit-chip-tab-group__tab-item-mobile-svg">
<CheckMark width={ 12 } height={ 12 } />
</span>
) }
{ group.LABEL }
{ selectedCounts[ group.SLUG ] > 0 && (
<span className="googlesitekit-chip-tab-group__chip-item-count">
({ selectedCounts[ group.SLUG ] })
</span>
) }
{ !! newlyDetectedMetrics?.[ group.SLUG ] && (
<span className="googlesitekit-chip-tab-group__chip-item-new-dot" />
) }
</Tab>
) ) }
{ allGroups.map( ( group, index ) => {
const Icon = icons[ group.SLUG ] || Null;
return (
<Tab key={ index } aria-label={ group.LABEL }>
<Icon
width={ 12 }
height={ 12 }
className={ `googlesitekit-chip-tab-group__chip-item-svg googlesitekit-chip-tab-group__tab-item-mobile-svg googlesitekit-chip-tab-group__chip-item-svg__${ group.SLUG }` }
/>
{ group.LABEL }
{ selectedCounts[ group.SLUG ] > 0 && (
<span className="googlesitekit-chip-tab-group__chip-item-count">
({ selectedCounts[ group.SLUG ] })
</span>
) }
{ !! newlyDetectedMetrics?.[
group.SLUG
] && (
<span className="googlesitekit-chip-tab-group__chip-item-new-dot" />
) }
</Tab>
);
} ) }
</TabBar>
) }
</div>
Expand Down
23 changes: 23 additions & 0 deletions assets/js/components/KeyMetrics/ChipTabGroup/index.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import Footer from '../MetricsSelectionPanel/Footer';
import WithRegistrySetup from '../../../../../tests/js/WithRegistrySetup';
import {
provideKeyMetrics,
provideKeyMetricsUserInputSettings,
provideModules,
provideSiteInfo,
provideUserAuthentication,
Expand Down Expand Up @@ -109,6 +110,9 @@ function Template() {
export const Default = Template.bind( {} );
Default.storyName = 'Default';
Default.args = {
setupRegistry: ( registry ) => {
registry.dispatch( CORE_USER ).receiveIsUserInputCompleted( false );
},
features: [ 'conversionReporting' ],
};
Default.scenario = {
Expand All @@ -127,6 +131,7 @@ WithError.args = {
];

provideKeyMetrics( registry, { widgetSlugs: savedKeyMetrics } );
registry.dispatch( CORE_USER ).receiveIsUserInputCompleted( false );

registry.dispatch( CORE_FORMS ).setValues( KEY_METRICS_SELECTION_FORM, {
[ KEY_METRICS_SELECTED ]: savedKeyMetrics,
Expand All @@ -147,6 +152,24 @@ WithError.scenario = {
label: 'Components/KeyMetrics/ChipTabGroup/WithError',
};

export const WithSuggestedGroup = Template.bind( {} );
WithSuggestedGroup.storyName = 'With Suggested Group';
WithSuggestedGroup.args = {
setupRegistry: ( registry ) => {
registry.dispatch( CORE_USER ).receiveIsUserInputCompleted( true );
provideKeyMetricsUserInputSettings( registry, {
purpose: {
values: [ 'sell_products' ],
scope: 'site',
},
} );
},
features: [ 'conversionReporting' ],
};
WithSuggestedGroup.scenario = {
label: 'Components/KeyMetrics/ChipTabGroup/WithSuggestedGroup',
};

export default {
title: 'Key Metrics/ChipTabGroup',
component: SelectionPanel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
*/
import {
createTestRegistry,
provideKeyMetricsUserInputSettings,
provideSiteInfo,
WithTestRegistry,
} from '../../../../tests/js/utils';
import { CORE_USER } from '../../googlesitekit/datastore/user/constants';
import { VIEW_CONTEXT_METRIC_SELECTION } from '../../googlesitekit/constants';
import { Provider as ViewContextProvider } from '../Root/ViewContextContext';
import FullScreenMetricsSelectionApp from './FullScreenMetricSelectionApp';
Expand Down Expand Up @@ -53,7 +53,8 @@ export default {
( Story, { args } ) => {
const registry = createTestRegistry();

provideKeyMetricsUserInputSettings( registry );
registry.dispatch( CORE_USER ).receiveIsUserInputCompleted( false );

provideSiteInfo( registry );

return (
Expand Down
10 changes: 8 additions & 2 deletions assets/js/components/KeyMetrics/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@ export const UNSTAGED_SELECTION = 'key-metrics-unstaged-selection';
export const MIN_SELECTED_METRICS_COUNT = 2;
export const MAX_SELECTED_METRICS_COUNT = 4;
export const MAX_SELECTED_METRICS_COUNT_WITH_CONVERSION_EVENTS = 8;

export const KEY_METRICS_CURRENT_SELECTION_GROUP_SLUG = 'current-selection';
export const KEY_METRICS_GROUP_CURRENT = {
SLUG: 'current-selection',
LABEL: __( 'Current selection', 'google-site-kit' ),
};
export const KEY_METRICS_GROUP_SUGGESTED = {
SLUG: 'suggested',
LABEL: __( 'Suggested', 'google-site-kit' ),
};
export const KEY_METRICS_GROUP_VISITORS = {
SLUG: 'visitors',
LABEL: __( 'Visitors', 'google-site-kit' ),
Expand Down
11 changes: 1 addition & 10 deletions assets/js/components/user-input/UserInputQuestionnaire.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,7 @@ export default function UserInputQuestionnaire() {
'questionNumber'
)
) || 1;
const userPickedMetrics = useSelect( ( select ) =>
select( CORE_USER ).getUserPickedMetrics()
);
const { saveUserInputSettings, resetKeyMetricsSelection } =
useDispatch( CORE_USER );
const { saveUserInputSettings } = useDispatch( CORE_USER );
const { navigateTo } = useDispatch( CORE_LOCATION );

const dashboardURL = useSelect( ( select ) =>
Expand Down Expand Up @@ -191,9 +187,6 @@ export default function UserInputQuestionnaire() {

const response = await saveUserInputSettings();
if ( ! response.error ) {
if ( !! userPickedMetrics ) {
await resetKeyMetricsSelection();
}
const url = new URL( dashboardURL );
navigateTo( url.toString() );
}
Expand All @@ -205,8 +198,6 @@ export default function UserInputQuestionnaire() {
setUserInputSetting,
navigateTo,
isConversionReportingEnabled,
userPickedMetrics,
resetKeyMetricsSelection,
] );

const settings = useSelect( ( select ) =>
Expand Down
Loading

0 comments on commit 345eea8

Please sign in to comment.