Skip to content

Commit

Permalink
Assembler: Add the shuffle button to the action bar (#80078)
Browse files Browse the repository at this point in the history
  • Loading branch information
arthur791004 authored Aug 1, 2023
1 parent 7fa254a commit d42ba25
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ export const PATTERN_ASSEMBLER_EVENTS = {
PATTERN_MOVEDOWN_CLICK: 'calypso_signup_pattern_assembler_pattern_movedown_click',
PATTERN_REPLACE_CLICK: 'calypso_signup_pattern_assembler_pattern_replace_click',
PATTERN_DELETE_CLICK: 'calypso_signup_pattern_assembler_pattern_delete_click',
PATTERN_SHUFFLE_CLICK: 'calypso_signup_pattern_assembler_pattern_shuffle_click',

PREVIEW_DEVICE_CLICK: 'calypso_signup_pattern_assembler_preview_device_click',

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import ScreenFontPairings from './screen-font-pairings';
import ScreenFooter from './screen-footer';
import ScreenHeader from './screen-header';
import ScreenMain from './screen-main';
import { encodePatternId } from './utils';
import { encodePatternId, getShuffledPattern, injectCategoryToPattern } from './utils';
import withGlobalStylesProvider from './with-global-styles-provider';
import type { Pattern } from './types';
import type { StepProps } from '../../types';
Expand Down Expand Up @@ -247,17 +247,17 @@ const PatternAssembler = ( {
}
};

const replaceSection = ( pattern: Pattern ) => {
if ( sectionPosition !== null ) {
const replaceSection = ( pattern: Pattern, position: number | null = sectionPosition ) => {
if ( position !== null ) {
setSections( [
...sections.slice( 0, sectionPosition ),
...sections.slice( 0, position ),
{
...pattern,
key: sections[ sectionPosition ].key,
key: sections[ position ].key,
},
...sections.slice( sectionPosition + 1 ),
...sections.slice( position + 1 ),
] );
updateActivePatternPosition( sectionPosition );
updateActivePatternPosition( position );
noticeOperations.showPatternInsertedNotice( pattern );
}
};
Expand Down Expand Up @@ -308,24 +308,7 @@ const PatternAssembler = ( {
selectedCategory?: string | null
) => {
if ( selectedPattern ) {
// Inject the selected pattern category or the first category
// to be used in tracks and as selected pattern name.
const [ firstCategory ] = Object.keys( selectedPattern.categories );
selectedPattern.category = categories.find( ( { name } ) => {
if ( selectedCategory === CATEGORY_ALL_SLUG ) {
return name === firstCategory;
}
return name === ( selectedCategory || firstCategory );
} );

if ( selectedCategory === CATEGORY_ALL_SLUG ) {
// Use 'all' rather than 'featured' as slug for tracks.
// Use the first category label as selected pattern name.
selectedPattern.category = {
name: 'all',
label: selectedPattern.category?.label,
};
}
injectCategoryToPattern( selectedPattern, categories, selectedCategory );

trackEventPatternSelect( {
patternType: type,
Expand Down Expand Up @@ -485,6 +468,23 @@ const PatternAssembler = ( {

const onDeleteFooter = () => onSelect( 'footer', null );

const onShuffle = ( type: string, pattern: Pattern, position?: number ) => {
const [ firstCategory ] = Object.keys( pattern.categories );
const selectedCategory = pattern.category?.name || firstCategory;
const patterns =
patternsMapByCategory[ selectedCategory ] || patternsMapByCategory[ CATEGORY_ALL_SLUG ];
const shuffledPattern = getShuffledPattern( patterns, pattern );
injectCategoryToPattern( shuffledPattern, categories, selectedCategory );

if ( type === 'header' ) {
updateHeader( shuffledPattern );
} else if ( type === 'footer' ) {
updateFooter( shuffledPattern );
} else {
replaceSection( shuffledPattern, position );
}
};

const onScreenColorsSelect = ( variation: GlobalStylesObject | null ) => {
setColorVariation( variation );
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.SCREEN_COLORS_PREVIEW_CLICK, {
Expand Down Expand Up @@ -619,6 +619,7 @@ const PatternAssembler = ( {
onMoveDownSection={ onMoveDownSection }
onDeleteHeader={ onDeleteHeader }
onDeleteFooter={ onDeleteFooter }
onShuffle={ onShuffle }
recordTracksEvent={ recordTracksEvent }
/>
<PremiumGlobalStylesUpgradeModal { ...globalStylesUpgradeModalProps } />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { Button } from '@wordpress/components';
import { chevronUp, chevronDown, close, edit } from '@wordpress/icons';
import { chevronUp, chevronDown, close, edit, shuffle } from '@wordpress/icons';
import { useTranslate } from 'i18n-calypso';
import { recordTracksEvent } from 'calypso/lib/analytics/tracks';
import { PATTERN_ASSEMBLER_EVENTS } from './events';
import type { Category } from './types';
import './pattern-action-bar.scss';

type PatternActionBarProps = {
onReplace?: () => void;
onDelete: () => void;
onMoveUp?: () => void;
onMoveDown?: () => void;
onShuffle: () => void;
disableMoveUp?: boolean;
disableMoveDown?: boolean;
patternType: string;
category?: Category;
isRemoveButtonTextOnly?: boolean;
source: 'list' | 'large_preview';
};
Expand All @@ -22,13 +25,21 @@ const PatternActionBar = ( {
onDelete,
onMoveUp,
onMoveDown,
onShuffle,
disableMoveUp,
disableMoveDown,
patternType,
category,
isRemoveButtonTextOnly,
source,
}: PatternActionBarProps ) => {
const translate = useTranslate();
const eventProps = {
pattern_type: patternType,
pattern_category: category?.name,
source,
};

return (
<div
className="pattern-action-bar"
Expand All @@ -43,9 +54,7 @@ const PatternActionBar = ( {
role="menuitem"
label={ translate( 'Move up' ) }
onClick={ () => {
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_MOVEUP_CLICK, {
source,
} );
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_MOVEUP_CLICK, eventProps );
onMoveUp?.();
} }
icon={ chevronUp }
Expand All @@ -57,26 +66,32 @@ const PatternActionBar = ( {
role="menuitem"
label={ translate( 'Move down' ) }
onClick={ () => {
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_MOVEDOWN_CLICK, {
source,
} );
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_MOVEDOWN_CLICK, eventProps );
onMoveDown?.();
} }
icon={ chevronDown }
iconSize={ 23 }
/>
</div>
) }
<Button
className="pattern-action-bar__block pattern-action-bar__action"
role="menuitem"
label={ translate( 'Shuffle' ) }
onClick={ () => {
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_SHUFFLE_CLICK, eventProps );
onShuffle();
} }
icon={ shuffle }
iconSize={ 23 }
/>
{ onReplace && (
<Button
className="pattern-action-bar__block pattern-action-bar__action"
role="menuitem"
label={ translate( 'Replace' ) }
onClick={ () => {
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_REPLACE_CLICK, {
pattern_type: patternType,
source,
} );
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_REPLACE_CLICK, eventProps );
onReplace();
} }
icon={ edit }
Expand All @@ -88,10 +103,7 @@ const PatternActionBar = ( {
role="menuitem"
label={ translate( 'Remove' ) }
onClick={ () => {
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_DELETE_CLICK, {
pattern_type: patternType,
source,
} );
recordTracksEvent( PATTERN_ASSEMBLER_EVENTS.PATTERN_DELETE_CLICK, eventProps );
onDelete();
} }
icon={ ! isRemoveButtonTextOnly ? close : null }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface Props {
onMoveDownSection: ( position: number ) => void;
onDeleteHeader: () => void;
onDeleteFooter: () => void;
onShuffle: ( type: string, pattern: Pattern, position?: number ) => void;
recordTracksEvent: ( name: string, eventProperties?: any ) => void;
}

Expand All @@ -39,6 +40,7 @@ const PatternLargePreview = ( {
onMoveDownSection,
onDeleteHeader,
onDeleteFooter,
onShuffle,
recordTracksEvent,
}: Props ) => {
const translate = useTranslate();
Expand Down Expand Up @@ -95,11 +97,12 @@ const PatternLargePreview = ( {

const renderPattern = ( type: string, pattern: Pattern, position = -1 ) => {
const key = type === 'section' ? pattern.key : type;
const handleShuffle = () => onShuffle( type, pattern, position );
const getActionBarProps = () => {
if ( type === 'header' ) {
return { onDelete: onDeleteHeader };
return { onDelete: onDeleteHeader, onShuffle: handleShuffle };
} else if ( type === 'footer' ) {
return { onDelete: onDeleteFooter };
return { onDelete: onDeleteFooter, onShuffle: handleShuffle };
}

return {
Expand All @@ -108,6 +111,7 @@ const PatternLargePreview = ( {
onDelete: () => onDeleteSection( position ),
onMoveUp: () => onMoveUpSection( position ),
onMoveDown: () => onMoveDownSection( position ),
onShuffle: handleShuffle,
};
};

Expand All @@ -128,6 +132,7 @@ const PatternLargePreview = ( {
/>
<PatternActionBar
patternType={ type }
category={ pattern.category }
isRemoveButtonTextOnly
source="large_preview"
{ ...getActionBarProps() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ type PatternLayoutProps = {
onAddFooter?: () => void;
onReplaceFooter?: () => void;
onDeleteFooter?: () => void;
onShuffle: ( type: string, pattern: Pattern, position?: number ) => void;
};

const PatternLayout = ( {
Expand All @@ -28,6 +29,7 @@ const PatternLayout = ( {
onDeleteSection,
onMoveUpSection,
onMoveDownSection,
onShuffle,
}: PatternLayoutProps ) => {
const translate = useTranslate();

Expand All @@ -37,7 +39,8 @@ const PatternLayout = ( {
<AsyncLoad require="./animate-list" featureName="domMax" placeholder={ <div /> }>
{ ( m: any ) => (
<m.ul className="pattern-layout__list" layoutScroll>
{ sections.map( ( { title, category, key }: Pattern, index ) => {
{ sections.map( ( pattern: Pattern, index ) => {
const { title, category, key } = pattern;
return (
<m.li
key={ key }
Expand All @@ -55,6 +58,7 @@ const PatternLayout = ( {
onDelete={ () => onDeleteSection( index ) }
onMoveUp={ () => onMoveUpSection( index ) }
onMoveDown={ () => onMoveDownSection( index ) }
onShuffle={ () => onShuffle( 'sections', pattern, index ) }
disableMoveUp={ index === 0 }
disableMoveDown={ sections?.length === index + 1 }
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { PATTERN_SOURCE_SITE_ID, CATEGORY_ALL_SLUG } from './constants';
import type { Pattern, Category } from './types';

export const encodePatternId = ( patternId: number ) =>
`${ patternId }-${ PATTERN_SOURCE_SITE_ID }`;
Expand All @@ -8,3 +9,37 @@ export const decodePatternId = ( encodedPatternId: number | string ) =>

export const replaceCategoryAllName = ( name?: string ) =>
name === CATEGORY_ALL_SLUG ? 'all' : name;

export const getShuffledPattern = ( candidates: Pattern[], current: Pattern ) => {
const filteredCandidates = candidates.filter( ( { ID } ) => ID !== current.ID );
const shuffledIndex = Math.floor( Math.random() * filteredCandidates.length );
return filteredCandidates[ shuffledIndex ];
};

export const injectCategoryToPattern = (
pattern: Pattern,
categories: Category[],
selectedCategory?: string | null
) => {
// Inject the selected pattern category or the first category
// to be used in tracks and as selected pattern name.
const [ firstCategory ] = Object.keys( pattern.categories );
let category = categories.find( ( { name } ) => {
if ( selectedCategory === CATEGORY_ALL_SLUG ) {
return name === firstCategory;
}
return name === ( selectedCategory || firstCategory );
} );

if ( selectedCategory === CATEGORY_ALL_SLUG ) {
// Use 'all' rather than 'featured' as slug for tracks.
// Use the first category label as selected pattern name.
category = {
name: 'all',
label: pattern.category?.label,
};
}

pattern.category = category;
return pattern;
};

0 comments on commit d42ba25

Please sign in to comment.