Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions components/admin/AdminPanel/modals/ImageStatisticsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ const ImageStatisticsModal = ({ stats, onClose }: ImageStatisticsModalProps) =>
<Card>
<Link
passHref
href={stat.src}
href={stat.src || ''}
title={stat.src}
target="_blank"
rel="noreferrer"
Expand Down Expand Up @@ -240,7 +240,7 @@ const ImageStatisticsModal = ({ stats, onClose }: ImageStatisticsModalProps) =>
<TableCell>
<Link
passHref
href={stat.src}
href={stat.src || ''}
target="_blank"
rel="noreferrer"
title={stat.src}
Expand Down
2 changes: 1 addition & 1 deletion components/cms-modern/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const Card = ({ image, cardName, description, links }: CardProps) => {
backgroundColor: '#000',
borderRadius: 3,
}}
href={link.value}
href={link.value || ''}
key={i}
>
<Typography
Expand Down
6 changes: 3 additions & 3 deletions components/cms-modern/Search/SearchResultsListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const SearchResultsListing = (props: SearchResultsListingProps) => {
<li>
<h3 className="search__results__listing__heading">Products</h3>
<ul className="search__results__section">
{searchResults.map(({ id, name, variants, href }: any, index: number) => {
{searchResults.map(({ id, name, variants, href = '' }: any, index: number) => {
// Need to manipulate the image url for smart imaging and resize for performance
let firstImage: string = '';
if (variants[0].images) {
Expand Down Expand Up @@ -79,7 +79,7 @@ const SearchResultsListing = (props: SearchResultsListingProps) => {
<li>
<h3 className="search__results__listing__heading">Categories</h3>
<ul className="search__results__section">
{categories.map(({ label, count, href }: any, index: number) => {
{categories.map(({ label, count, href = '' }: any, index: number) => {
return (
<li key={index}>
<Link passHref href={href}>
Expand Down Expand Up @@ -124,7 +124,7 @@ const SearchResultsListing = (props: SearchResultsListingProps) => {
<li>
<h3 className="search__results__listing__heading">Inspiration</h3>
<ul className="search__results__section">
{inspiration.map(({ label, href, count }: any, index: number) => {
{inspiration.map(({ label, href = '', count }: any, index: number) => {
return (
<li key={index}>
<Link passHref href={href}>
Expand Down
43 changes: 43 additions & 0 deletions docs/DeepDive.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
- [Fetching content](#fetching-content)
- [Filter API](#filter-api)
- [Navigation Hierarchy](#navigation-hierarchy)
- [Fetching Hierarchy Descendants](#fetching-hierarchy-descendants)
- [Product Detail Page Layout](#product-detail-page-layout)
- [Personalisation](#personalisation)
- [Theming](#theming)
Expand Down Expand Up @@ -142,6 +143,48 @@ const data = await fetchPageData(

[top](#table-of-contents)

## Fetching Hierarchy Descendants

An example of how to fetch hierarchy descendants using the root hierarchy nodes ID.

```js
async function fetchHierarchyDescendants(id: string, params = {}) {
const fetchParams = {
maxPageSize: 20,
hierarchyDepth: 10,
...params,
};
return fetch(`https://my-demo-hub.cdn.content.amplience.net/content/hierarchies/descendants/id/${id}?${stringify(fetchParams)}`).then((x) =>
x.json(),
);
}
```

If results exceed the max page size the response will include a page cursor. This cursor can then be used to request additional results.

```js
const results = await fetchHierarchyDescendants(parentId);

if (results.page.cursor) {
const nextPageResults = await fetchHierarchyDescendants(parentId, { pageCursor: results.page.cursor });
}
```

The results are returned in a flattened state. To be able to construct a full descendant tree you will need to retrieve all descedants (using the page cursor and a looping method of your choice if necessary). Once you have all descendants you can unflatten them.

```js
function unflattenDescendants(parentId: string, descendants: DefaultContentBody[] = []): any {
return descendants
.filter((item) => item.content._meta?.hierarchy?.parentId === parentId)
.map((child) => ({
...child,
children: unflattenDescendants(child.content._meta.deliveryId, descendants),
}));
}
```

[top](#table-of-contents)

## Product Detail Page Layout

Demostore features product detail page layouts that can be specific to:
Expand Down
84 changes: 55 additions & 29 deletions lib/cms/fetchHierarchy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { CmsContext } from './CmsContext';
import { CmsContent } from './CmsContent';

import fetchContent, { GetByFilterRequest } from './fetchContent';
import { createAppContext } from '@lib/config/AppContext';
import { stringify } from 'querystring';
import { ContentBody, DefaultContentBody } from 'dc-delivery-sdk-js';
import fetchContent from './fetchContent';

export type CmsHierarchyRequest = { tree: { key: string } };

Expand All @@ -10,44 +13,67 @@ export type CmsHierarchyNode = {
children: CmsHierarchyNode[];
};

async function getChildren(nodeId: string, context: CmsContext): Promise<CmsHierarchyNode[]> {
const childrenRequest: GetByFilterRequest = {
filterBy: [
{
path: '/_meta/hierarchy/parentId',
value: nodeId,
},
],
sortBy: {
key: 'default',
order: 'asc',
},
async function fetchHierarchyRootNode(
hierarchyRequest: CmsHierarchyRequest,
context: CmsContext,
): Promise<ContentBody> {
const [rootNode] = await fetchContent([{ key: hierarchyRequest.tree.key }], context, {
depth: 'root',
format: 'linked',
});

return rootNode as DefaultContentBody;
}

async function fetchHierarchyDescendants(id: string, context: CmsContext, params = {}) {
const { cms } = await createAppContext();
const host = context.stagingApi || `${cms.hub}.cdn.content.amplience.net`;
const fetchParams = {
maxPageSize: 20,
hierarchyDepth: 10,
...params,
};
const [children] = await fetchContent([childrenRequest], context, { depth: 'root', format: 'inlined' });
const responses: any[] = children?.responses || [];
const subChildren = await Promise.all(
responses.map((child: any) => {
return getChildren(child.content._meta.deliveryId, context);
}),
return fetch(`https://${host}/content/hierarchies/descendants/id/${id}?${stringify(fetchParams)}`).then((x) =>
x.json(),
);
responses.forEach((element: any, i: number) => {
responses[i].children = subChildren[i];
});
}

async function fetchAllHierarchyDescendants(parentId: string, context: CmsContext): Promise<DefaultContentBody[]> {
const pagingHandler = async (id: string, context: CmsContext, params = {}): Promise<DefaultContentBody[]> => {
const results = await fetchHierarchyDescendants(id, context, params);
if (results.page.cursor) {
return results.responses.concat(await pagingHandler(id, context, { pageCursor: results.page.cursor }));
}
return results.responses;
};

return await pagingHandler(parentId, context);
}

return responses;
function unflattenDescendants(parentId: string, descendants: DefaultContentBody[] = []): any {
return descendants
.filter((item) => item.content._meta?.hierarchy?.parentId === parentId)
.filter((item) => item.content.active === true)
.sort(
(a, b) =>
(a.content?.menu?.priority || a.content?.priority || 0) -
(b.content?.menu?.priority || b.content?.priority || 0),
)
.map((child) => ({
...child,
children: unflattenDescendants(child.content._meta.deliveryId, descendants),
}));
}

async function fetchHierarchy(items: CmsHierarchyRequest[], context: CmsContext): Promise<(CmsHierarchyNode | null)[]> {
return await Promise.all(
items.map(async (item) => {
const [rootNode] = await fetchContent([{ key: item.tree.key }], context, {
depth: 'root',
format: 'linked',
});
const children: CmsHierarchyNode[] = await getChildren((rootNode as any)._meta.deliveryId, context);
const rootNode = await fetchHierarchyRootNode(item, context);
const descendants = await fetchAllHierarchyDescendants(rootNode._meta.deliveryId, context);
const descendantsTree = unflattenDescendants(rootNode._meta.deliveryId, descendants);
const response: any = {
content: rootNode,
children: children,
children: descendantsTree,
};
return response;
}),
Expand Down
2 changes: 1 addition & 1 deletion lib/cms/fetchHierarchyMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { withRetry } from '@utils/withRetry';

async function fetchHierarchyMap<T extends FetchMapInput<CmsHierarchyRequest>>(
map: T,
context: CmsContext
context: CmsContext,
): Promise<FetchMapOutput<T, CmsHierarchyRequest, CmsHierarchyNode | null>> {
return await withRetry(() => {
return fetchMap(map, (items) => {
Expand Down
Loading