Skip to content

Commit

Permalink
Design Picker: Clean up filters when going back to previous step
Browse files Browse the repository at this point in the history
  • Loading branch information
arthur791004 committed Dec 6, 2024
1 parent 91cf911 commit a13f767
Show file tree
Hide file tree
Showing 10 changed files with 132 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ export const useFlowNavigation = (): FlowNavigation => {
const customNavigate = useCallback< Navigate< StepperStep[] > >(
( nextStep: string, extraData = {}, replace = false ) => {
const hasQueryParams = nextStep.includes( '?' );
const queryParams = ! hasQueryParams ? currentSearchParams : null;

// Get the latest search params from the current location
const queryParams = ! hasQueryParams ? new URLSearchParams( window.location.search ) : null;

setStepData( {
path: nextStep,
Expand All @@ -61,7 +63,7 @@ export const useFlowNavigation = (): FlowNavigation => {

navigate( addQueryParams( newPath, queryParams ), { replace } );
},
[ currentSearchParams, flow, intent, lang, navigate, setStepData, currentStepSlug ]
[ flow, intent, lang, navigate, setStepData, currentStepSlug ]
);

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ import type { GlobalStyles, OnboardSelect, StarterDesigns } from '@automattic/da
import type { Design, StyleVariation } from '@automattic/design-picker';
import type { GlobalStylesObject } from '@automattic/global-styles';

// The `currentSearchParams` parameter from the callback of the `setSearchParams` function
// might not have the latest query parameter on multiple calls at the same time.
const makeSearchParams = (
callback: ( currentSearchParams: URLSearchParams ) => URLSearchParams
) => callback( new URLSearchParams( window.location.search ) );

const useRecipe = (
siteId = 0,
allDesigns: StarterDesigns | undefined,
Expand Down Expand Up @@ -92,62 +98,64 @@ const useRecipe = (
}

if ( theme !== searchParams.get( 'theme' ) ) {
setSearchParams( ( currentSearchParams ) => {
if ( theme ) {
currentSearchParams.set( 'theme', theme );
} else {
currentSearchParams.delete( 'theme' );
}

return currentSearchParams;
} );
setSearchParams(
makeSearchParams( ( currentSearchParams ) => {
if ( theme ) {
currentSearchParams.set( 'theme', theme );
} else {
currentSearchParams.delete( 'theme' );
}

return currentSearchParams;
} )
);
}
};

const handleSelectedStyleVariationChange = ( variation?: StyleVariation ) => {
setSelectedStyleVariation( variation );
setSearchParams(
( currentSearchParams ) => {
makeSearchParams( ( currentSearchParams ) => {
if ( variation ) {
currentSearchParams.set( 'style_variation', variation.slug );
} else {
currentSearchParams.delete( 'style_variation' );
}

return currentSearchParams;
},
} ),
{ replace: true }
);
};

const handleSelectedColorVariationChange = ( variation: GlobalStyles | null ) => {
setSelectedColorVariation( variation );
setSearchParams(
( currentSearchParams ) => {
makeSearchParams( ( currentSearchParams ) => {
if ( variation && variation.title ) {
currentSearchParams.set( 'color_variation_title', variation.title );
} else {
currentSearchParams.delete( 'color_variation_title' );
}

return currentSearchParams;
},
} ),
{ replace: true }
);
};

const handleSelectedFontVariationChange = ( variation: GlobalStyles | null ) => {
setSelectedFontVariation( variation );
setSearchParams(
( currentSearchParams ) => {
makeSearchParams( ( currentSearchParams ) => {
if ( variation && variation.title ) {
currentSearchParams.set( 'font_variation_title', variation.title );
} else {
currentSearchParams.delete( 'font_variation_title' );
}

return currentSearchParams;
},
} ),
{ replace: true }
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ const useTrackFilters = ( { preselectedFilters, isBigSkyEligible, isMultiSelecti
return selectedFilters.reduce(
( result, filterSlug, index ) => ( {
...result,
[ `filters_${ filterSlug }` ]: `${ getCategoryType( filterSlug ) }:${ index }`,
// The property cannot contain `-` character.
[ `filters_${ filterSlug.replace( '-', '_' ) }` ]: `${ getCategoryType(
filterSlug
) }:${ index }`,
} ),
{}
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
import {
UnifiedDesignPicker,
useCategorization,
useDesignPickerFilters,
getDesignPreviewUrl,
isAssemblerDesign,
isAssemblerSupported,
Expand Down Expand Up @@ -254,6 +255,8 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow, stepName } ) => {
handleDeselect: handleDeselectFilter,
} );

const designPickerFilters = useDesignPickerFilters();

const handleChangeTier = ( value: boolean ) => {
if ( value ) {
handleSelectFilter( 'free', 'included_with_plan' );
Expand Down Expand Up @@ -779,6 +782,7 @@ const UnifiedDesignPickerStep: Step = ( { navigation, flow, stepName } ) => {
return;
}

designPickerFilters.resetFilters();
goBack?.();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ToggleControl } from '@wordpress/components';
import { useTranslate } from 'i18n-calypso';
import { useSearchParams } from 'react-router-dom';
import { useDesignPickerFilters } from '../../hooks/use-design-picker-filters';
import './style.scss';

interface Props {
Expand All @@ -9,21 +9,13 @@ interface Props {

const DesignPickerTierFilter = ( { onChange }: Props ) => {
const translate = useTranslate();
const [ searchParams, setSearchParams ] = useSearchParams();

const isFreeOnly = searchParams.get( 'tier' ) === 'free';
const { selectedDesignTier, setSelectedDesignTier } = useDesignPickerFilters();

const handleChange = ( value: boolean ) => {
setSearchParams( ( currentSearchParams: any ) => {
if ( value ) {
currentSearchParams.set( 'tier', 'free' );
} else {
currentSearchParams.delete( 'tier' );
}

return currentSearchParams;
} );
const isFreeOnly = selectedDesignTier === 'free';

const handleChange = ( value: boolean ) => {
setSelectedDesignTier( value ? 'free' : '' );
onChange?.( value );
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ const DesignPicker: React.FC< DesignPickerProps > = ( {
onChangeTier,
} ) => {
const hasCategories = !! Object.keys( categorization?.categories || {} ).length;
const filteredDesigns = useFilteredDesigns( designs, categorization );
const filteredDesigns = useFilteredDesigns( designs );
const features = [ 'blog', 'portfolio', 'podcast', 'store' ];
const featureCategories = useMemo(
() => ( categorization?.categories || [] ).filter( ( { slug } ) => features.includes( slug ) ),
Expand Down
44 changes: 15 additions & 29 deletions packages/design-picker/src/hooks/use-categorization.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useEffect, useMemo, useCallback } from 'react';
import { useSearchParams } from 'react-router-dom';
import { Category } from '../types';
import { useDesignPickerFilters } from './use-design-picker-filters';
import type { Category } from '../types';

export interface Categorization {
categories: Category[];
selections: string[];
onSelect: ( selectedSlug: string ) => void;
categories: Category[];
}

interface UseCategorizationOptions {
Expand All @@ -26,8 +26,6 @@ export function useCategorization(
handleDeselect,
}: UseCategorizationOptions
): Categorization {
const [ searchParams, setSearchParams ] = useSearchParams();

const categories = useMemo( () => {
const categoryMapKeys = Object.keys( categoryMap ) || [];
const result = categoryMapKeys.map( ( slug ) => ( {
Expand All @@ -38,55 +36,43 @@ export function useCategorization(
return result.sort( sort );
}, [ categoryMap, sort ] );

const selections = searchParams.get( 'categories' )?.split( ',' ) || [];

const setSelections = ( values: string[] ) => {
setSearchParams( ( currentSearchParams ) => {
if ( values.length > 0 ) {
currentSearchParams.set( 'categories', values.join( ',' ) );
} else {
currentSearchParams.delete( 'categories' );
}
return currentSearchParams;
} );
};
const { selectedCategories, setSelectedCategories } = useDesignPickerFilters();

const onSelect = useCallback(
( value: string ) => {
if ( ! isMultiSelection ) {
handleSelect?.( value );
setSelections( [ value ] );
setSelectedCategories( [ value ] );
return;
}

const currentSelections = searchParams.get( 'categories' )?.split( ',' ) || [];
const index = currentSelections.findIndex( ( selection ) => selection === value );
const index = selectedCategories.findIndex( ( selection ) => selection === value );
if ( index === -1 ) {
handleSelect?.( value );
return setSelections( [ ...currentSelections, value ] );
return setSelectedCategories( [ ...selectedCategories, value ] );
}

// The selections should at least have one.
if ( currentSelections.length > 1 ) {
if ( selectedCategories.length > 1 ) {
handleDeselect?.( value );
return setSelections( [
...currentSelections.slice( 0, index ),
...currentSelections.slice( index + 1 ),
return setSelectedCategories( [
...selectedCategories.slice( 0, index ),
...selectedCategories.slice( index + 1 ),
] );
}
},
[ searchParams, isMultiSelection, setSelections, handleSelect, handleDeselect ]
[ selectedCategories, isMultiSelection, setSelectedCategories, handleSelect, handleDeselect ]
);

useEffect( () => {
if ( selections.length === 0 ) {
setSelections( chooseDefaultSelections( categories, defaultSelections ) );
if ( selectedCategories.length === 0 ) {
setSelectedCategories( chooseDefaultSelections( categories, defaultSelections ) );
}
}, [] );

return {
categories,
selections,
selections: selectedCategories,
onSelect,
};
}
Expand Down
69 changes: 69 additions & 0 deletions packages/design-picker/src/hooks/use-design-picker-filters.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useSearchParams } from 'react-router-dom';

// The `currentSearchParams` parameter from the callback of the `setSearchParams` function
// might not have the latest query parameter on multiple calls at the same time.
const makeSearchParams = (
callback: ( currentSearchParams: URLSearchParams ) => URLSearchParams
) => callback( new URLSearchParams( window.location.search ) );

const useCategoriesFilter = () => {
const [ searchParams, setSearchParams ] = useSearchParams();
const selectedCategories = searchParams.get( 'categories' )?.split( ',' ) || [];
const setSelectedCategories = ( values: string[] ) => {
setSearchParams(
makeSearchParams( ( currentSearchParams ) => {
if ( values.length > 0 ) {
currentSearchParams.set( 'categories', values.join( ',' ) );
} else {
currentSearchParams.delete( 'categories' );
}
return currentSearchParams;
} ),
{ replace: true }
);
};

return { selectedCategories, setSelectedCategories };
};

const useDesignTierFilter = () => {
const [ searchParams, setSearchParams ] = useSearchParams();

const selectedDesignTier = searchParams.get( 'tier' ) ?? '';

const setSelectedDesignTier = ( value: string ) => {
setSearchParams(
makeSearchParams( ( currentSearchParams: any ) => {
if ( value ) {
currentSearchParams.set( 'tier', value );
} else {
currentSearchParams.delete( 'tier' );
}

return currentSearchParams;
} ),
{ replace: true }
);
};

return {
selectedDesignTier,
setSelectedDesignTier,
};
};

export const useDesignPickerFilters = () => {
const { selectedCategories, setSelectedCategories } = useCategoriesFilter();
const { selectedDesignTier, setSelectedDesignTier } = useDesignTierFilter();

return {
selectedCategories,
selectedDesignTier,
setSelectedCategories,
setSelectedDesignTier,
resetFilters: () => {
setSelectedCategories( [] );
setSelectedDesignTier( '' );
},
};
};
15 changes: 6 additions & 9 deletions packages/design-picker/src/hooks/use-filtered-designs.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { useMemo } from 'react';
import { useSearchParams } from 'react-router-dom';
import { isBlankCanvasDesign } from '../utils/available-designs';
import type { Categorization } from './use-categorization';
import { useDesignPickerFilters } from './use-design-picker-filters';
import type { Design } from '../types';

const getDesignSlug = ( design: Design ) => design.recipe?.slug ?? design.slug;
Expand Down Expand Up @@ -51,18 +50,16 @@ export const filterDesigns = (
return filteredDesigns;
};

export const useFilteredDesigns = ( designs: Design[], categorization?: Categorization ) => {
const [ searchParams ] = useSearchParams();

const selectedDesignTier = searchParams.get( 'tier' ) ?? '';
export const useFilteredDesigns = ( designs: Design[] ) => {
const { selectedCategories, selectedDesignTier } = useDesignPickerFilters();

const filteredDesigns = useMemo( () => {
if ( categorization?.selections || selectedDesignTier ) {
return filterDesigns( designs, categorization?.selections, selectedDesignTier );
if ( selectedCategories.length > 0 || selectedDesignTier ) {
return filterDesigns( designs, selectedCategories, selectedDesignTier );
}

return designs;
}, [ designs, categorization?.selections, selectedDesignTier ] );
}, [ designs, selectedCategories, selectedDesignTier ] );

return filteredDesigns;
};
1 change: 1 addition & 0 deletions packages/design-picker/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,5 @@ export type {
StyleVariationStylesColor,
} from './types';
export { useCategorization } from './hooks/use-categorization';
export { useDesignPickerFilters } from './hooks/use-design-picker-filters';
export { useThemeDesignsQuery } from './hooks/use-theme-designs-query';

0 comments on commit a13f767

Please sign in to comment.