Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import {
Availability,
AvailabilityContainer,
AvailabilityTemplate,
} from "@commercelayer/react-components"
import { ArgTypes, Canvas, Source } from "@storybook/addon-docs/blocks"
import type { Meta, StoryObj } from "@storybook/react-vite"
import CommerceLayer from "../_internals/CommerceLayer"

function AvailabilityContainerDocsPage(): JSX.Element {
return (
<>
<h1>AvailabilityContainer</h1>
<span title="Deprecated" type="warning">
<p>
<code>{"<AvailabilityContainer>"}</code> is deprecated. Use the standalone{" "}
<code>{"<Availability skuCode='...'>"}</code> component instead. See{" "}
<strong>Availability/Availability</strong> for the recommended pattern.{" "}
<code>{"<AvailabilityContainer>"}</code> will be removed in the next major version.
</p>
</span>
<p>
<code>{"<AvailabilityContainer>"}</code> fetches inventory data for a given SKU code and
makes it available to its <code>{"<AvailabilityTemplate>"}</code> children via context.
</p>
<ArgTypes />
<hr />
<h2>Migration guide</h2>
<p>
<strong>Before (deprecated):</strong>
</p>
<Source
language="jsx"
dark
code={`
import { CommerceLayer, AvailabilityContainer, AvailabilityTemplate } from '@commercelayer/react-components'

<CommerceLayer accessToken="...">
<AvailabilityContainer skuCode="TSHIRTMM000000FFFFFFXLXX">
<AvailabilityTemplate />
</AvailabilityContainer>
</CommerceLayer>
`}
/>
<p>
<strong>After (recommended):</strong>
</p>
<Source
language="jsx"
dark
code={`
import { CommerceLayer, Availability, AvailabilityTemplate } from '@commercelayer/react-components'

<CommerceLayer accessToken="...">
<Availability skuCode="TSHIRTMM000000FFFFFFXLXX">
<AvailabilityTemplate />
</Availability>
</CommerceLayer>
`}
/>
<hr />
<h2>Example</h2>
<Canvas of={DeprecatedContainer} />
</>
)
}

const meta = {
title: "Components/Availability/AvailabilityContainer",
component: AvailabilityContainer,
parameters: {
layout: "centered",
docs: {
page: AvailabilityContainerDocsPage,
},
},
argTypes: {
skuCode: {
control: "text",
description: "The SKU code to fetch availability for.",
},
skuId: {
control: "text",
description:
"The SKU resource ID. Takes precedence over `skuCode` and improves performance by skipping the code-to-id lookup.",
},
children: {
control: false,
description: "Accepts `<AvailabilityTemplate>` as a child.",
},
},
} satisfies Meta<typeof AvailabilityContainer>

export default meta
type Story = StoryObj<typeof meta>

export const DeprecatedContainer: Story = {
name: "AvailabilityContainer β€” deprecated (legacy)",
render: () => (
<CommerceLayer accessToken="my-access-token">
<AvailabilityContainer skuCode="POLOMXXX000000FFFFFFLXXX">
<AvailabilityTemplate />
</AvailabilityContainer>
</CommerceLayer>
),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
import {
Availability,
AvailabilityTemplate,
} from "@commercelayer/react-components"
import { ArgTypes, Canvas, Source } from "@storybook/addon-docs/blocks"
import type { Meta, StoryObj } from "@storybook/react-vite"
import CommerceLayer from "../_internals/CommerceLayer"

function AvailabilityTemplateDocsPage(): JSX.Element {
return (
<>
<h1>AvailabilityTemplate</h1>
<p>
Reads from the parent <code>{"<Availability>"}</code> context and renders a{" "}
<code>{"<span>"}</code> with availability text. Customise the label shown for each state (
<code>available</code>, <code>outOfStock</code>, <code>negativeStock</code>) and optionally
include delivery lead time and shipping method details.
</p>
<blockquote>
<p>
Must be a descendant of the <code>{"<Availability>"}</code> component.
</p>
</blockquote>
<ArgTypes />
<table>
<thead>
<tr>
<th>Prop</th>
<th>Type</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<code>labels.available</code>
</td>
<td>
<code>string</code>
</td>
<td>
<code>"Available"</code>
</td>
<td>Text shown when quantity &gt; 0</td>
</tr>
<tr>
<td>
<code>labels.outOfStock</code>
</td>
<td>
<code>string</code>
</td>
<td>
<code>"Out of stock"</code>
</td>
<td>Text shown when quantity is 0</td>
</tr>
<tr>
<td>
<code>labels.negativeStock</code>
</td>
<td>
<code>string</code>
</td>
<td>
<code>"Not available"</code>
</td>
<td>Text shown when quantity is negative</td>
</tr>
<tr>
<td>
<code>timeFormat</code>
</td>
<td>
<code>"days" | "hours"</code>
</td>
<td>β€”</td>
<td>When set, delivery lead time is appended to the label</td>
</tr>
<tr>
<td>
<code>showShippingMethodName</code>
</td>
<td>
<code>boolean</code>
</td>
<td>
<code>false</code>
</td>
<td>
Requires <code>timeFormat</code>. Appends the shipping method name
</td>
</tr>
<tr>
<td>
<code>showShippingMethodPrice</code>
</td>
<td>
<code>boolean</code>
</td>
<td>
<code>false</code>
</td>
<td>
Requires <code>timeFormat</code>. Appends the formatted shipping price
</td>
</tr>
</tbody>
</table>
<hr />
<h2>Custom labels</h2>
<p>
Customise the displayed text for all stock states via the <code>labels</code> prop.
</p>
<Canvas of={CustomLabels} />
<h2>Lead time</h2>
<p>
Set <code>timeFormat</code> to <code>"days"</code> or <code>"hours"</code> to show the
shipping lead time alongside the availability status.
</p>
<Canvas of={WithDeliveryLeadTimeDays} />
<Canvas of={WithDeliveryLeadTimeHours} />
<h2>Shipping method</h2>
<Canvas of={WithShippingMethodName} />
<Canvas of={WithShippingMethodPrice} />
<hr />
<h2>Children render prop</h2>
<p>
Pass a function as <code>children</code> to fully control the rendered output. The function
receives the full availability context including <code>quantity</code>, <code>text</code>,{" "}
<code>min</code>, <code>max</code>, and <code>shipping_method</code>.
</p>
<Source
language="jsx"
dark
code={`
<Availability skuCode="TSHIRTMM000000FFFFFFXLXX">
<AvailabilityTemplate>
{({ quantity, text, min, max }) => (
<div>
<strong>{text}</strong>
{quantity > 0 && min != null && (
<p>Ships in {min.days}–{max?.days ?? min.days} days</p>
)}
</div>
)}
</AvailabilityTemplate>
</Availability>
`}
/>
<Canvas of={WithChildrenRenderProp} />
</>
)
}

const meta = {
title: "Components/Availability/AvailabilityTemplate",
component: AvailabilityTemplate,
parameters: {
layout: "centered",
docs: {
page: AvailabilityTemplateDocsPage,
},
},
argTypes: {
labels: {
control: "object",
description:
"Text labels for each stock state: `available`, `outOfStock`, `negativeStock`.",
},
timeFormat: {
control: "select",
options: ["days", "hours"],
description:
"When set, delivery lead time is appended to the availability label.",
},
showShippingMethodName: {
control: "boolean",
description: "Requires `timeFormat`. Appends the shipping method name to the label.",
},
showShippingMethodPrice: {
control: "boolean",
description: "Requires `timeFormat`. Appends the formatted shipping price to the label.",
},
children: {
control: false,
description:
"Render prop receiving `{ quantity, text, min, max, shipping_method }` for a fully custom availability UI.",
},
},
} satisfies Meta<typeof AvailabilityTemplate>

export default meta
type Story = StoryObj<typeof meta>

export const CustomLabels: Story = {
name: "AvailabilityTemplate β€” custom labels",
render: () => (
<CommerceLayer accessToken="my-access-token">
<Availability skuCode="POLOMXXX000000FFFFFFLXXX">
<AvailabilityTemplate
labels={{
available: "βœ… In stock",
outOfStock: "❌ Sold out",
negativeStock: "⚠️ Not available",
}}
/>
</Availability>
</CommerceLayer>
),
}

export const WithDeliveryLeadTimeDays: Story = {
name: "AvailabilityTemplate β€” lead time in days",
render: () => (
<CommerceLayer accessToken="my-access-token">
<Availability skuCode="POLOMXXX000000FFFFFFLXXX">
<AvailabilityTemplate labels={{ available: "Available" }} timeFormat="days" />
</Availability>
</CommerceLayer>
),
}

export const WithDeliveryLeadTimeHours: Story = {
name: "AvailabilityTemplate β€” lead time in hours",
render: () => (
<CommerceLayer accessToken="my-access-token">
<Availability skuCode="POLOMXXX000000FFFFFFLXXX">
<AvailabilityTemplate labels={{ available: "Available" }} timeFormat="hours" />
</Availability>
</CommerceLayer>
),
}

export const WithShippingMethodName: Story = {
name: "AvailabilityTemplate β€” with shipping method name",
render: () => (
<CommerceLayer accessToken="my-access-token">
<Availability skuCode="POLOMXXX000000FFFFFFLXXX">
<AvailabilityTemplate timeFormat="days" showShippingMethodName />
</Availability>
</CommerceLayer>
),
}

export const WithShippingMethodPrice: Story = {
name: "AvailabilityTemplate β€” with shipping method price",
render: () => (
<CommerceLayer accessToken="my-access-token">
<Availability skuCode="POLOMXXX000000FFFFFFLXXX">
<AvailabilityTemplate timeFormat="days" showShippingMethodName showShippingMethodPrice />
</Availability>
</CommerceLayer>
),
}

export const WithChildrenRenderProp: Story = {
name: "AvailabilityTemplate β€” children render prop",
render: () => (
<CommerceLayer accessToken="my-access-token">
<Availability skuCode="POLOMXXX000000FFFFFFLXXX">
<AvailabilityTemplate>
{({ quantity, text, min, max }) => (
<div style={{ fontFamily: "monospace", fontSize: 14 }}>
<strong>{text}</strong>
{quantity > 0 && min != null && (
<p style={{ marginTop: 4, color: "#666" }}>
Ships in {min.days}–{max?.days ?? min.days} day(s)
</p>
)}
</div>
)}
</AvailabilityTemplate>
</Availability>
</CommerceLayer>
),
}
Loading
Loading