44import { __ , sprintf } from '@wordpress/i18n' ;
55import { useQueryStateByKey } from '@woocommerce/base-context/hooks' ;
66import { getSetting , getSettingWithCoercion } from '@woocommerce/settings' ;
7- import { useMemo , useEffect } from '@wordpress/element' ;
7+ import { useMemo , useEffect , useState } from '@wordpress/element' ;
88import classnames from 'classnames' ;
99import PropTypes from 'prop-types' ;
1010import Label from '@woocommerce/base-components/label' ;
@@ -16,6 +16,8 @@ import {
1616 isStockStatusOptions ,
1717} from '@woocommerce/types' ;
1818import { getUrlParameter } from '@woocommerce/utils' ;
19+ import FilterTitlePlaceholder from '@woocommerce/base-components/filter-placeholder' ;
20+ import { useIsMounted } from '@woocommerce/base-hooks' ;
1921
2022/**
2123 * Internal dependencies
@@ -27,8 +29,11 @@ import {
2729 renderRemovableListItem ,
2830 removeArgsFromFilterUrl ,
2931 cleanFilterUrl ,
32+ maybeUrlContainsFilters ,
33+ urlContainsAttributeFilter ,
3034} from './utils' ;
3135import ActiveAttributeFilters from './active-attribute-filters' ;
36+ import FilterPlaceholders from './filter-placeholders' ;
3237import { Attributes } from './types' ;
3338
3439/**
@@ -45,11 +50,20 @@ const ActiveFiltersBlock = ( {
4550 attributes : Attributes ;
4651 isEditor ?: boolean ;
4752} ) => {
53+ const isMounted = useIsMounted ( ) ;
54+ const componentHasMounted = isMounted ( ) ;
4855 const filteringForPhpTemplate = getSettingWithCoercion (
4956 'is_rendering_php_template' ,
5057 false ,
5158 isBoolean
5259 ) ;
60+ const [ isLoading , setIsLoading ] = useState ( true ) ;
61+ /*
62+ activeAttributeFilters is the only async query in this block. Because of this the rest of the filters will render null
63+ when in a loading state and activeAttributeFilters renders the placeholders.
64+ */
65+ const shouldShowLoadingPlaceholders =
66+ maybeUrlContainsFilters ( ) && ! isEditor && isLoading ;
5367 const [ productAttributes , setProductAttributes ] = useQueryStateByKey (
5468 'attributes' ,
5569 [ ]
@@ -62,8 +76,10 @@ const ActiveFiltersBlock = ( {
6276 const [ maxPrice , setMaxPrice ] = useQueryStateByKey ( 'max_price' ) ;
6377
6478 const STOCK_STATUS_OPTIONS = getSetting ( 'stockStatusOptions' , [ ] ) ;
79+ const STORE_ATTRIBUTES = getSetting ( 'attributes' , [ ] ) ;
6580 const activeStockStatusFilters = useMemo ( ( ) => {
6681 if (
82+ shouldShowLoadingPlaceholders ||
6783 productStockStatus . length === 0 ||
6884 ! isStockStatusQueryCollection ( productStockStatus ) ||
6985 ! isStockStatusOptions ( STOCK_STATUS_OPTIONS )
@@ -92,6 +108,7 @@ const ActiveFiltersBlock = ( {
92108 } ) ;
93109 } ) ;
94110 } , [
111+ shouldShowLoadingPlaceholders ,
95112 STOCK_STATUS_OPTIONS ,
96113 productStockStatus ,
97114 setProductStockStatus ,
@@ -100,7 +117,10 @@ const ActiveFiltersBlock = ( {
100117 ] ) ;
101118
102119 const activePriceFilters = useMemo ( ( ) => {
103- if ( ! Number . isFinite ( minPrice ) && ! Number . isFinite ( maxPrice ) ) {
120+ if (
121+ shouldShowLoadingPlaceholders ||
122+ ( ! Number . isFinite ( minPrice ) && ! Number . isFinite ( maxPrice ) )
123+ ) {
104124 return null ;
105125 }
106126 return renderRemovableListItem ( {
@@ -116,6 +136,7 @@ const ActiveFiltersBlock = ( {
116136 displayStyle : blockAttributes . displayStyle ,
117137 } ) ;
118138 } , [
139+ shouldShowLoadingPlaceholders ,
119140 minPrice ,
120141 maxPrice ,
121142 blockAttributes . displayStyle ,
@@ -125,7 +146,13 @@ const ActiveFiltersBlock = ( {
125146 ] ) ;
126147
127148 const activeAttributeFilters = useMemo ( ( ) => {
128- if ( ! isAttributeQueryCollection ( productAttributes ) ) {
149+ if (
150+ ( ! isAttributeQueryCollection ( productAttributes ) &&
151+ componentHasMounted ) ||
152+ ( ! productAttributes . length &&
153+ ! urlContainsAttributeFilter ( STORE_ATTRIBUTES ) )
154+ ) {
155+ setIsLoading ( false ) ;
129156 return null ;
130157 }
131158
@@ -135,6 +162,7 @@ const ActiveFiltersBlock = ( {
135162 ) ;
136163
137164 if ( ! attributeObject ) {
165+ setIsLoading ( false ) ;
138166 return null ;
139167 }
140168
@@ -145,10 +173,16 @@ const ActiveFiltersBlock = ( {
145173 slugs = { attribute . slug }
146174 key = { attribute . attribute }
147175 operator = { attribute . operator }
176+ isLoadingCallback = { setIsLoading }
148177 />
149178 ) ;
150179 } ) ;
151- } , [ productAttributes , blockAttributes . displayStyle ] ) ;
180+ } , [
181+ componentHasMounted ,
182+ setIsLoading ,
183+ productAttributes ,
184+ blockAttributes . displayStyle ,
185+ ] ) ;
152186
153187 const [ productRatings , setProductRatings ] =
154188 useQueryStateByKey ( 'ratings' ) ;
@@ -177,6 +211,7 @@ const ActiveFiltersBlock = ( {
177211
178212 const activeRatingFilters = useMemo ( ( ) => {
179213 if (
214+ shouldShowLoadingPlaceholders ||
180215 productRatings . length === 0 ||
181216 ! isRatingQueryCollection ( productRatings )
182217 ) {
@@ -206,6 +241,7 @@ const ActiveFiltersBlock = ( {
206241 } ) ;
207242 } ) ;
208243 } , [
244+ shouldShowLoadingPlaceholders ,
209245 productRatings ,
210246 setProductRatings ,
211247 blockAttributes . displayStyle ,
@@ -222,12 +258,25 @@ const ActiveFiltersBlock = ( {
222258 ) ;
223259 } ;
224260
225- if ( ! hasFilters ( ) && ! isEditor ) {
261+ if ( ! shouldShowLoadingPlaceholders && ! hasFilters ( ) && ! isEditor ) {
226262 return null ;
227263 }
228264
229265 const TagName =
230266 `h${ blockAttributes . headingLevel } ` as keyof JSX . IntrinsicElements ;
267+
268+ const heading = (
269+ < TagName className = "wc-block-active-filters__title" >
270+ { blockAttributes . heading }
271+ </ TagName >
272+ ) ;
273+
274+ const filterHeading = shouldShowLoadingPlaceholders ? (
275+ < FilterTitlePlaceholder > { heading } </ FilterTitlePlaceholder >
276+ ) : (
277+ heading
278+ ) ;
279+
231280 const hasFilterableProducts = getSettingWithCoercion (
232281 'has_filterable_products' ,
233282 false ,
@@ -241,15 +290,12 @@ const ActiveFiltersBlock = ( {
241290 const listClasses = classnames ( 'wc-block-active-filters__list' , {
242291 'wc-block-active-filters__list--chips' :
243292 blockAttributes . displayStyle === 'chips' ,
293+ 'wc-block-active-filters--loading' : shouldShowLoadingPlaceholders ,
244294 } ) ;
245295
246296 return (
247297 < >
248- { ! isEditor && blockAttributes . heading && (
249- < TagName className = "wc-block-active-filters__title" >
250- { blockAttributes . heading }
251- </ TagName >
252- ) }
298+ { ! isEditor && blockAttributes . heading && filterHeading }
253299 < div className = "wc-block-active-filters" >
254300 < ul className = { listClasses } >
255301 { isEditor ? (
@@ -279,36 +325,44 @@ const ActiveFiltersBlock = ( {
279325 </ >
280326 ) : (
281327 < >
328+ < FilterPlaceholders
329+ isLoading = { shouldShowLoadingPlaceholders }
330+ displayStyle = { blockAttributes . displayStyle }
331+ />
282332 { activePriceFilters }
283333 { activeStockStatusFilters }
284334 { activeAttributeFilters }
285335 { activeRatingFilters }
286336 </ >
287337 ) }
288338 </ ul >
289- < button
290- className = "wc-block-active-filters__clear-all"
291- onClick = { ( ) => {
292- cleanFilterUrl ( ) ;
293- if ( ! filteringForPhpTemplate ) {
294- setMinPrice ( undefined ) ;
295- setMaxPrice ( undefined ) ;
296- setProductAttributes ( [ ] ) ;
297- setProductStockStatus ( [ ] ) ;
298- }
299- } }
300- >
301- < Label
302- label = { __ (
303- 'Clear All' ,
304- 'woo-gutenberg-products-block'
305- ) }
306- screenReaderLabel = { __ (
307- 'Clear All Filters' ,
308- 'woo-gutenberg-products-block'
309- ) }
310- />
311- </ button >
339+ { shouldShowLoadingPlaceholders ? (
340+ < span className = "wc-block-active-filters__clear-all-placeholder" />
341+ ) : (
342+ < button
343+ className = "wc-block-active-filters__clear-all"
344+ onClick = { ( ) => {
345+ cleanFilterUrl ( ) ;
346+ if ( ! filteringForPhpTemplate ) {
347+ setMinPrice ( undefined ) ;
348+ setMaxPrice ( undefined ) ;
349+ setProductAttributes ( [ ] ) ;
350+ setProductStockStatus ( [ ] ) ;
351+ }
352+ } }
353+ >
354+ < Label
355+ label = { __ (
356+ 'Clear All' ,
357+ 'woo-gutenberg-products-block'
358+ ) }
359+ screenReaderLabel = { __ (
360+ 'Clear All Filters' ,
361+ 'woo-gutenberg-products-block'
362+ ) }
363+ />
364+ </ button >
365+ ) }
312366 </ div >
313367 </ >
314368 ) ;
0 commit comments