Skip to content

Commit 47eab25

Browse files
committed
fix: commerce pages in ssr
1 parent 8048bc6 commit 47eab25

12 files changed

Lines changed: 128 additions & 24 deletions

File tree

packages/react/src/contents/hooks/__tests__/useCommercePages.test.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
mockCommercePagesInitialState,
77
mockCommercePagesLoadingState,
88
mockCommercePagesState,
9+
slug,
910
} from 'tests/__fixtures__/contents/index.mjs';
1011
import { fetchCommercePages } from '@farfetch/blackout-redux';
1112
import { withStore } from '../../../../tests/helpers/index.js';
@@ -84,6 +85,7 @@ describe('useCommercePages', () => {
8485

8586
expect(fetchCommercePages).toHaveBeenCalledWith(
8687
{
88+
slug,
8789
brand: commercePageQuery.brand,
8890
category: commercePageQuery.category,
8991
contentTypeCode: commercePageQuery.contentTypeCode,
@@ -124,6 +126,7 @@ describe('useCommercePages', () => {
124126

125127
expect(fetchCommercePages).toHaveBeenCalledWith(
126128
{
129+
slug,
127130
brand: commercePageQuery.brand,
128131
category: commercePageQuery.category,
129132
contentTypeCode: commercePageQuery.contentTypeCode,

packages/react/src/contents/hooks/__tests__/useContentPage.test.tsx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { cleanup, renderHook } from '@testing-library/react';
22
import { ContentPageType } from '@farfetch/blackout-client';
33
import { fetchContentPage } from '@farfetch/blackout-redux';
44
import {
5+
mockCommercePageWithDataState,
56
mockContentPageEntry,
67
mockContentPageErrorState,
78
mockContentPageInitialState,
@@ -102,6 +103,34 @@ describe('useContentPage', () => {
102103

103104
expect(fetchContentPage).not.toHaveBeenCalled();
104105
});
106+
107+
it('should return values correctly with commercePagesHash option', () => {
108+
const { result } = renderHook(
109+
() =>
110+
useContentPage(
111+
ContentPageType.Listing,
112+
{ slug },
113+
{ isCommercePage: true },
114+
),
115+
{
116+
wrapper: withStore(mockCommercePageWithDataState),
117+
},
118+
);
119+
120+
expect(result.current).toStrictEqual({
121+
data: [
122+
mockCommercePageWithDataState.entities.contents[
123+
mockContentPageEntry.publicationId
124+
],
125+
],
126+
isLoading: false,
127+
error: null,
128+
isFetched: true,
129+
actions: {
130+
fetch: expect.any(Function),
131+
},
132+
});
133+
});
105134
});
106135

107136
describe('actions', () => {

packages/react/src/contents/hooks/types/useCommercePages.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { CommercePagesRankingStrategy } from '@farfetch/blackout-redux';
22
import type { Config, QueryCommercePages } from '@farfetch/blackout-client';
33

44
export interface UseCommercePagesOptions extends QueryCommercePages {
5+
slug: string;
56
enableAutoFetch?: boolean;
67
strategy?: CommercePagesRankingStrategy;
78
fetchConfig?: Config;

packages/react/src/contents/hooks/types/useContentPage.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ import type { Config } from '@farfetch/blackout-client';
33
export interface UseContentPageOptions {
44
enableAutoFetch?: boolean;
55
fetchConfig?: Config;
6+
isCommercePage?: boolean;
67
}

packages/react/src/contents/hooks/useCommercePages.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const useCommercePages = <T = ComponentType[]>(
2929
const query = useMemo(
3030
() => ({
3131
contentTypeCode: ContentTypeCode.CommercePages,
32-
...fetchQuery,
32+
codes: fetchQuery.slug,
3333
}),
3434
[fetchQuery],
3535
);

packages/react/src/contents/hooks/useContentPage.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,20 @@ const useContentPage = <T = [ComponentType]>(
2424
) => {
2525
const store = useStore();
2626

27-
const { enableAutoFetch = true, fetchConfig } = options;
27+
const {
28+
enableAutoFetch = true,
29+
fetchConfig,
30+
isCommercePage = false,
31+
} = options;
2832

2933
const query = useMemo(
3034
() => ({
31-
contentTypeCode: ContentTypeCode.ContentPage,
32-
codes: fetchQuery.slug.split('?')[0] as string,
35+
contentTypeCode: isCommercePage
36+
? ContentTypeCode.CommercePages
37+
: ContentTypeCode.ContentPage,
38+
codes: fetchQuery.slug,
3339
}),
34-
[fetchQuery.slug],
40+
[fetchQuery.slug, isCommercePage],
3541
);
3642

3743
const fetchQueryWithoutSlug = useMemo(() => {

packages/redux/src/contents/actions/factories/fetchCommercePagesFactory.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import {
77
type CommercePages,
88
type Config,
99
type GetCommercePages,
10-
type QueryCommercePages,
1110
toBlackoutError,
1211
} from '@farfetch/blackout-client';
1312
import {
1413
type CommercePagesRankingStrategy,
1514
ContentTypeCode,
1615
type FetchCommercePagesAction,
16+
type QueryCommercePagesWithSlug,
1717
} from '../../types/index.js';
1818
import { contentEntries } from '../../../entities/schemas/content.js';
1919
import { normalize } from 'normalizr';
@@ -29,7 +29,7 @@ import type { Dispatch } from 'redux';
2929
const fetchCommercePagesFactory =
3030
(getCommercePages: GetCommercePages) =>
3131
(
32-
query: QueryCommercePages,
32+
query: QueryCommercePagesWithSlug,
3333
strategy?: CommercePagesRankingStrategy,
3434
config?: Config,
3535
) =>
@@ -39,17 +39,19 @@ const fetchCommercePagesFactory =
3939
let hash: string | undefined;
4040

4141
try {
42+
const { slug, ...queryWithoutSlug } = query;
43+
4244
hash = generateContentHash({
4345
contentTypeCode: ContentTypeCode.CommercePages,
44-
...query,
46+
codes: slug,
4547
});
4648

4749
dispatch({
4850
payload: { hash },
4951
type: actionTypes.FETCH_COMMERCE_PAGES_REQUEST,
5052
});
5153

52-
const result = await getCommercePages(query, config);
54+
const result = await getCommercePages(queryWithoutSlug, config);
5355
const rankedResult = applyCommercePagesRankingStrategy(result, strategy);
5456

5557
dispatch({

packages/redux/src/contents/serverInitialState.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1+
import {
2+
applyCommercePagesRankingStrategy,
3+
generateContentHash,
4+
} from './utils.js';
15
import { buildQueryStringFromObject } from '../helpers/index.js';
26
import { contentEntries } from '../entities/schemas/content.js';
3-
import { generateContentHash } from './utils.js';
7+
import { type ContentsState } from './types/index.js';
48
import { get, merge } from 'lodash-es';
59
import { INITIAL_STATE_CONTENT } from './reducer.js';
610
import { normalize } from 'normalizr';
711
import parse from 'url-parse';
8-
import type { ContentsState } from './types/index.js';
912
import type { ServerInitialState } from '../types/serverInitialState.types.js';
1013

1114
/**
@@ -15,28 +18,34 @@ import type { ServerInitialState } from '../types/serverInitialState.types.js';
1518
*
1619
* @returns Initial state for the contents reducer.
1720
*/
18-
const serverInitialState: ServerInitialState = ({ model }) => {
21+
const serverInitialState: ServerInitialState = ({ model, strategy }) => {
1922
if (!get(model, 'searchContentRequests')) {
2023
return { contents: INITIAL_STATE_CONTENT };
2124
}
2225

2326
const { searchContentRequests, slug, seoMetadata, subfolder } = model;
27+
const url = subfolder !== '/' ? slug?.replace(subfolder, '') : slug;
28+
const normalizedUrl = url.replace('?json=true', '').replace('&json=true', '');
2429

2530
const contents = searchContentRequests.reduce((acc, item) => {
26-
const { searchResponse } = item;
27-
const firstSearchResponseItem = searchResponse.entries[0];
28-
29-
if (!firstSearchResponseItem) {
30-
return acc;
31-
}
32-
31+
const {
32+
searchResponse,
33+
filters: { codes, contentTypeCode },
34+
} = item;
35+
let response = searchResponse;
36+
const isCommercePage = contentTypeCode === 'commerce_pages';
37+
const code = isCommercePage ? normalizedUrl : codes?.[0];
3338
const hash = generateContentHash({
34-
codes: firstSearchResponseItem.code,
35-
contentTypeCode: firstSearchResponseItem.contentTypeCode,
39+
codes: code,
40+
contentTypeCode: contentTypeCode,
3641
});
3742

43+
if (isCommercePage) {
44+
response = applyCommercePagesRankingStrategy(searchResponse, strategy);
45+
}
46+
3847
const { entities, result } = {
39-
...normalize({ hash, ...searchResponse }, contentEntries),
48+
...normalize({ hash, ...response }, contentEntries),
4049
};
4150

4251
return merge(acc, {
@@ -53,7 +62,6 @@ const serverInitialState: ServerInitialState = ({ model }) => {
5362
});
5463
}, {});
5564

56-
const url = subfolder !== '/' ? slug?.replace(subfolder, '') : slug;
5765
const { pathname, query } = parse(url, true);
5866

5967
delete query.json;

packages/redux/src/contents/types/actions.types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
BlackoutError,
55
Contents,
66
ContentType,
7+
QueryCommercePages,
78
SEOMetadata,
89
} from '@farfetch/blackout-client';
910
import type { ContentEntity } from '../../entities/index.js';
@@ -22,6 +23,10 @@ export type ContentsPayload = NormalizedSchema<
2223
ContentsNormalized
2324
> & { hash: Hash };
2425

26+
export interface QueryCommercePagesWithSlug extends QueryCommercePages {
27+
slug: string;
28+
}
29+
2530
/**
2631
* Fetch Content Page Action
2732
*/

packages/redux/src/types/serverInitialState.types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
import type { CommercePagesRankingStrategy } from '../contents/types/commercePagesRankingStrategy.types.js';
12
import type { LocaleState } from '../locale/index.js';
23
import type { Model } from './model.types.js';
34
import type { ProductsState } from '../products/index.js';
45
import type { StoreState } from './storeState.types.js';
56

67
export type ServerInitialState = (data: {
78
model: Model;
9+
strategy?: CommercePagesRankingStrategy;
810
options?: { productImgQueryParam?: string };
911
}) => Omit<StoreState, 'products' | 'locale'> & {
1012
products?: Partial<ProductsState>;

0 commit comments

Comments
 (0)