Skip to content

Commit

Permalink
Pattern Library: Use new API endpoint in usePatternCategories (#88197)
Browse files Browse the repository at this point in the history
* Use `/ptk/categories` API endpoint in `usePatternCategories`

* Fix 404 page

* Fix test

* No fiddling with aspect-ratios in this PR

* Address review suggestions

* Fix import

* Use `label` instead of `title`

* More label
  • Loading branch information
fredrikekelund authored Mar 7, 2024
1 parent 52a957f commit 642ef7a
Show file tree
Hide file tree
Showing 10 changed files with 117 additions and 119 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const useAssemblerPatterns = (
queryOptions: Omit< UseQueryOptions< any, unknown, Pattern[] >, 'queryKey' > = {}
): Pattern[] => {
const { data } = useQuery< any, unknown, Pattern[] >( {
queryKey: [ 'patterns', 'assembler', lang ],
queryKey: [ 'pattern-assembler', lang ],
queryFn: () => {
return wpcomRequest( {
path: `/ptk/patterns/${ lang }`,
Expand Down
7 changes: 3 additions & 4 deletions client/my-sites/patterns/components/grid-gallery/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { PatternsSection } from 'calypso/my-sites/patterns/components/section';
import type { CSSProperties } from 'react';

import './style.scss';

Expand All @@ -9,7 +8,7 @@ type PatternsGridGalleryProps = {
columnCount?: number;
list?: {
name?: string;
label?: string;
label: string;
number: number;
image: string;
link: string;
Expand All @@ -30,14 +29,14 @@ export const PatternsGridGallery = ( {
<PatternsSection title={ title } description={ description }>
<div
className="patterns-grid-gallery"
style={ { '--column-count': columnCount } as CSSProperties }
style={ { '--column-count': columnCount } as React.CSSProperties }
>
{ list.map( ( { name, label, number, image, link } ) => (
<a className="patterns-grid-gallery__item" href={ link } key={ name }>
<div className="patterns-grid-gallery__item-image">
<img src={ image } alt={ label } />
</div>
<div className="patterns-grid-gallery__item-name">{ name }</div>
<div className="patterns-grid-gallery__item-name">{ label }</div>
<div className="patterns-grid-gallery__item-number">{ number } patterns</div>
</a>
) ) }
Expand Down
6 changes: 0 additions & 6 deletions client/my-sites/patterns/controller.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
import { PATTERN_CATEGORIES } from 'calypso/my-sites/patterns/hooks/use-pattern-categories';

export const RENDERER_SITE_ID = 226011606; // assemblerdemo

export function getPatternCategorySlugs() {
return PATTERN_CATEGORIES.join( '|' );
}
21 changes: 12 additions & 9 deletions client/my-sites/patterns/home/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { PatternsGetStarted } from 'calypso/my-sites/patterns/components/get-sta
import { PatternsGridGallery } from 'calypso/my-sites/patterns/components/grid-gallery';
import { PatternsHeader } from 'calypso/my-sites/patterns/components/header';
import { PatternsSection } from 'calypso/my-sites/patterns/components/section';
import { RENDERER_SITE_ID } from 'calypso/my-sites/patterns/controller';
import { usePatternCategories } from 'calypso/my-sites/patterns/hooks/use-pattern-categories';
import { usePatterns } from 'calypso/my-sites/patterns/hooks/use-patterns';
import { useSelector } from 'calypso/state';
Expand Down Expand Up @@ -35,7 +34,7 @@ export const PatternsHomePage = ( {
const locale = useLocale();
const isLoggedIn = useSelector( isUserLoggedIn );

const { data: categories } = usePatternCategories( locale, RENDERER_SITE_ID );
const { data: categories } = usePatternCategories( locale );
const { data: patterns } = usePatterns( locale, category );

return (
Expand All @@ -56,11 +55,12 @@ export const PatternsHomePage = ( {
list={ categories?.map( ( category ) => ( {
name: category.name,
label: category.label,
number: 15,
number: category.regularPatternCount,
image: ImgPattern,
link: `/patterns/${ category.name }`,
} ) ) }
/>

<PatternGallery patterns={ patterns } isGridView={ isGridView } />

<PatternsSection
Expand Down Expand Up @@ -116,12 +116,15 @@ export const PatternsHomePage = ( {
title="Beautifully curated page layouts"
description="Entire pages built of patterns, ready to be added to your site."
columnCount={ 3 }
list={ Array.from( Array( 5 ) ).map( () => ( {
name: 'About',
number: 7,
image: ImgLayout,
link: '#',
} ) ) }
list={ categories
?.filter( ( { pagePatternCount } ) => pagePatternCount )
.map( ( category ) => ( {
name: category.name,
label: category.label,
number: category.pagePatternCount,
image: ImgLayout,
link: `/patterns/${ category.name }`,
} ) ) }
/>

<PatternsGetStarted />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,11 @@ describe( 'usePatternCategories', () => {
test( 'calls the API endpoint with the right parameters', async () => {
( wpcom.req.get as jest.MockedFunction< typeof wpcom.req.get > ).mockResolvedValue( [] );

const { result } = renderHook( () => usePatternCategories( 'fr', 12345 ), { wrapper } );
const { result } = renderHook( () => usePatternCategories( 'fr' ), { wrapper } );

await waitFor( () => expect( result.current.isSuccess ).toBe( true ) );

expect( wpcom.req.get ).toHaveBeenCalledWith( '/sites/12345/block-patterns/categories', {
apiNamespace: 'wp/v2',
_locale: 'fr',
} );
expect( wpcom.req.get ).toHaveBeenCalledWith( '/ptk/categories/fr' );
expect( result.current.data ).toEqual( [] );
} );

Expand All @@ -54,7 +51,7 @@ describe( 'usePatternCategories', () => {
categories
);

const { result } = renderHook( () => usePatternCategories( 'fr', 12345 ), { wrapper } );
const { result } = renderHook( () => usePatternCategories( 'fr' ), { wrapper } );

await waitFor( () => expect( result.current.isSuccess ).toBe( true ) );

Expand Down
69 changes: 14 additions & 55 deletions client/my-sites/patterns/hooks/use-pattern-categories.ts
Original file line number Diff line number Diff line change
@@ -1,75 +1,34 @@
import { useQuery, UseQueryOptions } from '@tanstack/react-query';
import wpcom from 'calypso/lib/wp';
import type { Category } from 'calypso/my-sites/patterns/types';

export const PATTERN_CATEGORIES = [
'featured',
'intro',
'about',
// 'buttons',
// 'banner',
// 'query',
'blog',
'posts',
// 'call-to-action',
// 'columns',
// 'coming-soon',
'contact',
'footer',
'forms',
'gallery',
'header',
// 'link-in-bio',
// 'media',
'newsletter',
// 'podcast',
'portfolio', // For page patterns only in v1
// 'quotes',
'services',
'store',
// 'team',
'testimonials', // Reused as "Quotes"
// 'text',
];
import type { Category, CategorySnakeCase } from 'calypso/my-sites/patterns/types';

export function getPatternCategoriesQueryOptions(
locale: string,
siteId: undefined | number,
queryOptions: Omit< UseQueryOptions< Category[] >, 'queryKey' > = {}
): UseQueryOptions< Category[] > {
return {
queryKey: [ locale, siteId, 'pattern-library', 'categories' ],
queryKey: [ 'pattern-library', 'categories', locale ],
queryFn() {
return wpcom.req.get(
`/sites/${ encodeURIComponent( siteId ?? '' ) }/block-patterns/categories`,
{
apiNamespace: 'wp/v2',
_locale: locale,
}
);
},
select( categories ) {
const result = [];

for ( const name of PATTERN_CATEGORIES ) {
const category = categories.find( ( category ) => category.name === name );
if ( category ) {
result.push( category );
}
}

return result;
return wpcom.req
.get( `/ptk/categories/${ locale }` )
.then( ( categories: CategorySnakeCase[] ) => {
return categories.map(
( { regular_cattern_count, page_pattern_count, ...restCategory } ) => ( {
...restCategory,
pagePatternCount: page_pattern_count,
regularPatternCount: regular_cattern_count,
} )
);
} );
},
staleTime: Infinity,
...queryOptions,
enabled: !! siteId,
};
}

export function usePatternCategories(
locale: string,
siteId: undefined | number,
queryOptions: Omit< UseQueryOptions< Category[] >, 'queryKey' > = {}
) {
return useQuery< Category[] >( getPatternCategoriesQueryOptions( locale, siteId, queryOptions ) );
return useQuery< Category[] >( getPatternCategoriesQueryOptions( locale, queryOptions ) );
}
2 changes: 1 addition & 1 deletion client/my-sites/patterns/hooks/use-patterns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function getPatternsQueryOptions(
queryOptions: Omit< UseQueryOptions< Pattern[] >, 'queryKey' > = {}
) {
return {
queryKey: [ 'patterns', 'library', locale, category ],
queryKey: [ 'pattern-library', 'patterns', locale, category ],
queryFn: () => {
return wpcom.req.get( `/ptk/patterns/${ locale }`, {
categories: category,
Expand Down
47 changes: 27 additions & 20 deletions client/my-sites/patterns/index.node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import { getLanguageRouteParam } from '@automattic/i18n-utils';
import { makeLayout, ssrSetupLocale } from 'calypso/controller';
import { setHrefLangLinks, setLocalizedCanonicalUrl } from 'calypso/controller/localized-links';
import { PatternGalleryServer } from 'calypso/my-sites/patterns/components/pattern-gallery/server';
import { RENDERER_SITE_ID, getPatternCategorySlugs } from 'calypso/my-sites/patterns/controller';
import { PatternsHomePage } from 'calypso/my-sites/patterns/home';
import { getPatternCategoriesQueryOptions } from 'calypso/my-sites/patterns/hooks/use-pattern-categories';
import { getPatternsQueryOptions } from 'calypso/my-sites/patterns/hooks/use-patterns';
import { serverRouter } from 'calypso/server/isomorphic-routing';
import { getCurrentUserLocale } from 'calypso/state/current-user/selectors';
import type { RouterContext, RouterNext, Category, Pattern } from 'calypso/my-sites/patterns/types';
import type { RouterContext, RouterNext, Pattern } from 'calypso/my-sites/patterns/types';

function renderPatterns( context: RouterContext, next: RouterNext ) {
context.primary = (
Expand All @@ -22,7 +21,7 @@ function renderPatterns( context: RouterContext, next: RouterNext ) {
next();
}

function fetchPatterns( context: RouterContext, next: RouterNext ) {
function fetchCategoriesAndPatterns( context: RouterContext, next: RouterNext ) {
const { cachedMarkup, queryClient, lang, params, store } = context;

if ( cachedMarkup ) {
Expand All @@ -32,19 +31,31 @@ function fetchPatterns( context: RouterContext, next: RouterNext ) {

const locale = getCurrentUserLocale( store.getState() ) || lang || 'en';

const categoryPromise = queryClient.fetchQuery< Category[] >(
getPatternCategoriesQueryOptions( locale, RENDERER_SITE_ID, {
staleTime: 10 * 60 * 1000,
} )
);
// Fetches the list of categories first, then fetches patterns if a specific category was requested
queryClient
.fetchQuery(
getPatternCategoriesQueryOptions( locale, {
staleTime: 10 * 60 * 1000,
} )
)
.then( ( categories ) => {
if ( ! params.category ) {
return;
}

const patternPromise = params.category
? queryClient.fetchQuery< Pattern[] >(
getPatternsQueryOptions( locale, params.category, { staleTime: 10 * 60 * 1000 } )
)
: Promise.resolve();
const categoryNames = categories.map( ( category ) => category.name );

Promise.all( [ categoryPromise, patternPromise ] )
if ( ! categoryNames.includes( params.category ) ) {
throw {
status: 404,
message: 'Category Not Found',
};
}

return queryClient.fetchQuery< Pattern[] >(
getPatternsQueryOptions( locale, params.category, { staleTime: 10 * 60 * 1000 } )
);
} )
.then( () => {
next();
} )
Expand All @@ -55,17 +66,13 @@ function fetchPatterns( context: RouterContext, next: RouterNext ) {

export default function ( router: ReturnType< typeof serverRouter > ) {
const langParam = getLanguageRouteParam();
const categorySlugs = getPatternCategorySlugs();

router(
[
`/${ langParam }/patterns/:category(${ categorySlugs })?`,
`/patterns/:category(${ categorySlugs })?`,
],
[ `/${ langParam }/patterns/:category?`, `/patterns/:category?` ],
ssrSetupLocale,
setHrefLangLinks,
setLocalizedCanonicalUrl,
fetchPatterns,
fetchCategoriesAndPatterns,
renderPatterns,
makeLayout
);
Expand Down
50 changes: 38 additions & 12 deletions client/my-sites/patterns/index.web.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,59 @@ import {
makeLayout,
redirectWithoutLocaleParamInFrontIfLoggedIn,
render as clientRender,
notFound,
} from 'calypso/controller/index.web';
import { PatternGalleryClient } from 'calypso/my-sites/patterns/components/pattern-gallery/client';
import { getPatternCategorySlugs } from 'calypso/my-sites/patterns/controller';
import { PatternsHomePage } from 'calypso/my-sites/patterns/home';
import { getCurrentUserLocale } from 'calypso/state/current-user/selectors';
import { getPatternCategoriesQueryOptions } from './hooks/use-pattern-categories';
import type { RouterContext, RouterNext } from 'calypso/my-sites/patterns/types';

function renderPatterns( context: RouterContext, next: RouterNext ) {
context.primary = (
<PatternsHomePage
category={ context.params.category }
isGridView={ !! context.query.grid }
patternGallery={ PatternGalleryClient }
/>
);
if ( ! context.primary ) {
context.primary = (
<PatternsHomePage
category={ context.params.category }
isGridView={ !! context.query.grid }
patternGallery={ PatternGalleryClient }
/>
);
}

next();
}

function checkCategorySlug( context: RouterContext, next: RouterNext ) {
const { queryClient, lang, params, store } = context;
const locale = getCurrentUserLocale( store.getState() ) || lang || 'en';

queryClient
.fetchQuery( getPatternCategoriesQueryOptions( locale ) )
.then( ( categories ) => {
if ( params.category ) {
const categoryNames = categories.map( ( category ) => category.name );

if ( ! categoryNames.includes( params.category ) ) {
notFound( context, next );
return;
}
}

next();
} )
.catch( ( error ) => {
next( error );
} );
}

export default function ( router: typeof clientRouter ) {
const langParam = getLanguageRouteParam();
const categorySlugs = getPatternCategorySlugs();
const middleware = [ renderPatterns, makeLayout, clientRender ];
const middleware = [ checkCategorySlug, renderPatterns, makeLayout, clientRender ];

router(
`/${ langParam }/patterns/:category(${ categorySlugs })?`,
`/${ langParam }/patterns/:category?`,
redirectWithoutLocaleParamInFrontIfLoggedIn,
...middleware
);
router( `/patterns/:category(${ categorySlugs })?`, ...middleware );
router( `/patterns/:category?`, ...middleware );
}
Loading

0 comments on commit 642ef7a

Please sign in to comment.