Order Lines
Headless components for displaying and managing order line items in a cart or order.
Purpose
This library provides components for displaying and managing order line items, including product information, quantities, pricing, and line item operations. It's designed as a headless component that provides all the order line logic while allowing complete UI customization. Use this when you need to display order lines from an active cart or a specific order, with the ability to adjust quantities and remove items.
Features
- Order line display and management with context-based state
- Quantity adjustment controls with validation
- Price display with promotion and "from price" detection
- Product image display from featured assets
- Line item removal functionality
- Flexible render prop pattern for complete UI control
Installation
- npm
- Yarn
npm install @haus-storefront-react/order-lines
yarn add @haus-storefront-react/order-lines
Note: This is not a public package. Contact the Haus Tech Team for access.
API Reference
OrderLines.Root
Main container that provides order lines context and state. When no orderCode is provided, it fetches and manages the active order. When an orderCode is provided, it fetches and displays a specific order (read-only mode where adjusting and removing are disabled).
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | (props: OrderLinesContextValue) => ReactNode | No | - | Render prop that receives order lines data and functions |
orderCode | string | No | - | Optional order code for fetching specific order |
adjustable | boolean | No | true | Whether quantities can be adjusted |
removable | boolean | No | true | Whether items can be removed |
callbacks | { preAdjust?: (orderLineId: string, quantity: number) => Promise<void>; preRemove?: (lineId: string) => Promise<void> } | No | - | Optional callbacks for order line operations |
OrderLines.Item
Individual order line item component. Must be used within OrderLines.Root. Provides context for child components like OrderLines.Image, OrderLines.Price, OrderLines.Quantity, and OrderLines.Remove.
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | ReactNode | No | - | Child components or content |
orderLine | OrderLine | Yes | - | The order line data to display |
OrderLines.Image
Product image display component. Must be used within OrderLines.Item. Displays the featured asset preview for the order line. Returns null if no image is available.
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
alt | string | No | orderLine.productVariant.name | Alt text for the image |
asChild | boolean | No | false | Render as child element |
...imgProps | ImgHTMLAttributes<HTMLImageElement> | No | - | Standard image element props |
OrderLines.Price
Price display component for an order line. Must be used within OrderLines.Item. Uses a render prop pattern to provide price information including base price, price with tax, currency code, promotion status, and "from price" detection.
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | (props: PriceInfo) => ReactNode | No | - | Function that receives price information and returns React nodes |
withDiscountPrice | boolean | No | false | Whether to show discounted price and calculate promotion status |
Price Info Object
{
price: Price
priceWithTax: Price
currencyCode: CurrencyCode
isPromotion: boolean
isFromPrice: boolean
}
OrderLines.Quantity
Quantity adjustment component for an order line. Must be used within OrderLines.Item. Provides a compound component structure with Root, Decrement, Input, Increment, and Remove sub-components.
OrderLines.Quantity.Root
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | ReactNode | Yes | - | Child components (Decrement, Input, Increment, Remove) |
min | number | No | 0 | Minimum quantity allowed |
max | number | No | - | Maximum quantity allowed |
step | number | No | 1 | Step size for quantity changes |
Sub-components
OrderLines.Quantity.Decrement- Button to decrease quantityOrderLines.Quantity.Input- Input field for direct quantity entryOrderLines.Quantity.Increment- Button to increase quantityOrderLines.Quantity.Remove- Button to remove the line item
OrderLines.Remove
Remove line item button component. Must be used within OrderLines.Item. Automatically handles removal logic and is hidden when isRemovable is false.
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
children | ReactNode | No | - | Button content |
asChild | boolean | No | false | Render as child element |
...buttonProps | ButtonHTMLAttributes<HTMLButtonElement> | No | - | Standard button element props |
useOrderLinesProps
Hook for managing order lines data and operations. Returns order data, loading states, error states, and functions for adjusting quantities and removing lines.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
options | UseOrderLinesOptions | No | Configuration object for order lines management |
Options Object
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
orderCode | string | No | - | Order code for fetching specific order |
adjustable | boolean | No | true | Whether quantities can be adjusted |
removable | boolean | No | true | Whether items can be removed |
fetchActiveOrder | boolean | No | true | Whether to fetch active order when no orderCode provided |
min | number | No | 0 | Minimum quantity allowed |
max | number | No | - | Maximum quantity allowed |
step | number | No | 1 | Step size for quantity changes |
callbacks | { preAdjust?: (orderLineId: string, quantity: number) => Promise<void>; preRemove?: (lineId: string) => Promise<void> } | No | - | Optional callbacks for operations |
Returns
| Return Value | Type | Description |
|---|---|---|
data | Maybe<Order> | undefined | The loaded order data or undefined while loading |
orderLines | OrderLine[] | undefined | Extracted order lines array from the order |
isLoading | boolean | Loading state flag |
error | Error | null | Error object if request failed |
adjustOrderLine | (orderLineId: string, quantity: number) => Promise<unknown> | Function to adjust order line quantity |
removeOrderLine | (lineId: string) => Promise<unknown> | Function to remove an order line |
adjustError | Error | null | Error from adjust operation |
removeError | Error | null | Error from remove operation |
isAdjusting | boolean | Loading state for adjust operation |
isRemoving | boolean | Loading state for remove operation |
getRemoveProps | (orderLineId: string, props?) => ButtonHTMLAttributes | Function to get props for remove button |
getAdjustProps | (props?) => InputHTMLAttributes | Function to get props for quantity input |
getDecrementProps | (props?) => ButtonHTMLAttributes | Function to get props for decrement button |
getIncrementProps | (props?) => ButtonHTMLAttributes | Function to get props for increment button |
refetch | () => Promise<void> | Function to manually refetch data |
createOrderLinesScope
Utility function for creating a scoped context for OrderLines components. Useful when nesting multiple OrderLines components or when you need to isolate component state.
Signature
function createOrderLinesScope(): [Scope]
Returns
Scope - A scope identifier for the OrderLines context
Basic Usage
Simple Order Lines Display
- React
- React Native
import { OrderLines } from '@haus-storefront-react/order-lines'
function MyOrderLines() {
return (
<OrderLines.Root>
{({ orderLines, isLoading, error }) => {
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!orderLines) return <div>No order</div>
return (
<div>
{orderLines.map((orderLine) => (
<OrderLines.Item key={orderLine.id} orderLine={orderLine}>
<OrderLines.Image />
<OrderLines.Price>
{({ price, priceWithTax, currencyCode }) => (
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
<Price.Currency />
</Price.Root>
)}
</OrderLines.Price>
<OrderLines.Quantity.Root>
<OrderLines.Quantity.Decrement>-</OrderLines.Quantity.Decrement>
<OrderLines.Quantity.Input />
<OrderLines.Quantity.Increment>+</OrderLines.Quantity.Increment>
</OrderLines.Quantity.Root>
<OrderLines.Remove>Remove</OrderLines.Remove>
</OrderLines.Item>
))}
</div>
)
}}
</OrderLines.Root>
)
}
import { Text } from 'react-native'
import { OrderLines } from '@haus-storefront-react/order-lines'
import { Price } from '@haus-storefront-react/common-ui'
function MyOrderLines() {
return (
<OrderLines.Root>
{({ orderLines, isLoading, error }) => {
if (isLoading) return <Text>Loading...</Text>
if (error) return <Text>Error: {error.message}</Text>
if (!orderLines) return <Text>No order</Text>
return (
<>
{orderLines.map((orderLine) => (
<OrderLines.Item key={orderLine.id} orderLine={orderLine}>
<OrderLines.Image />
<OrderLines.Price>
{({ price, priceWithTax, currencyCode }) => (
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
<Price.Currency />
</Price.Root>
)}
</OrderLines.Price>
<OrderLines.Quantity.Root>
<OrderLines.Quantity.Decrement>-</OrderLines.Quantity.Decrement>
<OrderLines.Quantity.Input />
<OrderLines.Quantity.Increment>+</OrderLines.Quantity.Increment>
</OrderLines.Quantity.Root>
<OrderLines.Remove>Remove</OrderLines.Remove>
</OrderLines.Item>
))}
</>
)
}}
</OrderLines.Root>
)
}
Basic Hook Usage
- React
- React Native
import { useOrderLinesProps } from '@haus-storefront-react/order-lines'
function MyComponent() {
const {
data: order,
orderLines,
isLoading,
error,
} = useOrderLinesProps({
fetchActiveOrder: true,
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
if (!orderLines) return <div>No order lines</div>
return (
<div>
{orderLines.map((line) => (
<div key={line.id}>
<h3>{line.productVariant.product.name}</h3>
<p>Quantity: {line.quantity}</p>
</div>
))}
</div>
)
}
import { View, Text, ScrollView } from 'react-native'
import { useOrderLinesProps } from '@haus-storefront-react/order-lines'
function MyComponent() {
const {
data: order,
orderLines,
isLoading,
error,
} = useOrderLinesProps({
fetchActiveOrder: true,
})
if (isLoading) return <Text>Loading...</Text>
if (error) return <Text>Error: {error.message}</Text>
if (!orderLines) return <Text>No order lines</Text>
return (
<ScrollView>
{orderLines.map((line) => (
<View key={line.id}>
<Text>{line.productVariant.product.name}</Text>
<Text>Quantity: {line.quantity}</Text>
</View>
))}
</ScrollView>
)
}
Advanced Usage
Complex Component Configuration
- React
- React Native
import {
OrderLines,
useOrderLinesProps,
} from '@haus-storefront-react/order-lines'
import { Price } from '@haus-storefront-react/common-ui'
function AdvancedOrderLines() {
const handlePreAdjust = async (orderLineId: string, quantity: number) => {
console.log(`Adjusting line ${orderLineId} to quantity ${quantity}`)
// Perform validation or other pre-adjustment logic
}
return (
<OrderLines.Root
adjustable={true}
removable={true}
callbacks={{ preAdjust: handlePreAdjust }}
>
{({
data: order,
orderLines,
isLoading,
error,
adjustOrderLine,
removeOrderLine,
}) => {
if (isLoading) {
return (
<div className='loading-state'>
<div className='spinner' />
<span>Loading items...</span>
</div>
)
}
if (error) {
return (
<div className='error-state'>
<h3>Error Loading Items</h3>
<p>{error.message}</p>
</div>
)
}
return (
<div className='order-lines-container'>
{orderLines?.map((orderLine) => (
<div key={orderLine.id} className='order-line-card'>
<OrderLines.Item orderLine={orderLine}>
<div className='line-item'>
<div className='item-image-section'>
<OrderLines.Image className='product-image' />
</div>
<div className='item-details-section'>
<h3>{orderLine.productVariant.product.name}</h3>
<p>{orderLine.productVariant.name}</p>
<p>SKU: {orderLine.productVariant.sku}</p>
<OrderLines.Price withDiscountPrice={true}>
{({
price,
priceWithTax,
currencyCode,
isPromotion,
isFromPrice,
}) => (
<div className='item-pricing'>
<div className='unit-price'>
<span>Unit Price:</span>
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
</Price.Root>
</div>
<div className='line-total'>
<span>Total:</span>
{isFromPrice && <span>From </span>}
{isPromotion && (
<span className='sale-badge'>On Sale!</span>
)}
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
</Price.Root>
</div>
</div>
)}
</OrderLines.Price>
</div>
<div className='item-controls-section'>
<div className='quantity-controls'>
<label>Quantity:</label>
<OrderLines.Quantity.Root min={1} max={99} step={1}>
<OrderLines.Quantity.Decrement className='qty-btn' />
<OrderLines.Quantity.Input className='qty-input' />
<OrderLines.Quantity.Increment className='qty-btn' />
</OrderLines.Quantity.Root>
</div>
<div className='item-actions'>
<OrderLines.Remove className='remove-btn'>
Remove Item
</OrderLines.Remove>
</div>
</div>
</div>
</OrderLines.Item>
</div>
))}
</div>
)
}}
</OrderLines.Root>
)
}
import { View, Text, ScrollView, Pressable } from 'react-native'
import { OrderLines } from '@haus-storefront-react/order-lines'
import { Price } from '@haus-storefront-react/common-ui'
function AdvancedOrderLines() {
const handlePreAdjust = async (orderLineId: string, quantity: number) => {
console.log(`Adjusting line ${orderLineId} to quantity ${quantity}`)
}
return (
<OrderLines.Root
adjustable
removable
callbacks={{ preAdjust: handlePreAdjust }}
>
{({ orderLines, isLoading, error }) => {
if (isLoading) {
return <Text>Loading items...</Text>
}
if (error) {
return <Text>Error Loading Items: {error.message}</Text>
}
return (
<ScrollView>
{orderLines?.map((orderLine) => (
<OrderLines.Item key={orderLine.id} orderLine={orderLine}>
<View>
<OrderLines.Image />
<Text>{orderLine.productVariant.product.name}</Text>
<Text>{orderLine.productVariant.name}</Text>
<Text>SKU: {orderLine.productVariant.sku}</Text>
<OrderLines.Price withDiscountPrice>
{({
price,
priceWithTax,
currencyCode,
isPromotion,
isFromPrice,
}) => (
<View>
<Text>Unit Price:</Text>
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
</Price.Root>
<Text>Total:</Text>
{isFromPrice && <Text>From </Text>}
{isPromotion && <Text>On Sale!</Text>}
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
</Price.Root>
</View>
)}
</OrderLines.Price>
<OrderLines.Quantity.Root min={1} max={99} step={1}>
<OrderLines.Quantity.Decrement>
<Text>-</Text>
</OrderLines.Quantity.Decrement>
<OrderLines.Quantity.Input />
<OrderLines.Quantity.Increment>
<Text>+</Text>
</OrderLines.Quantity.Increment>
</OrderLines.Quantity.Root>
<OrderLines.Remove asChild>
<Pressable>
<Text>Remove Item</Text>
</Pressable>
</OrderLines.Remove>
</View>
</OrderLines.Item>
))}
</ScrollView>
)
}}
</OrderLines.Root>
)
}
Conditional Rendering Patterns
- React
- React Native
import { OrderLines } from '@haus-storefront-react/order-lines'
import { Price } from '@haus-storefront-react/common-ui'
function ConditionalOrderLines({ orderCode }: { orderCode?: string }) {
return (
<OrderLines.Root
orderCode={orderCode}
adjustable={!orderCode}
removable={!orderCode}
>
{({ data: order, orderLines, isLoading }) => {
if (isLoading) {
return <div>Loading...</div>
}
if (!orderLines || orderLines.length === 0) {
return (
<div className='empty-state'>
<p>No items in {orderCode ? 'this order' : 'your cart'}</p>
</div>
)
}
return (
<div className='order-lines-list'>
{orderLines.map((orderLine) => (
<OrderLines.Item key={orderLine.id} orderLine={orderLine}>
<div className='order-line-content'>
<OrderLines.Image />
<div className='order-line-details'>
<h3>{orderLine.productVariant.product.name}</h3>
<OrderLines.Price>
{({ price, priceWithTax, currencyCode }) => (
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
<Price.Currency />
</Price.Root>
)}
</OrderLines.Price>
{!orderCode && (
<>
<OrderLines.Quantity.Root>
<OrderLines.Quantity.Decrement />
<OrderLines.Quantity.Input />
<OrderLines.Quantity.Increment />
</OrderLines.Quantity.Root>
<OrderLines.Remove>Remove</OrderLines.Remove>
</>
)}
</div>
</div>
</OrderLines.Item>
))}
</div>
)
}}
</OrderLines.Root>
)
}
import { ScrollView, Text, View } from 'react-native'
import { OrderLines } from '@haus-storefront-react/order-lines'
import { Price } from '@haus-storefront-react/common-ui'
function ConditionalOrderLines({ orderCode }: { orderCode?: string }) {
return (
<OrderLines.Root
orderCode={orderCode}
adjustable={!orderCode}
removable={!orderCode}
>
{({ orderLines, isLoading }) => {
if (isLoading) {
return <Text>Loading...</Text>
}
if (!orderLines || orderLines.length === 0) {
return (
<Text>No items in {orderCode ? 'this order' : 'your cart'}</Text>
)
}
return (
<ScrollView>
{orderLines.map((orderLine) => (
<OrderLines.Item key={orderLine.id} orderLine={orderLine}>
<View>
<OrderLines.Image />
<View>
<Text>{orderLine.productVariant.product.name}</Text>
<OrderLines.Price>
{({ price, priceWithTax, currencyCode }) => (
<Price.Root
price={price}
priceWithTax={priceWithTax}
currencyCode={currencyCode}
>
<Price.Amount />
<Price.Currency />
</Price.Root>
)}
</OrderLines.Price>
{!orderCode && (
<>
<OrderLines.Quantity.Root>
<OrderLines.Quantity.Decrement>
<Text>-</Text>
</OrderLines.Quantity.Decrement>
<OrderLines.Quantity.Input />
<OrderLines.Quantity.Increment>
<Text>+</Text>
</OrderLines.Quantity.Increment>
</OrderLines.Quantity.Root>
<OrderLines.Remove>
<Text>Remove</Text>
</OrderLines.Remove>
</>
)}
</View>
</View>
</OrderLines.Item>
))}
</ScrollView>
)
}}
</OrderLines.Root>
)
}
Made with ❤️ by Haus Tech Team