-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(react|redux): commerce pages in ssr not working #960
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,14 +24,20 @@ const useContentPage = <T = [ComponentType]>( | |
) => { | ||
const store = useStore(); | ||
|
||
const { enableAutoFetch = true, fetchConfig } = options; | ||
const { | ||
enableAutoFetch = true, | ||
fetchConfig, | ||
isCommercePage = false, | ||
} = options; | ||
|
||
const query = useMemo( | ||
() => ({ | ||
contentTypeCode: ContentTypeCode.ContentPage, | ||
codes: fetchQuery.slug.split('?')[0] as string, | ||
contentTypeCode: isCommercePage | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not understand this approach. Why would the user need to set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Currently, to distinguish from the fetch to commerce pages endpoint directly we use the contentType commercePages and for the request to Serverless API, we use contentType contentPages, to generate the hash There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, but in that case, why not use the |
||
? ContentTypeCode.CommercePages | ||
: ContentTypeCode.ContentPage, | ||
codes: fetchQuery.slug, | ||
}), | ||
[fetchQuery.slug], | ||
[fetchQuery.slug, isCommercePage], | ||
); | ||
|
||
const fetchQueryWithoutSlug = useMemo(() => { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,13 +7,13 @@ import { | |
type CommercePages, | ||
type Config, | ||
type GetCommercePages, | ||
type QueryCommercePages, | ||
toBlackoutError, | ||
} from '@farfetch/blackout-client'; | ||
import { | ||
type CommercePagesRankingStrategy, | ||
ContentTypeCode, | ||
type FetchCommercePagesAction, | ||
type QueryCommercePagesWithSlug, | ||
} from '../../types/index.js'; | ||
import { contentEntries } from '../../../entities/schemas/content.js'; | ||
import { normalize } from 'normalizr'; | ||
|
@@ -29,7 +29,7 @@ import type { Dispatch } from 'redux'; | |
const fetchCommercePagesFactory = | ||
(getCommercePages: GetCommercePages) => | ||
( | ||
query: QueryCommercePages, | ||
query: QueryCommercePagesWithSlug, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be a breaking change, can't you calculate a default value for the slug or at least make it optional? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Only BG is using the commerce pages of this package version. We can change this an talk to them to implement this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our boilerplate is also making use of this, so we would have to update it as well. |
||
strategy?: CommercePagesRankingStrategy, | ||
config?: Config, | ||
) => | ||
|
@@ -39,17 +39,19 @@ const fetchCommercePagesFactory = | |
let hash: string | undefined; | ||
|
||
try { | ||
const { slug, ...queryWithoutSlug } = query; | ||
|
||
hash = generateContentHash({ | ||
contentTypeCode: ContentTypeCode.CommercePages, | ||
...query, | ||
codes: slug, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will make requests for commerce pages containing different query parameters to be indexed on the same entry in the redux store. Is this ok? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This only generate an hash differently. The hash for commerce pages need to be the url instead of query params |
||
}); | ||
|
||
dispatch({ | ||
payload: { hash }, | ||
type: actionTypes.FETCH_COMMERCE_PAGES_REQUEST, | ||
}); | ||
|
||
const result = await getCommercePages(query, config); | ||
const result = await getCommercePages(queryWithoutSlug, config); | ||
const rankedResult = applyCommercePagesRankingStrategy(result, strategy); | ||
|
||
dispatch({ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
import { | ||
applyCommercePagesRankingStrategy, | ||
generateContentHash, | ||
} from './utils.js'; | ||
import { buildQueryStringFromObject } from '../helpers/index.js'; | ||
import { contentEntries } from '../entities/schemas/content.js'; | ||
import { generateContentHash } from './utils.js'; | ||
import { type ContentsState } from './types/index.js'; | ||
import { get, merge } from 'lodash-es'; | ||
import { INITIAL_STATE_CONTENT } from './reducer.js'; | ||
import { normalize } from 'normalizr'; | ||
import parse from 'url-parse'; | ||
import type { ContentsState } from './types/index.js'; | ||
import type { ServerInitialState } from '../types/serverInitialState.types.js'; | ||
|
||
/** | ||
|
@@ -15,28 +18,36 @@ import type { ServerInitialState } from '../types/serverInitialState.types.js'; | |
* | ||
* @returns Initial state for the contents reducer. | ||
*/ | ||
const serverInitialState: ServerInitialState = ({ model }) => { | ||
const serverInitialState: ServerInitialState = ({ model, strategy }) => { | ||
if (!get(model, 'searchContentRequests')) { | ||
return { contents: INITIAL_STATE_CONTENT }; | ||
} | ||
|
||
const { searchContentRequests, slug, seoMetadata, subfolder } = model; | ||
const url = subfolder !== '/' ? slug?.replace(subfolder, '') : slug; | ||
const normalizedUrl = url | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this necessary? If json=true is passed, the response returned by FO will not be html, so the application will not be run in this case. |
||
?.replace('?json=true', '') | ||
.replace('&json=true', ''); | ||
|
||
const contents = searchContentRequests.reduce((acc, item) => { | ||
const { searchResponse } = item; | ||
const firstSearchResponseItem = searchResponse.entries[0]; | ||
|
||
if (!firstSearchResponseItem) { | ||
return acc; | ||
} | ||
|
||
const { | ||
searchResponse, | ||
filters: { codes, contentTypeCode }, | ||
} = item; | ||
let response = searchResponse; | ||
const isCommercePage = contentTypeCode === 'commerce_pages'; | ||
const code = isCommercePage ? normalizedUrl : codes?.[0]; | ||
const hash = generateContentHash({ | ||
codes: firstSearchResponseItem.code, | ||
contentTypeCode: firstSearchResponseItem.contentTypeCode, | ||
codes: code, | ||
contentTypeCode: contentTypeCode, | ||
}); | ||
|
||
if (isCommercePage) { | ||
response = applyCommercePagesRankingStrategy(searchResponse, strategy); | ||
richard190m marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
const { entities, result } = { | ||
...normalize({ hash, ...searchResponse }, contentEntries), | ||
...normalize({ hash, ...response }, contentEntries), | ||
}; | ||
|
||
return merge(acc, { | ||
|
@@ -53,7 +64,6 @@ const serverInitialState: ServerInitialState = ({ model }) => { | |
}); | ||
}, {}); | ||
|
||
const url = subfolder !== '/' ? slug?.replace(subfolder, '') : slug; | ||
const { pathname, query } = parse(url, true); | ||
|
||
delete query.json; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be a breaking change as well, can't it be at least defined as optional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned before, this is only used by BG and this will fix the commerce pages in this package version