diff --git a/packages/docs/.storybook/preview.tsx b/packages/docs/.storybook/preview.tsx
index b3cd2f12..be18fd44 100644
--- a/packages/docs/.storybook/preview.tsx
+++ b/packages/docs/.storybook/preview.tsx
@@ -28,9 +28,15 @@ const parameters: Parameters = {
'Components',
[
'Prices',
- ['PricesContainer', '*'],
+ ['PricesContainer'],
'Skus',
- ['AvailabilityContainer', '*']
+ [
+ 'SkusContainer',
+ 'Skus',
+ 'SkuField',
+ 'AvailabilityContainer',
+ 'AvailabilityTemplate'
+ ]
]
]
}
diff --git a/packages/docs/stories/_internals/CommerceLayer.tsx b/packages/docs/stories/_internals/CommerceLayer.tsx
index 2625f90c..b9cfec3c 100644
--- a/packages/docs/stories/_internals/CommerceLayer.tsx
+++ b/packages/docs/stories/_internals/CommerceLayer.tsx
@@ -14,7 +14,7 @@ interface Props {
*/
function CommerceLayer({ children, ...props }: Props): JSX.Element {
const { accessToken, endpoint } = useGetToken({
- userMode: props.accessToken === 'user-access-token'
+ userMode: props.accessToken === 'customer-access-token'
})
return (
diff --git a/packages/docs/stories/_internals/useGetToken.ts b/packages/docs/stories/_internals/useGetToken.ts
index 4eb2c4b5..d51ab0b7 100644
--- a/packages/docs/stories/_internals/useGetToken.ts
+++ b/packages/docs/stories/_internals/useGetToken.ts
@@ -65,7 +65,6 @@ export function useGetToken(
accessToken === '' ||
isTokenExpired({ accessToken, compareTo: new Date() })
) {
- console.log('initToken')
void initToken()
}
}, [accessToken])
diff --git a/packages/docs/stories/examples/order-list/OrderList.stories.tsx b/packages/docs/stories/examples/order-list/OrderList.stories.tsx
index 0ff2a4f9..1cad57e8 100644
--- a/packages/docs/stories/examples/order-list/OrderList.stories.tsx
+++ b/packages/docs/stories/examples/order-list/OrderList.stories.tsx
@@ -43,7 +43,7 @@ export const Default: StoryFn = (args) => {
]
return (
-
+
+
+# Skus
+
+This guide will explain how to render a list of skus with prices, availability, and add to cart buttons.
+
+As first thing, it uses both `` and `` to manage the state of the cart (remember that for us, the cart is a draft order).
+In this way the `` knows to which order it should add the sku.
+
+
+`} />
+
+
+The presentational part of the skus is handled with `` and `` components.
+
The delivery_lead_times object
-
- {JSON.stringify(childrenProps, null, 2)}
-
+
{JSON.stringify(childrenProps, null, 2)}
)
}}
diff --git a/packages/docs/stories/skus/Skus.stories.tsx b/packages/docs/stories/skus/Skus.stories.tsx
new file mode 100644
index 00000000..dff99239
--- /dev/null
+++ b/packages/docs/stories/skus/Skus.stories.tsx
@@ -0,0 +1,28 @@
+import type { Meta, StoryFn } from '@storybook/react'
+import CommerceLayer from '../_internals/CommerceLayer'
+import { Skus } from '#components/skus/Skus'
+import { SkusContainer } from '#components/skus/SkusContainer'
+import { Code } from 'stories/_internals/Code'
+
+const setup: Meta = {
+ title: 'Components/Skus/Skus',
+ component: Skus
+}
+
+export default setup
+
+export const Default: StoryFn = () => {
+ return (
+
+
+
+
+ I am Skus child
+
+
+
+
+ )
+}
diff --git a/packages/docs/stories/skus/SkusContainer.stories.tsx b/packages/docs/stories/skus/SkusContainer.stories.tsx
new file mode 100644
index 00000000..b74dc4f8
--- /dev/null
+++ b/packages/docs/stories/skus/SkusContainer.stories.tsx
@@ -0,0 +1,40 @@
+import type { Meta, StoryFn } from '@storybook/react'
+import CommerceLayer from '../_internals/CommerceLayer'
+import { SkusContainer } from '#components/skus/SkusContainer'
+import { Code } from '../_internals/Code'
+
+const setup: Meta = {
+ title: 'Components/Skus/SkusContainer',
+ component: SkusContainer
+}
+
+export default setup
+
+const Template: StoryFn = (args) => {
+ return (
+
+
+
+ I am the skus container, responsible to fetch alls skus{' '}
+ details and make them available to the children components.
+
+
+
+ )
+}
+
+export const Default = Template.bind({})
+Default.args = {
+ skus: ['POLOMXXX000000FFFFFFLXXX', 'CROPTOPWFFFFFF000000XSXX'],
+ queryParams: {
+ pageSize: 25,
+ pageNumber: 1,
+ fields: ['name', 'description', 'image_url', 'reference'],
+ sort: {
+ name: 'asc'
+ }
+ }
+}
diff --git a/packages/docs/stories/skus/SkusField.stories.tsx b/packages/docs/stories/skus/SkusField.stories.tsx
new file mode 100644
index 00000000..90a5e48b
--- /dev/null
+++ b/packages/docs/stories/skus/SkusField.stories.tsx
@@ -0,0 +1,98 @@
+import { type Meta, type StoryFn, type StoryObj } from '@storybook/react'
+import CommerceLayer from '../_internals/CommerceLayer'
+import { Skus } from '#components/skus/Skus'
+import { SkusContainer } from '#components/skus/SkusContainer'
+import { SkuField } from '#components/skus/SkuField'
+
+const setup: Meta = {
+ title: 'Components/Skus/SkuField',
+ component: SkuField,
+ argTypes: {
+ attribute: {
+ control: 'select',
+ options: ['name', 'code', 'description', 'image_url', 'weight'],
+ description: 'Resource attribute to display'
+ },
+ tagElement: {
+ control: 'select',
+ options: ['div', 'p', 'span', 'img', 'section'],
+ description:
+ 'Resource attribute to displayHtml tag to render. When tag is `img` the value will be used to fill the `src` attribute.'
+ }
+ }
+}
+
+export default setup
+
+const Template: StoryFn = (args) => {
+ return (
+
+
+
+
+
+
+
+ )
+}
+
+export const Default = Template.bind({})
+Default.args = {
+ attribute: 'name',
+ tagElement: 'div'
+}
+
+/**
+ * The `image_url` can be displayed as `` tag by setting `tagElement` prop to `img`.
+ * In general you can use the `tagElement` you prefer to render the `attribute` you need.
+ */
+export const SkuImageAsImgTag = Template.bind({})
+SkuImageAsImgTag.args = {
+ attribute: 'image_url',
+ tagElement: 'img',
+ width: 100
+}
+
+/**
+ * You can access the attribute value using the children props.
+ * In this way you will be able to apply your own logic if the default rendering is not enough.
+ *
+ * Using the children props is a good idea when you need to render skus' `metadata` the are usually stored as a JSON object or array.
+ * In this way you can access `childrenProps.attributeValue` and cycle through the object/array.
+ *
+ */
+export const ChildrenProps: StoryObj = () => {
+ return (
+
+ {(childrenProps: any) => {
+ return
{JSON.stringify(childrenProps, null, 2)}
+ }}
+
+ )
+}
+ChildrenProps.decorators = [
+ (Story) => {
+ return (
+
+
+
+
+
+
+
+ )
+ }
+]
+ChildrenProps.parameters = {
+ docs: {
+ source: {
+ type: 'code'
+ }
+ }
+}
diff --git a/packages/react-components/src/components/skus/AvailabilityContainer.tsx b/packages/react-components/src/components/skus/AvailabilityContainer.tsx
index 0e09f183..03acbb39 100644
--- a/packages/react-components/src/components/skus/AvailabilityContainer.tsx
+++ b/packages/react-components/src/components/skus/AvailabilityContainer.tsx
@@ -27,7 +27,8 @@ interface Props {
*
* It can be used to fetch the quantities for a specific `sku_code` passed as prop.
*
- * Must be a child of the `` component.
+ * Must be a child of the `` component.
+ * Can be a child of the `` component and receive the `sku_code` from its context.
*
*
* ``
diff --git a/packages/react-components/src/components/skus/SkuField.tsx b/packages/react-components/src/components/skus/SkuField.tsx
index 458690fb..5089a7ea 100644
--- a/packages/react-components/src/components/skus/SkuField.tsx
+++ b/packages/react-components/src/components/skus/SkuField.tsx
@@ -14,8 +14,19 @@ type Props = {
children?: (props: SkuFieldChildrenProps) => JSX.Element
} & TCondition
/**
- * @param props {@link Props}
- * @returns
+ * The SkuField component displays any attribute of the `sku` specified in the parent `` component.
+ *
+ * It also accepts a `tagElement` props to enable specific tag-related props.
+ * For examples, when `tagElement` is set to `img` it will also accept props related to `` tag such as `height` and `width`.
+ *
+ *
+ * It must to be used inside the `` component.
+ *
+
+ *
+ * Check the `skus` resource from our [Core API documentation](https://docs.commercelayer.io/core/v/api-reference/skus/object)
+ * for more details about the available attributes to render.
+ *
*/
export function SkuField
(props: P): JSX.Element {
const { attribute, tagElement = 'span', children, ...p } = props
diff --git a/packages/react-components/src/components/skus/Skus.tsx b/packages/react-components/src/components/skus/Skus.tsx
index dbfa5e90..02d9b698 100644
--- a/packages/react-components/src/components/skus/Skus.tsx
+++ b/packages/react-components/src/components/skus/Skus.tsx
@@ -6,6 +6,18 @@ interface Props {
children: ReactNode
}
+/**
+ * The `Skus` components loop through the list of `skus` found in `SkusContainer` context and render the children filled with the proper sku value.
+ * This means that the children will be rendered as many times as the number of skus found in the `skus` prop array
+ * and there is no need to manually loop through them from your consumer app.
+ *
+ *
+ * Must be a child of the `` component.
+ *
+ *
+ * ``, ``
+ *
+ */
export function Skus
({ children }: P): JSX.Element {
const { skus } = useContext(SkuContext)
const components = skus?.map((sku, key) => {
diff --git a/packages/react-components/src/components/skus/SkusContainer.tsx b/packages/react-components/src/components/skus/SkusContainer.tsx
index 49398795..f14682e8 100644
--- a/packages/react-components/src/components/skus/SkusContainer.tsx
+++ b/packages/react-components/src/components/skus/SkusContainer.tsx
@@ -16,7 +16,7 @@ interface Props {
*/
skus: string[]
/**
- * Accept a React node, [Skus](./Skus.d.ts), and [ItemContainer](../ItemContainer.d.ts) as children to display above the skus.
+ * Accept a React node and [Skus](./Skus.d.ts) component as children to display above the skus.
*/
children: ReactNode
/**
@@ -25,6 +25,19 @@ interface Props {
queryParams?: QueryParamsList
}
+/**
+ * Main container for the SKUs components.
+ * It stores - in its context - the details for each `sku` defined in the `skus` prop array.
+ *
+ * It also accept a `queryParams` prop to refine pagination, sorting, filtering and includes for the fetch request.
+ *
+ *
+ * Must be a child of the `` component.
+ *
+ *
+ * ``
+ *
+ */
export function SkusContainer
(props: P): JSX.Element {
const { skus, children, queryParams } = props
const [state, dispatch] = useReducer(skuReducer, skuInitialState)
diff --git a/packages/react-components/src/components/utils/GenericFieldComponent.tsx b/packages/react-components/src/components/utils/GenericFieldComponent.tsx
index 42fa2f82..1e38d0df 100644
--- a/packages/react-components/src/components/utils/GenericFieldComponent.tsx
+++ b/packages/react-components/src/components/utils/GenericFieldComponent.tsx
@@ -54,7 +54,13 @@ type GenericContext = Context<
interface Props {
children?: (props: TGenericChildrenProps) => JSX.Element
resource: E['resource']
+ /**
+ * Resource attribute to display.
+ */
attribute: keyof E
+ /**
+ * Html tag to render. When tag is `img` the value will be used to fill the `src` attribute.
+ */
tagElement: keyof JSX.IntrinsicElements
context: GenericContext
}